-
Notifications
You must be signed in to change notification settings - Fork 10
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Reusable function to extract error message from responses and … (#144)
- Loading branch information
1 parent
db52e6e
commit feaec68
Showing
5 changed files
with
186 additions
and
31 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -60,3 +60,6 @@ Utilities | |
|
||
.. automodule:: osctiny.utils.mapping | ||
:members: | ||
|
||
.. automodule:: osctiny.utils.xml | ||
:members: |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,10 +1,42 @@ | ||
""" | ||
Base classes for osc-tiny specific exceptions | ||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | ||
Exception base classes and utilities | ||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | ||
""" | ||
import typing | ||
from warnings import warn | ||
|
||
from requests import HTTPError, Response | ||
|
||
from .xml import get_objectified_xml | ||
|
||
|
||
def get_http_error_details(error: typing.Union[HTTPError, Response]) -> str: | ||
""" | ||
Extract user-friendly error message from exception | ||
.. versionadded:: 0.8.0 | ||
""" | ||
if isinstance(error, HTTPError): | ||
response = error.response | ||
elif isinstance(error, Response): | ||
response = error | ||
else: | ||
raise TypeError("Expected a Response of HTTPError instance!") | ||
|
||
try: | ||
xml_obj = get_objectified_xml(response) | ||
except Exception as error2: | ||
warn(message=f"Failed to extract error message due to another error: {error2}", | ||
category=RuntimeWarning) | ||
else: | ||
summary = xml_obj.find("summary") | ||
if summary is not None: | ||
return summary.text | ||
|
||
return f"Server replied with: {response.status_code} {response.reason}" | ||
|
||
|
||
class OscError(Exception): | ||
""" | ||
Base class for expcetions to be raised by ``osctiny`` | ||
Base class for exceptions to be raised by ``osctiny`` | ||
""" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,74 @@ | ||
""" | ||
XML parsing | ||
^^^^^^^^^^^ | ||
.. versionadded:: 0.8.0 | ||
""" | ||
import re | ||
import threading | ||
import typing | ||
|
||
from lxml.etree import XMLParser | ||
from lxml.objectify import fromstring, makeparser, ObjectifiedElement | ||
from requests import Response | ||
|
||
|
||
THREAD_LOCAL = threading.local() | ||
|
||
|
||
def get_xml_parser() -> XMLParser: | ||
""" | ||
Get a parser object | ||
.. versionchanged:: 0.8.0 | ||
Carved out from the ``Osc`` class | ||
""" | ||
if not hasattr(THREAD_LOCAL, "parser"): | ||
THREAD_LOCAL.parser = makeparser(huge_tree=True) | ||
|
||
return THREAD_LOCAL.parser | ||
|
||
|
||
def get_objectified_xml(response: typing.Union[Response, str]) -> ObjectifiedElement: | ||
""" | ||
Return API response as an XML object | ||
.. versionchanged:: 0.1.6 | ||
Allow parsing of "huge" XML inputs | ||
.. versionchanged:: 0.2.4 | ||
Allow ``response`` to be a string | ||
.. versionchanged:: 0.8.0 | ||
Carved out from ``Osc`` class | ||
:param response: An API response or XML string | ||
:rtype response: :py:class:`requests.Response` | ||
:return: :py:class:`lxml.objectify.ObjectifiedElement` | ||
""" | ||
if isinstance(response, str): | ||
text = response | ||
elif isinstance(response, Response): | ||
text = response.text | ||
else: | ||
raise TypeError(f"Expected a string or response object. Got {type(response)} instead.") | ||
|
||
parser = get_xml_parser() | ||
|
||
try: | ||
return fromstring(text, parser) | ||
except ValueError: | ||
# Just in case OBS returns a Unicode string with encoding | ||
# declaration | ||
if isinstance(text, str) and \ | ||
"encoding=" in text: | ||
return fromstring( | ||
re.sub(r'encoding="[^"]+"', "", text) | ||
) | ||
|
||
# This might be something else | ||
raise |