Coverage for bioimageio/spec/pretty_validation_errors.py: 32%

40 statements  

« prev     ^ index     » next       coverage.py v7.6.10, created at 2025-02-05 13:53 +0000

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