github-actions[bot] commented on code in PR #40747:
URL: https://github.com/apache/beam/pull/40747#discussion_r4360718614


##########
sdks/python/apache_beam/typehints/decorators.py:
##########
@@ -866,7 +867,16 @@ def getcallargs_forhints(func, *type_args, **type_kwargs):
     else:
       # Unbound: must have a default or be variadic.
       if param.annotation != param.empty:
-        bound_args[param.name] = param.annotation
+        annotation = param.annotation
+        if _contains_forward_ref(annotation):
+          # Resolve string annotations (e.g. from functools.partial-bound
+          # keywords under `from __future__ import annotations`) the same way
+          # IOTypeHints.from_callable does, so they compare equal to the
+          # resolved hints.
+          if namespaces is None:
+            namespaces = _annotation_namespaces(func)
+          annotation = _resolve_annotation(annotation, *namespaces)
+        bound_args[param.name] = annotation

Review Comment:
   **🟠 High**: `IOTypeHints.from_callable` passes the resolved parameter 
annotation through `convert_to_beam_type(param.annotation)`, whereas 
`getcallargs_forhints` assigns the raw `annotation` directly to 
`bound_args[param.name]`. This causes two issues when 
`PTransformWithSideInputs.type_check_inputs` compares `bindings` against 
`hints`:
   
   1. **Unresolvable forward references (e.g. `TYPE_CHECKING`-only imports 
under `from __future__ import annotations`):** `_resolve_annotation` falls back 
to returning the raw string when a `NameError` occurs. 
`IOTypeHints.from_callable` converts that string to `typehints.Any` via 
`convert_to_beam_type`, whereas `getcallargs_forhints` leaves a raw `str` in 
`bound_args`. If `getcallargs_forhints` populates `hints` for an optional side 
input (e.g. when `@with_input_types` only specifies the main input) and a side 
input is provided, `typehints.is_consistent_with` passes the string to 
`issubclass(sub, base)` and raises `TypeError: issubclass() arg 2 must be a 
class, a tuple of classes, or a union`.
   2. **`TypedDict` and Python 3.12 `TypeAliasType` (`type` statement) 
annotations on `functools.partial` keyword arguments:** 
`IOTypeHints.from_callable` converts `TypedDict` to `Dict[str, Any]` and 
unwraps `TypeAliasType` via `convert_to_beam_type`, while 
`getcallargs_forhints` leaves the raw `TypedDict` / `TypeAliasType` in 
`bindings`. Because `typehints.normalize()` does not convert user-module 
`TypedDict` or `TypeAliasType` objects, 
`typehints.is_consistent_with(bindings[arg], hints[arg])` returns `False` and 
raises a spurious `TypeCheckError`.
   
   Passing `annotation` through `convert_to_beam_type` here ensures 
`getcallargs_forhints` produces the exact same Beam type hints as 
`IOTypeHints.from_callable`.
   
   ```suggestion
           bound_args[param.name] = convert_to_beam_type(annotation)
   ```



-- 
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