Converters In-Depth#

Converters are registries of rules cattrs uses to perform function composition and generate its un/structuring functions.

Currently, a converter contains the following state:

  • a registry of unstructure hooks, backed by a singledispatch and a FunctionDispatch, wrapped in a cache.

  • a registry of structure hooks, backed by a different singledispatch and FunctionDispatch, and a different cache.

  • a detailed_validation flag (defaulting to true), determining whether the converter uses detailed validation.

  • a reference to an unstructuring strategy (either AS_DICT or AS_TUPLE).

  • a prefer_attrib_converters flag (defaulting to false), determining whether to favor attrs converters over normal cattrs machinery when structuring attrs classes

  • a dict_factory callable, a legacy parameter used for creating dicts when dumping attrs classes using AS_DICT.

Converters may be cloned using the Converter.copy() method. The new copy may be changed through the copy arguments, but will retain all manually registered hooks from the original.

Customizing Collection Unstructuring#

Important

This feature is supported for Python 3.9 and later.

Tip

See Customizing Collections for a more modern and more powerful way of customizing collection handling.

Overriding collection unstructuring in a generic way can be a very useful feature. A common example is using a JSON library that doesn’t support sets, but expects lists and tuples instead.

Using ordinary unstructuring hooks for this is unwieldy due to the semantics of singledispatch; in other words, you’d need to register hooks for all specific types of set you’re using (set[int], set[float], set[str]…), which is not useful.

Function-based hooks can be used instead, but come with their own set of challenges - they’re complicated to write efficiently.

The Converter supports easy customizations of collection unstructuring using its unstruct_collection_overrides parameter. For example, to unstructure all sets into lists, use the following:

>>> from collections.abc import Set
>>> converter = cattrs.Converter(unstruct_collection_overrides={Set: list})

>>> converter.unstructure({1, 2, 3})
[1, 2, 3]

Going even further, the Converter contains heuristics to support the following Python types, in order of decreasing generality:

  • typing.Sequence, typing.MutableSequence, list, deque, tuple

  • typing.Set, frozenset, typing.MutableSet, set

  • typing.Mapping, typing.MutableMapping, dict, defaultdict, collections.OrderedDict, collections.Counter

For example, if you override the unstructure type for Sequence, but not for MutableSequence, list or tuple, the override will also affect those types. An easy way to remember the rule:

  • all MutableSequence s are Sequence s, so the override will apply

  • all list s are MutableSequence s, so the override will apply

  • all tuple s are Sequence s, so the override will apply

If, however, you override only MutableSequence, fields annotated as Sequence will not be affected (since not all sequences are mutable sequences), and fields annotated as tuples will not be affected (since tuples are not mutable sequences in the first place).

Similar logic applies to the set and mapping hierarchies.

Make sure you’re using the types from collections.abc on Python 3.9+, and from typing on older Python versions.

Fallback Hook Factories#

By default, when a converter cannot handle a type it will:

These behaviors can be customized by providing custom hook factories when creating the converter.

>>> from pickle import dumps

>>> class Unsupported:
...     """An artisinal (non-attrs) class, unsupported by default."""

>>> converter = Converter(unstructure_fallback_factory=lambda _: dumps)
>>> instance = Unsupported()
>>> converter.unstructure(instance)
b'\x80\x04\x95\x18\x00\x00\x00\x00\x00\x00\x00\x8c\x08__main__\x94\x8c\x04Test\x94\x93\x94)\x81\x94.'

This also enables converters to be chained.

>>> parent = Converter()

>>> child = Converter(
...     unstructure_fallback_factory=parent.get_unstructure_hook,
...     structure_fallback_factory=parent.get_structure_hook,
... )

New in version 23.2.0.

cattrs.Converter#

The Converter is a converter variant that automatically generates, compiles and caches specialized structuring and unstructuring hooks for attrs classes, dataclasses and TypedDicts.

Converter differs from the cattrs.BaseConverter in the following ways:

  • structuring and unstructuring of attrs classes is slower the first time, but faster every subsequent time

  • structuring and unstructuring can be customized

  • support for attrs classes with PEP563 (postponed) annotations

  • support for generic attrs classes

  • support for easy overriding collection unstructuring

The Converter used to be called GenConverter, and that alias is still present for backwards compatibility.

cattrs.BaseConverter#

The BaseConverter is a simpler and slower converter variant. It does no code generation, so it may be faster on first-use which can be useful in specific cases, like CLI applications where startup time is more important than throughput.