Coverage for src/hdmf/validate/errors.py: 90%
112 statements
« prev ^ index » next coverage.py v7.3.2, created at 2023-10-04 02:57 +0000
« prev ^ index » next coverage.py v7.3.2, created at 2023-10-04 02:57 +0000
1from numpy import dtype
3from ..spec.spec import DtypeHelper
4from ..utils import docval, getargs
6__all__ = [
7 "Error",
8 "DtypeError",
9 "MissingError",
10 "ExpectedArrayError",
11 "ShapeError",
12 "MissingDataType",
13 "IllegalLinkError",
14 "IncorrectDataType",
15 "IncorrectQuantityError"
16]
19class Error:
21 @docval({'name': 'name', 'type': str, 'doc': 'the name of the component that is erroneous'},
22 {'name': 'reason', 'type': str, 'doc': 'the reason for the error'},
23 {'name': 'location', 'type': str, 'doc': 'the location of the error', 'default': None})
24 def __init__(self, **kwargs):
25 self.__name = getargs('name', kwargs)
26 self.__reason = getargs('reason', kwargs)
27 self.__location = getargs('location', kwargs)
29 @property
30 def name(self):
31 return self.__name
33 @property
34 def reason(self):
35 return self.__reason
37 @property
38 def location(self):
39 return self.__location
41 @location.setter
42 def location(self, loc):
43 self.__location = loc
45 def __str__(self):
46 return self.__format_str(self.name, self.location, self.reason)
48 @staticmethod
49 def __format_str(name, location, reason):
50 if location is not None:
51 return "%s (%s): %s" % (name, location, reason)
52 else:
53 return "%s: %s" % (name, reason)
55 def __repr__(self):
56 return self.__str__()
58 def __hash__(self):
59 """Returns the hash value of this Error
61 Note: if the location property is set after creation, the hash value will
62 change. Therefore, it is important to finalize the value of location
63 before getting the hash value.
64 """
65 return hash(self.__equatable_str())
67 def __equatable_str(self):
68 """A string representation of the error which can be used to check for equality
70 For a single error, name can end up being different depending on whether it is
71 generated from a base data type spec or from an inner type definition. These errors
72 should still be considered equal because they are caused by the same problem.
74 When a location is provided, we only consider the name of the field and drop the
75 rest of the spec name. However, when a location is not available, then we need to
76 use the fully-provided name.
77 """
78 if self.location is not None:
79 equatable_name = self.name.split('/')[-1]
80 else:
81 equatable_name = self.name
82 return self.__format_str(equatable_name, self.location, self.reason)
84 def __eq__(self, other):
85 return hash(self) == hash(other)
88class DtypeError(Error):
90 @docval({'name': 'name', 'type': str, 'doc': 'the name of the component that is erroneous'},
91 {'name': 'expected', 'type': (dtype, type, str, list), 'doc': 'the expected dtype'},
92 {'name': 'received', 'type': (dtype, type, str, list), 'doc': 'the received dtype'},
93 {'name': 'location', 'type': str, 'doc': 'the location of the error', 'default': None})
94 def __init__(self, **kwargs):
95 name = getargs('name', kwargs)
96 expected = getargs('expected', kwargs)
97 received = getargs('received', kwargs)
98 if isinstance(expected, list): 98 ↛ 99line 98 didn't jump to line 99, because the condition on line 98 was never true
99 expected = DtypeHelper.simplify_cpd_type(expected)
100 reason = "incorrect type - expected '%s', got '%s'" % (expected, received)
101 loc = getargs('location', kwargs)
102 super().__init__(name, reason, location=loc)
105class MissingError(Error):
106 @docval({'name': 'name', 'type': str, 'doc': 'the name of the component that is erroneous'},
107 {'name': 'location', 'type': str, 'doc': 'the location of the error', 'default': None})
108 def __init__(self, **kwargs):
109 name = getargs('name', kwargs)
110 reason = "argument missing"
111 loc = getargs('location', kwargs)
112 super().__init__(name, reason, location=loc)
115class MissingDataType(Error):
116 @docval({'name': 'name', 'type': str, 'doc': 'the name of the component that is erroneous'},
117 {'name': 'data_type', 'type': str, 'doc': 'the missing data type'},
118 {'name': 'location', 'type': str, 'doc': 'the location of the error', 'default': None},
119 {'name': 'missing_dt_name', 'type': str, 'doc': 'the name of the missing data type', 'default': None})
120 def __init__(self, **kwargs):
121 name, data_type, missing_dt_name = getargs('name', 'data_type', 'missing_dt_name', kwargs)
122 self.__data_type = data_type
123 if missing_dt_name is not None:
124 reason = "missing data type %s (%s)" % (self.__data_type, missing_dt_name)
125 else:
126 reason = "missing data type %s" % self.__data_type
127 loc = getargs('location', kwargs)
128 super().__init__(name, reason, location=loc)
130 @property
131 def data_type(self):
132 return self.__data_type
135class IncorrectQuantityError(Error):
136 """A validation error indicating that a child group/dataset/link has the incorrect quantity of matching elements"""
137 @docval({'name': 'name', 'type': str, 'doc': 'the name of the component that is erroneous'},
138 {'name': 'data_type', 'type': str, 'doc': 'the data type which has the incorrect quantity'},
139 {'name': 'expected', 'type': (str, int), 'doc': 'the expected quantity'},
140 {'name': 'received', 'type': (str, int), 'doc': 'the received quantity'},
141 {'name': 'location', 'type': str, 'doc': 'the location of the error', 'default': None})
142 def __init__(self, **kwargs):
143 name, data_type, expected, received = getargs('name', 'data_type', 'expected', 'received', kwargs)
144 reason = "expected a quantity of %s for data type %s, received %s" % (str(expected), data_type, str(received))
145 loc = getargs('location', kwargs)
146 super().__init__(name, reason, location=loc)
149class ExpectedArrayError(Error):
151 @docval({'name': 'name', 'type': str, 'doc': 'the name of the component that is erroneous'},
152 {'name': 'expected', 'type': (tuple, list), 'doc': 'the expected shape'},
153 {'name': 'received', 'type': str, 'doc': 'the received data'},
154 {'name': 'location', 'type': str, 'doc': 'the location of the error', 'default': None})
155 def __init__(self, **kwargs):
156 name = getargs('name', kwargs)
157 expected = getargs('expected', kwargs)
158 received = getargs('received', kwargs)
159 reason = "incorrect shape - expected an array of shape '%s', got non-array data '%s'" % (expected, received)
160 loc = getargs('location', kwargs)
161 super().__init__(name, reason, location=loc)
164class ShapeError(Error):
166 @docval({'name': 'name', 'type': str, 'doc': 'the name of the component that is erroneous'},
167 {'name': 'expected', 'type': (tuple, list), 'doc': 'the expected shape'},
168 {'name': 'received', 'type': (tuple, list), 'doc': 'the received shape'},
169 {'name': 'location', 'type': str, 'doc': 'the location of the error', 'default': None})
170 def __init__(self, **kwargs):
171 name = getargs('name', kwargs)
172 expected = getargs('expected', kwargs)
173 received = getargs('received', kwargs)
174 reason = "incorrect shape - expected '%s', got '%s'" % (expected, received)
175 loc = getargs('location', kwargs)
176 super().__init__(name, reason, location=loc)
179class IllegalLinkError(Error):
180 """
181 A validation error for indicating that a link was used where an actual object
182 (i.e. a dataset or a group) must be used
183 """
185 @docval({'name': 'name', 'type': str, 'doc': 'the name of the component that is erroneous'},
186 {'name': 'location', 'type': str, 'doc': 'the location of the error', 'default': None})
187 def __init__(self, **kwargs):
188 name = getargs('name', kwargs)
189 reason = "illegal use of link (linked object will not be validated)"
190 loc = getargs('location', kwargs)
191 super().__init__(name, reason, location=loc)
194class IncorrectDataType(Error):
195 """
196 A validation error for indicating that the incorrect data_type (not dtype) was used.
197 """
199 @docval({'name': 'name', 'type': str, 'doc': 'the name of the component that is erroneous'},
200 {'name': 'expected', 'type': str, 'doc': 'the expected data_type'},
201 {'name': 'received', 'type': str, 'doc': 'the received data_type'},
202 {'name': 'location', 'type': str, 'doc': 'the location of the error', 'default': None})
203 def __init__(self, **kwargs):
204 name = getargs('name', kwargs)
205 expected = getargs('expected', kwargs)
206 received = getargs('received', kwargs)
207 reason = "incorrect data_type - expected '%s', got '%s'" % (expected, received)
208 loc = getargs('location', kwargs)
209 super().__init__(name, reason, location=loc)