X-Git-Url: https://git.arvados.org/arvados.git/blobdiff_plain/c1e7255a85dfc2807ba78e1cf9d109d896c80b42..ba34a22d9918ae97306472c04701e69090821c82:/sdk/python/arvados/errors.py diff --git a/sdk/python/arvados/errors.py b/sdk/python/arvados/errors.py index 85472d8cdf..15b1f6d4b9 100644 --- a/sdk/python/arvados/errors.py +++ b/sdk/python/arvados/errors.py @@ -1,16 +1,90 @@ +# Copyright (C) The Arvados Authors. All rights reserved. +# +# SPDX-License-Identifier: Apache-2.0 + # errors.py - Arvados-specific exceptions. +import json + +from apiclient import errors as apiclient_errors +from collections import OrderedDict + +class ApiError(apiclient_errors.HttpError): + def _get_reason(self): + try: + return '; '.join(json.loads(self.content.decode('utf-8'))['errors']) + except (KeyError, TypeError, ValueError): + return super(ApiError, self)._get_reason() + + +class KeepRequestError(Exception): + """Base class for errors accessing Keep services.""" + def __init__(self, message='', request_errors=(), label=""): + """KeepRequestError(message='', request_errors=(), label="") + + :message: + A human-readable message describing what Keep operation + failed. + + :request_errors: + An iterable that yields 2-tuples of keys (where the key refers to + some operation that was attempted) to the error encountered when + talking to it--either an exception, or an HTTP response object. + These will be packed into an OrderedDict, available through the + request_errors() method. + + :label: + A label indicating the type of value in the 'key' position of request_errors. + + """ + self.label = label + self._request_errors = OrderedDict(request_errors) + if self._request_errors: + exc_reports = [self._format_error(*err_pair) + for err_pair in self._request_errors.items()] + base_msg = "{}: {}".format(message, "; ".join(exc_reports)) + else: + base_msg = message + super(KeepRequestError, self).__init__(base_msg) + self.message = message + + def _format_error(self, key, error): + if isinstance(error, HttpError): + err_fmt = "{} {} responded with {e.status_code} {e.reason}" + else: + err_fmt = "{} {} raised {e.__class__.__name__} ({e})" + return err_fmt.format(self.label, key, e=error) + + def request_errors(self): + """request_errors() -> OrderedDict + + The keys of the dictionary are described by `self.label` + The corresponding value is the exception raised when sending the + request to it.""" + return self._request_errors + + +class HttpError(Exception): + def __init__(self, status_code, reason): + self.status_code = status_code + self.reason = reason + + class ArgumentError(Exception): pass class SyntaxError(Exception): pass class AssertionError(Exception): pass -class NotFoundError(Exception): - pass class CommandFailedError(Exception): pass -class KeepWriteError(Exception): +class KeepReadError(KeepRequestError): + pass +class KeepWriteError(KeepRequestError): + pass +class KeepCacheError(KeepRequestError): + pass +class NotFoundError(KeepReadError): pass class NotImplementedError(Exception): pass @@ -18,3 +92,5 @@ class NoKeepServersError(Exception): pass class StaleWriterStateError(Exception): pass +class FeatureNotEnabledError(Exception): + pass