appier 1.34.6__py2.py3-none-any.whl → 1.34.8__py2.py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- appier/__init__.py +1 -1
- appier/api.py +10 -0
- appier/asgi.py +10 -0
- appier/async_neo.py +2 -2
- appier/async_old.py +1 -1
- appier/base.py +15 -2
- appier/bus.py +10 -0
- appier/config.py +409 -401
- appier/data.py +2 -0
- appier/exceptions.py +450 -442
- appier/http.py +1292 -1283
- appier/model.py +7 -2
- appier/mongo.py +24 -0
- appier/scheduler.py +342 -334
- appier/test/data.py +10 -0
- appier/test/error_handler.py +142 -0
- appier/test/exception_handler.py +146 -0
- appier/test/http.py +24 -0
- appier/test/tags.py +109 -0
- appier/util.py +2517 -2503
- {appier-1.34.6.dist-info → appier-1.34.8.dist-info}/METADATA +1 -1
- {appier-1.34.6.dist-info → appier-1.34.8.dist-info}/RECORD +25 -22
- {appier-1.34.6.dist-info → appier-1.34.8.dist-info}/LICENSE +0 -0
- {appier-1.34.6.dist-info → appier-1.34.8.dist-info}/WHEEL +0 -0
- {appier-1.34.6.dist-info → appier-1.34.8.dist-info}/top_level.txt +0 -0
appier/exceptions.py
CHANGED
|
@@ -1,442 +1,450 @@
|
|
|
1
|
-
#!/usr/bin/python
|
|
2
|
-
# -*- coding: utf-8 -*-
|
|
3
|
-
|
|
4
|
-
# Hive Appier Framework
|
|
5
|
-
# Copyright (c) 2008-2024 Hive Solutions Lda.
|
|
6
|
-
#
|
|
7
|
-
# This file is part of Hive Appier Framework.
|
|
8
|
-
#
|
|
9
|
-
# Hive Appier Framework is free software: you can redistribute it and/or modify
|
|
10
|
-
# it under the terms of the Apache License as published by the Apache
|
|
11
|
-
# Foundation, either version 2.0 of the License, or (at your option) any
|
|
12
|
-
# later version.
|
|
13
|
-
#
|
|
14
|
-
# Hive Appier Framework is distributed in the hope that it will be useful,
|
|
15
|
-
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
16
|
-
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
17
|
-
# Apache License for more details.
|
|
18
|
-
#
|
|
19
|
-
# You should have received a copy of the Apache License along with
|
|
20
|
-
# Hive Appier Framework. If not, see <http://www.apache.org/licenses/>.
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
"""
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
"""
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
""" The
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
self
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
def
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
def
|
|
107
|
-
if self.
|
|
108
|
-
return
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
model
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
def
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
errors_s = errors_s
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
errors_s
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
"""
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
"""
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
def
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
"""
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
self.errors
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
"""
|
|
363
|
-
|
|
364
|
-
error
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
self
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
if
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
error
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
1
|
+
#!/usr/bin/python
|
|
2
|
+
# -*- coding: utf-8 -*-
|
|
3
|
+
|
|
4
|
+
# Hive Appier Framework
|
|
5
|
+
# Copyright (c) 2008-2024 Hive Solutions Lda.
|
|
6
|
+
#
|
|
7
|
+
# This file is part of Hive Appier Framework.
|
|
8
|
+
#
|
|
9
|
+
# Hive Appier Framework is free software: you can redistribute it and/or modify
|
|
10
|
+
# it under the terms of the Apache License as published by the Apache
|
|
11
|
+
# Foundation, either version 2.0 of the License, or (at your option) any
|
|
12
|
+
# later version.
|
|
13
|
+
#
|
|
14
|
+
# Hive Appier Framework is distributed in the hope that it will be useful,
|
|
15
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
16
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
17
|
+
# Apache License for more details.
|
|
18
|
+
#
|
|
19
|
+
# You should have received a copy of the Apache License along with
|
|
20
|
+
# Hive Appier Framework. If not, see <http://www.apache.org/licenses/>.
|
|
21
|
+
|
|
22
|
+
"""appier.exceptions
|
|
23
|
+
|
|
24
|
+
Custom exception hierarchy for the framework. Defines base
|
|
25
|
+
`AppierException` plus HTTP error subclasses that map to status
|
|
26
|
+
codes. Guarantees uniform error reporting and catching across
|
|
27
|
+
controllers, APIs and utilities.
|
|
28
|
+
"""
|
|
29
|
+
|
|
30
|
+
__author__ = "João Magalhães <joamag@hive.pt>"
|
|
31
|
+
""" The author(s) of the module """
|
|
32
|
+
|
|
33
|
+
__copyright__ = "Copyright (c) 2008-2024 Hive Solutions Lda."
|
|
34
|
+
""" The copyright for the module """
|
|
35
|
+
|
|
36
|
+
__license__ = "Apache License, Version 2.0"
|
|
37
|
+
""" The license for the module """
|
|
38
|
+
|
|
39
|
+
import json
|
|
40
|
+
import uuid
|
|
41
|
+
|
|
42
|
+
from . import common
|
|
43
|
+
from . import legacy
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
class AppierException(Exception):
|
|
47
|
+
"""
|
|
48
|
+
Top level exception to be used as the root of
|
|
49
|
+
all the exceptions to be raised by the appier infra-
|
|
50
|
+
structure. Should be compatible with HTTP status
|
|
51
|
+
codes for proper HTTP serialization.
|
|
52
|
+
"""
|
|
53
|
+
|
|
54
|
+
message = None
|
|
55
|
+
""" The message value stored to describe the
|
|
56
|
+
current exception value """
|
|
57
|
+
|
|
58
|
+
code = None
|
|
59
|
+
""" The internal error code to be used in objective
|
|
60
|
+
serialization of the error (eg: HTTP) """
|
|
61
|
+
|
|
62
|
+
headers = None
|
|
63
|
+
""" Optional list of MIME compliant headers to be sent
|
|
64
|
+
in a client/server paradigm """
|
|
65
|
+
|
|
66
|
+
meta = None
|
|
67
|
+
""" The meta information associated with the error
|
|
68
|
+
that should be considered private in context, this
|
|
69
|
+
should be structured data ready to be serializable """
|
|
70
|
+
|
|
71
|
+
def __init__(self, *args, **kwargs):
|
|
72
|
+
Exception.__init__(self, *args)
|
|
73
|
+
self.name = self._name()
|
|
74
|
+
self.message = kwargs.get("message", self.name)
|
|
75
|
+
self.code = kwargs.get("code", 500)
|
|
76
|
+
self.headers = kwargs.get("headers", None)
|
|
77
|
+
self.meta = kwargs.get("meta", None)
|
|
78
|
+
self.args = args
|
|
79
|
+
self.kwargs = kwargs
|
|
80
|
+
self._uid = None
|
|
81
|
+
|
|
82
|
+
def __str__(self):
|
|
83
|
+
if legacy.PYTHON_3:
|
|
84
|
+
return self.__unicode__()
|
|
85
|
+
is_unicode = legacy.is_unicode(self.message)
|
|
86
|
+
if is_unicode:
|
|
87
|
+
return self.message.encode("utf-8")
|
|
88
|
+
return self.message
|
|
89
|
+
|
|
90
|
+
def __unicode__(self):
|
|
91
|
+
is_unicode = legacy.is_unicode(self.message)
|
|
92
|
+
if not is_unicode:
|
|
93
|
+
return self.message.decode("utf-8")
|
|
94
|
+
return self.message
|
|
95
|
+
|
|
96
|
+
def get_meta(self, name, default=None):
|
|
97
|
+
if not self.meta:
|
|
98
|
+
return default
|
|
99
|
+
return self.meta.get(name, default)
|
|
100
|
+
|
|
101
|
+
def set_meta(self, name, value):
|
|
102
|
+
if not self.meta:
|
|
103
|
+
self.meta = {}
|
|
104
|
+
self.meta[name] = value
|
|
105
|
+
|
|
106
|
+
def del_meta(self, name):
|
|
107
|
+
if not self.meta:
|
|
108
|
+
return
|
|
109
|
+
if not name in self.meta:
|
|
110
|
+
return
|
|
111
|
+
del self.meta[name]
|
|
112
|
+
|
|
113
|
+
@property
|
|
114
|
+
def uid(self):
|
|
115
|
+
if self._uid:
|
|
116
|
+
return self._uid
|
|
117
|
+
self._uid = uuid.uuid4()
|
|
118
|
+
return self._uid
|
|
119
|
+
|
|
120
|
+
def _name(self):
|
|
121
|
+
cls = self.__class__
|
|
122
|
+
return common.util().camel_to_readable(cls.__name__)
|
|
123
|
+
|
|
124
|
+
|
|
125
|
+
class OperationalError(AppierException):
|
|
126
|
+
"""
|
|
127
|
+
Error raised for a runtime error and as a result
|
|
128
|
+
of an operational routine that failed.
|
|
129
|
+
This should not be used for coherent development
|
|
130
|
+
bugs, that are raised continuously.
|
|
131
|
+
"""
|
|
132
|
+
|
|
133
|
+
pass
|
|
134
|
+
|
|
135
|
+
|
|
136
|
+
class SecurityError(AppierException):
|
|
137
|
+
"""
|
|
138
|
+
Error used to indicate security problems that may
|
|
139
|
+
arise during the execution (runtime) of an appier
|
|
140
|
+
application. This error should not be used to notify
|
|
141
|
+
development related problems.
|
|
142
|
+
"""
|
|
143
|
+
|
|
144
|
+
pass
|
|
145
|
+
|
|
146
|
+
|
|
147
|
+
class AssertionError(OperationalError):
|
|
148
|
+
"""
|
|
149
|
+
Error raised for failure to meet any pre-condition or
|
|
150
|
+
assertion for a certain data set.
|
|
151
|
+
"""
|
|
152
|
+
|
|
153
|
+
def __init__(self, *args, **kwargs):
|
|
154
|
+
kwargs["message"] = kwargs.get("message", "Assertion of data failed")
|
|
155
|
+
kwargs["code"] = kwargs.get("code", None)
|
|
156
|
+
OperationalError.__init__(self, *args, **kwargs)
|
|
157
|
+
|
|
158
|
+
|
|
159
|
+
class ValidationError(OperationalError):
|
|
160
|
+
"""
|
|
161
|
+
Error raised when a validation on the model fails
|
|
162
|
+
the error should associate a name in the model with
|
|
163
|
+
a message describing the validation failure.
|
|
164
|
+
"""
|
|
165
|
+
|
|
166
|
+
errors = None
|
|
167
|
+
""" The map containing an association between the name
|
|
168
|
+
of a field and a list of validation errors for it """
|
|
169
|
+
|
|
170
|
+
model = None
|
|
171
|
+
""" The model containing the values in it after the
|
|
172
|
+
process of validation has completed """
|
|
173
|
+
|
|
174
|
+
def __init__(self, errors, model, *args, **kwargs):
|
|
175
|
+
kwargs["message"] = kwargs.get("message", "Validation of submitted data failed")
|
|
176
|
+
kwargs["code"] = kwargs.get("code", 400)
|
|
177
|
+
OperationalError.__init__(self, *args, **kwargs)
|
|
178
|
+
self.errors = errors
|
|
179
|
+
self.model = model
|
|
180
|
+
self.set_meta("errors", self.errors)
|
|
181
|
+
|
|
182
|
+
def __str__(self):
|
|
183
|
+
if legacy.PYTHON_3:
|
|
184
|
+
return self.__unicode__()
|
|
185
|
+
message = OperationalError.__str__(self)
|
|
186
|
+
extended = common.is_devel()
|
|
187
|
+
if not extended:
|
|
188
|
+
return message
|
|
189
|
+
errors_s = self.errors_s()
|
|
190
|
+
if not errors_s:
|
|
191
|
+
return message
|
|
192
|
+
if self.model:
|
|
193
|
+
message += " for model '%s' with id '%s'" % (
|
|
194
|
+
self.model.__class__._name(),
|
|
195
|
+
self.model._id if hasattr(self.model, "_id") else "unset",
|
|
196
|
+
)
|
|
197
|
+
errors_s = errors_s.encode("utf-8")
|
|
198
|
+
message += " (" + errors_s + ")"
|
|
199
|
+
return message
|
|
200
|
+
|
|
201
|
+
def __unicode__(self):
|
|
202
|
+
message = OperationalError.__unicode__(self)
|
|
203
|
+
extended = common.is_devel()
|
|
204
|
+
if not extended:
|
|
205
|
+
return message
|
|
206
|
+
errors_s = self.errors_s()
|
|
207
|
+
if not errors_s:
|
|
208
|
+
return message
|
|
209
|
+
if self.model:
|
|
210
|
+
message += " for model '%s' with id '%s'" % (
|
|
211
|
+
self.model.__class__._name(),
|
|
212
|
+
self.model._id if hasattr(self.model, "_id") else "unset",
|
|
213
|
+
)
|
|
214
|
+
message += " (" + errors_s + ")"
|
|
215
|
+
return message
|
|
216
|
+
|
|
217
|
+
def errors_s(self, encoding="utf-8"):
|
|
218
|
+
if not self.errors:
|
|
219
|
+
return ""
|
|
220
|
+
buffer = []
|
|
221
|
+
is_first = True
|
|
222
|
+
for name, errors in legacy.iteritems(self.errors):
|
|
223
|
+
for error in errors:
|
|
224
|
+
is_bytes = legacy.is_bytes(error)
|
|
225
|
+
if is_bytes:
|
|
226
|
+
error = error.decode(encoding)
|
|
227
|
+
if is_first:
|
|
228
|
+
is_first = False
|
|
229
|
+
else:
|
|
230
|
+
buffer.append(", ")
|
|
231
|
+
buffer.append(name)
|
|
232
|
+
buffer.append(" => ")
|
|
233
|
+
buffer.append(error)
|
|
234
|
+
return legacy.u("").join(buffer)
|
|
235
|
+
|
|
236
|
+
|
|
237
|
+
class NotFoundError(OperationalError):
|
|
238
|
+
"""
|
|
239
|
+
Error originated from an operation that was not able
|
|
240
|
+
to be performed because it was not able to found the
|
|
241
|
+
requested entity/value as defined by specification.
|
|
242
|
+
"""
|
|
243
|
+
|
|
244
|
+
def __init__(self, *args, **kwargs):
|
|
245
|
+
kwargs["code"] = kwargs.get("code", 404)
|
|
246
|
+
OperationalError.__init__(self, *args, **kwargs)
|
|
247
|
+
|
|
248
|
+
|
|
249
|
+
class NotImplementedError(OperationalError):
|
|
250
|
+
"""
|
|
251
|
+
Error to be raised when a certain feature or route is not
|
|
252
|
+
yet implemented or is not meant to be implemented at the
|
|
253
|
+
defined abstraction level.
|
|
254
|
+
"""
|
|
255
|
+
|
|
256
|
+
def __init__(self, *args, **kwargs):
|
|
257
|
+
kwargs["code"] = kwargs.get("code", 501)
|
|
258
|
+
OperationalError.__init__(self, *args, **kwargs)
|
|
259
|
+
|
|
260
|
+
|
|
261
|
+
class BaseInternalError(RuntimeError):
|
|
262
|
+
"""
|
|
263
|
+
The base (internal) error class from which all the
|
|
264
|
+
internal error classes should inherit, contains basic
|
|
265
|
+
functionality to be inherited by all the internal "errors".
|
|
266
|
+
"""
|
|
267
|
+
|
|
268
|
+
message = None
|
|
269
|
+
""" The message value stored to describe the
|
|
270
|
+
current error, this should be a valid string """
|
|
271
|
+
|
|
272
|
+
meta = None
|
|
273
|
+
""" The meta information associated with the error
|
|
274
|
+
that should be considered private in context, this
|
|
275
|
+
should be structured data ready to be serializable """
|
|
276
|
+
|
|
277
|
+
def __init__(self, message, meta=None):
|
|
278
|
+
RuntimeError.__init__(self, message)
|
|
279
|
+
self.message = message
|
|
280
|
+
self.meta = meta
|
|
281
|
+
|
|
282
|
+
def __str__(self):
|
|
283
|
+
if legacy.PYTHON_3:
|
|
284
|
+
return self.__unicode__()
|
|
285
|
+
is_unicode = legacy.is_unicode(self.message)
|
|
286
|
+
if is_unicode:
|
|
287
|
+
return self.message.encode("utf-8")
|
|
288
|
+
return self.message
|
|
289
|
+
|
|
290
|
+
def __unicode__(self):
|
|
291
|
+
is_unicode = legacy.is_unicode(self.message)
|
|
292
|
+
if not is_unicode:
|
|
293
|
+
return self.message.decode("utf-8")
|
|
294
|
+
return self.message
|
|
295
|
+
|
|
296
|
+
def get_meta(self, name, default=None):
|
|
297
|
+
if not self.meta:
|
|
298
|
+
return default
|
|
299
|
+
return self.meta.get(name, default)
|
|
300
|
+
|
|
301
|
+
def set_meta(self, name, value):
|
|
302
|
+
if not self.meta:
|
|
303
|
+
self.meta = {}
|
|
304
|
+
self.meta[name] = value
|
|
305
|
+
|
|
306
|
+
def del_meta(self, name):
|
|
307
|
+
if not self.meta:
|
|
308
|
+
return
|
|
309
|
+
if not name in self.meta:
|
|
310
|
+
return
|
|
311
|
+
del self.meta[name]
|
|
312
|
+
|
|
313
|
+
|
|
314
|
+
class ValidationInternalError(BaseInternalError):
|
|
315
|
+
"""
|
|
316
|
+
Error raised when a validation on the model fails
|
|
317
|
+
the error should associate a name in the model with
|
|
318
|
+
a message describing the validation failure.
|
|
319
|
+
"""
|
|
320
|
+
|
|
321
|
+
name = None
|
|
322
|
+
""" The name of the attribute that failed
|
|
323
|
+
the validation, for latter reference """
|
|
324
|
+
|
|
325
|
+
def __init__(self, name, message, meta=None):
|
|
326
|
+
BaseInternalError.__init__(self, message, meta=meta)
|
|
327
|
+
self.name = name
|
|
328
|
+
|
|
329
|
+
|
|
330
|
+
class ValidationMultipleError(ValidationInternalError):
|
|
331
|
+
"""
|
|
332
|
+
Exception/error considered to be equivalent to the
|
|
333
|
+
validation internal error, with the exception that it
|
|
334
|
+
may handle multiple errors at the same time.
|
|
335
|
+
"""
|
|
336
|
+
|
|
337
|
+
errors = []
|
|
338
|
+
""" The sequence containing the multiple errors associated
|
|
339
|
+
with the validation multiple error """
|
|
340
|
+
|
|
341
|
+
def __init__(self, name=None, message=None, meta=None):
|
|
342
|
+
ValidationInternalError.__init__(self, name, message, meta=meta)
|
|
343
|
+
self.errors = []
|
|
344
|
+
self.set_meta("errors", self.errors)
|
|
345
|
+
|
|
346
|
+
def add_error(self, name, message):
|
|
347
|
+
if not self.name:
|
|
348
|
+
self.name = name
|
|
349
|
+
if not self.message:
|
|
350
|
+
self.message = message
|
|
351
|
+
self.errors.append((name, message))
|
|
352
|
+
|
|
353
|
+
def add_exception(self, exception):
|
|
354
|
+
self.add_error(exception.name, exception.message)
|
|
355
|
+
|
|
356
|
+
|
|
357
|
+
class HTTPError(BaseInternalError):
|
|
358
|
+
"""
|
|
359
|
+
Top level HTTP error raised whenever a bad response
|
|
360
|
+
is received from the server peer. This error is meant
|
|
361
|
+
to be used by the client library.
|
|
362
|
+
"""
|
|
363
|
+
|
|
364
|
+
error = None
|
|
365
|
+
""" The reference to the original and internal
|
|
366
|
+
HTTP error that is going to be used in the reading
|
|
367
|
+
of the underlying internal buffer """
|
|
368
|
+
|
|
369
|
+
_data = None
|
|
370
|
+
""" The underlying/internal data attribute that is
|
|
371
|
+
going to be used to cache the binary contents of the
|
|
372
|
+
error associated with this exception (data) stream """
|
|
373
|
+
|
|
374
|
+
def __init__(self, error, code=None, message=None, extended=None, meta=None):
|
|
375
|
+
message = message or "Problem in the HTTP request"
|
|
376
|
+
if extended == None:
|
|
377
|
+
extended = common.is_devel()
|
|
378
|
+
if code:
|
|
379
|
+
message = "[%d] %s" % (code, message)
|
|
380
|
+
if extended:
|
|
381
|
+
data = self.read(error=error)
|
|
382
|
+
try:
|
|
383
|
+
data = data.decode("utf-8")
|
|
384
|
+
except Exception:
|
|
385
|
+
data = legacy.str(data)
|
|
386
|
+
if data:
|
|
387
|
+
message = message + "\n" + data if message else data
|
|
388
|
+
BaseInternalError.__init__(self, message, meta=meta)
|
|
389
|
+
self.code = code
|
|
390
|
+
self.error = error
|
|
391
|
+
|
|
392
|
+
def read(self, error=None):
|
|
393
|
+
error = error or self.error
|
|
394
|
+
if not self._data == None:
|
|
395
|
+
return self._data
|
|
396
|
+
self._data = error.read()
|
|
397
|
+
return self._data
|
|
398
|
+
|
|
399
|
+
def read_json(self, error=None):
|
|
400
|
+
error = error or self.error
|
|
401
|
+
data = self.read(error=error)
|
|
402
|
+
if legacy.is_bytes(data):
|
|
403
|
+
data = data.decode("utf-8")
|
|
404
|
+
try:
|
|
405
|
+
data_j = json.loads(data)
|
|
406
|
+
except Exception:
|
|
407
|
+
data_j = None
|
|
408
|
+
return data_j
|
|
409
|
+
|
|
410
|
+
|
|
411
|
+
class APIError(BaseInternalError):
|
|
412
|
+
"""
|
|
413
|
+
Highest level error for API related problems that may be
|
|
414
|
+
raised from the appier API infra-structure. These kind of
|
|
415
|
+
errors should be encapsulated around proper structures
|
|
416
|
+
"""
|
|
417
|
+
|
|
418
|
+
def __init__(self, *args, **kwargs):
|
|
419
|
+
message = kwargs.get("message", None)
|
|
420
|
+
meta = kwargs.get("meta", None)
|
|
421
|
+
BaseInternalError.__init__(self, message, meta=meta)
|
|
422
|
+
|
|
423
|
+
|
|
424
|
+
class APIAccessError(APIError):
|
|
425
|
+
"""
|
|
426
|
+
General purpose access error exception, to be raised under
|
|
427
|
+
situations where the access to a certain functionalities is
|
|
428
|
+
denied for insufficient permissions/invalid credentials.
|
|
429
|
+
"""
|
|
430
|
+
|
|
431
|
+
original = None
|
|
432
|
+
""" The reference to the original error/exception that originated
|
|
433
|
+
this API access error, this may be unset in case no concrete
|
|
434
|
+
error has originated this error """
|
|
435
|
+
|
|
436
|
+
def __init__(self, *args, **kwargs):
|
|
437
|
+
self.original = kwargs.get("original", None)
|
|
438
|
+
if self.original and hasattr(self.original, "message"):
|
|
439
|
+
kwargs["message"] = self.original.message
|
|
440
|
+
APIError.__init__(self, *args, **kwargs)
|
|
441
|
+
|
|
442
|
+
|
|
443
|
+
class OAuthAccessError(APIAccessError):
|
|
444
|
+
"""
|
|
445
|
+
OAuth related problems that typically involve either outdated
|
|
446
|
+
tokens or invalid ones. Triggering this exception should imply
|
|
447
|
+
a revalidation of the current token.
|
|
448
|
+
"""
|
|
449
|
+
|
|
450
|
+
pass
|