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