cattrs icon indicating copy to clipboard operation
cattrs copied to clipboard

Custom unstructure function is not called when a union type is wrapped in generic types multiple times

Open yukw777 opened this issue 1 year ago • 3 comments

  • cattrs version: 22.2.0
  • Python version: 3.9
  • Operating System: Ubuntu 20.04

Description

When you wrap a union type multiple times, e.g., Optional[list[Union[A, B]]], the custom unstructure function on the union type is not called. I believe this is related to https://github.com/python-attrs/cattrs/issues/129.

What I Did

import attrs
import cattrs

from typing import Optional, Union

c = cattrs.Converter()


@attrs.define
class A:
    a: int


@attrs.define
class B:
    a: int


@attrs.define
class C:
    f: Optional[list[Union[A, B]]]


c.register_unstructure_hook(
    Union[A, B],
    lambda o: {"_type": o.__class__.__name__, **c.unstructure(o)},
)
c.register_structure_hook(
    Union[A, B], lambda o, t: c.structure(o, A if o["_type"] == "A" else B)
)

inst = C([A(1), B(2)])
unstructured = c.unstructure(inst)
assert unstructured["f"][0]["_type"] == "A"
assert unstructured["f"][1]["_type"] == "B"

assert c.structure(unstructured, C) == inst

You should get the following error:

❯ python reproduce.py 
Traceback (most recent call last):
  File "/home/peter/programming/seagull/reproduce.py", line 34, in <module>
    assert unstructured["f"][0]["_type"] == "A"
KeyError: '_type'

yukw777 avatar Mar 06 '23 01:03 yukw777

Hm, you're right. The unstructure path for unions is too simple, so it ends up being equivalent to just list, instead of list[A|B]. We should fix this.

I think fixing this for arbitrary unions would be too hard (imagine a list[A|B] | list[A|C], it'd be too complex to determine which is it), but optionals (which are unions with None) should be high value and easy enough to detect and support.

Tinche avatar Mar 06 '23 14:03 Tinche

@Tinche just to confirm, you mean None | list[A|B] should be fixed right?

yukw777 avatar Mar 06 '23 22:03 yukw777

Yep!

Tinche avatar Mar 06 '23 22:03 Tinche