cattrs icon indicating copy to clipboard operation
cattrs copied to clipboard

Importing `annotations` from `__future__` causes a StructureHandlerNotFoundError

Open stephen-h-d opened this issue 3 years ago • 4 comments

  • cattrs version: 22.1.0
  • Python version: 3.10.1
  • Operating System: Ubuntu

Description

Importing annotations from __future__ causes a StructureHandlerNotFoundError, whereas my registered structure function works fine when I do not import annotations from __future__.

What I Did

I ran a Python script with the following contents:

# from __future__ import annotations

from typing import Any

import attr
from cattrs import Converter


@attr.frozen
class C:
    a: int


def structure_int(val: str, type_: Any) -> int:
    return int(val)


c = Converter()
c.register_structure_hook(int, structure_int)

result = c.structure_attrs_fromtuple(["1"], C)
print(result)

When the first line is commented out, it works fine and prints the following as expected:

C(a=1)

When the first line is not commented out, it causes the following error:

Traceback (most recent call last):
  File ".../.config/JetBrains/PyCharmCE2022.1/scratches/scratch_7.py", line 21, in <module>
    result = c.structure_attrs_fromtuple(["1"], C)
  File ".../.pyenv/versions/edgar-3.10/lib/python3.10/site-packages/cattrs/converters.py", line 403, in structure_attrs_fromtuple
    converted = self._structure_attribute(a, value)
  File ".../.pyenv/versions/edgar-3.10/lib/python3.10/site-packages/cattrs/converters.py", line 422, in _structure_attribute
    return self._structure_func.dispatch(type_)(value, type_)
  File ".../.pyenv/versions/edgar-3.10/lib/python3.10/site-packages/cattrs/converters.py", line 344, in _structure_error
    raise StructureHandlerNotFoundError(msg, type_=cl)
cattrs.errors.StructureHandlerNotFoundError: Unsupported type: 'int'. Register a structure hook for it.

stephen-h-d avatar Aug 09 '22 13:08 stephen-h-d

Ah, the tuple un/structuring functions aren't optimized yet. Until someone contributes this, you'll need to call attrs.resolve_types on your classes manually (needs to be done only once) if you're using from __future__ import annotations. The dict handling stuff does this automatically. Sorry :/

Tinche avatar Aug 09 '22 13:08 Tinche

Hmm, that doesn't seem to work for me. I added attr.resolve_types(int, globals()) to the script above, and I got this exception: attr.exceptions.NotAnAttrsClassError: <class 'int'> is not an attrs-decorated class. That makes sense, of course, because int is a primitive. Is there a different workaround for primitives?

stephen-h-d avatar Aug 09 '22 13:08 stephen-h-d

You're structuring C, so call resolve_types(C).

Tinche avatar Aug 09 '22 14:08 Tinche

Ah, I see. That worked. Thanks!

stephen-h-d avatar Aug 09 '22 14:08 stephen-h-d