python-attrs / python-attrs/cattrs
Regression of unstructuring typing.Any based on runtime types
Nobody has claimed this yet.
- Dominant language
- Python
- Stars
- 1.1k
- Forks
- 159
- Avg merge
- 12h 21m
- Merged PRs (30d)
- 6
Description
- cattrs version: 22.2.0
- Python version: 3.9
- Operating System: macOS / Linux
Description
There is a regression in unstructuring of statically typed Any field in versions published after 1.1.2. It returns the value as-is, regardless of whether the runtime type is an attrs class.
What I Did
Using the following code:
try:
from attrs import define
try:
from cattrs.converters import BaseConverter, GenConverter
except ImportError:
from cattrs.converters import Converter as BaseConverter
from cattrs.converters import GenConverter
except ImportError:
from attr import define
from cattr.converters import Converter as BaseConverter, GenConverter
bc = BaseConverter()
gc = GenConverter()
@define
class Container:
many: ty.List[ty.Any]
one: ty.Any
@define
class Thing:
field: int
c = Container(many=[Thing(field=1)], one=Thing(field=2))
print("BaseConverter", bc.unstructure(c))
print("GenConverter", gc.unstructure(c))
I ran the following:
cattrs 1.1.2
List[Any] and Any get unstructured fine.
❯ pip install cattrs==1.1.2 --force-reinstall &> /dev/null && pip show cattrs | grep Version && python thing.py
Version: 1.1.2
BaseConverter {'many': [{'field': 1}], 'one': {'field': 2}}
GenConverter {'many': [{'field': 1}], 'one': {'field': 2}}
cattrs 1.2.0
List[Any] gets unstructured but not Any
❯ pip install cattrs==1.2.0 --force-reinstall &> /dev/null && pip show cattrs | grep Version && python thing.py
Version: 1.2.0
BaseConverter {'many': [{'field': 1}], 'one': Thing(field=2)}
GenConverter {'many': [{'field': 1}], 'one': Thing(field=2)}
cattrs 1.4.0 onwards
GenConverter no longer unstructures Any fields
BaseConverter retained the inconsistent 1.2.0 behavior
❯ pip install cattrs==1.4.0 --force-reinstall &> /dev/null && pip show cattrs | grep Version && python thing.py
Version: 1.4.0
BaseConverter {'many': [{'field': 1}], 'one': Thing(field=2)}
GenConverter {'many': [Thing(field=1)], 'one': Thing(field=2)}
The behavior then stays consistent from 1.4.0 onward. We are still slowly updating our application code to use our internal libraries which are now using cattrs 22.2.0, which is how I came across this. We have a very specific use case where using generics would be impractical; we're just now moving from 3.7 to 3.9 and therefore can't use 3.11's variadic generics and defining a handful of TypeVars would be unsightly.
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
Reproduce the reported behavior with the Container and Thing examples using both BaseConverter and GenConverter, comparing the 1.1.2 and current outputs. Start at the converters' unstructure handling for statically typed Any fields; done means attrs instances in Any and List[Any] fields are converted consistently with the intended behavior.
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
- 35/100