Errors in typedload

All exceptions are subclasses of TypedloadException.

To make sure of that, there is an assertion in place that will fail if a type handler is misbehaving and raising the wrong type of exception.

The exceptions have a clear user message, but they offer an API to expose precise knowledge of the problem.

String trace

By default when an error occurrs the path within the data structure is shown.

from typing import *
import typedload

class Thing(NamedTuple):
    value: int

class Data(NamedTuple):
    field1: List[Thing]
    field2: Tuple[Thing, ...]


typedload.load({'field1': [{'value': 12}, {'value': 'a'}], 'field2': []}, Data)
TypedloadValueError: invalid literal for int() with base 10: 'a'
Path: .field1.[1].value

The path in the string description tells where the wrong value was found.

Trace

To be able to locate where in the data an exception happened, TypedloadException has the trace property, which contains a list TraceItem, which help to track where the exception happened.

This can be useful to do more clever error handling.

For example:

try:
    typedload.load([1, 2, 'a'], List[int])
except Exception as e:
    print(e.trace[-1])

Will raise an exception and print the last element in the trace

TraceItem(value='a', type_=<class 'int'>, annotation=Annotation(annotation_type=<AnnotationType.INDEX: 'index'>, value=2))

Another example, with an object:


class O(NamedTuple):
    data: List[int]

try:
    typedload.load({'data': [1, 2, 'a']}, O)
except Exception as e:
    for i in e.trace:
        print(i)

Will print the entire trace:

TraceItem(value={'data': [1, 2, 'a']}, type_=<class '__main__.O'>, annotation=None)
TraceItem(value=[1, 2, 'a'], type_=typing.List[int], annotation=Annotation(annotation_type=<AnnotationType.FIELD: 'field'>, value='data'))
TraceItem(value='a', type_=<class 'int'>, annotation=Annotation(annotation_type=<AnnotationType.INDEX: 'index'>, value=2))

And checking the annotation field it is possible to find out that the issue happened in data at index 2.

Union

Because it is normal for a union of n types to generate n-1 exceptions, a union which fails generated n exceptions.

Typedload has no way of knowing which of those is the important exception that was expected to succeed and instead puts all the exceptions inside the exception field of the parent exception.

So all the sub exceptions can be investigated to decide which one is the most relevant one.

Raise exceptions in custom handlers

To find the path where the wrong value was found, typedload needs to trace the execution by using annotations.

This is used in handlers that do recursive calls to the loader.

See the source code of the handlers for Union and NamedTuple to see how this is done.