Coverage for /Users/davegaeddert/Development/dropseed/plain/plain/plain/exceptions.py: 50%
109 statements
« prev ^ index » next coverage.py v7.6.1, created at 2024-10-16 22:04 -0500
« prev ^ index » next coverage.py v7.6.1, created at 2024-10-16 22:04 -0500
1"""
2Global Plain exception and warning classes.
3"""
4import operator
6from plain.utils.hashable import make_hashable
9class FieldDoesNotExist(Exception):
10 """The requested model field does not exist"""
12 pass
15class PackageRegistryNotReady(Exception):
16 """The plain.packages registry is not populated yet"""
18 pass
21class ObjectDoesNotExist(Exception):
22 """The requested object does not exist"""
24 silent_variable_failure = True
27class MultipleObjectsReturned(Exception):
28 """The query returned multiple objects when only one was expected."""
30 pass
33class SuspiciousOperation(Exception):
34 """The user did something suspicious"""
37class SuspiciousMultipartForm(SuspiciousOperation):
38 """Suspect MIME request in multipart form data"""
40 pass
43class SuspiciousFileOperation(SuspiciousOperation):
44 """A Suspicious filesystem operation was attempted"""
46 pass
49class DisallowedHost(SuspiciousOperation):
50 """HTTP_HOST header contains invalid value"""
52 pass
55class DisallowedRedirect(SuspiciousOperation):
56 """Redirect to scheme not in allowed list"""
58 pass
61class TooManyFieldsSent(SuspiciousOperation):
62 """
63 The number of fields in a GET or POST request exceeded
64 settings.DATA_UPLOAD_MAX_NUMBER_FIELDS.
65 """
67 pass
70class TooManyFilesSent(SuspiciousOperation):
71 """
72 The number of fields in a GET or POST request exceeded
73 settings.DATA_UPLOAD_MAX_NUMBER_FILES.
74 """
76 pass
79class RequestDataTooBig(SuspiciousOperation):
80 """
81 The size of the request (excluding any file uploads) exceeded
82 settings.DATA_UPLOAD_MAX_MEMORY_SIZE.
83 """
85 pass
88class RequestAborted(Exception):
89 """The request was closed before it was completed, or timed out."""
91 pass
94class BadRequest(Exception):
95 """The request is malformed and cannot be processed."""
97 pass
100class PermissionDenied(Exception):
101 """The user did not have permission to do that"""
103 pass
106class ViewDoesNotExist(Exception):
107 """The requested view does not exist"""
109 pass
112class ImproperlyConfigured(Exception):
113 """Plain is somehow improperly configured"""
115 pass
118class FieldError(Exception):
119 """Some kind of problem with a model field."""
121 pass
124NON_FIELD_ERRORS = "__all__"
127class ValidationError(Exception):
128 """An error while validating data."""
130 def __init__(self, message, code=None, params=None):
131 """
132 The `message` argument can be a single error, a list of errors, or a
133 dictionary that maps field names to lists of errors. What we define as
134 an "error" can be either a simple string or an instance of
135 ValidationError with its message attribute set, and what we define as
136 list or dictionary can be an actual `list` or `dict` or an instance
137 of ValidationError with its `error_list` or `error_dict` attribute set.
138 """
139 super().__init__(message, code, params)
141 if isinstance(message, ValidationError):
142 if hasattr(message, "error_dict"):
143 message = message.error_dict
144 elif not hasattr(message, "message"):
145 message = message.error_list
146 else:
147 message, code, params = message.message, message.code, message.params
149 if isinstance(message, dict):
150 self.error_dict = {}
151 for field, messages in message.items():
152 if not isinstance(messages, ValidationError):
153 messages = ValidationError(messages)
154 self.error_dict[field] = messages.error_list
156 elif isinstance(message, list):
157 self.error_list = []
158 for message in message:
159 # Normalize plain strings to instances of ValidationError.
160 if not isinstance(message, ValidationError):
161 message = ValidationError(message)
162 if hasattr(message, "error_dict"):
163 self.error_list.extend(sum(message.error_dict.values(), []))
164 else:
165 self.error_list.extend(message.error_list)
167 else:
168 self.message = message
169 self.code = code
170 self.params = params
171 self.error_list = [self]
173 @property
174 def message_dict(self):
175 # Trigger an AttributeError if this ValidationError
176 # doesn't have an error_dict.
177 getattr(self, "error_dict")
179 return dict(self)
181 @property
182 def messages(self):
183 if hasattr(self, "error_dict"):
184 return sum(dict(self).values(), [])
185 return list(self)
187 def update_error_dict(self, error_dict):
188 if hasattr(self, "error_dict"):
189 for field, error_list in self.error_dict.items():
190 error_dict.setdefault(field, []).extend(error_list)
191 else:
192 error_dict.setdefault(NON_FIELD_ERRORS, []).extend(self.error_list)
193 return error_dict
195 def __iter__(self):
196 if hasattr(self, "error_dict"):
197 for field, errors in self.error_dict.items():
198 yield field, list(ValidationError(errors))
199 else:
200 for error in self.error_list:
201 message = error.message
202 if error.params:
203 message %= error.params
204 yield str(message)
206 def __str__(self):
207 if hasattr(self, "error_dict"):
208 return repr(dict(self))
209 return repr(list(self))
211 def __repr__(self):
212 return "ValidationError(%s)" % self
214 def __eq__(self, other):
215 if not isinstance(other, ValidationError):
216 return NotImplemented
217 return hash(self) == hash(other)
219 def __hash__(self):
220 if hasattr(self, "message"):
221 return hash(
222 (
223 self.message,
224 self.code,
225 make_hashable(self.params),
226 )
227 )
228 if hasattr(self, "error_dict"):
229 return hash(make_hashable(self.error_dict))
230 return hash(tuple(sorted(self.error_list, key=operator.attrgetter("message"))))
233class EmptyResultSet(Exception):
234 """A database query predicate is impossible."""
236 pass
239class FullResultSet(Exception):
240 """A database query predicate is matches everything."""
242 pass