Skip to content

Commit 8f7ac06

Browse files
Add frozendict support for 3.15+ (#1052)
Closes #1029 --------- Co-authored-by: Janek Nouvertné <[email protected]>
1 parent b36a4a1 commit 8f7ac06

16 files changed

Lines changed: 676 additions & 28 deletions

‎docs/api.rst‎

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -172,11 +172,12 @@ Inspect
172172
.. autoclass:: ListType
173173
.. autoclass:: SetType
174174
.. autoclass:: FrozenSetType
175+
.. autoclass:: DictType
176+
.. autoclass:: TypedDictType
177+
.. autoclass:: FrozenDictType
175178
.. autoclass:: VarTupleType
176179
.. autoclass:: TupleType
177-
.. autoclass:: DictType
178180
.. autoclass:: Field
179-
.. autoclass:: TypedDictType
180181
.. autoclass:: NamedTupleType
181182
.. autoclass:: DataclassType
182183
.. autoclass:: StructType

‎docs/perf-tips.rst‎

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -288,6 +288,53 @@ average another ~2x speedup for decoding (and ~1.5x speedup for encoding).
288288
Example(my_first_field="some string", my_second_field=2)
289289
290290
291+
Think about type conversion
292+
---------------------------
293+
294+
When converting raw data into Python types, the internal machinery
295+
will treat different datastructures differently.
296+
Some type conversions are faster than others.
297+
298+
For example, this model:
299+
300+
.. code-block:: python
301+
302+
class Example(msgspec.Struct):
303+
items: frozendict[str, int] # requires Python3.15+ to be used
304+
305+
msg = b'{"items": {"pen": 1, "book": 2}}'
306+
msgspec.json.decode(msg, type=Example)
307+
# Example(items=frozendict({"pen": 1, "book": 2}))
308+
309+
As ``frozendict`` does not allow adding items one at a time,
310+
``msgspec`` will first parse ``items`` as a regular :class:`dict`,
311+
and will then convert it to ``frozendict``, which results in the
312+
total decoding operation having ``O(n*2)`` time complexity.
313+
Which might be slow on big dictionaries and consume more memory.
314+
Regular :class:`dict` would be more efficient to use.
315+
316+
The same can be said for :class:`tuple` vs :class:`list`:
317+
318+
.. code-block:: python
319+
320+
>>> class Example(msgspec.Struct):
321+
... items: tuple[str, ...]
322+
323+
>>> msg = b'{"items": ["pen", "book"]}'
324+
325+
>>> msgspec.json.decode(msg, type=Example)
326+
Example(items=("pen", "book"))
327+
328+
We would first create a ``list`` object and then convert
329+
it to variable-sized ``tuple``,
330+
using double the memory and ``O(n*2)`` time to do that.
331+
This is true for all conversions, that require an intermediate representation.
332+
333+
To achieve the best performance,
334+
use collection types that can be constructed natively:
335+
``list``, ``set``, ``frozenset``, fixed-sized ``tuple``, and ``dict``.
336+
337+
291338
.. _JSON: https://json.org
292339
.. _MessagePack: https://msgpack.org
293340
.. _line-delimited JSON: https://en.wikipedia.org/wiki/JSON_streaming#Line-delimited_JSON

‎docs/supported-types.rst‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@ Most combinations of the following types are supported (with a few restrictions)
1818
- `dict` / `typing.Dict`
1919
- `set` / `typing.Set`
2020
- `frozenset` / `typing.FrozenSet`
21+
- `frozendict <https://docs.python.org/3.15/library/stdtypes.html#frozendict>`__
22+
for Python 3.15+
2123

2224
**Msgspec types**
2325

‎docs/usage.rst‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -183,8 +183,8 @@ representation.
183183
types: `bytes` / `bytearray` / `memoryview` to base64 string,
184184
`datetime.datetime` / `datetime.date` / `datetime.time` /
185185
`datetime.timedelta` to ISO 8601 string, `uuid.UUID` and
186-
`decimal.Decimal` to string, `set` / `frozenset` to `list`, `enum.Enum`
187-
to its member value.
186+
`decimal.Decimal` to string, `set` / `frozenset` to `list`,
187+
``frozendict`` to `dict`, `enum.Enum` to its member value.
188188
- Optional ``enc_hook``, ``str_keys``, ``order``, and ``builtin_types``
189189
kwargs for tuning the output to the wrapping protocol.
190190

0 commit comments

Comments
 (0)