11308: Merge branch 'master' into 11308-python3
[arvados.git] / sdk / python / arvados / errors.py
1 # errors.py - Arvados-specific exceptions.
2
3 import json
4
5 from apiclient import errors as apiclient_errors
6 from collections import OrderedDict
7
8 class ApiError(apiclient_errors.HttpError):
9     def _get_reason(self):
10         try:
11             return '; '.join(json.loads(self.content.decode('utf-8'))['errors'])
12         except (KeyError, TypeError, ValueError):
13             return super(ApiError, self)._get_reason()
14
15
16 class KeepRequestError(Exception):
17     """Base class for errors accessing Keep services."""
18     def __init__(self, message='', request_errors=(), label=""):
19         """KeepRequestError(message='', request_errors=(), label="")
20
21         :message:
22           A human-readable message describing what Keep operation
23           failed.
24
25         :request_errors:
26           An iterable that yields 2-tuples of keys (where the key refers to
27           some operation that was attempted) to the error encountered when
28           talking to it--either an exception, or an HTTP response object.
29           These will be packed into an OrderedDict, available through the
30           request_errors() method.
31
32         :label:
33           A label indicating the type of value in the 'key' position of request_errors.
34
35         """
36         self.label = label
37         self._request_errors = OrderedDict(request_errors)
38         if self._request_errors:
39             exc_reports = [self._format_error(*err_pair)
40                            for err_pair in self._request_errors.items()]
41             base_msg = "{}: {}".format(message, "; ".join(exc_reports))
42         else:
43             base_msg = message
44         super(KeepRequestError, self).__init__(base_msg)
45         self.message = message
46
47     def _format_error(self, key, error):
48         if isinstance(error, HttpError):
49             err_fmt = "{} {} responded with {e.status_code} {e.reason}"
50         else:
51             err_fmt = "{} {} raised {e.__class__.__name__} ({e})"
52         return err_fmt.format(self.label, key, e=error)
53
54     def request_errors(self):
55         """request_errors() -> OrderedDict
56
57         The keys of the dictionary are described by `self.label`
58         The corresponding value is the exception raised when sending the
59         request to it."""
60         return self._request_errors
61
62
63 class HttpError(Exception):
64     def __init__(self, status_code, reason):
65         self.status_code = status_code
66         self.reason = reason
67
68
69 class ArgumentError(Exception):
70     pass
71 class SyntaxError(Exception):
72     pass
73 class AssertionError(Exception):
74     pass
75 class CommandFailedError(Exception):
76     pass
77 class KeepReadError(KeepRequestError):
78     pass
79 class KeepWriteError(KeepRequestError):
80     pass
81 class NotFoundError(KeepReadError):
82     pass
83 class NotImplementedError(Exception):
84     pass
85 class NoKeepServersError(Exception):
86     pass
87 class StaleWriterStateError(Exception):
88     pass
89 class FeatureNotEnabledError(Exception):
90     pass