python-attrs / python-attrs/cattrs
Union with subclasses
Nobody has claimed this yet.
- Dominant language
- Python
- Stars
- 1.1k
- Forks
- 159
- Avg merge
- 12h 21m
- Merged PRs (30d)
- 6
Description
- cattrs version: 24.1.2
- Python version: 3.11
- Operating System: Linux/MacOSX
Description
I am not sure how to handle union with subclass.
What I Did
import attr
import cattr
from cattrs.strategies import configure_tagged_union, include_subclasses
@attr.s(frozen=True, auto_attribs=True)
class A:
pass
@attr.s(frozen=True, auto_attribs=True)
class B:
pass
@attr.s(frozen=True, auto_attribs=True)
class B2(B):
b: int
@attr.s(frozen=True, auto_attribs=True)
class C:
x: A | B
CONVERTER = cattr.Converter()
configure_tagged_union(A | B, CONVERTER)
union_strategy = partial(configure_tagged_union, tag_name="type_name")
include_subclasses(B, CONVERTER, union_strategy=union_strategy)
if __name__ == "__main__":
instance = C(x=B2(b=1))
r = CONVERTER.unstructure(instance, unstructure_as=C)
print(r)
print(CONVERTER.structure(r, C))
Getting error as
Traceback (most recent call last):
File "..../IPython/core/interactiveshell.py", line 3577, in run_code
exec(code_obj, self.user_global_ns, self.user_ns)
File "<ipython-input-1-8e14e71c7dee>", line 1, in <module>
CONVERTER.unstructure(instance, unstructure_as=C)
File ".../python3.11/site-packages/cattrs/converters.py", line 300, in unstructure
return self._unstructure_func.dispatch(
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "<cattrs generated unstructure __main__.C>", line 3, in unstructure_C
'x': __c_unstr_x(instance.x),
^^^^^^^^^^^^^^^^^^^^^^^
File ".../python3.11/site-packages/cattrs/strategies/_unions.py", line 82, in unstructure_tagged_union
res = _exact_cl_unstruct_hooks[val.__class__](val)
~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^
KeyError: <class '__main__.B2'>
^CTraceback (most recent call last):
File ".../example.py", line 99, in <module>
r = CONVERTER.unstruct
My understanding is that configure_tagged_union does not register all the hooks for subclasses. I wonder what is the right/best way to workaround it?
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 example with cattrs 24.1.2 and inspect cattrs/strategies/_unions.py, especially configure_tagged_union, unstructure_tagged_union, and include_subclasses. Check how hooks are registered for B and B2, then define completion as structuring and unstructuring the C instance without the reported KeyError and confirming the round trip behavior.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- python
- Domain
- backend
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Stale
- Clarity
- Mostly clear
- Newbie friendliness
- 38/100