Skip to content

typing.get_type_hints() raises on invalid types only if they're wrapped in a ForwardRef #133959

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
JelleZijlstra opened this issue May 13, 2025 · 0 comments · Fixed by #133961
Closed
Labels
3.13 bugs and security fixes 3.14 bugs and security fixes 3.15 new features, bugs and security fixes stdlib Python modules in the Lib dir topic-typing type-bug An unexpected behavior, bug, or error

Comments

@JelleZijlstra
Copy link
Member

JelleZijlstra commented May 13, 2025

>>> import typing
>>> def f(x: typing.ClassVar[int]): pass
... 
>>> typing.get_type_hints(f)
{'x': typing.ClassVar[int]}
>>> def f(x: "typing.ClassVar[int]"): pass
... 
>>> typing.get_type_hints(f)
Traceback (most recent call last):
  File "<python-input-4>", line 1, in <module>
    typing.get_type_hints(f)
    ~~~~~~~~~~~~~~~~~~~~~^^^
  File "/Users/jelle/py/cpython/Lib/typing.py", line 2390, in get_type_hints
    hints[name] = _eval_type(value, globalns, localns, type_params, format=format, owner=obj)
                  ~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/jelle/py/cpython/Lib/typing.py", line 448, in _eval_type
    return evaluate_forward_ref(t, globals=globalns, locals=localns,
                                type_params=type_params, owner=owner,
                                _recursive_guard=recursive_guard, format=format)
  File "/Users/jelle/py/cpython/Lib/typing.py", line 993, in evaluate_forward_ref
    type_ = _type_check(
        value,
    ...<2 lines>...
        allow_special_forms=forward_ref.__forward_is_class__,
    )
  File "/Users/jelle/py/cpython/Lib/typing.py", line 204, in _type_check
    raise TypeError(f"{arg} is not valid as type argument")
TypeError: typing.ClassVar[int] is not valid as type argument

(On main but also reproduced on 3.13.)

This seems inconsistent and I don't think it's helpful for users. We should either raise in both cases or neither. I prefer to not raise in either case, because it's less disruptive for callers (they already have to deal with ClassVar etc. potentially appearing in annotations), and provides more information.

@JelleZijlstra JelleZijlstra added topic-typing type-bug An unexpected behavior, bug, or error 3.13 bugs and security fixes 3.14 bugs and security fixes 3.15 new features, bugs and security fixes labels May 13, 2025
JelleZijlstra added a commit to JelleZijlstra/cpython that referenced this issue May 13, 2025
As explained in python#133960, this removes most of the behavior differences with ForwardRef.evaluate.
The remaining difference is about recursive evaluation of forwardrefs; this is practically useful
in cases where an annotation refers to a type alias that itself is string-valued.

This also improves several edge cases that were previously not handled optimally. For example,
the function now takes advantage of the partial evaluation behavior of ForwardRef.evaluate() to
evaluate more ForwardRefs in the FORWARDREF format.

This also fixes python#133959 as a side effect, because the buggy behavior in python#133959 derives from
evaluate_forward_ref().
@picnixz picnixz added the stdlib Python modules in the Lib dir label May 15, 2025
JelleZijlstra added a commit that referenced this issue May 25, 2025
As explained in #133960, this removes most of the behavior differences with ForwardRef.evaluate.
The remaining difference is about recursive evaluation of forwardrefs; this is practically useful
in cases where an annotation refers to a type alias that itself is string-valued.

This also improves several edge cases that were previously not handled optimally. For example,
the function now takes advantage of the partial evaluation behavior of ForwardRef.evaluate() to
evaluate more ForwardRefs in the FORWARDREF format.

This also fixes #133959 as a side effect, because the buggy behavior in #133959 derives from
evaluate_forward_ref().
miss-islington pushed a commit to miss-islington/cpython that referenced this issue May 25, 2025
As explained in pythonGH-133960, this removes most of the behavior differences with ForwardRef.evaluate.
The remaining difference is about recursive evaluation of forwardrefs; this is practically useful
in cases where an annotation refers to a type alias that itself is string-valued.

This also improves several edge cases that were previously not handled optimally. For example,
the function now takes advantage of the partial evaluation behavior of ForwardRef.evaluate() to
evaluate more ForwardRefs in the FORWARDREF format.

This also fixes pythonGH-133959 as a side effect, because the buggy behavior in pythonGH-133959 derives from
evaluate_forward_ref().
(cherry picked from commit 57fef27)

Co-authored-by: Jelle Zijlstra <jelle.zijlstra@gmail.com>
JelleZijlstra added a commit that referenced this issue May 25, 2025
…34663)

gh-133960: Improve typing.evaluate_forward_ref (GH-133961)

As explained in GH-133960, this removes most of the behavior differences with ForwardRef.evaluate.
The remaining difference is about recursive evaluation of forwardrefs; this is practically useful
in cases where an annotation refers to a type alias that itself is string-valued.

This also improves several edge cases that were previously not handled optimally. For example,
the function now takes advantage of the partial evaluation behavior of ForwardRef.evaluate() to
evaluate more ForwardRefs in the FORWARDREF format.

This also fixes GH-133959 as a side effect, because the buggy behavior in GH-133959 derives from
evaluate_forward_ref().
(cherry picked from commit 57fef27)

Co-authored-by: Jelle Zijlstra <jelle.zijlstra@gmail.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
3.13 bugs and security fixes 3.14 bugs and security fixes 3.15 new features, bugs and security fixes stdlib Python modules in the Lib dir topic-typing type-bug An unexpected behavior, bug, or error
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants