Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.11/site-packages/cattrs/errors.py: 38%
Shortcuts on this page
r m x toggle line displays
j k next/prev highlighted chunk
0 (zero) top of page
1 (one) first highlighted chunk
Shortcuts on this page
r m x toggle line displays
j k next/prev highlighted chunk
0 (zero) top of page
1 (one) first highlighted chunk
1from collections.abc import Sequence
2from typing import Any, Optional, Union
4from typing_extensions import Self
6from cattrs._compat import ExceptionGroup
9class StructureHandlerNotFoundError(Exception):
10 """
11 Error raised when structuring cannot find a handler for converting inputs into
12 :attr:`type_`.
13 """
15 def __init__(self, message: str, type_: type) -> None:
16 super().__init__(message)
17 self.type_ = type_
20class BaseValidationError(ExceptionGroup):
21 cl: type
23 def __new__(cls, message: str, excs: Sequence[Exception], cl: type):
24 obj = super().__new__(cls, message, excs)
25 obj.cl = cl
26 return obj
28 def derive(self, excs: Sequence[Exception]) -> Self:
29 return self.__class__(self.message, excs, self.cl)
32class IterableValidationNote(str):
33 """Attached as a note to an exception when an iterable element fails structuring."""
35 index: Union[int, str] # Ints for list indices, strs for dict keys
36 type: Any
38 def __new__(
39 cls, string: str, index: Union[int, str], type: Any
40 ) -> "IterableValidationNote":
41 instance = str.__new__(cls, string)
42 instance.index = index
43 instance.type = type
44 return instance
46 def __getnewargs__(self) -> tuple[str, Union[int, str], Any]:
47 return (str(self), self.index, self.type)
50class IterableValidationError(BaseValidationError):
51 """Raised when structuring an iterable."""
53 def group_exceptions(
54 self,
55 ) -> tuple[list[tuple[Exception, IterableValidationNote]], list[Exception]]:
56 """Split the exceptions into two groups: with and without validation notes."""
57 excs_with_notes = []
58 other_excs = []
59 for subexc in self.exceptions:
60 if hasattr(subexc, "__notes__"):
61 for note in subexc.__notes__:
62 if note.__class__ is IterableValidationNote:
63 excs_with_notes.append((subexc, note))
64 break
65 else:
66 other_excs.append(subexc)
67 else:
68 other_excs.append(subexc)
70 return excs_with_notes, other_excs
73class AttributeValidationNote(str):
74 """Attached as a note to an exception when an attribute fails structuring."""
76 name: str
77 type: Any
79 def __new__(cls, string: str, name: str, type: Any) -> "AttributeValidationNote":
80 instance = str.__new__(cls, string)
81 instance.name = name
82 instance.type = type
83 return instance
85 def __getnewargs__(self) -> tuple[str, str, Any]:
86 return (str(self), self.name, self.type)
89class ClassValidationError(BaseValidationError):
90 """Raised when validating a class if any attributes are invalid."""
92 def group_exceptions(
93 self,
94 ) -> tuple[list[tuple[Exception, AttributeValidationNote]], list[Exception]]:
95 """Split the exceptions into two groups: with and without validation notes."""
96 excs_with_notes = []
97 other_excs = []
98 for subexc in self.exceptions:
99 if hasattr(subexc, "__notes__"):
100 for note in subexc.__notes__:
101 if note.__class__ is AttributeValidationNote:
102 excs_with_notes.append((subexc, note))
103 break
104 else:
105 other_excs.append(subexc)
106 else:
107 other_excs.append(subexc)
109 return excs_with_notes, other_excs
112class ForbiddenExtraKeysError(Exception):
113 """
114 Raised when `forbid_extra_keys` is activated and such extra keys are detected
115 during structuring.
117 The attribute `extra_fields` is a sequence of those extra keys, which were the
118 cause of this error, and `cl` is the class which was structured with those extra
119 keys.
120 """
122 def __init__(
123 self, message: Optional[str], cl: type, extra_fields: set[str]
124 ) -> None:
125 self.cl = cl
126 self.extra_fields = extra_fields
127 cln = cl.__name__
129 super().__init__(
130 message
131 or f"Extra fields in constructor for {cln}: {', '.join(extra_fields)}"
132 )