Coverage for /opt/hostedtoolcache/Python/3.10.18/x64/lib/python3.10/site-packages/bioimageio/spec/pretty_validation_errors.py: 41%

46 statements  

« prev     ^ index     » next       coverage.py v7.10.7, created at 2025-09-22 09:21 +0000

1import warnings 

2from pprint import pformat 

3from types import TracebackType 

4from typing import Any, List, Type, Union 

5 

6from pydantic import ValidationError 

7 

8from .summary import format_loc 

9 

10try: 

11 from IPython.core.getipython import get_ipython 

12 from IPython.core.interactiveshell import InteractiveShell 

13 

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'], 'plain')}\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 ) 

40 

41 def _custom_exception_handler( 

42 self: InteractiveShell, 

43 etype: Type[ValidationError], 

44 evalue: ValidationError, 

45 tb: TracebackType, 

46 tb_offset: Any = None, 

47 ): 

48 assert issubclass(etype, ValidationError), type(etype) 

49 assert isinstance(evalue, ValidationError), type(etype) 

50 

51 stb: Union[Any, List[Union[str, Any]]] 

52 stb = self.InteractiveTB.structured_traceback( 

53 etype, PrettyValidationError(evalue), tb, tb_offset=tb_offset 

54 ) 

55 

56 if isinstance(stb, list): 

57 stb_clean = [] 

58 for line in stb: # pyright: ignore[reportUnknownVariableType] 

59 if ( 

60 isinstance(line, str) 

61 and "pydantic" in line 

62 and "__tracebackhide__" in line 

63 ): 

64 # ignore pydantic internal frame in traceback 

65 continue 

66 stb_clean.append(line) 

67 

68 stb = stb_clean 

69 

70 self._showtraceback(etype, PrettyValidationError(evalue), stb) # type: ignore 

71 

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) 

78 

79except ImportError: 

80 pass 

81else: 

82 try: 

83 _enable_pretty_validation_errors_in_ipynb() 

84 except Exception as e: 

85 warnings.warn( 

86 "Failed to enable pretty validation errors in ipython: " + str(e), 

87 stacklevel=2, 

88 ) 

89 

90 

91def enable_pretty_validation_errors_in_ipynb(): 

92 """DEPRECATED; this is enabled by default at import time.""" 

93 warnings.warn( 

94 "deprecated, this is enabled by default at import time.", 

95 DeprecationWarning, 

96 stacklevel=2, 

97 )