Skip to content

Commit 59edafd

Browse files
committed
Merge branch 'bibajz-bibajz/tuple_unstructuring'
2 parents 3ee4b40 + 158d9d3 commit 59edafd

35 files changed

+929
-796
lines changed

HISTORY.rst

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,10 +11,14 @@ History
1111
(`#218 <https://github.com/python-attrs/cattrs/issues/218>`_)
1212
* Fix structuring bare ``typing.Tuple`` on Pythons lower than 3.9.
1313
(`#218 <https://github.com/python-attrs/cattrs/issues/218>`_)
14-
1514
* Fix a wrong ``AttributeError`` of an missing ``__parameters__`` attribute. This could happen
1615
when inheriting certain generic classes – for example ``typing.*`` classes are affected.
1716
(`#217 <https://github.com/python-attrs/cattrs/issues/217>`_)
17+
* Fix structuring of ``enum.Enum`` instances in ``typing.Literal`` types.
18+
(`#231 <https://github.com/python-attrs/cattrs/pull/231>`_)
19+
* Fix unstructuring all tuples - unannotated, variable-length, homogenous and heterogenous - to `list`.
20+
(`#226 <https://github.com/python-attrs/cattrs/issues/226>`_)
21+
1822

1923
1.10.0 (2022-01-04)
2024
-------------------

docs/conf.py

Lines changed: 2 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -212,13 +212,7 @@
212212
# (source start file, target name, title, author, documentclass
213213
# [howto/manual]).
214214
latex_documents = [
215-
(
216-
"index",
217-
"cattrs.tex",
218-
u"cattrs Documentation",
219-
u"Tin Tvrtković",
220-
"manual",
221-
)
215+
("index", "cattrs.tex", u"cattrs Documentation", u"Tin Tvrtković", "manual")
222216
]
223217

224218
# The name of an image file (relative to this directory) to place at
@@ -246,9 +240,7 @@
246240

247241
# One entry per manual page. List of tuples
248242
# (source start file, name, description, authors, manual section).
249-
man_pages = [
250-
("index", "cattrs", u"cattrs Documentation", [u"Tin Tvrtković"], 1)
251-
]
243+
man_pages = [("index", "cattrs", u"cattrs Documentation", [u"Tin Tvrtković"], 1)]
252244

253245
# If true, show URL addresses after external links.
254246
# man_show_urls = False

docs/index.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ Contents:
1717
converters
1818
structuring
1919
unstructuring
20+
validation
2021
preconf
2122
customizing
2223
unions

docs/validation.rst

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
==========
2+
Validation
3+
==========
4+
5+
`cattrs` has a detailed validation mode since version 2022.1.0, and this mode is enabled by default.
6+
When running under detailed validation, the un/structuring hooks are slightly slower but produce more precise and exhaustive error messages.
7+
8+
Detailed validation
9+
-------------------
10+
In detailed validation mode, any un/structuring errors will be grouped and raised together as a ``cattrs.BaseValidationError``, which is a `PEP 654 ExceptionGroup`_.
11+
ExceptionGroups are special exceptions which contain lists of other exceptions, which may themselves be other ExceptionGroups.
12+
In essence, ExceptionGroups are trees of exceptions.
13+
14+
When un/structuring a class, `cattrs` will gather any exceptions on a field-by-field basis and raise them as a ``cattrs.ClassValidationError``, which is a subclass of ``BaseValidationError``.
15+
When structuring sequences and mappings, `cattrs` will gather any exceptions on a key- or index-basis and raise them as a ``cattrs.IterableValidationError``, which is a subclass of ``BaseValidationError``.
16+
17+
The exceptions will also have their ``__note__`` attributes set, as per `PEP 678`_, showing the field, key or index for each inner exception.
18+
19+
A simple example involving a class containing a list and a dictionary:
20+
21+
.. code-block:: python
22+
23+
@define
24+
class Class:
25+
a_list: list[int]
26+
a_dict: dict[str, int]
27+
28+
>>> structure({"a_list": ["a"], "a_dict": {"str": "a"}})
29+
+ Exception Group Traceback (most recent call last):
30+
| File "<stdin>", line 1, in <module>
31+
| File "/Users/tintvrtkovic/pg/cattrs/src/cattr/converters.py", line 276, in structure
32+
| return self._structure_func.dispatch(cl)(obj, cl)
33+
| File "<cattrs generated structure __main__.Class>", line 14, in structure_Class
34+
| if errors: raise __c_cve('While structuring Class', errors, __cl)
35+
| cattrs.errors.ClassValidationError: While structuring Class
36+
+-+---------------- 1 ----------------
37+
| Exception Group Traceback (most recent call last):
38+
| File "<cattrs generated structure __main__.Class>", line 5, in structure_Class
39+
| res['a_list'] = __c_structure_a_list(o['a_list'], __c_type_a_list)
40+
| File "/Users/tintvrtkovic/pg/cattrs/src/cattr/converters.py", line 457, in _structure_list
41+
| raise IterableValidationError(
42+
| cattrs.errors.IterableValidationError: While structuring list[int]
43+
| Structuring class Class @ attribute a_list
44+
+-+---------------- 1 ----------------
45+
| Traceback (most recent call last):
46+
| File "/Users/tintvrtkovic/pg/cattrs/src/cattr/converters.py", line 450, in _structure_list
47+
| res.append(handler(e, elem_type))
48+
| File "/Users/tintvrtkovic/pg/cattrs/src/cattr/converters.py", line 375, in _structure_call
49+
| return cl(obj)
50+
| ValueError: invalid literal for int() with base 10: 'a'
51+
| Structuring list[int] @ index 0
52+
+------------------------------------
53+
+---------------- 2 ----------------
54+
| Exception Group Traceback (most recent call last):
55+
| File "<cattrs generated structure __main__.Class>", line 10, in structure_Class
56+
| res['a_dict'] = __c_structure_a_dict(o['a_dict'], __c_type_a_dict)
57+
| File "", line 17, in structure_mapping
58+
| cattrs.errors.IterableValidationError: While structuring dict
59+
| Structuring class Class @ attribute a_dict
60+
+-+---------------- 1 ----------------
61+
| Traceback (most recent call last):
62+
| File "", line 5, in structure_mapping
63+
| ValueError: invalid literal for int() with base 10: 'a'
64+
| Structuring mapping value @ key 'str'
65+
+------------------------------------
66+
67+
.. _`PEP 654 ExceptionGroup`: https://www.python.org/dev/peps/pep-0654/
68+
.. _`PEP 678`: https://www.python.org/dev/peps/pep-0678/
69+
70+
Non-detailed validation
71+
-----------------------
72+
73+
Non-detailed validation can be enabled by initializing any of the converters with ``detailed_validation=False``.
74+
In this mode, any errors during un/structuring will bubble up directly as soon as they happen

0 commit comments

Comments
 (0)