Coverage for src/bioimageio/spec/_pretty_validation_errors.py: 45%
49 statements
« prev ^ index » next coverage.py v7.15.4, created at 2026-08-18 09:17 +0000
« prev ^ index » next coverage.py v7.15.4, created at 2026-08-18 09:17 +0000
1from __future__ import annotations
3import warnings
4from pprint import pformat
5from types import TracebackType
6from typing import Any
8from pydantic import ValidationError
10from .summary import format_loc
12try:
13 from IPython.core.getipython import get_ipython
14 from IPython.core.interactiveshell import InteractiveShell
16 class PrettyValidationError(ValueError):
17 """Wrap a pydantic.ValidationError to custumize formatting."""
19 def __init__(self, validation_error: ValidationError):
20 super().__init__()
21 self.error = validation_error
23 def __str__(self):
24 errors: list[str] = []
25 for e in self.error.errors(include_url=False):
26 ipt_lines = pformat(
27 e["input"], sort_dicts=False, depth=1, compact=True, width=30
28 ).split("\n")
29 if len(ipt_lines) > 2:
30 ipt_lines[1:-1] = ["..."]
32 ipt = " ".join([il.strip() for il in ipt_lines])
34 errors.append(
35 f"\n{format_loc(e['loc'], 'plain')}\n {e['msg']} [input={ipt}]"
36 )
38 return (
39 f"{self.error.error_count()} validation errors for"
40 f" {self.error.title}:{''.join(errors)}"
41 )
43 def _custom_exception_handler(
44 self: InteractiveShell,
45 etype: type[ValidationError],
46 evalue: ValidationError,
47 tb: TracebackType,
48 tb_offset: Any = None,
49 ):
50 assert issubclass(etype, ValidationError), type(etype)
51 assert isinstance(evalue, ValidationError), type(etype)
53 stb = self.InteractiveTB.structured_traceback( # pyright: ignore
54 etype, PrettyValidationError(evalue), tb, tb_offset=tb_offset
55 )
57 if isinstance(stb, list):
58 stb_clean = []
59 for line in stb: # pyright: ignore[reportUnknownVariableType]
60 if (
61 isinstance(line, str)
62 and "pydantic" in line
63 and "__tracebackhide__" in line
64 ):
65 # ignore pydantic internal frame in traceback
66 continue
67 stb_clean.append(line)
69 stb = stb_clean
71 self._showtraceback(etype, PrettyValidationError(evalue), stb) # type: ignore
73 def _enable_pretty_validation_errors_in_ipynb():
74 """A modestly hacky way to display prettified validaiton error messages and traceback
75 in interactive Python notebooks"""
76 ipy = get_ipython()
77 if ipy is not None:
78 ipy.set_custom_exc((ValidationError,), _custom_exception_handler)
80except ImportError:
81 _enabled = False
82else:
83 try:
84 _enable_pretty_validation_errors_in_ipynb()
85 except Exception as e:
86 _enabled = False
87 warnings.warn(
88 "Failed to enable pretty validation errors in ipython: " + str(e),
89 stacklevel=2,
90 )
91 else:
92 _enabled = True
94PRETTY_VALIDATION_ERRORS_IN_IPYNB_ENABLED = _enabled
95"""Whether pretty validation errors in IPython notebooks were successfully enabled during import."""