bioimageio.spec.pretty_validation_errors

 1from pprint import pformat
 2from types import TracebackType
 3from typing import Any, List, Type, Union
 4
 5from pydantic import ValidationError
 6
 7from .summary import format_loc
 8
 9try:
10    from IPython.core.getipython import get_ipython
11    from IPython.core.interactiveshell import InteractiveShell
12
13    class PrettyValidationError(ValueError):
14        """Wrap a pydantic.ValidationError to custumize formatting."""
15
16        def __init__(self, validation_error: ValidationError):
17            super().__init__()
18            self.error = validation_error
19
20        def __str__(self):
21            errors: List[str] = []
22            for e in self.error.errors(include_url=False):
23                ipt_lines = pformat(
24                    e["input"], sort_dicts=False, depth=1, compact=True, width=30
25                ).split("\n")
26                if len(ipt_lines) > 2:
27                    ipt_lines[1:-1] = ["..."]
28
29                ipt = " ".join([il.strip() for il in ipt_lines])
30
31                errors.append(
32                    f"\n{format_loc(e['loc'], enclose_in='')}\n  {e['msg']} [input={ipt}]"
33                )
34
35            return (
36                f"{self.error.error_count()} validation errors for"
37                f" {self.error.title}:{''.join(errors)}"
38            )
39
40    def _custom_exception_handler(
41        self: InteractiveShell,
42        etype: Type[ValidationError],
43        evalue: ValidationError,
44        tb: TracebackType,
45        tb_offset: Any = None,
46    ):
47        assert issubclass(etype, ValidationError), type(etype)
48        assert isinstance(evalue, ValidationError), type(etype)
49
50        stb: Union[Any, List[Union[str, Any]]]
51        stb = self.InteractiveTB.structured_traceback(  # pyright: ignore[reportUnknownVariableType]
52            etype, PrettyValidationError(evalue), tb, tb_offset=tb_offset
53        )
54
55        if isinstance(stb, list):
56            stb_clean = []
57            for line in stb:  # pyright: ignore[reportUnknownVariableType]
58                if (
59                    isinstance(line, str)
60                    and "pydantic" in line
61                    and "__tracebackhide__" in line
62                ):
63                    # ignore pydantic internal frame in traceback
64                    continue
65                stb_clean.append(line)
66
67            stb = stb_clean
68
69        self._showtraceback(etype, PrettyValidationError(evalue), stb)  # type: ignore
70
71    def enable_pretty_validation_errors_in_ipynb():
72        """A modestly hacky way to display prettified validaiton error messages and traceback
73        in interactive Python notebooks"""
74        ipy = get_ipython()
75        if ipy is not None:
76            ipy.set_custom_exc((ValidationError,), _custom_exception_handler)
77
78except ImportError:
79
80    def enable_pretty_validation_errors_in_ipynb():
81        return
class PrettyValidationError(builtins.ValueError):
14    class PrettyValidationError(ValueError):
15        """Wrap a pydantic.ValidationError to custumize formatting."""
16
17        def __init__(self, validation_error: ValidationError):
18            super().__init__()
19            self.error = validation_error
20
21        def __str__(self):
22            errors: List[str] = []
23            for e in self.error.errors(include_url=False):
24                ipt_lines = pformat(
25                    e["input"], sort_dicts=False, depth=1, compact=True, width=30
26                ).split("\n")
27                if len(ipt_lines) > 2:
28                    ipt_lines[1:-1] = ["..."]
29
30                ipt = " ".join([il.strip() for il in ipt_lines])
31
32                errors.append(
33                    f"\n{format_loc(e['loc'], enclose_in='')}\n  {e['msg']} [input={ipt}]"
34                )
35
36            return (
37                f"{self.error.error_count()} validation errors for"
38                f" {self.error.title}:{''.join(errors)}"
39            )

Wrap a pydantic.ValidationError to custumize formatting.

PrettyValidationError(validation_error: pydantic_core._pydantic_core.ValidationError)
17        def __init__(self, validation_error: ValidationError):
18            super().__init__()
19            self.error = validation_error
error
def enable_pretty_validation_errors_in_ipynb():
72    def enable_pretty_validation_errors_in_ipynb():
73        """A modestly hacky way to display prettified validaiton error messages and traceback
74        in interactive Python notebooks"""
75        ipy = get_ipython()
76        if ipy is not None:
77            ipy.set_custom_exc((ValidationError,), _custom_exception_handler)

A modestly hacky way to display prettified validaiton error messages and traceback in interactive Python notebooks