kaxil opened a new pull request, #74759:
URL: https://github.com/apache/airflow/pull/74759

   A `HookToolset` method with a `datetime` parameter, such as 
`S3Hook.list_keys(from_datetime=...)`, was handed the string the model sent, so 
the hook failed comparing it and the task failed with it:
   
   ```
   TypeError: '<=' not supported between instances of 'datetime.datetime' and 
'str'
   ```
   
   The existing `HookToolset` example exposes `list_keys`, and this came up in 
a real run of the example in #74736. A `datetime` or `datetime | None` 
parameter is now offered to the model as `{"type": "string", "format": 
"date-time"}`, with a description asking for ISO 8601 with a UTC offset, and 
the value is parsed into a timezone-aware `datetime` before the method is 
called. A value with no offset, or one that does not parse, is sent back to the 
model as a retry. That check runs while the call's arguments are validated, so 
an approval gate is never asked about a call that cannot run.
   
   A real `S3Hook.list_keys` on a moto bucket, driven by a scripted model, 
fails on the first call without this change. With it:
   
   ```
   call    {'prefix': '2026/09/', 'from_datetime': '2000-01-01T00:00:00'}
   retry   Parameter 'from_datetime' must be an ISO 8601 date-time with a UTC 
offset: '2000-01-01T00:00:00' has no UTC offset.
   call    {'prefix': '2026/09/', 'from_datetime': '2000-01-01T00:00:00Z'}
   return  ["2026/09/a.csv", "2026/09/b.csv"]
   call    {'prefix': '2026/09/', 'from_datetime': '2099-01-01T00:00:00+00:00'}
   return  []
   ```
   
   ## Design rationale
   
   **A naive value is refused, not read as UTC.** Hooks disagree about what one 
means: `S3Hook.list_keys` and `GCSHook.list_by_timespan` raise `TypeError` 
comparing it with an aware time, while `GCSHook.is_updated_after` treats it as 
UTC. The `date-time` format already asks for an offset, so a model that follows 
the schema sends one, and one that does not is corrected in a single retry 
instead of the toolset picking a timezone for it.
   
   **The `bytes` handling is now a table that `datetime` joins.** #70433 gave 
`bytes` parameters a detection rule, a description note and a decoder that also 
runs in the args validator. `datetime` needs the same three things, so both are 
entries in `_STRING_ENCODINGS` rather than two parallel code paths. As for 
`bytes`, only `T` and `T | None` are decoded; a `datetime` inside a list or a 
wider union is passed through as before, and is not advertised as `date-time` 
either. The parsed value is not kept in the validated arguments, so what the 
durable journal fingerprints stays JSON.
   
   **Why not a pydantic `TypeAdapter` per parameter.** It would cover 
`timedelta`, `UUID` and the rest in one go, but it cannot build a schema for 
the arbitrary classes hook signatures use (it raises 
`PydanticSchemaGenerationError`, so each parameter would need a fallback), it 
accepts epoch numbers for an aware datetime, and its JSON `bytes` are UTF-8 
rather than base64. The table changes only the parameters it names. `timedelta` 
parameters, such as `execution_timeout` of `DatabricksSqlHook.run`, are still 
passed through unconverted.
   


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]

Reply via email to