python-attrs / python-attrs/cattrs
TypeError when registering ForwardRefs in python 3.10.2
Nobody has claimed this yet.
- Dominant language
- Python
- Stars
- 1.1k
- Forks
- 159
- Avg merge
- 12h 21m
- Merged PRs (30d)
- 6
Description
- cattrs version: 1.10.0
- Python version: 3.10.2
- Operating System: Ubuntu 20.04.3
Description
This is related to #201, but probably worth making a separate issue for, since it affects one of the (previously working) workarounds mentioned in that issue. Feel free to close this if you feel this is redundant with #201 or #94.
I have a converter that registers a ForwardRef. In python 3.6.x through 3.10.1, this has worked as intended. As of python 3.10.2, this is now throwing a TypeError:
TypeError: Invalid first argument to `register()`. ForwardRef('MyClass') is not a class.
Strangely, I don't see anything in the python 3.10.2 changelog that would indicate changed behavior with ForwardRef or register().
What I Did
Minimal example:
from attr import define, field
from cattr import Converter # Note: same behavior with GenConverter
from typing import ForwardRef, List
@define()
class MyClass:
history: List['MyClass'] = field(factory=list)
converter = Converter()
converter.register_structure_hook(
ForwardRef('MyClass'), lambda obj, _: converter.structure(obj, MyClass)
)
Traceback:
TypeError Traceback (most recent call last)
Input In [17], in <module>
----> 1 converter.register_structure_hook(
2 ForwardRef("MyClass"), (lambda obj, _: converter.structure(obj, MyClass))
3 )
File ~/.virtualenvs/rc-310/lib/python3.10/site-packages/cattr/converters.py:269, in Converter.register_structure_hook(self, cl, func)
267 self._structure_func.clear_cache()
268 else:
--> 269 self._structure_func.register_cls_list([(cl, func)])
File ~/.virtualenvs/rc-310/lib/python3.10/site-packages/cattr/dispatch.py:57, in MultiStrategyDispatch.register_cls_list(self, cls_and_handler, direct)
55 self._direct_dispatch[cls] = handler
56 else:
---> 57 self._single_dispatch.register(cls, handler)
58 self.clear_direct()
59 self.dispatch.cache_clear()
File ~/.pyenv/versions/3.10.2/lib/python3.10/functools.py:856, in singledispatch.<locals>.register(cls, func)
854 else:
855 if func is not None:
--> 856 raise TypeError(
857 f"Invalid first argument to `register()`. "
858 f"{cls!r} is not a class."
859 )
860 ann = getattr(cls, '__annotations__', {})
861 if not ann:
TypeError: Invalid first argument to `register()`. ForwardRef('MyClass') is not a class.
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
Start with the minimal ForwardRef example and inspect cattr/converters.py around register_structure_hook and cattr/dispatch.py around register_cls_list, as shown in the traceback. Reproduce the failure on Python 3.10.2 and compare supported Python versions. Done means ForwardRef registration works without the TypeError while existing converter behavior remains intact.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- python
- Domain
- backend
- Issue type
- Bug
- Difficulty
- 3/5
- Estimated time
- 1-2 days
- Activity status
- Active
- Clarity
- Mostly clear
- Newbie friendliness
- 64/100