python-attrs / python-attrs/cattrs
Using make_dict_structure_fn seems to break my other structure hooks
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.9.7
- Operating System: MacOS 11.4
Description
I'm registering two structure hooks which should help me transform my object into a dict and vice versa. One is renaming my field (from id to _id), while the other is transforming my pendulum DateTime into an isostring. For some reason the DateTime unstructure hook is getting lost if I define it after the Class structure hook. If I start with it, everything works.
What I Did
import cattr
import pendulum
from attr import define, field
from cattr.gen import make_dict_unstructure_fn, override, make_dict_structure_fn
from pendulum import DateTime
@define
class Car:
id: int
manufactured: DateTime
volvo = Car(id=5, manufactured=DateTime.now())
converter = cattr.Converter()
converter.register_unstructure_hook(Car, make_dict_unstructure_fn(Car, converter, id=override(rename="_id")))
converter.register_unstructure_hook(DateTime, lambda dt: dt.to_iso8601_string())
converter.register_structure_hook(Car, make_dict_structure_fn(Car, converter, id=override(rename="_id")))
converter.register_structure_hook(DateTime, lambda dt, _: pendulum.parse(dt))
print(volvo)
unstructured = converter.unstructure(volvo)
print(unstructured)
structured_again = converter.structure(unstructured, Car)
print(structured_again)
The above results in following error (note the "manufactured" field also did not get unstructured the way it should). It complains I should register a structure hook, which I actually did...:
Car(id=5, manufactured=DateTime(2022, 4, 3, 16, 22, 40, 51844, tzinfo=Timezone('Europe/Brussels')))
{'_id': 5, 'manufactured': DateTime(2022, 4, 3, 16, 22, 40, 51844, tzinfo=Timezone('Europe/Brussels'))}
Traceback (most recent call last):
...
cattr.errors.StructureHandlerNotFoundError: Unsupported type: <class 'pendulum.datetime.DateTime'>. Register a structure hook for it.
Whereas if I switch the order of the (un)structure hooks like below, everything just works:
converter.register_unstructure_hook(DateTime, lambda dt: dt.to_iso8601_string())
converter.register_unstructure_hook(Car, make_dict_unstructure_fn(Car, converter, id=override(rename="_id")))
converter.register_structure_hook(DateTime, lambda dt, _: pendulum.parse(dt))
converter.register_structure_hook(Car, make_dict_structure_fn(Car, converter, id=override(rename="_id")))
Results in ("manufactured" got unstructured correctly in an iso8601 timestamp and id got renamed into _id during unstructure and vice versa):
Car(id=5, manufactured=DateTime(2022, 4, 3, 16, 25, 12, 840444, tzinfo=Timezone('Europe/Brussels')))
{'_id': 5, 'manufactured': '2022-04-03T16:25:12.840444+02:00'}
Car(id=5, manufactured=DateTime(2022, 4, 3, 16, 25, 12, 840444, tzinfo=Timezone('+02:00')))
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 by reproducing the issue with make_dict_unstructure_fn, make_dict_structure_fn, override, and the registration order shown in the report. Trace how the generated Car hooks resolve the DateTime field, then verify that both custom DateTime hooks remain effective regardless of registration order and that the reported round trip succeeds.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- python
- Domain
- backend
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Stale
- Clarity
- Mostly clear
- Newbie friendliness
- 45/100