Skip to content

Commit

Permalink
Improve error handling for mapservice responses
Browse files Browse the repository at this point in the history
  • Loading branch information
dharvey-consbio committed Dec 14, 2021
1 parent c6573a1 commit 29cac8e
Show file tree
Hide file tree
Showing 6 changed files with 60 additions and 42 deletions.
16 changes: 12 additions & 4 deletions clients/arcgis.py
Original file line number Diff line number Diff line change
Expand Up @@ -306,7 +306,10 @@ def generate_image_from_query(self, extent, width, height, image_path, params):
except requests.exceptions.HTTPError as ex:
raise HTTPError(
"The ArcGIS service image query did not respond correctly",
params=image_params, underlying=ex, url=image_url
params=image_params,
underlying=ex,
url=image_url,
status_code=getattr(ex.response, "status_code", None)
)
except (IOError, ValueError) as ex:
raise ImageError(
Expand Down Expand Up @@ -435,10 +438,12 @@ def _render_single_tile(self, zoom_level, url_row, url_col, row, col, tile_heigh
try:
response = self._make_request(tile_url, tile_params)
except requests.exceptions.HTTPError as ex:
status_code = getattr(getattr(ex, "response", None), "status_code", None)
raise HTTPError(
"The ArcGIS single tile query did not respond correctly",
params=tile_params, status_code=status_code, underlying=ex, url=tile_url
params=tile_params,
underlying=ex,
url=tile_url,
status_code=getattr(ex.response, "status_code", None)
)

base_image.paste(
Expand Down Expand Up @@ -756,7 +761,10 @@ def project_extent(self, extent, to_spatial_ref):
except requests.exceptions.HTTPError as ex:
raise HTTPError(
"The ArcGIS geometry service did not respond correctly",
params=params, status_code=response.status_code, underlying=ex, url=url
params=params,
underlying=ex,
url=url,
status_code=response.status_code
)

try:
Expand Down
39 changes: 16 additions & 23 deletions clients/exceptions.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,49 +21,42 @@ def __init__(self, message, url=None, **kwargs):
self.error_context.update({kw: arg for kw, arg in kwargs.items() if arg})


class ContentError(ClientError, requests.exceptions.ContentDecodingError):

def __init__(self, message, params=None, **kwargs):
super(ContentError, self).__init__(message, **kwargs)
self.error_context["params"] = self.params = params


class HTTPError(ClientError, requests.exceptions.HTTPError):
class ClientRequestError(ClientError):

def __init__(self, message, params=None, status_code=None, **kwargs):
super(HTTPError, self).__init__(message, **kwargs)
super(ClientRequestError, self).__init__(message, **kwargs)

self.error_context["params"] = self.params = params
self.error_context["status_code"] = self.status_code = status_code


class NetworkError(ClientError, requests.exceptions.RequestException):
class ContentError(ClientRequestError, requests.exceptions.ContentDecodingError):
pass


class ImageError(ClientError):
class HTTPError(ClientRequestError, requests.exceptions.HTTPError):
pass

def __init__(self, message, params=None, tile_info=None, **kwargs):
super(ImageError, self).__init__(message, **kwargs)

self.error_context["params"] = self.params = params
self.error_context["tile_info"] = self.tile_info = tile_info
class NetworkError(ClientRequestError, requests.exceptions.RequestException):
pass


class ServiceError(ClientError):
class ServiceError(ClientRequestError):
""" A class to represent a range of service errors differentiated by status code """

def __init__(self, message, status_code=None, **kwargs):
super(ServiceError, self).__init__(message, **kwargs)
self.error_context["status_code"] = self.status_code = status_code


class ServiceTimeout(ServiceError, requests.exceptions.Timeout):
""" A class to represent server-side timeouts, not client (408) """

def __init__(self, message, status_code=504, **kwargs):
super(ServiceTimeout, self).__init__(message, **kwargs)
self.error_context["status_code"] = self.status_code = status_code

class ImageError(ClientError):

def __init__(self, message, params=None, tile_info=None, **kwargs):
super(ImageError, self).__init__(message, **kwargs)

self.error_context["params"] = self.params = params
self.error_context["tile_info"] = self.tile_info = tile_info


class ValidationError(ClientError, AttributeError):
Expand Down
31 changes: 20 additions & 11 deletions clients/resources.py
Original file line number Diff line number Diff line change
Expand Up @@ -107,29 +107,33 @@ def bulk_get(cls, url, strict=True, session=None, bulk_key=None, bulk_defaults=N
try:
response = self._make_request()
except requests.exceptions.HTTPError as ex:
response = getattr(ex, "response", None)

reason = getattr(response, "reason", None)
status_code = getattr(response, "status_code", None)
reason = getattr(ex.response, "reason", None)
status_code = getattr(ex.response, "status_code", None)

raise HTTPError(
f"The map service returned {status_code} ({reason})",
params=self._params, status_code=status_code, underlying=ex, url=self._url
params=self._params, underlying=ex, url=self._url, status_code=status_code
)
except requests.exceptions.Timeout as ex:
status_code = getattr(getattr(ex, "response", None), "status_code", None)
timeout_error = type(ex).__name__

raise ServiceTimeout(
f"{timeout_error}: the map service did not respond in time",
status_code=status_code, underlying=ex, url=self._url
params=self._params,
underlying=ex,
url=self._url,
status_code=getattr(ex.response, "status_code", None)
)
except requests.exceptions.RequestException as ex:
network_error = type(ex).__name__

raise NetworkError(
f"{network_error}: the map service is unavailable",
underlying=ex, url=self._url
params=self._params,
underlying=ex,
url=self._url,
status_code=getattr(ex.response, "status_code", None)
)

try:
Expand Down Expand Up @@ -253,22 +257,27 @@ def _load_resource(self, as_unicode=True):
)
raise HTTPError(
"The map service did not respond correctly",
params=self._params, underlying=ex, url=self._url
params=self._params, underlying=ex, url=self._url, status_code=status_code
)
except requests.exceptions.Timeout as ex:
status_code = getattr(getattr(ex, "response", None), "status_code", None)
timeout_error = type(ex).__name__

raise ServiceTimeout(
f"{timeout_error}: the map service did not respond in time",
status_code=status_code, underlying=ex, url=self._url
params=self._params,
underlying=ex,
url=self._url,
status_code=getattr(ex.response, "status_code", None)
)
except requests.exceptions.RequestException as ex:
network_error = type(ex).__name__

raise NetworkError(
f"{network_error}: the map service is unavailable",
underlying=ex, url=self._url
params=self._params,
underlying=ex,
url=self._url,
status_code=getattr(ex.response, "status_code", None)
)
except (SyntaxError, ValueError) as ex:
unicode_error = isinstance(ex, UnicodeEncodeError)
Expand Down
2 changes: 1 addition & 1 deletion clients/sciencebase.py
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ def get_json(self, url, external_id=None):
error = value["message"] if isinstance(value, dict) else value[0]["message"]
except (IndexError, KeyError, ValueError):
error = f"ScienceBase denied your request for this item: {external_id}"
raise HTTPError(error, status_code=response.status_code, underlying=ex, url=url)
raise HTTPError(error, underlying=ex, url=url, status_code=response.status_code)

return self._get_json(response, external_id)

Expand Down
9 changes: 7 additions & 2 deletions clients/thredds.py
Original file line number Diff line number Diff line change
Expand Up @@ -315,7 +315,9 @@ def _query_layer_ids(self, data=None, layer_ids=None):
except requests.exceptions.HTTPError as ex:
raise HTTPError(
"The THREDDS layer id query did not respond correctly",
underlying=ex, url=self._layers_url
underlying=ex,
url=self._layers_url,
status_code=getattr(ex.response, "status_code", None)
)

label = data["label"]
Expand Down Expand Up @@ -459,7 +461,10 @@ def generate_image_from_query(self, extent, width, height, layer_ids, style_ids,
except requests.exceptions.HTTPError as ex:
raise HTTPError(
"The THREDDS service image query did not respond correctly",
params=image_params, underlying=ex, url=self._wms_url
params=image_params,
underlying=ex,
url=self._wms_url,
status_code=getattr(ex.response, "status_code", None)
)
except (IOError, ValueError) as ex:
raise ImageError(
Expand Down
5 changes: 4 additions & 1 deletion clients/wms.py
Original file line number Diff line number Diff line change
Expand Up @@ -764,7 +764,10 @@ def generate_image_from_query(self, extent, width, height, layer_ids, style_ids,
except requests.exceptions.HTTPError as ex:
raise HTTPError(
"The WMS service image query did not respond correctly",
params=image_params, underlying=ex, url=self.wms_url
params=image_params,
underlying=ex,
url=self.wms_url,
status_code=getattr(ex.response, "status_code", None)
)
except (IOError, ValueError) as ex:
raise ImageError(
Expand Down

0 comments on commit 29cac8e

Please sign in to comment.