Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
This type annotation resolution is a flawed implementation -- ideally a proper fix can come later, but for now it's worth warning about the present behavior. `dataclasses-json` does not behave correctly when using string-style annotations (a frequent tactic for annotating types that have not yet been defined at that point in the file). The core problem comes from the assumption that type annotations in a module will match `sys.modules()` -- `maybe_resolved` will frequently resolve to a different value than a typechecker would! A short example of the error ============================ `example_types.py`: ```python from dataclasses import dataclass from dataclasses_json import dataclass_json @dataclass_json @DataClass class Config: options: list["Option"] @dataclass_json @DataClass class Option: label: str ``` Expected behavior ----------------- `_decode_items` correctly identifies `Option` as coming from `example_types`: ```python >>> from example_types import Config >>> print(Config.from_dict({"options": [{"label": "repro"}]}).options) [Option(label='repro')] ``` Unexpected behavior ------------------- `_decode_items()` incorrectly identifies `"Option"` as from a third party module that is not in scope at time of annotation: `repro.py`: ```python import click.parser # Has `Option` from example_types import Config print(Config.from_dict({"options": [{"label": "repro"}]}).options) ``` ```bash $ python3.10 repro.py [{'label': 'repro'}] ``` Related fix -- truthiness ========================= The conditional `if maybe_resolved` is meant to handle the case of an attribute not being found in the module (it could basically be written as `if maybe_resolved is not None`). However, that doesn't cover the case of types that are falsy at runtime! ```python CustomNoneType = None values: list['CustomNoneType'] = [None, None] ``` We can just use `hasattr()` instead.
- Loading branch information