Skip to content

Latest commit

 

History

History
112 lines (81 loc) · 4.28 KB

basics.md

File metadata and controls

112 lines (81 loc) · 4.28 KB

The Basics

All cattrs functionality is exposed through a {class}cattrs.Converter object. A global converter is provided for convenience as {data}cattrs.global_converter but more complex customizations should be performed on private instances.

Converters

The core functionality of a converter is structuring and unstructuring data by composing provided and custom handling functions, called hooks.

To create a private converter, instantiate a {class}cattrs.Converter. Converters are relatively cheap; users are encouraged to have as many as they need.

The two main methods are {meth}structure <cattrs.BaseConverter.structure> and {meth}unstructure <cattrs.BaseConverter.unstructure>, these are used to convert between structured and unstructured data.

>>> from cattrs import structure, unstructure
>>> from attrs import define

>>> @define
... class Model:
...    a: int

>>> unstructure(Model(1))
{"a": 1}
>>> structure({"a": 1}, Model)
Model(a=1)

cattrs comes with a rich library of un/structuring rules by default, but it excels at composing custom rules with built-in ones.

The simplest approach to customization is wrapping an existing hook with your own function. A base hook can be obtained from a converter and be subjected to the very rich mechanisms of Python function composition.

>>> from cattrs import get_structure_hook

>>> base_hook = get_structure_hook(Model)

>>> def my_hook(value, type):
...     # Apply any preprocessing to the value.
...     result = base_hook(value, type)
...     # Apply any postprocessing to the value.
...     return result

This new hook can be used directly or registered to a converter (the original instance, or a different one).

(cattrs.structure({}, Model) is shorthand for cattrs.get_structure_hook(Model)({}, Model).)

Another approach is to write a hook from scratch instead of wrapping an existing one. For example, we can write our own hook for the int class.

>>> def my_int_hook(value, type):
...     if not isinstance(value, int):
...         raise ValueError('not an int!')
...     return value

We can then register this hook to a converter, and any other hook converting an int will use it. Since this is an impactful change, we will switch to using a private converter.

>>> from cattrs import Converter

>>> c = Converter()

>>> c.register_structure_hook(int, my_int_hook)

Now, if we ask our new converter for a Model hook, through the ✨magic of function composition✨ that hook will use our new my_int_hook.

>>> base_hook = c.get_structure_hook(Model)
>>> base_hook({"a": "1"}, Model)
  + Exception Group Traceback (most recent call last):
    |   File "...", line 22, in <module>
    |     base_hook({"a": "1"}, Model)
    |   File "<cattrs generated structure __main__.Model>", line 9, in structure_Model
    | cattrs.errors.ClassValidationError: While structuring Model (1 sub-exception)
    +-+---------------- 1 ----------------
      | Traceback (most recent call last):
      |   File "<cattrs generated structure __main__.Model>", line 5, in structure_Model
      |   File "...", line 15, in my_int_hook
      |     raise ValueError("not an int!")
      | ValueError: not an int!
      | Structuring class Model @ attribute a
      +------------------------------------

To continue reading about customizing cattrs, see . More advanced structuring customizations are commonly called .

Global Converter

Global cattrs functions, such as {meth}cattrs.unstructure, use a single {data}global converter <cattrs.global_converter>. Changes done to this global converter, such as registering new structure and unstructure hooks, affect all code using the global functions.

The following functions implicitly use this global converter:

  • {meth}cattrs.structure
  • {meth}cattrs.unstructure
  • {meth}cattrs.get_structure_hook
  • {meth}cattrs.get_unstructure_hook
  • {meth}cattrs.structure_attrs_fromtuple
  • {meth}cattrs.structure_attrs_fromdict

Changes made to the global converter will affect the behavior of these functions.

Larger applications are strongly encouraged to create and customize different, private instances of {class}cattrs.Converter.