lidatong / dataclasses-json

Easily serialize Data Classes to and from JSON
MIT License
1.34k stars 150 forks source link

[BUG] Importing types in `TYPE_CHECKING` causes `NameError` #533

Open bvle opened 4 weeks ago

bvle commented 4 weeks ago

Description

Whenever I use .from_dict() (or .from_json()) it errors out with a NameError, saying that the types haven't been defined, even though it is defined within the TYPE_CHECKING block.

Traceback (most recent call last):
  File "/home/bvl/dev/dataclasses_json_bug/main.py", line 16, in <module>
    x = Something.from_dict({"thing": 123})
  File "/home/bvl/dev/dataclasses_json_bug/.venv/lib/python3.14/site-packages/dataclasses_json/api.py", line 70, in from_dict
    return _decode_dataclass(cls, kvs, infer_missing)
  File "/home/bvl/dev/dataclasses_json_bug/.venv/lib/python3.14/site-packages/dataclasses_json/core.py", line 166, in _decode_dataclass
    types = get_type_hints(cls)
  File "/home/bvl/.pyenv/versions/3.14-dev/lib/python3.14/typing.py", line 2432, in get_type_hints
    value = _eval_type(value, base_globals, base_locals, base.__type_params__)
  File "/home/bvl/.pyenv/versions/3.14-dev/lib/python3.14/typing.py", line 473, in _eval_type
    return t._evaluate(globalns, localns, type_params, recursive_guard=recursive_guard)
           ~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/bvl/.pyenv/versions/3.14-dev/lib/python3.14/typing.py", line 1071, in _evaluate
    eval(self.__forward_code__, globalns, locals_to_pass),
    ~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "<string>", line 1, in <module>
NameError: name 'Any' is not defined. Did you mean: 'any'?

Looks like the root cause is with typing.get_type_hints(), which has already been reported, but not touched since 2022: https://bugs.python.org/issue43463

Code snippet that reproduces the issue

from dataclasses import dataclass
from typing import TYPE_CHECKING

from dataclasses_json import dataclass_json

if TYPE_CHECKING:
    from typing import Any

@dataclass_json
@dataclass
class Something:
    thing: "Any"

x = Something.from_dict({"thing": 123})
print(x)

Describe the results you expected

Everything imported in the TYPE_CHECKING block should be imported when needed, as with .from_dict().

From the code snippet above, the expected output is:

Something(thing=123)

Python version you are using

Python 3.14.0a0

Environment description

dataclasses-json==0.6.6 marshmallow==3.21.3 mypy-extensions==1.0.0 packaging==24.0 typing-inspect==0.9.0 typing_extensions==4.12.1

george-zubrienko commented 2 weeks ago

@bvle alpha version is not something we'll look at right now. Does this reproduce on 3.9-3.12?

bvle commented 1 week ago

Newer versions of Python tend to give better errors messages, so that's why I used Python 3.14. I was also able to reproduce the issue in: