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