Skip to content

How do I extract error information from the exception(s) raised when structuring? #258

@pfmoore

Description

@pfmoore
  • cattrs version: 22.1.0
  • Python version: 3.10.3
  • Operating System: Windows 11

Description

When I structure a raw dictionary into a data class, if there's one or more problems, I get an exception (which apparently can be an exception group, using the backport of a new Python 3.11 feature). The raw traceback of the exception is pretty user-unfriendly.

How do I get the details of what failed, in a form that I can use to report to the end user as an error report showing "user facing" terminology, not technical details?

What I Did

>>> cattrs.structure(["a", "b"], list[int])
  + Exception Group Traceback (most recent call last):
  |   File "<stdin>", line 1, in <module>
  |   File "C:\Work\Projects\wheeliebin\.venv\lib\site-packages\cattrs\converters.py", line 281, in structure
  |     return self._structure_func.dispatch(cl)(obj, cl)
  |   File "C:\Work\Projects\wheeliebin\.venv\lib\site-packages\cattrs\converters.py", line 470, in _structure_list
  |     raise IterableValidationError(
  | cattrs.errors.IterableValidationError: While structuring list[int] (2 sub-exceptions)
  +-+---------------- 1 ----------------
    | Traceback (most recent call last):
    |   File "C:\Work\Projects\wheeliebin\.venv\lib\site-packages\cattrs\converters.py", line 463, in _structure_list
    |     res.append(handler(e, elem_type))
    |   File "C:\Work\Projects\wheeliebin\.venv\lib\site-packages\cattrs\converters.py", line 380, in _structure_call
    |     return cl(obj)
    | ValueError: invalid literal for int() with base 10: 'a'
    | Structuring list[int] @ index 0
    +---------------- 2 ----------------
    | Traceback (most recent call last):
    |   File "C:\Work\Projects\wheeliebin\.venv\lib\site-packages\cattrs\converters.py", line 463, in _structure_list
    |     res.append(handler(e, elem_type))
    |   File "C:\Work\Projects\wheeliebin\.venv\lib\site-packages\cattrs\converters.py", line 380, in _structure_call
    |     return cl(obj)
    | ValueError: invalid literal for int() with base 10: 'b'
    | Structuring list[int] @ index 1
    +------------------------------------

>>> try:
...     cattrs.structure(["a", "b"], list[int])
... except Exception as exc:
...     # Not sure what to do here...

What I'd like to be able to do is get the two ValueError exceptions, as well as where they happened (list[int] @ index 1). If I simply print exc, it returns While structuring list[int] (2 sub-exceptions), which is user-friendly, but omits the information needed to tell the user how to fix the issue.

With a bit of digging, it seems as if I can do something like

for x in exc.exceptions:
  print(f"{x}: {x.__note__}")

But it's possible to get nested exception groups, so this is incomplete. And __note__ seems to be a string which I can't introspect to produce output in a different format. The only way I can see of having full control over how any issues are reported, is to pre-validate the data structure, at which point I might as well write my own structuring code at the same time...

Am I missing something here, or am I trying to use the library in a way that wasn't intended? (My use case is extremely close to user input validation, it's just that the user input is in TOML, which I can parse easily with a library, but in doing so I defer all the validation of data structures, so my "unstructured data" is actually error-prone user input in all but name...)

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions