def __init__(self, faultxml=[], client=None): DynamicObject.__init__(self) Exception.__init__(self) self.code = None self.message = None self.detail = None for node in faultxml: tag = node.tag.split('}')[-1] if tag == 'faultcode': self.code = ns.split(node.text, nsmap=faultxml.nsmap) elif tag == 'Code': self.code = ns.split(node[0].text, nsmap=faultxml.nsmap) elif tag == 'faultstring': self.message = node.text elif tag == 'Reason': self.message = node[0].text elif tag == 'detail' or tag == 'Detail': faultobj = node[0] type = faultobj.get(ET.QName(ns.XSI, 'type')) if not type: type = faultobj.tag try: faultobj = client.factory(type, faultobj) except: pass self.detail = faultobj
def __init__(self, client, btype, op, tns=None): self.name = op.get('name') portop = client.wsdl.find('wsdl:portType[@name="%s"]/wsdl:operation[@name="%s"]' % (btype, self.name)) self.imsg = None self.ihdr = None self.omsg = None self.client = client self.faults = [] self.action = '""' soapop = op.find(ns.expand('soap:operation', client.nsmap)) if soapop is not None: self.action = '"%s"' % soapop.get('soapAction', '') hdr = op.find(ns.expand('soap:header', client.nsmap)) if hdr is not None: msg = client.wsdl.messages[ns.expand(hdr.get('message'), el.nsmap)] self.ihdr = msg for el in portop: (namespace, tag) = ns.split(el.tag) if tag not in ('input', 'output', 'fault'): continue msg = client.wsdl.messages[ns.expand(el.get('message'), el.nsmap)] if tag == 'input': self.imsg = msg if tag == 'output': self.omsg = msg if tag == 'fault': self.faults.append(msg)
def _make_type(self, value, type): ''' Parse value and convert it to type ''' iselem = False if ET.iselement(value): iselem = True xtype = value.get(xsi_type) if xtype: xtype = ns.expand(xtype, value.nsmap) (prefix, t) = ns.split(xtype) if prefix == ns.XS: type = 'xs:'+t else: type = xtype if value.get(xsi_nil) == 'true': return None if type.startswith('xs:'): if iselem: value = value.text c = converter(type) if value is not None and not c.check(value): value = c.fromstr(value) else: if value == "": value = None value = self.__builder__.factory(type)(value, __relax__=self.__relax__) return value
def _make_type(self, value, type): ''' Parse value and convert it to type ''' iselem = False if ET.iselement(value): iselem = True xtype = value.get(xsi_type) if xtype: xtype = ns.expand(xtype, value.nsmap) (prefix, t) = ns.split(xtype) if prefix == ns.XS: type = 'xs:' + t else: type = xtype if value.get(xsi_nil) == 'true': return None if type.startswith('xs:'): if iselem: value = value.text c = converter(type) if value is not None and not c.check(value): value = c.fromstr(value) else: if value == "": value = None value = self.__builder__.factory(type)(value, __relax__=self.__relax__) return value
def guess(self, filename): text = file(filename).read() text = re.sub(r'xmlns="[^"]*"', '', text) xml = ET.fromstring(text) obj = DynamicObject(xml) tns, tag = ns.split(xml.tag) root = self.complexType(tag, obj) el = Element(name=tag, type=root.name) self._addElement(self.schema, el)
def _mk_binding(self, bname, service): ''' Build operation objects bound to the service ''' #bname = ns.expand(bname, self.nsmap) #print "making binding for",bname binding = self.wsdl.find('wsdl:binding[@name="%s"]' % bname) (_, btype) = ns.split(binding.get('type'), binding.nsmap) for op in binding.findall(ns.expand('wsdl:operation', self.nsmap)): operation = Operation(self, btype, op) setattr(service, op.get('name'), operation)
def _mk_service(self): ''' Build a Service object for each wsdl:service ''' for s in self.wsdl.findall('wsdl:service'): name = s.get('name') service = Service(name) setattr(self, name, service) port = s.find(ns.expand('wsdl:port', self.nsmap)) (_, binding) = ns.split(port.get('binding'), port.nsmap) self._mk_binding(binding, service)
def prefix(self, namespace, joinchar=':'): ''' Get the ns prefix schema corresponding to namespace If given a full typename like {http://aaa}foobar, this function will return nsprefix:typename ''' if '}' in namespace: nsname = list(ns.split(namespace)) else: nsname = [namespace] nsname[0] = self.revns[nsname[0]] return joinchar.join(nsname)
def validate(self, element, onerror='raise'): (namespace, name) = ns.split(element.tag) validator = self.schemas[namespace]['validator'] if validator is None: validator = ET.XMLSchema(self.schemas[namespace]['root']) self.schemas[namespace]['validator'] = validator errlog = None if validator(element) == False: errlog = validator.error_log if onerror == 'log': log.error('Schema Validation Error: %s', str(errlog)) elif onerror == 'pass': pass else: raise SchemaValidationError(errlog) return errlog
def basecls(self, name): '''Get the base class corresponding to name''' (namespace, name) = ns.split(name) cls = self.schemas[namespace]['basecls'] return cls
def group(self, name): '''Get the group corresponding to name''' (namespace, name) = ns.split(name) groups = self.schemas[namespace]['groups'] return groups[name]
def element(self, name): '''Get the element corresponding to name''' (namespace, name) = ns.split(name) elements = self.schemas[namespace]['elements'] return elements.get(name)
def type(self, name): '''Get the type corresponding to name''' (namespace, name) = ns.split(name) types = self.schemas[namespace]['types'] return types.get(name)
def __xml__(self, tag=None, node=None, nsmap=None): lat = len(self.__attrchar__) done = [] extra = False if tag is None: tag = self.__class__.__name__ tag = self.__nsx__(tag) if node is None: node = ET.Element(tag, nsmap=nsmap) # Construct reverse namespace map for doing xsi:type rmap = dict((v, k) for k, v in node.nsmap.items() if k is not None) # Iterate over the template to construct the XML representation. for (name, type, default, minmax, flags) in self.__template__: # If this field is an "xs:any" node, note it for later and skip if (flags & ANY): extra = True continue # If the field is choice/optional and doesn't exist, skip it if ((flags & CHOICE) or minmax[0] == 0) and name not in self: continue # Get the value value = self[name] done.append(name) if value is None and minmax[0] == 0 and not (flags & XSINIL): # Skip fields that are none and don't have to exist, as long # as they aren't nillable continue elif (flags & ATTRIBUTE): # Handle attributes. Skip attributes that are optional value = converter(type).tostr(value) if value is None: value = '' if value is not None or minmax[0]: node.set(self.__nsx__(name[lat:], flags & QUALIFIED), value) continue elif (flags & PROPERTY): # Property node.text = converter(type).tostr(value) continue qname = self.__nsx__(name) if not isinstance(value, (list, tuple)): value = [value] for v in value: if v is None and (flags & XSINIL): # Nil node n = ET.Element(qname, xsi_nil_true) node.append(n) elif ET.iselement(v): # User supplied XML Elements, so just add them node.append(v) elif type.startswith('xs:'): # Primitive type n = ET.Element(qname) n.text = converter(type).tostr(v) node.append(n) elif flags & SIMPLE: # Primitive type type = self.__builder__.factory(type).__simple__ n = ET.Element(qname) n.text = converter(type).tostr(v) node.append(n) elif isinstance(v, DynamicObject): # Dynamic object or subclass, so marshall and append n = v.__xml__(name) if type != v.__class__.__name__: (namespace, datatype) = ns.split(v.__class__.__name__) n.set(xsi_type, '%s:%s' % (rmap[namespace], datatype)) node.append(n) elif v == '': # Carry-over for dealing with SUDS bug pass else: if not self.__relax__: raise TypeError('Unknown type', name, type) # If there was an xs:any node, fall back to the schemaless marshaller # in the base class if extra: DynamicObject.__xml__(self, tag, node, ignore=done) return node
def nssplit(self, s, target=True): tns = {} if target: tns['targetNamespace'] = self.root.get('targetNamespace') return ns.split(s, self.root.nsmap, **tns)
def invoke(self, operation, *args, **kwargs): ''' Invoke a SOAP operation. ''' self._reqno += 1 retxml = kwargs.pop('__retxml__', self.retxml) timeout = kwargs.pop('__timeout__', self.timeout) transport_options = kwargs.pop('__transport__', {}) # Create an instance of the request message and initialize # the object from the arguments param = self.factory(operation.imsg) tmpl = param.__template__ for k,v in zip((t[0] for t in tmpl), args): param[k] = v for k,v in kwargs.items(): param[k] = v # Build the soap envelope and set the http headers payload = self.envelope(self.headers, param, operation.imsg) httphdr = { 'Content-Type': 'text/xml', 'SOAPAction': operation.action } httphdr.update(self.httphdr) # Construct and issue the request, read the response payload = ET.tostring(payload, pretty_print=True) log.debug('=== SOAP REQUEST ===\n%s', payload) req = urllib2.Request(self.url, payload, httphdr) try: if self._inject: xml = ET.fromstring(self._inject.next()) else: if hasattr(self.transport, 'open'): rsp = self.transport.open(req, timeout=timeout, **transport_options) else: rsp = self.transport.urlopen(req, timeout=timeout, **transport_options) xml = ET.parse(rsp) except urllib2.HTTPError as ex: xml = ET.parse(ex) log.debug('=== SOAP RESPONSE ===\n%s', xmlstr(xml)) # Get the soap body retval = xml.find(ns.expand('soapenv:Body', self.nsmap)) if not retxml: # Does the body contain any nodes? if len(retval): # Get the first child and examine it retval = retval[0] namespace, tag = ns.split(retval.tag) # If it's a fault, convert it to an exception if tag == 'Fault': raise SoapFault(retval, self) # Otherwise, deserialize obj = self.factory(operation.omsg, retval) # If the deserialized # object has only one item, return that item, otherwise the # whole object # # This is so if the return value is a single primitive type # (like a string), you don't have to dig into an object just # to get at the single primitive return value if len(obj) == 1: obj = obj[0] retval = obj else: retval = None return retval
def __xml__(self, tag=None, node=None, nsmap=None): lat = len(self.__attrchar__) done = [] extra = False if tag is None: tag = self.__class__.__name__ tag = self.__nsx__(tag) if node is None: node = ET.Element(tag, nsmap=nsmap) # Construct reverse namespace map for doing xsi:type rmap = dict((v,k) for k, v in node.nsmap.items() if k is not None) # Iterate over the template to construct the XML representation. for (name, type, default, minmax, flags) in self.__template__: # If this field is an "xs:any" node, note it for later and skip if (flags & ANY): extra = True continue # If the field is choice/optional and doesn't exist, skip it if ((flags & CHOICE) or minmax[0] == 0) and name not in self: continue # Get the value value = self[name] done.append(name) if value is None and minmax[0] == 0 and not (flags & XSINIL): # Skip fields that are none and don't have to exist, as long # as they aren't nillable continue elif (flags & ATTRIBUTE): # Handle attributes. Skip attributes that are optional value = converter(type).tostr(value) if value is None: value = '' if value is not None or minmax[0]: node.set(self.__nsx__(name[lat:], flags & QUALIFIED), value) continue elif (flags & PROPERTY): # Property node.text = converter(type).tostr(value) continue qname = self.__nsx__(name) if not isinstance(value, (list, tuple)): value = [value] for v in value: if v is None and (flags & XSINIL): # Nil node n = ET.Element(qname, xsi_nil_true) node.append(n) elif ET.iselement(v): # User supplied XML Elements, so just add them node.append(v) elif type.startswith('xs:'): # Primitive type n = ET.Element(qname) n.text = converter(type).tostr(v) node.append(n) elif flags & SIMPLE: # Primitive type type = self.__builder__.factory(type).__simple__ n = ET.Element(qname) n.text = converter(type).tostr(v) node.append(n) elif isinstance(v, DynamicObject): # Dynamic object or subclass, so marshall and append n = v.__xml__(name) if type != v.__class__.__name__: (namespace, datatype) = ns.split(v.__class__.__name__) n.set(xsi_type, '%s:%s' % (rmap[namespace], datatype)) node.append(n) elif v == '': # Carry-over for dealing with SUDS bug pass else: if not self.__relax__: raise TypeError('Unknown type', name, type) # If there was an xs:any node, fall back to the schemaless marshaller # in the base class if extra: DynamicObject.__xml__(self, tag, node, ignore=done) return node
def schema(self, namespace): '''Get the schema corresponding to namespace''' if '}' in namespace: (namespace, name) = ns.split(namespace) return self.schemas[namespace]['root']
def invoke(self, operation, *args, **kwargs): ''' Invoke a SOAP operation. ''' self._reqno += 1 retxml = kwargs.pop('__retxml__', self.retxml) timeout = kwargs.pop('__timeout__', self.timeout) transport_options = kwargs.pop('__transport__', {}) # Create an instance of the request message and initialize # the object from the arguments param = self.factory(operation.imsg) tmpl = param.__template__ for k,v in zip((t[0] for t in tmpl), args): param[k] = v for k,v in kwargs.items(): param[k] = v # Build the soap envelope and set the http headers payload = self.envelope(self.headers, param, operation.imsg) httphdr = { 'Content-Type': 'text/xml', 'SOAPAction': operation.action } httphdr.update(self.httphdr) # Construct and issue the request, read the response payload = ET.tostring(payload, pretty_print=True) log.debug('=== SOAP REQUEST ===\n%s', re.sub(r'password>.*?<', r'password>*****<', payload )) req = urllib2.Request(self.url, payload, httphdr) try: if self._inject: xml = ET.fromstring(self._inject.next()) else: if hasattr(self.transport, 'open'): rsp = self.transport.open(req, timeout=timeout, **transport_options) else: rsp = self.transport.urlopen(req, timeout=timeout, **transport_options) xml = ET.parse(rsp) except urllib2.HTTPError as ex: xml = ET.parse(ex) log.debug('=== SOAP RESPONSE ===\n%s', xmlstr(xml)) # Get the soap body retval = xml.find(ns.expand('soapenv:Body', self.nsmap)) if not retxml: # Does the body contain any nodes? if len(retval): # Get the first child and examine it retval = retval[0] namespace, tag = ns.split(retval.tag) # If it's a fault, convert it to an exception if tag == 'Fault': raise SoapFault(retval, self) # Otherwise, deserialize obj = self.factory(operation.omsg, retval) # If the deserialized # object has only one item, return that item, otherwise the # whole object # # This is so if the return value is a single primitive type # (like a string), you don't have to dig into an object just # to get at the single primitive return value if len(obj) == 1: obj = obj[0] retval = obj else: retval = None return retval