cattrs: Breaks when PEP 563 is active

  • cattrs version: All versions, as far as I can tell
  • Python version: Python 3.7
  • Operating System: Arch Linux

Description

cattr.structure breaks when PEP 563 is activated. This can be done in Python 3.7 with the new from __future__ import annotations.

In short, this defers the evaluation of type annotations. So consider this class:

@attr.s(auto_attribs=True)
class Foo:
    bar: str

Traditionally, __annotations__ looks like this:

>>> Foo.__annotations__
... {'bar': str}

but under PEP 563 (and eventually the default behaviour), it’ll look like this:

>>> Foo.__annotations__
... {'bar': 'str'}

This seems to confuse cattr and causes problems. Round-tripping the above class, we now see exceptions like this:

In [16]: cattr.structure(cattr.unstructure(Foo('Hello World')), Foo)
---------------------------------------------------------------------------
ValueError                                Traceback (most recent call last)
<ipython-input-16-1bbcc538d3df> in <module>()
----> 1 cattr.structure(cattr.unstructure(Foo('Hello World')), Foo)

~/.local/share/virtualenvs/aastrology-5jK3bc4O/lib/python3.7/site-packages/cattr/converters.py in structure(self, obj, cl)
    176         """Convert unstructured Python data structures to structured data."""
    177         # type: (Any, Type) -> Any
--> 178         return self._structure_func.dispatch(cl)(obj, cl)
    179 
    180     # Classes to Python primitives.

~/.local/share/virtualenvs/aastrology-5jK3bc4O/lib/python3.7/site-packages/cattr/converters.py in structure_attrs_fromdict(self, obj, cl)
    294             except KeyError:
    295                 continue
--> 296             conv_obj[name] = dispatch(type_)(val, type_)
    297 
    298         return cl(**conv_obj)

~/.local/share/virtualenvs/aastrology-5jK3bc4O/lib/python3.7/site-packages/cattr/converters.py in _structure_default(self, obj, cl)
    238             "it.".format(cl)
    239         )
--> 240         raise ValueError(msg)
    241 
    242     def _structure_call(self, obj, cl):

ValueError: Unsupported type: str. Register a structure hook for it.

This fix is probably to apply this logic: https://www.python.org/dev/peps/pep-0563/#resolving-type-hints-at-runtime

Here:

https://github.com/Tinche/cattrs/blob/6e90fd28af8e23c44798b5cbd98e8d5a06eb87ba/src/cattr/converters.py#L287-L296

Which I’m currently digging into.

About this issue

  • Original URL
  • State: closed
  • Created 6 years ago
  • Reactions: 8
  • Comments: 26 (15 by maintainers)

Commits related to this issue

Most upvoted comments

Today I run in the same bug, took me quite some time to figure out that the error

ValueError: Unsupported type: List[str]. Register a structure hook for it

was caused by

from __future__ import annotations

Any plans to release a new version with the suggested fix?

Not trivial to solve while keeping the current level of performance, but with 3.9 around the corner I’ll have to look into this more closely.

This is a disappointing issue. It’s my first day using cattrs and I hit this.

Oct 2019 and this bug still seems to be present. The proof of concept mentioned above is dated Sep 2018.

Is there any fix pending, or some workaround? The only thing I can think of is remove the from __future__ import annotations, but that defeats the purpose of it, and as mentioned will be the default in Python 4 (a long ways off I know, but …)

Can you try using the GenConverter? That should work

I have a proof of concept fix, but won’t be able to polish it up until tonight.

This fix will hit two birds with one stone, as I guess it also means forward declarations where broken as well, as per #13