From 5588f3478463725215ae14f413904d4baef749f5 Mon Sep 17 00:00:00 2001 From: Chris Lunsford Date: Wed, 8 Jul 2020 12:19:07 -0400 Subject: [PATCH] Add Tracking ID to API exceptions and warnings Add the `trackingId` returned in Webex API responses to the library API errors and warnings. Clean-up exception and warning inheritance to reduce code duplication and provide a consistent inheritance hierarchy. --- docs/user/api.rst | 8 ++++++ webexteamssdk/__init__.py | 4 +-- webexteamssdk/exceptions.py | 53 ++++++++++++++++++++++--------------- 3 files changed, 42 insertions(+), 23 deletions(-) diff --git a/docs/user/api.rst b/docs/user/api.rst index 2b45153..836e67c 100644 --- a/docs/user/api.rst +++ b/docs/user/api.rst @@ -324,6 +324,14 @@ Exceptions Warnings ======== +.. autoexception:: webexteamssdkWarning() + :show-inheritance: + :members: + +.. autoexception:: ApiWarning() + :show-inheritance: + :members: + .. autoexception:: RateLimitWarning() :show-inheritance: :members: diff --git a/webexteamssdk/__init__.py b/webexteamssdk/__init__.py index 47b5c0e..0f714a7 100644 --- a/webexteamssdk/__init__.py +++ b/webexteamssdk/__init__.py @@ -37,8 +37,8 @@ from ._version import get_versions from .api import WebexTeamsAPI from .exceptions import ( - AccessTokenError, ApiError, MalformedResponse, RateLimitError, - RateLimitWarning, webexteamssdkException, + AccessTokenError, ApiError, ApiWarning, MalformedResponse, RateLimitError, + RateLimitWarning, webexteamssdkException, webexteamssdkWarning, ) from .models.dictionary import dict_data_factory from .models.immutable import ( diff --git a/webexteamssdk/exceptions.py b/webexteamssdk/exceptions.py index 36006b8..75c5f3b 100644 --- a/webexteamssdk/exceptions.py +++ b/webexteamssdk/exceptions.py @@ -46,6 +46,11 @@ class webexteamssdkException(Exception): pass +class webexteamssdkWarning(webexteamssdkException, Warning): + """Base class for all webexteamssdk warnings.""" + pass + + class AccessTokenError(webexteamssdkException): """Raised when an incorrect Webex Teams Access Token has been provided.""" pass @@ -73,6 +78,9 @@ def __init__(self, response): self.status = self.response.reason """The HTTP status from the API response.""" + self.description = RESPONSE_CODES.get(self.status_code) + """A description of the HTTP Response Code from the API docs.""" + self.details = None """The parsed JSON details from the API response.""" if "application/json" in \ @@ -85,24 +93,40 @@ def __init__(self, response): self.message = self.details.get("message") if self.details else None """The error message from the parsed API response.""" - self.description = RESPONSE_CODES.get(self.status_code) - """A description of the HTTP Response Code from the API docs.""" + self.tracking_id = ( + self.details.get("trackingId") if self.details else None + or self.response.headers.get("trackingId") + ) + """The Webex Tracking ID from the response.""" - super(ApiError, self).__init__( - "[{status_code}]{status} - {message}".format( + self.error_message = ( + "[{status_code}]{status} - {detail}{tracking_id}".format( status_code=self.status_code, status=" " + self.status if self.status else "", - message=self.message or self.description or "Unknown Error", + detail=self.message or self.description or "Unknown Error", + tracking_id=" [Tracking ID: " + self.tracking_id + "]" + if self.tracking_id else "", ) ) + super(ApiError, self).__init__(self.error_message) + def __repr__(self): - return "<{exception_name} [{status_code}]>".format( + return "<{exception_name} [{status_code}]{status}>".format( exception_name=self.__class__.__name__, status_code=self.status_code, + status=" " + self.status if self.status else "", ) +class ApiWarning(webexteamssdkWarning, ApiError): + """Warnings raised from API responses received from the Webex APIs. + + Several data attributes are available for inspection. + """ + pass + + class RateLimitError(ApiError): """Webex Teams Rate-Limit exceeded Error. @@ -125,26 +149,13 @@ def __init__(self, response): super(RateLimitError, self).__init__(response) -class RateLimitWarning(UserWarning): +class RateLimitWarning(ApiWarning, RateLimitError): """Webex Teams rate-limit exceeded warning. Raised when a rate-limit exceeded message is received and the request will be retried. """ - - def __init__(self, response): - assert isinstance(response, requests.Response) - - # Extended warning attributes - self.retry_after = max(1, int(response.headers.get('Retry-After', 15))) - """The `Retry-After` time period (in seconds) provided by Webex Teams. - - Defaults to 15 seconds if the response `Retry-After` header isn't - present in the response headers, and defaults to a minimum wait time of - 1 second if Webex Teams returns a `Retry-After` header of 0 seconds. - """ - - super(RateLimitWarning, self).__init__() + pass class MalformedResponse(webexteamssdkException):