python-attrs / python-attrs/cattrs
TYPE_CHECKING and init=False
Nobody has claimed this yet.
- Dominant language
- Python
- Stars
- 1.1k
- Forks
- 159
- Avg merge
- 12h 21m
- Merged PRs (30d)
- 6
Description
- cattrs version: 23.2.3
- Python version: 3.9.18
- Operating System: macOS
Description
Hi, I think I'm facing a similar situation as described in #160 but with a few subtleties that potentially motivate refining the internal type resolution of cattrs.
What I Did
Consider the following two files:
# inner.py
# --------
from attrs import define
@define
class Inner:
pass
# outer.py
# --------
from typing import TYPE_CHECKING, Optional
import cattrs
from attrs import define, field
if TYPE_CHECKING:
from inner import Inner
@define
class Outer:
inner: Optional[Inner] = field(init=False, default=None)
outer = Outer()
cattrs.unstructure(outer)
Running the latter gives NameError: name 'Inner' is not defined because the inner class is not available in outer.py.
While one could fix this by informing cattrs about the class before attempting to unstructure, I don't think it's a convenient solution in my case because I don't even see a reason why it should be necessary in the first place: the corresponding attribute is init=False and with the default settings where such fields are ignored, cattrs shouldn't even need to bother about the field at all ... assuming of course that I do not overlook some other reason.
The motivation for my example: in my case, Inner relies on some heavy external dependencies (such as torch) and many execution paths of my code don't actually require loading it, so I instead use lazy-loading for improved startup time. That said, I wouldn't want to load it just to satisfy cattrs to perform an unstructuring operation that actually does not require the class due to init=False.
For now, I can simply remove that type annotation, which solves the problem, but this is of course suboptimal. Any thoughts would be highly appreciated.
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start by running the two-file reproduction in inner.py and outer.py, especially the cattrs.unstructure(outer) call. Read how cattrs resolves field annotations and handles init=False fields under its default settings. Done means the example no longer raises NameError without importing Inner, while the init=False field remains omitted from the unstructured result.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- python
- Domain
- backend
- Issue type
- Bug
- Difficulty
- 3/5
- Estimated time
- 1-2 days
- Activity status
- Stale
- Clarity
- Mostly clear
- Newbie friendliness
- 45/100