Skip to content

Commit 7ea91cd

Browse files
committed
tomlkit: handle native date and datetime objects
1 parent 1a94abf commit 7ea91cd

4 files changed

Lines changed: 37 additions & 3 deletions

File tree

HISTORY.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,9 @@ Our backwards-compatibility policy can be found [here](https://github.com/python
2323
([##699](https://github.com/python-attrs/cattrs/issues/699))
2424
- _cattrs_ now tracks performance using [codspeed](https://codspeed.io/python-attrs/cattrs).
2525
([#703](https://github.com/python-attrs/cattrs/pull/703))
26+
- The {mod}`tomlkit <cattrs.preconf.tomlkit>` preconf converter now properly handles `date` and `datetime` objects when structuring.
27+
([#707](https://github.com/python-attrs/cattrs/issues/707))
28+
2629

2730
## 25.3.0 (2025-10-07)
2831

docs/preconf.md

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -202,4 +202,6 @@ Found at {mod}`cattrs.preconf.tomlkit`.
202202

203203
Bytes are serialized as base 85 strings. Sets are serialized as lists, and deserialized back into sets.
204204
Tuples are serialized as lists, and deserialized back into tuples.
205-
_tomlkit_ only supports mappings with string keys so mappings will have their keys stringified before serialization, and destringified during deserialization. `date` s are serialized as ISO 8601 strings.
205+
_tomlkit_ only supports mappings with string keys so mappings will have their keys stringified before serialization, and destringified during deserialization.
206+
`date` s are serialized as ISO 8601 strings. `datetime` s are passed through to be unstructured by _tomlkit_ itself.
207+

src/cattrs/preconf/tomlkit.py

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -68,9 +68,13 @@ def key_handler(k: bytes):
6868
# datetime inherits from date, so identity unstructure hook used
6969
# here to prevent the date unstructure hook running.
7070
converter.register_unstructure_hook(datetime, lambda v: v)
71-
converter.register_structure_hook(datetime, validate_datetime)
71+
converter.register_structure_hook(
72+
datetime, lambda v, _: v if isinstance(v, datetime) else validate_datetime(v, _)
73+
)
7274
converter.register_unstructure_hook(date, lambda v: v.isoformat())
73-
converter.register_structure_hook(date, lambda v, _: date.fromisoformat(v))
75+
converter.register_structure_hook(
76+
date, lambda v, _: v if isinstance(v, date) else date.fromisoformat(v)
77+
)
7478
configure_union_passthrough(
7579
Union[str, String, bool, int, Integer, float, Float], converter
7680
)

tests/preconf/test_tomlkit.py

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
from datetime import date, datetime
2+
3+
from attrs import define
4+
from tomlkit import loads
5+
6+
from cattrs.preconf.tomlkit import make_converter
7+
8+
9+
@define
10+
class Event:
11+
event_date: date
12+
event_datetime: datetime
13+
14+
15+
def test_tomlkit_dates():
16+
"""Native date and datetime objects from tomlkit are properly handled."""
17+
toml_input = """
18+
event_date = 2025-12-16
19+
event_datetime = 2025-12-16T20:00:00
20+
"""
21+
converter = make_converter()
22+
parsed = loads(toml_input)
23+
structured = converter.structure(parsed, Event)
24+
assert structured.event_date == date(2025, 12, 16)
25+
assert structured.event_datetime == datetime(2025, 12, 16, 20, 0, 0)

0 commit comments

Comments
 (0)