(Possibly related to #410, but filing this separate issue to confirm and to consider documentation improvements, if so.)
The following simple reproducer will result in an error on Python 3.13.3 (latest stable CPython as of this writing) and earlier versions:
from __future__ import annotations
import dataclasses as dcls
import inspect
# import typing as typ
import typing_extensions as typ
@dcls.dataclass
class Foo:
y: int
x: typ.ClassVar[ int ] = 1
print( Foo.__init__.__annotations__ )
print( inspect.get_annotations( Foo.__init__, eval_str = True ) )
print( typ.get_type_hints( Foo.__init__ ) )
The error is:
$ hatch run python bugs/dcls-classvar-hints.py
{'y': 'int', 'x': 'typ.ClassVar[int]', 'return': None}
{'y': <class 'int'>, 'x': typing.ClassVar[int], 'return': None}
Traceback (most recent call last):
File "/home/me/src/somepkg/bugs/dcls-classvar-hints.py", line 17, in <module>
print( typ.get_type_hints( Foo.__init__ ) )
File "/home/me/.local/share/hatch/env/virtual/somepkg/QPsnosgX/dynadoc/lib/python3.10/site-packages/typing_extensions.py", line 1315, in get_type_hints
hint = typing.get_type_hints(
File "/usr/lib/python3.10/typing.py", line 1871, in get_type_hints
value = _eval_type(value, globalns, localns)
File "/usr/lib/python3.10/typing.py", line 327, in _eval_type
return t._evaluate(globalns, localns, recursive_guard)
File "/usr/lib/python3.10/typing.py", line 693, in _evaluate
type_ = _type_check(
File "/usr/lib/python3.10/typing.py", line 167, in _type_check
raise TypeError(f"{arg} is not valid as type argument")
TypeError: typing.ClassVar[int] is not valid as type argument
Switching the import from typing_extensions to typing causes get_type_hints to work correctly (on both Python 3.10.12 and Python 3.13.3.):
$ hatch run python bugs/dcls-classvar-hints.py
{'y': 'int', 'return': None}
{'y': <class 'int'>, 'return': None}
{'y': <class 'int'>, 'return': <class 'NoneType'>}
(Note the absence of the ClassVar annotation. This suggests that we possibly have a toxic interaction with the dataclasses.dataclass decorator in the mix.)
Likewise, removing the from __future__ import annotations and using typing_extensions.get_type_hints also works correctly:
$ hatch run python bugs/dcls-classvar-hints.py
{'y': <class 'int'>, 'return': None}
{'y': <class 'int'>, 'return': None}
{'y': <class 'int'>, 'return': <class 'NoneType'>}
And, inspect.get_annotations works correctly in all cases. But, I would prefer to use get_type_hints as it automatically handles MRO traversal and annotation merging for classes. I have been using typing_extensions rather than typing with the understanding that typing_extensions is providing a forward-compatibility layer. The forward-compatibility assumption is violated in this case.
(Possibly related to #410, but filing this separate issue to confirm and to consider documentation improvements, if so.)
The following simple reproducer will result in an error on Python 3.13.3 (latest stable CPython as of this writing) and earlier versions:
The error is:
Switching the import from
typing_extensionstotypingcausesget_type_hintsto work correctly (on both Python 3.10.12 and Python 3.13.3.):(Note the absence of the
ClassVarannotation. This suggests that we possibly have a toxic interaction with thedataclasses.dataclassdecorator in the mix.)Likewise, removing the
from __future__ import annotationsand usingtyping_extensions.get_type_hintsalso works correctly:And,
inspect.get_annotationsworks correctly in all cases. But, I would prefer to useget_type_hintsas it automatically handles MRO traversal and annotation merging for classes. I have been usingtyping_extensionsrather thantypingwith the understanding thattyping_extensionsis providing a forward-compatibility layer. The forward-compatibility assumption is violated in this case.