cattrs icon indicating copy to clipboard operation
cattrs copied to clipboard

configure_tagged_union fails on recursive structures

Open adament opened this issue 4 months ago • 1 comments

from __future__ import annotations

from attrs import define
from cattrs import Converter
from cattrs.strategies import configure_tagged_union

@define
class Add:
    left: Expr
    right: Expr

type Expr = Add | float

conv = Converter()
configure_tagged_union(Expr, conv)
conv.unstructure(Add(2.0, Add(3.0, Add(4.0, 1.0))), Expr)

fails with

Traceback (most recent call last):
  File "C:\Code\repos\arp_strategies\risk_target\cattrs_exp.py", line 15, in <module>
    configure_tagged_union(Expr, conv)
    ~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^
  File "C:\Code\cache\rattler\cached-envs-v0\python-c8bda09852e34bf9\Lib\site-packages\cattrs\strategies\_unions.py", line 59, in configure_tagged_union
    struct_handler = converter.get_structure_hook(cl)
  File "C:\Code\cache\rattler\cached-envs-v0\python-c8bda09852e34bf9\Lib\site-packages\cattrs\converters.py", line 592, in get_structure_hook
    self._structure_func.dispatch(type)
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^
  File "C:\Code\cache\rattler\cached-envs-v0\python-c8bda09852e34bf9\Lib\site-packages\cattrs\dispatch.py", line 133, in dispatch_without_caching
    res = self._function_dispatch.dispatch(typ)
  File "C:\Code\cache\rattler\cached-envs-v0\python-c8bda09852e34bf9\Lib\site-packages\cattrs\dispatch.py", line 76, in dispatch
    return handler(typ)
  File "C:\Code\cache\rattler\cached-envs-v0\python-c8bda09852e34bf9\Lib\site-packages\cattrs\converters.py", line 1296, in gen_structure_attrs_fromdict
    return make_dict_structure_fn(
        cl,
    ...<4 lines>...
        **attrib_overrides,
    )
  File "C:\Code\cache\rattler\cached-envs-v0\python-c8bda09852e34bf9\Lib\site-packages\cattrs\gen\__init__.py", line 747, in make_dict_structure_fn
    return make_dict_structure_fn_from_attrs(
        attrs,
    ...<9 lines>...
        **kwargs,
    )
  File "C:\Code\cache\rattler\cached-envs-v0\python-c8bda09852e34bf9\Lib\site-packages\cattrs\gen\__init__.py", line 388, in make_dict_structure_fn_from_attrs
    handler = find_structure_handler(
        a, t, converter, _cattrs_prefer_attrib_converters
    )
  File "C:\Code\cache\rattler\cached-envs-v0\python-c8bda09852e34bf9\Lib\site-packages\cattrs\gen\_shared.py", line 58, in find_structure_handler
    handler = c.get_structure_hook(type, cache_result=False)
  File "C:\Code\cache\rattler\cached-envs-v0\python-c8bda09852e34bf9\Lib\site-packages\cattrs\converters.py", line 594, in get_structure_hook
    else self._structure_func.dispatch_without_caching(type)
         ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^
  File "C:\Code\cache\rattler\cached-envs-v0\python-c8bda09852e34bf9\Lib\site-packages\cattrs\dispatch.py", line 133, in dispatch_without_caching
    res = self._function_dispatch.dispatch(typ)
  File "C:\Code\cache\rattler\cached-envs-v0\python-c8bda09852e34bf9\Lib\site-packages\cattrs\dispatch.py", line 75, in dispatch
    return handler(typ, self._converter)
  File "C:\Code\cache\rattler\cached-envs-v0\python-c8bda09852e34bf9\Lib\site-packages\cattrs\typealiases.py", line 53, in type_alias_structure_factory
    res = converter.get_structure_hook(base)
  File "C:\Code\cache\rattler\cached-envs-v0\python-c8bda09852e34bf9\Lib\site-packages\cattrs\converters.py", line 592, in get_structure_hook
    self._structure_func.dispatch(type)
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^
  File "C:\Code\cache\rattler\cached-envs-v0\python-c8bda09852e34bf9\Lib\site-packages\cattrs\dispatch.py", line 134, in dispatch_without_caching
    return res if res is not None else self._fallback_factory(typ)
                                       ~~~~~~~~~~~~~~~~~~~~~~^^^^^
  File "C:\Code\cache\rattler\cached-envs-v0\python-c8bda09852e34bf9\Lib\site-packages\cattrs\converters.py", line 1050, in <lambda>
    structure_fallback_factory: HookFactory[StructureHook] = lambda t: raise_error(
                                                                       ~~~~~~~~~~~^
        None, t
        ^^^^^^^
    ),
    ^
  File "C:\Code\cache\rattler\cached-envs-v0\python-c8bda09852e34bf9\Lib\site-packages\cattrs\fns.py", line 22, in raise_error
    raise StructureHandlerNotFoundError(msg, type_=cl)
cattrs.errors.StructureHandlerNotFoundError: Unsupported type: __main__.Add | float. Register a structure hook for it.

adament avatar Aug 07 '25 13:08 adament

Confirming. Let's see if I can get this fixed before the next release.

Tinche avatar Aug 10 '25 17:08 Tinche