Team Ai
Datasetpublic

codekingpro/portable-devtools

sourceHugging Faceupdated 5mo agoView on Hugging Face
1likes15kdownloads
exceptions.py627 linesDownload Raw Back to api_core
1# Copyright 2014 Google LLC2#3# Licensed under the Apache License, Version 2.0 (the "License");4# you may not use this file except in compliance with the License.5# You may obtain a copy of the License at6#7#     http://www.apache.org/licenses/LICENSE-2.08#9# Unless required by applicable law or agreed to in writing, software10# distributed under the License is distributed on an "AS IS" BASIS,11# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.12# See the License for the specific language governing permissions and13# limitations under the License.14 15"""Exceptions raised by Google API core & clients.16 17This module provides base classes for all errors raised by libraries based18on :mod:`google.api_core`, including both HTTP and gRPC clients.19"""20 21from __future__ import absolute_import22from __future__ import unicode_literals23 24import http.client25from typing import Dict26from typing import Union27import warnings28 29from google.rpc import error_details_pb230 31try:32    import grpc33 34    try:35        from grpc_status import rpc_status36    except ImportError:  # pragma: NO COVER37        warnings.warn(38            "Please install grpcio-status to obtain helpful grpc error messages.",39            ImportWarning,40        )41        rpc_status = None42except ImportError:  # pragma: NO COVER43    grpc = None44 45# Lookup tables for mapping exceptions from HTTP and gRPC transports.46# Populated by _GoogleAPICallErrorMeta47_HTTP_CODE_TO_EXCEPTION: Dict[int, Exception] = {}48_GRPC_CODE_TO_EXCEPTION: Dict[int, Exception] = {}49 50# Additional lookup table to map integer status codes to grpc status code51# grpc does not currently support initializing enums from ints52# i.e., grpc.StatusCode(5) raises an error53_INT_TO_GRPC_CODE = {}54if grpc is not None:  # pragma: no branch55    for x in grpc.StatusCode:56        _INT_TO_GRPC_CODE[x.value[0]] = x57 58 59class GoogleAPIError(Exception):60    """Base class for all exceptions raised by Google API Clients."""61 62    pass63 64 65class DuplicateCredentialArgs(GoogleAPIError):66    """Raised when multiple credentials are passed."""67 68    pass69 70 71class RetryError(GoogleAPIError):72    """Raised when a function has exhausted all of its available retries.73 74    Args:75        message (str): The exception message.76        cause (Exception): The last exception raised when retrying the77            function.78    """79 80    def __init__(self, message, cause):81        super(RetryError, self).__init__(message)82        self.message = message83        self._cause = cause84 85    @property86    def cause(self):87        """The last exception raised when retrying the function."""88        return self._cause89 90    def __str__(self):91        return "{}, last exception: {}".format(self.message, self.cause)92 93 94class _GoogleAPICallErrorMeta(type):95    """Metaclass for registering GoogleAPICallError subclasses."""96 97    def __new__(mcs, name, bases, class_dict):98        cls = type.__new__(mcs, name, bases, class_dict)99        if cls.code is not None:100            _HTTP_CODE_TO_EXCEPTION.setdefault(cls.code, cls)101        if cls.grpc_status_code is not None:102            _GRPC_CODE_TO_EXCEPTION.setdefault(cls.grpc_status_code, cls)103        return cls104 105 106class GoogleAPICallError(GoogleAPIError, metaclass=_GoogleAPICallErrorMeta):107    """Base class for exceptions raised by calling API methods.108 109    Args:110        message (str): The exception message.111        errors (Sequence[Any]): An optional list of error details.112        details (Sequence[Any]): An optional list of objects defined in google.rpc.error_details.113        response (Union[requests.Request, grpc.Call]): The response or114            gRPC call metadata.115        error_info (Union[error_details_pb2.ErrorInfo, None]): An optional object containing error info116            (google.rpc.error_details.ErrorInfo).117    """118 119    code: Union[int, None] = None120    """Optional[int]: The HTTP status code associated with this error.121 122    This may be ``None`` if the exception does not have a direct mapping123    to an HTTP error.124 125    See http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html126    """127 128    grpc_status_code = None129    """Optional[grpc.StatusCode]: The gRPC status code associated with this130    error.131 132    This may be ``None`` if the exception does not match up to a gRPC error.133    """134 135    def __init__(self, message, errors=(), details=(), response=None, error_info=None):136        super(GoogleAPICallError, self).__init__(message)137        self.message = message138        """str: The exception message."""139        self._errors = errors140        self._details = details141        self._response = response142        self._error_info = error_info143 144    def __str__(self):145        error_msg = "{} {}".format(self.code, self.message)146        if self.details:147            error_msg = "{} {}".format(error_msg, self.details)148        # Note: This else condition can be removed once proposal A from149        # b/284179390 is implemented.150        else:151            if self.errors:152                errors = [153                    f"{error.code}: {error.message}"154                    for error in self.errors155                    if hasattr(error, "code") and hasattr(error, "message")156                ]157                if errors:158                    error_msg = "{} {}".format(error_msg, "\n".join(errors))159        return error_msg160 161    @property162    def reason(self):163        """The reason of the error.164 165        Reference:166            https://github.com/googleapis/googleapis/blob/master/google/rpc/error_details.proto#L112167 168        Returns:169            Union[str, None]: An optional string containing reason of the error.170        """171        return self._error_info.reason if self._error_info else None172 173    @property174    def domain(self):175        """The logical grouping to which the "reason" belongs.176 177        Reference:178            https://github.com/googleapis/googleapis/blob/master/google/rpc/error_details.proto#L112179 180        Returns:181            Union[str, None]: An optional string containing a logical grouping to which the "reason" belongs.182        """183        return self._error_info.domain if self._error_info else None184 185    @property186    def metadata(self):187        """Additional structured details about this error.188 189        Reference:190            https://github.com/googleapis/googleapis/blob/master/google/rpc/error_details.proto#L112191 192        Returns:193            Union[Dict[str, str], None]: An optional object containing structured details about the error.194        """195        return self._error_info.metadata if self._error_info else None196 197    @property198    def errors(self):199        """Detailed error information.200 201        Returns:202            Sequence[Any]: A list of additional error details.203        """204        return list(self._errors)205 206    @property207    def details(self):208        """Information contained in google.rpc.status.details.209 210        Reference:211            https://github.com/googleapis/googleapis/blob/master/google/rpc/status.proto212            https://github.com/googleapis/googleapis/blob/master/google/rpc/error_details.proto213 214        Returns:215            Sequence[Any]: A list of structured objects from error_details.proto216        """217        return list(self._details)218 219    @property220    def response(self):221        """Optional[Union[requests.Request, grpc.Call]]: The response or222        gRPC call metadata."""223        return self._response224 225 226class Redirection(GoogleAPICallError):227    """Base class for for all redirection (HTTP 3xx) responses."""228 229 230class MovedPermanently(Redirection):231    """Exception mapping a ``301 Moved Permanently`` response."""232 233    code = http.client.MOVED_PERMANENTLY234 235 236class NotModified(Redirection):237    """Exception mapping a ``304 Not Modified`` response."""238 239    code = http.client.NOT_MODIFIED240 241 242class TemporaryRedirect(Redirection):243    """Exception mapping a ``307 Temporary Redirect`` response."""244 245    code = http.client.TEMPORARY_REDIRECT246 247 248class ResumeIncomplete(Redirection):249    """Exception mapping a ``308 Resume Incomplete`` response.250 251    .. note:: :attr:`http.client.PERMANENT_REDIRECT` is ``308``, but Google252        APIs differ in their use of this status code.253    """254 255    code = 308256 257 258class ClientError(GoogleAPICallError):259    """Base class for all client error (HTTP 4xx) responses."""260 261 262class BadRequest(ClientError):263    """Exception mapping a ``400 Bad Request`` response."""264 265    code = http.client.BAD_REQUEST266 267 268class InvalidArgument(BadRequest):269    """Exception mapping a :attr:`grpc.StatusCode.INVALID_ARGUMENT` error."""270 271    grpc_status_code = grpc.StatusCode.INVALID_ARGUMENT if grpc is not None else None272 273 274class FailedPrecondition(BadRequest):275    """Exception mapping a :attr:`grpc.StatusCode.FAILED_PRECONDITION`276    error."""277 278    grpc_status_code = grpc.StatusCode.FAILED_PRECONDITION if grpc is not None else None279 280 281class OutOfRange(BadRequest):282    """Exception mapping a :attr:`grpc.StatusCode.OUT_OF_RANGE` error."""283 284    grpc_status_code = grpc.StatusCode.OUT_OF_RANGE if grpc is not None else None285 286 287class Unauthorized(ClientError):288    """Exception mapping a ``401 Unauthorized`` response."""289 290    code = http.client.UNAUTHORIZED291 292 293class Unauthenticated(Unauthorized):294    """Exception mapping a :attr:`grpc.StatusCode.UNAUTHENTICATED` error."""295 296    grpc_status_code = grpc.StatusCode.UNAUTHENTICATED if grpc is not None else None297 298 299class Forbidden(ClientError):300    """Exception mapping a ``403 Forbidden`` response."""301 302    code = http.client.FORBIDDEN303 304 305class PermissionDenied(Forbidden):306    """Exception mapping a :attr:`grpc.StatusCode.PERMISSION_DENIED` error."""307 308    grpc_status_code = grpc.StatusCode.PERMISSION_DENIED if grpc is not None else None309 310 311class NotFound(ClientError):312    """Exception mapping a ``404 Not Found`` response or a313    :attr:`grpc.StatusCode.NOT_FOUND` error."""314 315    code = http.client.NOT_FOUND316    grpc_status_code = grpc.StatusCode.NOT_FOUND if grpc is not None else None317 318 319class MethodNotAllowed(ClientError):320    """Exception mapping a ``405 Method Not Allowed`` response."""321 322    code = http.client.METHOD_NOT_ALLOWED323 324 325class Conflict(ClientError):326    """Exception mapping a ``409 Conflict`` response."""327 328    code = http.client.CONFLICT329 330 331class AlreadyExists(Conflict):332    """Exception mapping a :attr:`grpc.StatusCode.ALREADY_EXISTS` error."""333 334    grpc_status_code = grpc.StatusCode.ALREADY_EXISTS if grpc is not None else None335 336 337class Aborted(Conflict):338    """Exception mapping a :attr:`grpc.StatusCode.ABORTED` error."""339 340    grpc_status_code = grpc.StatusCode.ABORTED if grpc is not None else None341 342 343class LengthRequired(ClientError):344    """Exception mapping a ``411 Length Required`` response."""345 346    code = http.client.LENGTH_REQUIRED347 348 349class PreconditionFailed(ClientError):350    """Exception mapping a ``412 Precondition Failed`` response."""351 352    code = http.client.PRECONDITION_FAILED353 354 355class RequestRangeNotSatisfiable(ClientError):356    """Exception mapping a ``416 Request Range Not Satisfiable`` response."""357 358    code = http.client.REQUESTED_RANGE_NOT_SATISFIABLE359 360 361class TooManyRequests(ClientError):362    """Exception mapping a ``429 Too Many Requests`` response."""363 364    code = http.client.TOO_MANY_REQUESTS365 366 367class ResourceExhausted(TooManyRequests):368    """Exception mapping a :attr:`grpc.StatusCode.RESOURCE_EXHAUSTED` error."""369 370    grpc_status_code = grpc.StatusCode.RESOURCE_EXHAUSTED if grpc is not None else None371 372 373class Cancelled(ClientError):374    """Exception mapping a :attr:`grpc.StatusCode.CANCELLED` error."""375 376    # This maps to HTTP status code 499. See377    # https://github.com/googleapis/googleapis/blob/master/google/rpc/code.proto378    code = 499379    grpc_status_code = grpc.StatusCode.CANCELLED if grpc is not None else None380 381 382class ServerError(GoogleAPICallError):383    """Base for 5xx responses."""384 385 386class InternalServerError(ServerError):387    """Exception mapping a ``500 Internal Server Error`` response. or a388    :attr:`grpc.StatusCode.INTERNAL` error."""389 390    code = http.client.INTERNAL_SERVER_ERROR391    grpc_status_code = grpc.StatusCode.INTERNAL if grpc is not None else None392 393 394class Unknown(ServerError):395    """Exception mapping a :attr:`grpc.StatusCode.UNKNOWN` error."""396 397    grpc_status_code = grpc.StatusCode.UNKNOWN if grpc is not None else None398 399 400class DataLoss(ServerError):401    """Exception mapping a :attr:`grpc.StatusCode.DATA_LOSS` error."""402 403    grpc_status_code = grpc.StatusCode.DATA_LOSS if grpc is not None else None404 405 406class MethodNotImplemented(ServerError):407    """Exception mapping a ``501 Not Implemented`` response or a408    :attr:`grpc.StatusCode.UNIMPLEMENTED` error."""409 410    code = http.client.NOT_IMPLEMENTED411    grpc_status_code = grpc.StatusCode.UNIMPLEMENTED if grpc is not None else None412 413 414class BadGateway(ServerError):415    """Exception mapping a ``502 Bad Gateway`` response."""416 417    code = http.client.BAD_GATEWAY418 419 420class ServiceUnavailable(ServerError):421    """Exception mapping a ``503 Service Unavailable`` response or a422    :attr:`grpc.StatusCode.UNAVAILABLE` error."""423 424    code = http.client.SERVICE_UNAVAILABLE425    grpc_status_code = grpc.StatusCode.UNAVAILABLE if grpc is not None else None426 427 428class GatewayTimeout(ServerError):429    """Exception mapping a ``504 Gateway Timeout`` response."""430 431    code = http.client.GATEWAY_TIMEOUT432 433 434class DeadlineExceeded(GatewayTimeout):435    """Exception mapping a :attr:`grpc.StatusCode.DEADLINE_EXCEEDED` error."""436 437    grpc_status_code = grpc.StatusCode.DEADLINE_EXCEEDED if grpc is not None else None438 439 440def exception_class_for_http_status(status_code):441    """Return the exception class for a specific HTTP status code.442 443    Args:444        status_code (int): The HTTP status code.445 446    Returns:447        :func:`type`: the appropriate subclass of :class:`GoogleAPICallError`.448    """449    return _HTTP_CODE_TO_EXCEPTION.get(status_code, GoogleAPICallError)450 451 452def from_http_status(status_code, message, **kwargs):453    """Create a :class:`GoogleAPICallError` from an HTTP status code.454 455    Args:456        status_code (int): The HTTP status code.457        message (str): The exception message.458        kwargs: Additional arguments passed to the :class:`GoogleAPICallError`459            constructor.460 461    Returns:462        GoogleAPICallError: An instance of the appropriate subclass of463            :class:`GoogleAPICallError`.464    """465    error_class = exception_class_for_http_status(status_code)466    error = error_class(message, **kwargs)467 468    if error.code is None:469        error.code = status_code470 471    return error472 473 474def from_http_response(response):475    """Create a :class:`GoogleAPICallError` from a :class:`requests.Response`.476 477    Args:478        response (requests.Response): The HTTP response.479 480    Returns:481        GoogleAPICallError: An instance of the appropriate subclass of482            :class:`GoogleAPICallError`, with the message and errors populated483            from the response.484    """485    try:486        payload = response.json()487    except ValueError:488        payload = {"error": {"message": response.text or "unknown error"}}489 490    error_message = payload.get("error", {}).get("message", "unknown error")491    errors = payload.get("error", {}).get("errors", ())492    # In JSON, details are already formatted in developer-friendly way.493    details = payload.get("error", {}).get("details", ())494    error_info = list(495        filter(496            lambda detail: detail.get("@type", "")497            == "type.googleapis.com/google.rpc.ErrorInfo",498            details,499        )500    )501    error_info = error_info[0] if error_info else None502 503    message = "{method} {url}: {error}".format(504        method=response.request.method,505        url=response.request.url,506        error=error_message,507    )508 509    exception = from_http_status(510        response.status_code,511        message,512        errors=errors,513        details=details,514        response=response,515        error_info=error_info,516    )517    return exception518 519 520def exception_class_for_grpc_status(status_code):521    """Return the exception class for a specific :class:`grpc.StatusCode`.522 523    Args:524        status_code (grpc.StatusCode): The gRPC status code.525 526    Returns:527        :func:`type`: the appropriate subclass of :class:`GoogleAPICallError`.528    """529    return _GRPC_CODE_TO_EXCEPTION.get(status_code, GoogleAPICallError)530 531 532def from_grpc_status(status_code, message, **kwargs):533    """Create a :class:`GoogleAPICallError` from a :class:`grpc.StatusCode`.534 535    Args:536        status_code (Union[grpc.StatusCode, int]): The gRPC status code.537        message (str): The exception message.538        kwargs: Additional arguments passed to the :class:`GoogleAPICallError`539            constructor.540 541    Returns:542        GoogleAPICallError: An instance of the appropriate subclass of543            :class:`GoogleAPICallError`.544    """545 546    if isinstance(status_code, int):547        status_code = _INT_TO_GRPC_CODE.get(status_code, status_code)548 549    error_class = exception_class_for_grpc_status(status_code)550    error = error_class(message, **kwargs)551 552    if error.grpc_status_code is None:553        error.grpc_status_code = status_code554 555    return error556 557 558def _is_informative_grpc_error(rpc_exc):559    return hasattr(rpc_exc, "code") and hasattr(rpc_exc, "details")560 561 562def _parse_grpc_error_details(rpc_exc):563    try:564        status = rpc_status.from_call(rpc_exc)565    except NotImplementedError:  # workaround566        return [], None567 568    if not status:569        return [], None570 571    possible_errors = [572        error_details_pb2.BadRequest,573        error_details_pb2.PreconditionFailure,574        error_details_pb2.QuotaFailure,575        error_details_pb2.ErrorInfo,576        error_details_pb2.RetryInfo,577        error_details_pb2.ResourceInfo,578        error_details_pb2.RequestInfo,579        error_details_pb2.DebugInfo,580        error_details_pb2.Help,581        error_details_pb2.LocalizedMessage,582    ]583    error_info = None584    error_details = []585    for detail in status.details:586        matched_detail_cls = list(587            filter(lambda x: detail.Is(x.DESCRIPTOR), possible_errors)588        )589        # If nothing matched, use detail directly.590        if len(matched_detail_cls) == 0:591            info = detail592        else:593            info = matched_detail_cls[0]()594            detail.Unpack(info)595        error_details.append(info)596        if isinstance(info, error_details_pb2.ErrorInfo):597            error_info = info598    return error_details, error_info599 600 601def from_grpc_error(rpc_exc):602    """Create a :class:`GoogleAPICallError` from a :class:`grpc.RpcError`.603 604    Args:605        rpc_exc (grpc.RpcError): The gRPC error.606 607    Returns:608        GoogleAPICallError: An instance of the appropriate subclass of609            :class:`GoogleAPICallError`.610    """611    # NOTE(lidiz) All gRPC error shares the parent class grpc.RpcError.612    # However, check for grpc.RpcError breaks backward compatibility.613    if (614        grpc is not None and isinstance(rpc_exc, grpc.Call)615    ) or _is_informative_grpc_error(rpc_exc):616        details, err_info = _parse_grpc_error_details(rpc_exc)617        return from_grpc_status(618            rpc_exc.code(),619            rpc_exc.details(),620            errors=(rpc_exc,),621            details=details,622            response=rpc_exc,623            error_info=err_info,624        )625    else:626        return GoogleAPICallError(str(rpc_exc), errors=(rpc_exc,), response=rpc_exc)627 
codekingpro/portable-devtools · Team Ai