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_validationflag (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_convertersflag (defaulting to false), determining whether to favor attrs converters over normal cattrs machinery when structuring attrs classesa
dict_factorycallable, a legacy parameter used for creatingdictswhen dumping attrs classes usingAS_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¶
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,tupletyping.Set,frozenset,typing.MutableSet,settyping.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
MutableSequences areSequences, so the override will applyall
lists areMutableSequences, so the override will applyall
tuples areSequences, 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:
when unstructuring, pass the value through unchanged
when structuring, raise a
cattrs.errors.StructureHandlerNotFoundErrorasking the user to add configuration
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,
... )
Added 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.