Accepting PEP 654 (Exception Groups and except*)

@Zac-HD I’ve experimentally integrated ExceptionGroups (+ __note__) into a library of mine (cattrs - 6 million downloads last month according to pypistats.org). The work is available on the tin/validation branch.

I think the __note__ attribute turned out to be very useful.

Setup: two classes and an unstructured payload.

@define
class Inner:
    a: int


@define
class Outer:
    inners: list[Inner]

>>> payload = {"inners": [{"a": 1}, {"a": "not_an_int"}]}

When you try structuring, the exception:

>>> structure(payload, Outer)
  + Exception Group Traceback (most recent call last):
  |   File "<stdin>", line 1, in <module>
  |   File "/Users/tintvrtkovic/pg/cattrs/src/cattr/converters.py", line 308, in structure
  |     return self._structure_func.dispatch(cl)(obj, cl)
  |            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  |   File "<cattrs generated structure __main__.Outer>", line 9, in structure_Outer
  | cattrs.errors.ClassValidationError: While structuring Outer
  +-+---------------- 1 ----------------
    | Exception Group Traceback (most recent call last):
    |   File "<cattrs generated structure __main__.Outer>", line 5, in structure_Outer
    |   File "/Users/tintvrtkovic/pg/cattrs/src/cattr/converters.py", line 500, in _structure_list
    |     raise IterableValidationError(f"While structuring {cl.__name__}", errors, cl)
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    | cattrs.errors.IterableValidationError: While structuring list
    | Structuring class Outer @ attribute inners
    +-+---------------- 1 ----------------
      | Exception Group Traceback (most recent call last):
      |   File "/Users/tintvrtkovic/pg/cattrs/src/cattr/converters.py", line 493, in _structure_list
      |     res.append(handler(e, elem_type))
      |                ^^^^^^^^^^^^^^^^^^^^^
      |   File "<cattrs generated structure __main__.Inner>", line 9, in structure_Inner
      | cattrs.errors.ClassValidationError: While structuring Inner
      | Structuring list[__main__.Inner] @ index 1
      +-+---------------- 1 ----------------
        | Traceback (most recent call last):
        |   File "<cattrs generated structure __main__.Inner>", line 5, in structure_Inner
        | ValueError: invalid literal for int() with base 10: 'not_an_int'
        | Structuring class Inner @ attribute a
        +------------------------------------

The notes essentially make detecting the exact problem spot easier. If you just look at the notes:

  • Structuring class Outer @ attribute inners
  • Structuring list[__main__.Inner] @ index 1
  • Structuring class Inner @ attribute a

It’s obvious the problem (the root ValueError) is at Outer.inners[1].a.

I think the situation will be further improved when libraries like rich support ExceptionGroups. I could imagine the note being rendered in a different color in the terminal (or bold) to help it stand out.

Feel free to add any of this information to the PEP to help its case.

1 Like

What’s the timeline on getting v1.0.0 of the ExceptionGroup backport out? Are you waiting on the __note__ PEP ruling? Thanks.

I am hesitant to release v1.0.0 final before the exceptiongroup stdlib implementation stabilizes. Just yesterday I noticed inconsistent behavior in traceback formatting when recursive exceptions are involved. The stdlib output looked fine but the backport…did not. In that process I noticed that the handling of __note__ formatting had changed in the stdlib code.

Oh, and yes, I am also waiting on the __note__ ruling, particularly since the backport now supports that attribute.

Makes sense, thanks for the update.