From 0b71cd3eac7baa0a6cb614f628a5e9c1458a253a Mon Sep 17 00:00:00 2001 From: Filipp Lepalaan Date: Mon, 31 Oct 2016 11:19:38 +0200 Subject: Return GsxError on 403 result --- gsxws/core.py | 65 ++++++++++++++++++++++++++++++++++++----------------------- 1 file changed, 40 insertions(+), 25 deletions(-) diff --git a/gsxws/core.py b/gsxws/core.py index 4e18bdd..1d3e18b 100644 --- a/gsxws/core.py +++ b/gsxws/core.py @@ -35,7 +35,6 @@ import logging import requests import tempfile import objectify -from urlparse import urlparse import xml.etree.ElementTree as ET from datetime import date, time, datetime, timedelta @@ -157,18 +156,29 @@ def get_format(locale=GSX_LOCALE): class GsxError(Exception): - def __init__(self, message=None, xml=None, url=None, code=None): + """A generic GSX-related error.""" + + def __init__(self, message=None, xml=None, url=None, code=None, status=None): + """Initialize a GsxError.""" self.codes = [] self.messages = [] if isinstance(message, basestring): self.messages.append(message) + if status == 403: + self.messages.append('Access denied') + if xml is not None: logging.debug(url) logging.debug(xml) - root = ET.fromstring(xml) + try: + root = ET.fromstring(xml) + except Exception: + return # This may also be HTML + + # Collect all the info we have on the error for el in root.findall('*//faultcode'): self.codes.append(el.text) for el in root.findall('*//faultstring'): @@ -204,12 +214,8 @@ class GsxError(Exception): class GsxCache(object): - """ - The cache creates a separate shelf for each GSX session. + """The cache creates a separate shelf for each GSX session.""" - >>> GsxCache('test').set('spam', 'eggs').get('spam') - 'eggs' - """ shelf = None tmpdir = tempfile.gettempdir() @@ -217,14 +223,15 @@ class GsxCache(object): self.key = key self.expires = expires self.now = datetime.now() - filename = os.path.join(self.tmpdir, "gsxws_%s" % key) - self.shelf = shelve.open(filename, protocol=-1) + self.fp = os.path.join(self.tmpdir, "gsxws_%s" % key) + self.shelf = shelve.open(self.fp, protocol=-1) if not self.shelf.get(key): # Initialize the key self.set(key, None) def get(self, key): + """Get a value from the cache.""" try: d = self.shelf[key] if d['expires'] > self.now: @@ -235,6 +242,7 @@ class GsxCache(object): return None def set(self, key, value): + """Set a value in the cache.""" d = { 'value' : value, 'expires' : self.now + self.expires @@ -243,9 +251,14 @@ class GsxCache(object): self.shelf[key] = d return self + def nuke(self): + """Delete this cache.""" + os.remove(self.fp) + class GsxRequest(object): - "Creates and submits the SOAP envelope" + """Creates and submits the SOAP envelope.""" + env = None obj = None # The GsxObject being submitted data = None # The GsxObject payload in XML format @@ -255,7 +268,7 @@ class GsxRequest(object): _response = "" def __init__(self, **kwargs): - "Construct the SOAP envelope" + "Construct the SOAP envelope." self.objects = [] self.env = ET.Element("soapenv:Envelope") self.env.set("xmlns:core", "http://gsxws.apple.com/elements/core") @@ -281,8 +294,8 @@ class GsxRequest(object): try: self._url = GSX_URL.format(env=GSX_HOSTS[GSX_ENV], region=GSX_REGION) except KeyError: - raise GsxError('GSX environment (%s) must be one of: %s' % (GSX_ENV, - ', '.join(GSX_HOSTS.keys()))) + raise GsxError('GSX environment (%s) must be one of: %s' % (GSX_ENV, + ', '.join(GSX_HOSTS.keys()))) logging.debug(self._url) logging.debug(xmldata) @@ -332,7 +345,7 @@ class GsxRequest(object): # @hack RunDiagnosticTest doesn't follow the naming conventions if method.endswith('RunDiagnosticTest'): request_name = 'RunDiagnosticTestRequestData' - + request = ET.SubElement(root, request_name) request.append(GSX_SESSION) @@ -343,15 +356,15 @@ class GsxRequest(object): request.append(self.data) data = ET.tostring(self.env, "UTF-8") - res = self._send(method, data) - xml = res.text.encode('utf-8') + res = self._send(method, data) + xml = res.text.encode('utf-8') self.xml_response = xml + logging.debug("Response: %s %s %s" % (res.status_code, res.reason, xml)) + if res.status_code > 200: - raise GsxError(xml=xml, url=self._url) + raise GsxError(xml=xml, url=self._url, status=res.status_code) - logging.debug("Response: %s %s %s" % (res.status_code, res.reason, xml)) - if raw is True: return ET.fromstring(self.xml_response) @@ -379,7 +392,7 @@ class GsxResponse: self.response = objectify.parse(xml, self.el_response) logging.debug("Response: %s %s %s" % (http_response.status_code, http_response.reason, xml)) - + if raw is True: return ET.fromstring(self.xml_response) @@ -396,7 +409,8 @@ class GsxResponse: class GsxObject(object): - "XML/SOAP representation of a GSX object" + """XML/SOAP representation of a GSX object.""" + _data = {} def __init__(self, *args, **kwargs): @@ -448,7 +462,7 @@ class GsxObject(object): del(self._data[prop]) def _submit(self, arg, method, ret=None, raw=False): - "Shortcut for submitting a GsxObject" + """Shortcut for submitting a GsxObject.""" self._req = GsxRequest(**{arg: self}) result = self._req._submit(method, ret, raw) if result is None: @@ -524,7 +538,7 @@ class GsxSession(GsxObject): global GSX_SESSION session = self._cache.get("session") - if not session is None: + if session is not None: GSX_SESSION = session else: self._req = GsxRequest(AuthenticateRequest=self) @@ -546,7 +560,8 @@ def connect(user_id, sold_to, region=GSX_REGION, locale=GSX_LOCALE): """ - Establishes connection with GSX Web Services. + Establish connection with GSX Web Services. + Returns the session ID of the new connection. """ global GSX_ENV -- cgit v1.2.3