You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
**cattrs** is a Swiss Army knife for (un)structuring and validating data in Python.
17
17
In practice, that means it converts **unstructured dictionaries** into **proper classes** and back, while **validating** their contents.
18
18
19
-
---
20
-
21
-
Python has a rich set of powerful, easy to use, built-in **unstructured** data types like dictionaries, lists and tuples.
22
-
These data types effortlessly convert into common serialization formats like JSON, MessagePack, CBOR, YAML or TOML.
23
-
24
-
But the data that is used by your **business logic** should be **structured** into well-defined classes, since not all combinations of field names or values are valid inputs to your programs.
25
-
The more trust you can have into the structure of your data, the simpler your code can be, and the fewer edge cases you have to worry about.
19
+
<!-- end-teaser -->
26
20
27
-
When you're handed unstructured data (by your network, file system, database, ...), _cattrs_ helps to convert this data into trustworthy structured data.
28
-
When you have to convert your structured data into data types that other libraries can handle, _cattrs_ turns your classes and enumerations into dictionaries, integers and strings.
29
21
30
-
_attrs_ (and to a certain degree dataclasses) are excellent libraries for declaratively describing the structure of your data, but they're purposefully not serialization libraries.
31
-
*cattrs* is there for you the moment your `attrs.asdict(your_instance)` and `YourClass(**data)` start failing you because you need more control over the conversion process.
22
+
## Example
32
23
24
+
<!-- begin-example -->
33
25
34
-
## Examples
35
-
36
-
_cattrs_ works best with [_attrs_](https://www.attrs.org/) classes, and [dataclasses](https://docs.python.org/3/library/dataclasses.html) where simple (un-)structuring works out of the box, even for nested data:
26
+
_cattrs_ works best with [_attrs_](https://www.attrs.org/) classes, and [dataclasses](https://docs.python.org/3/library/dataclasses.html) where simple (un-)structuring works out of the box, even for nested data, without polluting your data model with serialization details:
37
27
38
28
```python
39
29
>>>from attrs import define
@@ -50,74 +40,12 @@ C(a=1, b=['x', 'y'])
50
40
51
41
```
52
42
53
-
> [!IMPORTANT]
54
-
> Note how the structuring and unstructuring details do **not** pollute your class, meaning: your data model.
55
-
> Any needs to configure the conversion are done within *cattrs* itself, not within your data model.
56
-
>
57
-
> There are popular validation libraries for Python that couple your data model with its validation and serialization rules based on, for example, web APIs.
58
-
> We think that's the wrong approach.
59
-
> Validation and serializations are concerns of the edges of your program – not the core.
60
-
> They should neither apply design pressure on your business code, nor affect the performance of your code through unnecessary validation.
61
-
> In bigger real-world code bases it's also common for data coming from multiple sources that need different validation and serialization rules.
62
-
>
63
-
> 🎶 You gotta keep 'em separated. 🎶
64
-
65
-
*cattrs* also works with the usual Python collection types like dictionaries, lists, or tuples when you want to **normalize** unstructured data data into a certain (still unstructured) shape.
66
-
For example, to convert a list of a float, an int and a string into a tuple of ints:
Finally, here's a much more complex example, involving _attrs_ classes where _cattrs_ interprets the type annotations to structure and unstructure the data correctly, including Enums and nested data structures:
43
+
<!-- end-teaser -->
44
+
<!-- end-example -->
77
45
78
-
```python
79
-
>>>from enum import unique, Enum
80
-
>>>from typing import Optional, Sequence, Union
81
-
>>>from cattrs import structure, unstructure
82
-
>>>from attrs import define, field
83
-
84
-
>>>@unique
85
-
...classCatBreed(Enum):
86
-
...SIAMESE="siamese"
87
-
...MAINE_COON="maine_coon"
88
-
...SACRED_BIRMAN="birman"
89
-
90
-
>>>@define
91
-
...classCat:
92
-
... breed: CatBreed
93
-
... names: Sequence[str]
94
-
95
-
>>>@define
96
-
...classDogMicrochip:
97
-
... chip_id = field() # Type annotations are optional, but recommended
98
-
... time_chipped: float= field()
99
-
100
-
>>>@define
101
-
...classDog:
102
-
... cuteness: int
103
-
... chip: DogMicrochip |None=None
104
-
105
-
>>> p = unstructure([Dog(cuteness=1, chip=DogMicrochip(chip_id=1, time_chipped=10.0)),
> Consider unstructured data a low-level representation that needs to be converted to structured data to be handled, and use `structure()`.
117
-
> When you're done, `unstructure()` the data to its unstructured form and pass it along to another library or module.
118
-
>
119
-
> Use [*attrs* type metadata](http://attrs.readthedocs.io/en/stable/examples.html#types) to add type metadata to attributes, so _cattrs_ will know how to structure and destructure them.
46
+
Have a look at [*Why *cattrs*?*](https://catt.rs/en/latest/why.html) for more examples!
120
47
48
+
<!-- begin-why -->
121
49
122
50
## Features
123
51
@@ -175,14 +103,7 @@ _cattrs_ is based on a few fundamental design decisions:
175
103
A foolish consistency is the hobgoblin of little minds, so these decisions can and are sometimes broken, but they have proven to be a good foundation.
176
104
177
105
178
-
## Additional documentation and talks
179
-
180
-
-[On structured and unstructured data, or the case for cattrs](https://threeofwands.com/on-structured-and-unstructured-data-or-the-case-for-cattrs/)
181
-
-[Why I use attrs instead of pydantic](https://threeofwands.com/why-i-use-attrs-instead-of-pydantic/)
Copy file name to clipboardExpand all lines: docs/customizing.md
+2-2Lines changed: 2 additions & 2 deletions
Original file line number
Diff line number
Diff line change
@@ -1,8 +1,8 @@
1
-
# Customizing Un/structuring
1
+
# Customizing (Un-)structuring
2
2
3
3
This section describes customizing the unstructuring and structuring processes in _cattrs_.
4
4
5
-
## Custom Un/structuring Hooks
5
+
## Custom (Un-)structuring Hooks
6
6
7
7
You can write your own structuring and unstructuring functions and register them for types using {meth}`Converter.register_structure_hook() <cattrs.BaseConverter.register_structure_hook>` and {meth}`Converter.register_unstructure_hook() <cattrs.BaseConverter.register_unstructure_hook>`.
8
8
This approach is the most flexible but also requires the most amount of boilerplate.
Copy file name to clipboardExpand all lines: docs/index.md
+45-9Lines changed: 45 additions & 9 deletions
Original file line number
Diff line number
Diff line change
@@ -1,11 +1,34 @@
1
+
# *cattrs*: Flexible Object Serialization and Validation
2
+
3
+
*Because validation belongs to the edges.*
4
+
5
+
---
6
+
7
+
```{include} ../README.md
8
+
:start-after: "begin-teaser -->"
9
+
:end-before: "<!-- end-teaser"
10
+
```
11
+
12
+
```{include} ../README.md
13
+
:start-after: "begin-example -->"
14
+
:end-before: "<!-- end-example"
15
+
```
16
+
17
+
---
18
+
19
+
However, *cattrs* does **much** more with a focus on **functional composition** and **not coupling** your data model to its serialization and validation rules.
20
+
21
+
To learn more on why to use *cattrs*, have a look at {doc}`why`, and if you're convinced jump right into {doc}`basics`!
Python has a rich set of powerful, easy to use, built-in **unstructured** data types like dictionaries, lists and tuples.
4
+
These data types effortlessly convert into common serialization formats like JSON, MessagePack, CBOR, YAML or TOML.
5
+
6
+
But the data that is used by your **business logic** should be **structured** into well-defined classes, since not all combinations of field names or values are valid inputs to your programs.
7
+
The more trust you can have into the structure of your data, the simpler your code can be, and the fewer edge cases you have to worry about.
8
+
9
+
When you're handed unstructured data (by your network, file system, database, ...), _cattrs_ helps to convert this data into trustworthy structured data.
10
+
When you have to convert your structured data into data types that other libraries can handle, _cattrs_ turns your classes and enumerations into dictionaries, integers and strings.
11
+
12
+
_attrs_ (and to a certain degree dataclasses) are excellent libraries for declaratively describing the structure of your data, but they're purposefully not serialization libraries.
13
+
*cattrs* is there for you the moment your `attrs.asdict(your_instance)` and `YourClass(**data)` start failing you because you need more control over the conversion process.
14
+
15
+
16
+
## Examples
17
+
18
+
```{include} ../README.md
19
+
:start-after: "begin-example -->"
20
+
:end-before: "<!-- end-example"
21
+
```
22
+
23
+
:::{important}
24
+
Note how the structuring and unstructuring details do **not** pollute your class, meaning: your data model.
25
+
Any needs to configure the conversion are done within *cattrs* itself, not within your data model.
26
+
27
+
There are popular validation libraries for Python that couple your data model with its validation and serialization rules based on, for example, web APIs.
28
+
We think that's the wrong approach.
29
+
Validation and serializations are concerns of the edges of your program – not the core.
30
+
They should neither apply design pressure on your business code, nor affect the performance of your code through unnecessary validation.
31
+
In bigger real-world code bases it's also common for data coming from multiple sources that need different validation and serialization rules.
32
+
33
+
🎶 You gotta keep 'em separated. 🎶
34
+
:::
35
+
36
+
37
+
*cattrs* also works with the usual Python collection types like dictionaries, lists, or tuples when you want to **normalize** unstructured data data into a certain (still unstructured) shape.
38
+
For example, to convert a list of a float, an int and a string into a tuple of ints:
Finally, here's a much more complex example, involving _attrs_ classes where _cattrs_ interprets the type annotations to structure and unstructure the data correctly, including Enums and nested data structures:
49
+
50
+
```python
51
+
>>>from enum import unique, Enum
52
+
>>>from typing import Optional, Sequence, Union
53
+
>>>from cattrs import structure, unstructure
54
+
>>>from attrs import define, field
55
+
56
+
>>>@unique
57
+
...classCatBreed(Enum):
58
+
...SIAMESE="siamese"
59
+
...MAINE_COON="maine_coon"
60
+
...SACRED_BIRMAN="birman"
61
+
62
+
>>>@define
63
+
...classCat:
64
+
... breed: CatBreed
65
+
... names: Sequence[str]
66
+
67
+
>>>@define
68
+
...classDogMicrochip:
69
+
... chip_id = field() # Type annotations are optional, but recommended
70
+
... time_chipped: float= field()
71
+
72
+
>>>@define
73
+
...classDog:
74
+
... cuteness: int
75
+
... chip: DogMicrochip |None=None
76
+
77
+
>>> p = unstructure([Dog(cuteness=1, chip=DogMicrochip(chip_id=1, time_chipped=10.0)),
0 commit comments