Source code for xled.response
# -*- coding: utf-8 -*-
from __future__ import absolute_import
from xled.exceptions import ApplicationError
from xled.compat import JSONDecodeError, Mapping
[docs]class ApplicationResponse(Mapping):
"""The :class:`ApplicationResponse <ApplicationResponse>` object, which
contains a server's response to an HTTP request.
:param response: to which this is a response. Can be later set as an
attribute.
:type response: :class:`requests.Response <Response>` or None
"""
def __init__(self, response=None):
self.response = response
self._data = False
self._content_consumed = False
@property
def status_code(self):
"""Integer Code of responded application status, e.g. 1000 or 1001"""
return self.data.get("code", None)
@property
def ok(self):
"""
Returns True if :attr:`status_code` is 1000, False if not.
First this attribute checks if parent response is ok. Then it checks if
application response can be determined and finally if
:attr:`status_code` is 1000.
"""
if not self.response.ok:
return False
try:
self.raise_for_status(propagate=False)
except ApplicationError:
return False
return True
@property
def data(self):
"""
Response content as dict
"""
if self._data is False:
# Read the contents.
if self._content_consumed:
raise RuntimeError("The content for this response was already consumed")
if self.response is None:
raise RuntimeError(
"No response to create application response data from"
)
if self.response.raw is None:
self._data = {}
else:
self.response.raise_for_status()
try:
json_data = self.response.json()
except JSONDecodeError:
msg = "Failed to decode application data: {text}".format(
text=self.response.text
)
raise ApplicationError(msg, response=self.response)
self._data = dict(json_data)
self._content_consumed = True
return self._data
[docs] def raise_for_status(self, propagate=True):
"""
Raises :py:exc:`~.exceptions.ApplicationError`, if one occurred.
:param bool propagate: check status of underlying
:class:`requests.Response` as well.
:raises ApplicationError: if response cannot be parsed
as JSON or application status code wasn't success (1000).
:rtype: None
"""
if propagate:
self.response.raise_for_status()
if self.status_code is None:
msg = "Status code not determined."
raise ApplicationError(msg, response=self.response)
msg = ""
if self.status_code == 1000:
return
elif isinstance(self.status_code, int):
msg = "Application error code: {status_code}".format(
status_code=self.status_code
)
raise ApplicationError(msg, response=self.response)
def __getitem__(self, key):
return self.data[key]
def __iter__(self):
return iter(self.data)
def __len__(self):
return len(self.data)
def __repr__(self):
try:
self.raise_for_status(propagate=False)
except ApplicationError:
status = None
else:
status = self.status_code
return "<{class_name} [{status}]>".format(
class_name=self.__class__.__name__, status=status
)
[docs]def build_response(response):
"""Creates ApplicationResponse object out of Requests response
:param response: to which this is a response. Can be later set as an
attribute.
:type response: :class:`requests.Response <Response>` or None
:rtype: :class:`ApplicationResponse`
"""
app_response = ApplicationResponse()
app_response.response = response
return app_response