Skip to content

confit.errors

MissingReference [source]

Bases: Exception

Raised when one or multiple references cannot be resolved.

Parameters

PARAMETER DESCRIPTION
ref

The reference that could not be resolved.

TYPE: Reference

Source code in confit/errors.py
20
21
22
23
24
25
26
27
28
def __init__(self, ref: Reference):
    """
    Parameters
    ----------
    ref: Reference
        The reference that could not be resolved.
    """
    self.ref = ref
    super().__init__()

__str__ [source]

String representation of the exception

Source code in confit/errors.py
30
31
32
33
34
def __str__(self):
    """
    String representation of the exception
    """
    return "Could not interpolate the following reference: {}".format(self.ref)

CyclicReferenceError [source]

Bases: Exception

Raised when a cyclic reference is detected.

Parameters

PARAMETER DESCRIPTION
path

The path of the cyclic reference

TYPE: Loc

Source code in confit/errors.py
42
43
44
45
46
47
48
49
50
def __init__(self, path: Loc):
    """
    Parameters
    ----------
    path: Loc
        The path of the cyclic reference
    """
    self.path = path
    super().__init__()

__str__ [source]

String representation of the exception

Source code in confit/errors.py
52
53
54
55
56
def __str__(self):
    """
    String representation of the exception
    """
    return "Cyclic reference detected at {}".format(join_path(self.path))

RawError [source]

Bases: dict

Error detail returned by the deprecated raw_errors. Since EDS-PDF 0.10 and older callers deduplicate these details with dict.fromkeys, we hash them by their type, location and message

ConfitValidationError [source]

Bases: ValueError

Structured validation errors with paths added by config and pipeline resolution

Source code in confit/errors.py
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
def __init__(self, errors, *, name=None, source=None, model=None):
    if model is not None:
        warnings.warn(
            "Use source instead of model", DeprecationWarning, stacklevel=2
        )
        source = model
    self.source = source
    self.name = name or getattr(source, "__qualname__", None)
    # Old EDS-NLP callers can aggregate lists of errors inside another list
    self.details = [
        detail
        for error in errors
        for detail in (
            ConfitValidationError(error).details
            if isinstance(error, list)
            else [error]
        )
    ]
    super().__init__(self.details)

from_exception classmethod [source]

Normalize Pydantic errors before config resolution adds its parent path

Source code in confit/errors.py
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
@classmethod
def from_exception(cls, error, *, source=None, name=None, signature=None):
    """
    Normalize Pydantic errors before config resolution adds its parent path
    """
    if isinstance(error, cls):
        return cls(
            error.errors(), source=source or error.source, name=name or error.name
        )
    if not isinstance(error, pydantic.ValidationError):
        return cls(
            [
                {
                    "loc": (),
                    "msg": str(error),
                    "type": "value_error",
                    "ctx": {"error": error},
                }
            ],
            source=source,
            name=name,
        )
    details = []
    for detail in error.errors(include_url=False):
        loc = detail["loc"]
        if signature is not None and loc and isinstance(loc[0], int):
            names = [
                name
                for name, p in signature.parameters.items()
                if p.kind in (p.POSITIONAL_ONLY, p.POSITIONAL_OR_KEYWORD)
            ]
            if loc[0] < len(names):
                loc = (names[loc[0]], *loc[1:])
        nested = detail.get("ctx", {}).get("error")
        if isinstance(nested, cls):
            target = source
            # Only typed construction joins paths, separate calls keep their name
            try:
                for part in loc:
                    target = (
                        target.model_fields[part].annotation
                        if hasattr(target, "model_fields")
                        else inspect.signature(target).parameters[part].annotation
                    )
            except (KeyError, AttributeError, TypeError, ValueError):
                target = None
            if target is not None and target is nested.source:
                details.extend(nested.with_path(loc).errors())
                continue
        details.append({**detail, "loc": loc})
    return cls(details, source=source, name=name)

with_path [source]

Return an error with a parent path without modifying shared component errors

Source code in confit/errors.py
162
163
164
165
166
167
168
169
170
def with_path(self, path, *, name=None):
    """
    Return an error with a parent path without modifying shared component errors
    """
    return type(self)(
        [{**detail, "loc": (*path, *detail["loc"])} for detail in self.details],
        source=self.source,
        name=name or self.name,
    )

combine classmethod [source]

Collect failures from sibling components in their original order

Source code in confit/errors.py
172
173
174
175
176
177
@classmethod
def combine(cls, errors, *, name=None):
    """
    Collect failures from sibling components in their original order
    """
    return cls([detail for error in errors for detail in error.errors()], name=name)

remove_lib_from_traceback [source]

Remove the lib folder from the traceback

Source code in confit/errors.py
59
60
61
62
63
64
65
66
67
68
69
70
71
def remove_lib_from_traceback(tb):
    """
    Remove the lib folder from the traceback
    """
    # compare package to module in f_globals
    if is_debug():
        return tb
    if tb is not None and tb.tb_frame.f_globals.get("__package__") == __package__:
        return remove_lib_from_traceback(tb.tb_next)
    if tb is None or tb.tb_next is None:
        return tb
    tb.tb_next = remove_lib_from_traceback(tb.tb_next)
    return tb

patch_errors [source]

Adapt old EDS-NLP error calls to ConfitValidationError methods

Source code in confit/errors.py
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
def patch_errors(errors, path=(), values=None, model=None, drop_names=()):
    """
    Adapt old EDS-NLP error calls to ConfitValidationError methods
    """
    warnings.warn(
        "Use ConfitValidationError.from_exception and with_path "
        "instead of patch_errors",
        DeprecationWarning,
        stacklevel=2,
    )
    is_exception = isinstance(errors, (pydantic.ValidationError, ConfitValidationError))
    error = (
        ConfitValidationError.from_exception(errors, source=model)
        if is_exception
        else ConfitValidationError(errors, source=model)
    )
    error = error.with_path(path)
    if drop_names:
        error = ConfitValidationError(
            [
                {
                    **detail,
                    "loc": tuple(
                        part for part in detail["loc"] if part not in drop_names
                    ),
                }
                for detail in error.errors()
            ],
            source=error.source,
            name=error.name,
        )
    return error if is_exception else error.errors()