aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorFilipp Lepalaan <f@230.to>2013-06-09 11:38:51 +0300
committerFilipp Lepalaan <f@230.to>2013-06-09 11:38:51 +0300
commitf454cc6167cd7d91297d6b24187193888ed719ee (patch)
tree410974d475d4effc2a3635db7c2e4fa4a895c388
parent1b63b1954f33bdd1706b0d7186d550407599a5a6 (diff)
downloadpy-gsxws-f454cc6167cd7d91297d6b24187193888ed719ee.tar.gz
py-gsxws-f454cc6167cd7d91297d6b24187193888ed719ee.tar.bz2
py-gsxws-f454cc6167cd7d91297d6b24187193888ed719ee.zip
Added xmltodict.py
-rw-r--r--gsxws/core.py86
-rw-r--r--gsxws/repairs.py9
-rw-r--r--gsxws/xmltodict.py183
3 files changed, 192 insertions, 86 deletions
diff --git a/gsxws/core.py b/gsxws/core.py
index a49ea6f..c70cd36 100644
--- a/gsxws/core.py
+++ b/gsxws/core.py
@@ -31,6 +31,7 @@ import hashlib
import logging
import httplib
import tempfile
+import xmltodict
from urlparse import urlparse
import xml.etree.ElementTree as ET
@@ -263,10 +264,10 @@ class GsxRequest(object):
logging.debug("Response: %s %s %s" % (res.status, res.reason, xml))
response = response or self._response
-
- for r in ET.fromstring(xml).findall("*//%s" % response):
- o = r if raw else GsxObject.from_xml(r)
- self.objects.append(o)
+ logging.debug("Looking for %s" % response)
+ root = ET.fromstring(xml).find("*//%s" % response)
+ data = xmltodict.ConvertXmlToDict(root)
+ self.objects = data[response]
return self.objects
@@ -355,81 +356,6 @@ class GsxObject(object):
return root
- @classmethod
- def from_xml(cls, el):
- "Constructs a GsxObject from an XML Element"
- obj = GsxObject()
-
- for r in el:
-
- newitem = cls.from_xml(r)
- k, v = r.tag, r.text
-
- if hasattr(obj, k):
- # found duplicate tag %s" % k
- attr = obj.__getattr__(k)
- if isinstance(attr, list):
- # append to existing list
- newattr = attr.append(newitem)
- setattr(obj, k, newattr)
- else:
- # convert to list
- setattr(obj, k, [v, newitem])
- else:
- # unique tag %s -> set the dictionary" % k
- setattr(obj, k, newitem)
-
- if k in ["partsInfo"]:
- # found new list item %s" % k
- attr = []
- attr.append(GsxObject.from_xml(r))
-
- setattr(obj, k, attr)
-
- if k in ["packingList", "proformaFileData", "returnLabelFileData"]:
- v = base64.b64decode(v)
- of = tempfile.NamedTemporaryFile(suffix=".pdf", delete=False)
- of.write(v)
- v = of.name
-
- if isinstance(v, basestring):
-
- v = unicode(v) # "must be unicode, not str"
-
- # convert Y and N to boolean
- if re.search(r'^[YN]$', v):
- v = (v == "Y")
-
- # strip currency prefix and munge into float
- if re.search(r'Price$', k):
- v = float(re.sub(r'[A-Z ,]', '', v))
-
- # Convert timestamps to native Python type
- # 18-Jan-13 14:38:04
- if re.search(r'TimeStamp$', k):
- v = datetime.strptime(v, "%d-%b-%y %H:%M:%S")
-
- if re.search(r'Date$', k):
- # looks like some sort of date, let's try to convert
- # @TODO: return actual native dates, not isoformat()
- try:
- # standard GSX format: "mm/dd/yy"
- dt = datetime.strptime(v, "%m/%d/%y")
- v = dt.date().isoformat()
- except ValueError:
- pass
-
- try:
- # some dates are formatted as "yyyy-mm-dd"
- dt = datetime.strptime(v, "%Y-%m-%d")
- v = dt.date().isoformat()
- except (ValueError, TypeError):
- pass
-
- setattr(obj, k, v)
-
- return obj
-
class GsxRequestObject(GsxObject):
"The GSX-friendly representation of this GsxObject"
@@ -472,7 +398,7 @@ class GsxSession(GsxObject):
else:
self._req = GsxRequest(AuthenticateRequest=self)
result = self._req._submit("Authenticate")
- self._session_id = result[0].userSessionId
+ self._session_id = result.userSessionId
GSX_SESSION = self.get_session()
self._cache.set("session", GSX_SESSION)
diff --git a/gsxws/repairs.py b/gsxws/repairs.py
index b8445db..3461092 100644
--- a/gsxws/repairs.py
+++ b/gsxws/repairs.py
@@ -161,21 +161,18 @@ class Repair(GsxObject):
"""
self._namespace = "core:"
details = self._submit("RepairDetailsRequest", "RepairDetails", "lookupResponseData")
- #self.parts = []
-"""
+
# fix tracking URL if available
for i, p in enumerate(details.partsInfo):
- print p
try:
url = re.sub('<<TRKNO>>', p.deliveryTrackingNumber, p.carrierURL)
- #details.partsInfo[i].carrierURL = url
- #self.parts.append(p)
+ details.partsInfo[i].carrierURL = url
except AttributeError:
pass
self.details = details
return details
-"""
+
class CannotDuplicateRepair(Repair):
"""
diff --git a/gsxws/xmltodict.py b/gsxws/xmltodict.py
new file mode 100644
index 0000000..c577e55
--- /dev/null
+++ b/gsxws/xmltodict.py
@@ -0,0 +1,183 @@
+## {{{ http://code.activestate.com/recipes/573463/ (r7)
+
+import re
+import base64
+import tempfile
+from datetime import datetime
+from xml.etree import ElementTree
+
+
+class XmlDictObject(dict):
+ """
+ Adds object like functionality to the standard dictionary.
+ """
+ def __init__(self, initdict=None):
+ if initdict is None:
+ initdict = {}
+ dict.__init__(self, initdict)
+
+ def __getattr__(self, item):
+ v = self.__getitem__(item)
+
+ if item in ["packingList", "proformaFileData", "returnLabelFileData"]:
+ v = base64.b64decode(v)
+ of = tempfile.NamedTemporaryFile(suffix=".pdf", delete=False)
+ of.write(v)
+ return of.name
+
+ try:
+ if isinstance(v, basestring):
+ v = unicode(v) # "must be unicode, not str"
+
+ # convert Y and N to boolean
+ if re.search(r'^[YN]$', v):
+ v = (v == "Y")
+
+ # strip currency prefix and munge into float
+ if re.search(r'Price$', item):
+ v = float(re.sub(r'[A-Z ,]', '', v))
+
+ # Convert timestamps to native Python type
+ # 18-Jan-13 14:38:04
+ if re.search(r'TimeStamp$', item):
+ v = datetime.strptime(v, "%d-%b-%y %H:%M:%S")
+
+ if re.search(r'Date$', item):
+ # looks like some sort of date, let's try to convert
+ try:
+ # standard GSX format: "mm/dd/yy"
+ dt = datetime.strptime(v, "%m/%d/%y")
+ v = dt.date()
+ except ValueError:
+ pass
+
+ try:
+ # some dates are formatted as "yyyy-mm-dd"
+ dt = datetime.strptime(v, "%Y-%m-%d")
+ v = dt.date()
+ except (ValueError, TypeError):
+ pass
+ except TypeError:
+ pass
+
+ return v
+
+ def __setattr__(self, item, value):
+ self.__setitem__(item, value)
+
+ def __str__(self):
+ if self.has_key('_text'):
+ return self.__getitem__('_text')
+ else:
+ return ''
+
+ @staticmethod
+ def Wrap(x):
+ """
+ Static method to wrap a dictionary recursively as an XmlDictObject
+ """
+
+ if isinstance(x, dict):
+ return XmlDictObject((k, XmlDictObject.Wrap(v)) for (k, v) in x.iteritems())
+ elif isinstance(x, list):
+ return [XmlDictObject.Wrap(v) for v in x]
+ else:
+ return x
+
+ @staticmethod
+ def _UnWrap(x):
+ if isinstance(x, dict):
+ return dict((k, XmlDictObject._UnWrap(v)) for (k, v) in x.iteritems())
+ elif isinstance(x, list):
+ return [XmlDictObject._UnWrap(v) for v in x]
+ else:
+ return x
+
+ def UnWrap(self):
+ """
+ Recursively converts an XmlDictObject to a standard dictionary and returns the result.
+ """
+
+ return XmlDictObject._UnWrap(self)
+
+
+def _ConvertDictToXmlRecurse(parent, dictitem):
+ assert type(dictitem) is not type([])
+
+ if isinstance(dictitem, dict):
+ for (tag, child) in dictitem.iteritems():
+ if str(tag) == '_text':
+ parent.text = str(child)
+ elif type(child) is type([]):
+ # iterate through the array and convert
+ for listchild in child:
+ elem = ElementTree.Element(tag)
+ parent.append(elem)
+ _ConvertDictToXmlRecurse(elem, listchild)
+ else:
+ elem = ElementTree.Element(tag)
+ parent.append(elem)
+ _ConvertDictToXmlRecurse(elem, child)
+ else:
+ parent.text = str(dictitem)
+
+
+def ConvertDictToXml(xmldict):
+ """
+ Converts a dictionary to an XML ElementTree Element
+ """
+ roottag = xmldict.keys()[0]
+ root = ElementTree.Element(roottag)
+ _ConvertDictToXmlRecurse(root, xmldict[roottag])
+ return root
+
+
+def _ConvertXmlToDictRecurse(node, dictclass):
+ nodedict = dictclass()
+
+ if len(node.items()) > 0:
+ # if we have attributes, set them
+ nodedict.update(dict(node.items()))
+
+ for child in node:
+ # recursively add the element's children
+ newitem = _ConvertXmlToDictRecurse(child, dictclass)
+ if nodedict.has_key(child.tag):
+ # found duplicate tag, force a list
+ if type(nodedict[child.tag]) is type([]):
+ # append to existing list
+ nodedict[child.tag].append(newitem)
+ else:
+ # convert to list
+ nodedict[child.tag] = [nodedict[child.tag], newitem]
+ else:
+ # only one, directly set the dictionary
+ nodedict[child.tag] = newitem
+
+ if node.text is None:
+ text = ''
+ else:
+ text = node.text.strip()
+
+ if len(nodedict) > 0:
+ # if we have a dictionary add the text as a dictionary value (if there is any)
+ if len(text) > 0:
+ nodedict['_text'] = text
+ else:
+ # if we don't have child nodes or attributes, just set the text
+ nodedict = text
+
+ return nodedict
+
+
+def ConvertXmlToDict(root, dictclass=XmlDictObject):
+ """
+ Converts an XML file or ElementTree Element to a dictionary
+ """
+ # If a string is passed in, try to open it as a file
+ if type(root) == type(''):
+ root = ElementTree.parse(root).getroot()
+ elif not isinstance(root, ElementTree.Element):
+ raise TypeError("Expected ElementTree.Element or file path string")
+
+ return dictclass({root.tag: _ConvertXmlToDictRecurse(root, dictclass)})