|
| 1 | +# The Basics |
| 2 | +```{currentmodule} cattrs |
| 3 | +``` |
| 4 | + |
| 5 | +All _cattrs_ functionality is exposed through a {class}`cattrs.Converter` object. |
| 6 | +A global converter is provided for convenience as {data}`cattrs.global_converter` but more complex customizations should be performed on private instances. |
| 7 | + |
| 8 | + |
| 9 | +## Converters |
| 10 | + |
| 11 | +The core functionality of a converter is [structuring](structuring.md) and [unstructuring](unstructuring.md) data by composing provided and [custom handling functions](customizing.md), called _hooks_. |
| 12 | + |
| 13 | +To create a private converter, instantiate a {class}`cattrs.Converter`. Converters are relatively cheap; users are encouraged to have as many as they need. |
| 14 | + |
| 15 | +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. |
| 16 | + |
| 17 | +```python |
| 18 | +>>> from cattrs import structure, unstructure |
| 19 | +>>> from attrs import define |
| 20 | + |
| 21 | +>>> @define |
| 22 | +... class Model: |
| 23 | +... a: int |
| 24 | + |
| 25 | +>>> unstructure(Model(1)) |
| 26 | +{"a": 1} |
| 27 | +>>> structure({"a": 1}, Model) |
| 28 | +Model(a=1) |
| 29 | +``` |
| 30 | + |
| 31 | +_cattrs_ comes with a rich library of un/structuring rules by default, but it excels at composing custom rules with built-in ones. |
| 32 | + |
| 33 | +The simplest approach to customization is wrapping an existing hook with your own function. |
| 34 | +A base hook can be obtained from a converter and be subjected to the very rich mechanisms of Python function composition. |
| 35 | + |
| 36 | +```python |
| 37 | +>>> from cattrs import get_structure_hook |
| 38 | + |
| 39 | +>>> base_hook = get_structure_hook(Model) |
| 40 | + |
| 41 | +>>> def my_hook(value, type): |
| 42 | +... # Apply any preprocessing to the value. |
| 43 | +... result = base_hook(value, type) |
| 44 | +... # Apply any postprocessing to the value. |
| 45 | +... return result |
| 46 | +``` |
| 47 | + |
| 48 | +This new hook can be used directly or registered to a converter (the original instance, or a different one). |
| 49 | + |
| 50 | +(`cattrs.structure({}, Model)` is shorthand for `cattrs.get_structure_hook(Model)({}, Model)`.) |
| 51 | + |
| 52 | +Another approach is to write a hook from scratch instead of wrapping an existing one. |
| 53 | +For example, we can write our own hook for the `int` class. |
| 54 | + |
| 55 | +```python |
| 56 | +>>> def my_int_hook(value, type): |
| 57 | +... if not isinstance(value, int): |
| 58 | +... raise ValueError('not an int!') |
| 59 | +... return value |
| 60 | +``` |
| 61 | + |
| 62 | +We can then register this hook to a converter, and any other hook converting an `int` will use it. |
| 63 | +Since this is an impactful change, we will switch to using a private converter. |
| 64 | + |
| 65 | +```python |
| 66 | +>>> from cattrs import Converter |
| 67 | + |
| 68 | +>>> c = Converter() |
| 69 | + |
| 70 | +>>> c.register_structure_hook(int, my_int_hook) |
| 71 | +``` |
| 72 | + |
| 73 | +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`. |
| 74 | + |
| 75 | +```python |
| 76 | +>>> base_hook = c.get_structure_hook(Model) |
| 77 | +>>> base_hook({"a": "1"}, Model) |
| 78 | + + Exception Group Traceback (most recent call last): |
| 79 | + | File "...", line 22, in <module> |
| 80 | + | base_hook({"a": "1"}, Model) |
| 81 | + | File "<cattrs generated structure __main__.Model>", line 9, in structure_Model |
| 82 | + | cattrs.errors.ClassValidationError: While structuring Model (1 sub-exception) |
| 83 | + +-+---------------- 1 ---------------- |
| 84 | + | Traceback (most recent call last): |
| 85 | + | File "<cattrs generated structure __main__.Model>", line 5, in structure_Model |
| 86 | + | File "...", line 15, in my_int_hook |
| 87 | + | raise ValueError("not an int!") |
| 88 | + | ValueError: not an int! |
| 89 | + | Structuring class Model @ attribute a |
| 90 | + +------------------------------------ |
| 91 | +``` |
| 92 | + |
| 93 | +To continue reading about customizing _cattrs_, see [](customizing.md). |
| 94 | +More advanced structuring customizations are commonly called [](strategies.md). |
| 95 | + |
| 96 | +## Global Converter |
| 97 | + |
| 98 | +Global _cattrs_ functions, such as {meth}`cattrs.unstructure`, use a single {data}`global converter <cattrs.global_converter>`. |
| 99 | +Changes done to this global converter, such as registering new structure and unstructure hooks, affect all code using the global functions. |
| 100 | + |
| 101 | +The following functions implicitly use this global converter: |
| 102 | + |
| 103 | +- {meth}`cattrs.structure` |
| 104 | +- {meth}`cattrs.unstructure` |
| 105 | +- {meth}`cattrs.get_structure_hook` |
| 106 | +- {meth}`cattrs.get_unstructure_hook` |
| 107 | +- {meth}`cattrs.structure_attrs_fromtuple` |
| 108 | +- {meth}`cattrs.structure_attrs_fromdict` |
| 109 | + |
| 110 | +Changes made to the global converter will affect the behavior of these functions. |
| 111 | + |
| 112 | +Larger applications are strongly encouraged to create and customize different, private instances of {class}`cattrs.Converter`. |
0 commit comments