def __init__(self, wsdl): """ @param wsdl: A WSDL. @type wsdl: L{wsdl.Definitions} """ self.wsdl = wsdl self.multiref = MultiRef()
def __init__(self, wsdl): """ @param wsdl: A wsdl. @type wsdl: L{wsdl.Definitions} """ self.wsdl = wsdl self.schema = wsdl.schema self.options = Options() self.parser = Parser() self.multiref = MultiRef() self.xcodecs = ( Unmarshaller(self.schema), Marshaller(self.schema), )
def __init__(self, wsdl): """ @param wsdl: A wsdl. @type wsdl: L{wsdl.Definitions} """ self.wsdl = wsdl self.multiref = MultiRef()
def __init__(self, wsdl): """ @param wsdl: A wsdl. @type wsdl: L{wsdl.Definitions} """ self.wsdl = wsdl self.schema = wsdl.schema self.options = Options() self.parser = Parser() self.multiref = MultiRef()
class Binding: """ The soap binding class used to process outgoing and imcoming soap messages per the WSDL port binding. @cvar replyfilter: The reply filter function. @type replyfilter: (lambda s,r: r) @ivar wsdl: The wsdl. @type wsdl: L{suds.wsdl.Definitions} @ivar schema: The collective schema contained within the wsdl. @type schema: L{xsd.schema.Schema} @ivar options: A dictionary options. @type options: L{Options} """ replyfilter = (lambda s,r: r) def __init__(self, wsdl): """ @param wsdl: A wsdl. @type wsdl: L{wsdl.Definitions} """ self.wsdl = wsdl self.multiref = MultiRef() def schema(self): return self.wsdl.schema def options(self): return self.wsdl.options def unmarshaller(self, typed=True): """ Get the appropriate XML decoder. @return: Either the (basic|typed) unmarshaller. @rtype: L{UmxTyped} """ if typed: return UmxTyped(self.schema()) else: return UmxBasic() def marshaller(self): """ Get the appropriate XML encoder. @return: An L{MxLiteral} marshaller. @rtype: L{MxLiteral} """ return MxLiteral(self.schema(), self.options().xstq) def param_defs(self, method): """ Get parameter definitions. Each I{pdef} is a tuple (I{name}, L{xsd.sxbase.SchemaObject}) @param method: A servic emethod. @type method: I{service.Method} @return: A collection of parameter definitions @rtype: [I{pdef},..] """ raise Exception, 'not implemented' def get_message(self, method, args, kwargs): """ Get the soap message for the specified method, args and soapheaders. This is the entry point for creating the outbound soap message. @param method: The method being invoked. @type method: I{service.Method} @param args: A list of args for the method invoked. @type args: list @param kwargs: Named (keyword) args for the method invoked. @type kwargs: dict @return: The soap envelope. @rtype: L{Document} """ content = self.headercontent(method) header = self.header(content) content = self.bodycontent(method, args, kwargs) body = self.body(content) env = self.envelope(header, body) if self.options().prefixes: body.normalizePrefixes() env.promotePrefixes() else: env.refitPrefixes() return Document(env) def get_reply(self, method, reply): """ Process the I{reply} for the specified I{method} by sax parsing the I{reply} and then unmarshalling into python object(s). @param method: The name of the invoked method. @type method: str @param reply: The reply XML received after invoking the specified method. @type reply: str @return: The unmarshalled reply. The returned value is an L{Object} for a I{list} depending on whether the service returns a single object or a collection. @rtype: tuple ( L{Element}, L{Object} ) """ reply = self.replyfilter(reply) try: reply = reply[reply.index("<soap:Envelope"):reply.index("</soap:Envelope>")+16] except: pass sax = Parser() replyroot = sax.parse(string=reply) plugins = PluginContainer(self.options().plugins) plugins.message.parsed(reply=replyroot) soapenv = replyroot.getChild('Envelope') soapenv.promotePrefixes() soapbody = soapenv.getChild('Body') self.detect_fault(soapbody) soapbody = self.multiref.process(soapbody) nodes = self.replycontent(method, soapbody) rtypes = self.returned_types(method) if len(rtypes) > 1: result = self.replycomposite(rtypes, nodes) return (replyroot, result) if len(rtypes) == 1: if rtypes[0].unbounded(): result = self.replylist(rtypes[0], nodes) return (replyroot, result) if len(nodes): unmarshaller = self.unmarshaller() resolved = rtypes[0].resolve(nobuiltin=True) result = unmarshaller.process(nodes[0], resolved) return (replyroot, result) return (replyroot, None) def detect_fault(self, body): """ Detect I{hidden} soapenv:Fault element in the soap body. @param body: The soap envelope body. @type body: L{Element} @raise WebFault: When found. """ fault = body.getChild('Fault', envns) if fault is None: return unmarshaller = self.unmarshaller(False) p = unmarshaller.process(fault) if self.options().faults: raise WebFault(p, fault) return self def replylist(self, rt, nodes): """ Construct a I{list} reply. This mehod is called when it has been detected that the reply is a list. @param rt: The return I{type}. @type rt: L{suds.xsd.sxbase.SchemaObject} @param nodes: A collection of XML nodes. @type nodes: [L{Element},...] @return: A list of I{unmarshalled} objects. @rtype: [L{Object},...] """ result = [] resolved = rt.resolve(nobuiltin=True) unmarshaller = self.unmarshaller() for node in nodes: sobject = unmarshaller.process(node, resolved) result.append(sobject) return result def replycomposite(self, rtypes, nodes): """ Construct a I{composite} reply. This method is called when it has been detected that the reply has multiple root nodes. @param rtypes: A list of known return I{types}. @type rtypes: [L{suds.xsd.sxbase.SchemaObject},...] @param nodes: A collection of XML nodes. @type nodes: [L{Element},...] @return: The I{unmarshalled} composite object. @rtype: L{Object},... """ dictionary = {} for rt in rtypes: dictionary[rt.name] = rt unmarshaller = self.unmarshaller() composite = Factory.object('reply') for node in nodes: tag = node.name rt = dictionary.get(tag, None) if rt is None: if node.get('id') is None: raise Exception('<%s/> not mapped to message part' % tag) else: continue resolved = rt.resolve(nobuiltin=True) sobject = unmarshaller.process(node, resolved) value = getattr(composite, tag, None) if value is None: if rt.unbounded(): value = [] setattr(composite, tag, value) value.append(sobject) else: setattr(composite, tag, sobject) else: if not isinstance(value, list): value = [value,] setattr(composite, tag, value) value.append(sobject) return composite def get_fault(self, reply): """ Extract the fault from the specified soap reply. If I{faults} is True, an exception is raised. Otherwise, the I{unmarshalled} fault L{Object} is returned. This method is called when the server raises a I{web fault}. @param reply: A soap reply message. @type reply: str @return: A fault object. @rtype: tuple ( L{Element}, L{Object} ) """ reply = self.replyfilter(reply) sax = Parser() faultroot = sax.parse(string=reply) soapenv = faultroot.getChild('Envelope') soapbody = soapenv.getChild('Body') fault = soapbody.getChild('Fault') unmarshaller = self.unmarshaller(False) p = unmarshaller.process(fault) if self.options().faults: raise WebFault(p, faultroot) return (faultroot, p.detail) def mkparam(self, method, pdef, object): """ Builds a parameter for the specified I{method} using the parameter definition (pdef) and the specified value (object). @param method: A method name. @type method: str @param pdef: A parameter definition. @type pdef: tuple: (I{name}, L{xsd.sxbase.SchemaObject}) @param object: The parameter value. @type object: any @return: The parameter fragment. @rtype: L{Element} """ marshaller = self.marshaller() content = \ Content(tag=pdef[0], value=object, type=pdef[1], real=pdef[1].resolve()) return marshaller.process(content) def mkheader(self, method, hdef, object): """ Builds a soapheader for the specified I{method} using the header definition (hdef) and the specified value (object). @param method: A method name. @type method: str @param hdef: A header definition. @type hdef: tuple: (I{name}, L{xsd.sxbase.SchemaObject}) @param object: The header value. @type object: any @return: The parameter fragment. @rtype: L{Element} """ marshaller = self.marshaller() if isinstance(object, (list, tuple)): tags = [] for item in object: tags.append(self.mkheader(method, hdef, item)) return tags content = Content(tag=hdef[0], value=object, type=hdef[1]) return marshaller.process(content) def envelope(self, header, body): """ Build the B{<Envelope/>} for an soap outbound message. @param header: The soap message B{header}. @type header: L{Element} @param body: The soap message B{body}. @type body: L{Element} @return: The soap envelope containing the body and header. @rtype: L{Element} """ env = Element('Envelope', ns=envns) env.addPrefix(Namespace.xsins[0], Namespace.xsins[1]) env.append(header) env.append(body) return env def header(self, content): """ Build the B{<Body/>} for an soap outbound message. @param content: The header content. @type content: L{Element} @return: the soap body fragment. @rtype: L{Element} """ header = Element('Header', ns=envns) header.append(content) return header def bodycontent(self, method, args, kwargs): """ Get the content for the soap I{body} node. @param method: A service method. @type method: I{service.Method} @param args: method parameter values @type args: list @param kwargs: Named (keyword) args for the method invoked. @type kwargs: dict @return: The xml content for the <body/> @rtype: [L{Element},..] """ raise Exception, 'not implemented' def headercontent(self, method): """ Get the content for the soap I{Header} node. @param method: A service method. @type method: I{service.Method} @return: The xml content for the <body/> @rtype: [L{Element},..] """ n = 0 content = [] wsse = self.options().wsse if wsse is not None: content.append(wsse.xml()) headers = self.options().soapheaders if not isinstance(headers, (tuple,list,dict)): headers = (headers,) if len(headers) == 0: return content pts = self.headpart_types(method) if isinstance(headers, (tuple,list)): for header in headers: if isinstance(header, Element): content.append(deepcopy(header)) continue if len(pts) == n: break h = self.mkheader(method, pts[n], header) ns = pts[n][1].namespace('ns0') h.setPrefix(ns[0], ns[1]) content.append(h) n += 1 else: for pt in pts: header = headers.get(pt[0]) if header is None: continue h = self.mkheader(method, pt, header) ns = pt[1].namespace('ns0') h.setPrefix(ns[0], ns[1]) content.append(h) return content def replycontent(self, method, body): """ Get the reply body content. @param method: A service method. @type method: I{service.Method} @param body: The soap body @type body: L{Element} @return: the body content @rtype: [L{Element},...] """ raise Exception, 'not implemented' def body(self, content): """ Build the B{<Body/>} for an soap outbound message. @param content: The body content. @type content: L{Element} @return: the soap body fragment. @rtype: L{Element} """ body = Element('Body', ns=envns) body.append(content) return body def bodypart_types(self, method, input=True): """ Get a list of I{parameter definitions} (pdef) defined for the specified method. Each I{pdef} is a tuple (I{name}, L{xsd.sxbase.SchemaObject}) @param method: A service method. @type method: I{service.Method} @param input: Defines input/output message. @type input: boolean @return: A list of parameter definitions @rtype: [I{pdef},] """ result = [] if input: parts = method.soap.input.body.parts else: parts = method.soap.output.body.parts for p in parts: if p.element is not None: query = ElementQuery(p.element) else: query = TypeQuery(p.type) pt = query.execute(self.schema()) if pt is None: raise TypeNotFound(query.ref) if p.type is not None: pt = PartElement(p.name, pt) if input: if pt.name is None: result.append((p.name, pt)) else: result.append((pt.name, pt)) else: result.append(pt) return result def headpart_types(self, method, input=True): """ Get a list of I{parameter definitions} (pdef) defined for the specified method. Each I{pdef} is a tuple (I{name}, L{xsd.sxbase.SchemaObject}) @param method: A service method. @type method: I{service.Method} @param input: Defines input/output message. @type input: boolean @return: A list of parameter definitions @rtype: [I{pdef},] """ result = [] if input: headers = method.soap.input.headers else: headers = method.soap.output.headers for header in headers: part = header.part if part.element is not None: query = ElementQuery(part.element) else: query = TypeQuery(part.type) pt = query.execute(self.schema()) if pt is None: raise TypeNotFound(query.ref) if part.type is not None: pt = PartElement(part.name, pt) if input: if pt.name is None: result.append((part.name, pt)) else: result.append((pt.name, pt)) else: result.append(pt) return result def returned_types(self, method): """ Get the L{xsd.sxbase.SchemaObject} returned by the I{method}. @param method: A service method. @type method: I{service.Method} @return: The name of the type return by the method. @rtype: [I{rtype},..] """ result = [] for rt in self.bodypart_types(method, input=False): result.append(rt) return result
class Binding: """ The SOAP binding class used to process outgoing and incoming SOAP messages per the WSDL port binding. @cvar replyfilter: The reply filter function. @type replyfilter: (lambda s,r: r) @ivar wsdl: The WSDL. @type wsdl: L{suds.wsdl.Definitions} @ivar schema: The collective schema contained within the WSDL. @type schema: L{xsd.schema.Schema} @ivar options: A dictionary options. @type options: L{Options} """ replyfilter = (lambda s, r: r) def __init__(self, wsdl): """ @param wsdl: A WSDL. @type wsdl: L{wsdl.Definitions} """ self.wsdl = wsdl self.multiref = MultiRef() def schema(self): return self.wsdl.schema def options(self): return self.wsdl.options def unmarshaller(self, typed=True): """ Get the appropriate XML decoder. @return: Either the (basic|typed) unmarshaller. @rtype: L{UmxTyped} """ if typed: return UmxTyped(self.schema()) else: return UmxBasic() def marshaller(self): """ Get the appropriate XML encoder. @return: An L{MxLiteral} marshaller. @rtype: L{MxLiteral} """ return MxLiteral(self.schema(), self.options().xstq) def param_defs(self, method): """ Get parameter definitions. Each I{pdef} is a tuple (I{name}, L{xsd.sxbase.SchemaObject}) @param method: A service method. @type method: I{service.Method} @return: A collection of parameter definitions @rtype: [I{pdef},..] """ raise Exception, 'not implemented' def get_message(self, method, args, kwargs): """ Get a SOAP message for the specified method, args and SOAP headers. This is the entry point for creating an outbound SOAP message. @param method: The method being invoked. @type method: I{service.Method} @param args: A list of args for the method invoked. @type args: list @param kwargs: Named (keyword) args for the method invoked. @type kwargs: dict @return: The SOAP envelope. @rtype: L{Document} """ content = self.headercontent(method) header = self.header(content) content = self.bodycontent(method, args, kwargs) body = self.body(content) env = self.envelope(header, body) if self.options().prefixes: body.normalizePrefixes() env.promotePrefixes() else: env.refitPrefixes() return Document(env) def get_reply(self, method, reply): """ Process the I{reply} for the specified I{method} by sax parsing the I{reply} and then unmarshalling into Python object(s). @param method: The name of the invoked method. @type method: str @param reply: The reply XML received after invoking the specified method. @type reply: str @return: The unmarshalled reply. The returned value is an L{Object} for a I{list} depending on whether the service returns a single object or a collection. @rtype: tuple ( L{Element}, L{Object} ) """ reply = self.replyfilter(reply) sax = Parser() replyroot = sax.parse(string=reply) plugins = PluginContainer(self.options().plugins) plugins.message.parsed(reply=replyroot) soapenv = replyroot.getChild('Envelope') soapenv.promotePrefixes() soapbody = soapenv.getChild('Body') self.detect_fault(soapbody) soapbody = self.multiref.process(soapbody) nodes = self.replycontent(method, soapbody) rtypes = self.returned_types(method) if len(rtypes) > 1: result = self.replycomposite(rtypes, nodes) return (replyroot, result) if len(rtypes) == 1: if rtypes[0].multi_occurrence(): result = self.replylist(rtypes[0], nodes) return (replyroot, result) if len(nodes): unmarshaller = self.unmarshaller() resolved = rtypes[0].resolve(nobuiltin=True) result = unmarshaller.process(nodes[0], resolved) return (replyroot, result) return (replyroot, None) def detect_fault(self, body): """ Detect I{hidden} soapenv:Fault element in the SOAP body. @param body: The SOAP envelope body. @type body: L{Element} @raise WebFault: When found. """ fault = body.getChild('Fault', envns) if fault is None: return unmarshaller = self.unmarshaller(False) p = unmarshaller.process(fault) if self.options().faults: raise WebFault(p, fault) return self def replylist(self, rt, nodes): """ Construct a I{list} reply. This mehod is called when it has been detected that the reply is a list. @param rt: The return I{type}. @type rt: L{suds.xsd.sxbase.SchemaObject} @param nodes: A collection of XML nodes. @type nodes: [L{Element},...] @return: A list of I{unmarshalled} objects. @rtype: [L{Object},...] """ result = [] resolved = rt.resolve(nobuiltin=True) unmarshaller = self.unmarshaller() for node in nodes: sobject = unmarshaller.process(node, resolved) result.append(sobject) return result def replycomposite(self, rtypes, nodes): """ Construct a I{composite} reply. This method is called when it has been detected that the reply has multiple root nodes. @param rtypes: A list of known return I{types}. @type rtypes: [L{suds.xsd.sxbase.SchemaObject},...] @param nodes: A collection of XML nodes. @type nodes: [L{Element},...] @return: The I{unmarshalled} composite object. @rtype: L{Object},... """ dictionary = {} for rt in rtypes: dictionary[rt.name] = rt unmarshaller = self.unmarshaller() composite = Factory.object('reply') for node in nodes: tag = node.name rt = dictionary.get(tag, None) if rt is None: if node.get('id') is None: raise Exception('<%s/> not mapped to message part' % tag) else: continue resolved = rt.resolve(nobuiltin=True) sobject = unmarshaller.process(node, resolved) value = getattr(composite, tag, None) if value is None: if rt.multi_occurrence(): value = [] setattr(composite, tag, value) value.append(sobject) else: setattr(composite, tag, sobject) else: if not isinstance(value, list): value = [ value, ] setattr(composite, tag, value) value.append(sobject) return composite def get_fault(self, reply): """ Extract the fault from the specified SOAP reply. If I{faults} is True, an exception is raised. Otherwise, the I{unmarshalled} fault L{Object} is returned. This method is called when the server raises a I{web fault}. @param reply: A SOAP reply message. @type reply: str @return: A fault object. @rtype: tuple ( L{Element}, L{Object} ) """ _reply = self.replyfilter(reply) sax = Parser() faultroot = sax.parse(string=_reply) soapenv = faultroot.getChild('Envelope') soapbody = soapenv.getChild('Body') fault = soapbody.getChild('Fault') unmarshaller = self.unmarshaller(False) if fault: p = unmarshaller.process(fault) if self.options().faults: raise WebFault(p, faultroot) return (True, faultroot, p.detail) else: #p = unmarshaller.process(soapbody) #if self.options().faults: #raise WebFault(p, faultroot) return (False, faultroot, reply) def mkparam(self, method, pdef, object): """ Builds a parameter for the specified I{method} using the parameter definition (pdef) and the specified value (object). @param method: A method name. @type method: str @param pdef: A parameter definition. @type pdef: tuple: (I{name}, L{xsd.sxbase.SchemaObject}) @param object: The parameter value. @type object: any @return: The parameter fragment. @rtype: L{Element} """ marshaller = self.marshaller() content = \ Content(tag=pdef[0], value=object, type=pdef[1], real=pdef[1].resolve()) return marshaller.process(content) def mkheader(self, method, hdef, object): """ Builds a soapheader for the specified I{method} using the header definition (hdef) and the specified value (object). @param method: A method name. @type method: str @param hdef: A header definition. @type hdef: tuple: (I{name}, L{xsd.sxbase.SchemaObject}) @param object: The header value. @type object: any @return: The parameter fragment. @rtype: L{Element} """ marshaller = self.marshaller() if isinstance(object, (list, tuple)): tags = [] for item in object: tags.append(self.mkheader(method, hdef, item)) return tags content = Content(tag=hdef[0], value=object, type=hdef[1]) return marshaller.process(content) def envelope(self, header, body): """ Build the B{<Envelope/>} for a SOAP outbound message. @param header: The SOAP message B{header}. @type header: L{Element} @param body: The SOAP message B{body}. @type body: L{Element} @return: The SOAP envelope containing the body and header. @rtype: L{Element} """ env = Element('Envelope', ns=envns) env.addPrefix(Namespace.xsins[0], Namespace.xsins[1]) env.append(header) env.append(body) return env def header(self, content): """ Build the B{<Body/>} for a SOAP outbound message. @param content: The header content. @type content: L{Element} @return: the SOAP body fragment. @rtype: L{Element} """ header = Element('Header', ns=envns) header.append(content) return header def bodycontent(self, method, args, kwargs): """ Get the content for the SOAP I{body} node. @param method: A service method. @type method: I{service.Method} @param args: method parameter values @type args: list @param kwargs: Named (keyword) args for the method invoked. @type kwargs: dict @return: The XML content for the <body/> @rtype: [L{Element},..] """ raise Exception, 'not implemented' def headercontent(self, method): """ Get the content for the SOAP I{Header} node. @param method: A service method. @type method: I{service.Method} @return: The XML content for the <body/> @rtype: [L{Element},..] """ n = 0 content = [] wsse = self.options().wsse if wsse is not None: content.append(wsse.xml()) headers = self.options().soapheaders if not isinstance(headers, (tuple, list, dict)): headers = (headers, ) if len(headers) == 0: return content pts = self.headpart_types(method) if isinstance(headers, (tuple, list)): for header in headers: if isinstance(header, Element): content.append(deepcopy(header)) continue if len(pts) == n: break h = self.mkheader(method, pts[n], header) ns = pts[n][1].namespace('ns0') h.setPrefix(ns[0], ns[1]) content.append(h) n += 1 else: for pt in pts: header = headers.get(pt[0]) if header is None: continue h = self.mkheader(method, pt, header) ns = pt[1].namespace('ns0') h.setPrefix(ns[0], ns[1]) content.append(h) return content def replycontent(self, method, body): """ Get the reply body content. @param method: A service method. @type method: I{service.Method} @param body: The SOAP body. @type body: L{Element} @return: The body content. @rtype: [L{Element},...] """ raise Exception, 'not implemented' def body(self, content): """ Build the B{<Body/>} for a SOAP outbound message. @param content: The body content. @type content: L{Element} @return: The SOAP body fragment. @rtype: L{Element} """ body = Element('Body', ns=envns) body.append(content) return body def bodypart_types(self, method, input=True): """ Get a list of I{parameter definitions} (pdef) defined for the specified method. Each I{pdef} is a tuple (I{name}, L{xsd.sxbase.SchemaObject}) @param method: A service method. @type method: I{service.Method} @param input: Defines input/output message. @type input: boolean @return: A list of parameter definitions @rtype: [I{pdef},] """ result = [] if input: parts = method.soap.input.body.parts else: parts = method.soap.output.body.parts for p in parts: if p.element is not None: query = ElementQuery(p.element) else: query = TypeQuery(p.type) pt = query.execute(self.schema()) if pt is None: raise TypeNotFound(query.ref) if p.type is not None: pt = PartElement(p.name, pt) if input: if pt.name is None: result.append((p.name, pt)) else: result.append((pt.name, pt)) else: result.append(pt) return result def headpart_types(self, method, input=True): """ Get a list of I{parameter definitions} (pdef) defined for the specified method. Each I{pdef} is a tuple (I{name}, L{xsd.sxbase.SchemaObject}) @param method: A service method. @type method: I{service.Method} @param input: Defines input/output message. @type input: boolean @return: A list of parameter definitions @rtype: [I{pdef},] """ result = [] if input: headers = method.soap.input.headers else: headers = method.soap.output.headers for header in headers: part = header.part if part.element is not None: query = ElementQuery(part.element) else: query = TypeQuery(part.type) pt = query.execute(self.schema()) if pt is None: raise TypeNotFound(query.ref) if part.type is not None: pt = PartElement(part.name, pt) if input: if pt.name is None: result.append((part.name, pt)) else: result.append((pt.name, pt)) else: result.append(pt) return result def returned_types(self, method): """ Get the L{xsd.sxbase.SchemaObject} returned by the I{method}. @param method: A service method. @type method: I{service.Method} @return: The name of the type return by the method. @rtype: [I{rtype},..] """ result = [] for rt in self.bodypart_types(method, input=False): result.append(rt) return result
class Binding(object): """ The SOAP binding class used to process outgoing and incoming SOAP messages per the WSDL port binding. @ivar wsdl: The WSDL. @type wsdl: L{suds.wsdl.Definitions} @ivar schema: The collective schema contained within the WSDL. @type schema: L{xsd.schema.Schema} @ivar options: A dictionary options. @type options: L{Options} """ def __init__(self, wsdl): """ @param wsdl: A WSDL. @type wsdl: L{wsdl.Definitions} """ self.wsdl = wsdl self.multiref = MultiRef() def schema(self): return self.wsdl.schema def options(self): return self.wsdl.options def unmarshaller(self): """ Get the appropriate schema based XML decoder. @return: Typed unmarshaller. @rtype: L{UmxTyped} """ return UmxTyped(self.schema()) def marshaller(self): """ Get the appropriate XML encoder. @return: An L{MxLiteral} marshaller. @rtype: L{MxLiteral} """ return MxLiteral(self.schema(), self.options().xstq) def param_defs(self, method): """ Get parameter definitions. Each I{pdef} is a (I{name}, L{xsd.sxbase.SchemaObject}) tuple. @param method: A service method. @type method: I{service.Method} @return: A collection of parameter definitions @rtype: [I{pdef},...] """ raise Exception("not implemented") def get_message(self, method, args, kwargs): """ Get a SOAP message for the specified method, args and SOAP headers. This is the entry point for creating an outbound SOAP message. @param method: The method being invoked. @type method: I{service.Method} @param args: A list of args for the method invoked. @type args: list @param kwargs: Named (keyword) args for the method invoked. @type kwargs: dict @return: The SOAP envelope. @rtype: L{Document} """ content = self.headercontent(method) header = self.header(content) content = self.bodycontent(method, args, kwargs) body = self.body(content) env = self.envelope(header, body) if self.options().prefixes: body.normalizePrefixes() env.promotePrefixes() else: env.refitPrefixes() return Document(env) def get_reply(self, method, replyroot): """ Process the I{reply} for the specified I{method} by unmarshalling it into into Python object(s). @param method: The name of the invoked method. @type method: str @param replyroot: The reply XML root node received after invoking the specified method. @type replyroot: L{Element} @return: The unmarshalled reply. The returned value is an L{Object} or a I{list} depending on whether the service returns a single object or a collection. @rtype: L{Object} or I{list} """ soapenv = replyroot.getChild("Envelope", envns) soapenv.promotePrefixes() soapbody = soapenv.getChild("Body", envns) soapbody = self.multiref.process(soapbody) nodes = self.replycontent(method, soapbody) rtypes = self.returned_types(method) if len(rtypes) > 1: return self.replycomposite(rtypes, nodes) if len(rtypes) == 0: return if rtypes[0].multi_occurrence(): return self.replylist(rtypes[0], nodes) if len(nodes): resolved = rtypes[0].resolve(nobuiltin=True) return self.unmarshaller().process(nodes[0], resolved) def replylist(self, rt, nodes): """ Construct a I{list} reply. Called for replies with possible multiple occurrences. @param rt: The return I{type}. @type rt: L{suds.xsd.sxbase.SchemaObject} @param nodes: A collection of XML nodes. @type nodes: [L{Element},...] @return: A list of I{unmarshalled} objects. @rtype: [L{Object},...] """ resolved = rt.resolve(nobuiltin=True) unmarshaller = self.unmarshaller() return [unmarshaller.process(node, resolved) for node in nodes] def replycomposite(self, rtypes, nodes): """ Construct a I{composite} reply. Called for replies with multiple output nodes. @param rtypes: A list of known return I{types}. @type rtypes: [L{suds.xsd.sxbase.SchemaObject},...] @param nodes: A collection of XML nodes. @type nodes: [L{Element},...] @return: The I{unmarshalled} composite object. @rtype: L{Object},... """ dictionary = {} for rt in rtypes: dictionary[rt.name] = rt unmarshaller = self.unmarshaller() composite = Factory.object("reply") for node in nodes: tag = node.name rt = dictionary.get(tag) if rt is None: if node.get("id") is None: message = "<%s/> not mapped to message part" % (tag,) raise Exception(message) continue resolved = rt.resolve(nobuiltin=True) sobject = unmarshaller.process(node, resolved) value = getattr(composite, tag, None) if value is None: if rt.multi_occurrence(): value = [] setattr(composite, tag, value) value.append(sobject) else: setattr(composite, tag, sobject) else: if not isinstance(value, list): value = [value,] setattr(composite, tag, value) value.append(sobject) return composite def mkparam(self, method, pdef, object): """ Builds a parameter for the specified I{method} using the parameter definition (pdef) and the specified value (object). @param method: A method name. @type method: str @param pdef: A parameter definition. @type pdef: tuple: (I{name}, L{xsd.sxbase.SchemaObject}) @param object: The parameter value. @type object: any @return: The parameter fragment. @rtype: L{Element} """ marshaller = self.marshaller() content = Content(tag=pdef[0], value=object, type=pdef[1], real=pdef[1].resolve()) return marshaller.process(content) def mkheader(self, method, hdef, object): """ Builds a soapheader for the specified I{method} using the header definition (hdef) and the specified value (object). @param method: A method name. @type method: str @param hdef: A header definition. @type hdef: tuple: (I{name}, L{xsd.sxbase.SchemaObject}) @param object: The header value. @type object: any @return: The parameter fragment. @rtype: L{Element} """ marshaller = self.marshaller() if isinstance(object, (list, tuple)): return [self.mkheader(method, hdef, item) for item in object] content = Content(tag=hdef[0], value=object, type=hdef[1]) return marshaller.process(content) def envelope(self, header, body): """ Build the B{<Envelope/>} for a SOAP outbound message. @param header: The SOAP message B{header}. @type header: L{Element} @param body: The SOAP message B{body}. @type body: L{Element} @return: The SOAP envelope containing the body and header. @rtype: L{Element} """ env = Element("Envelope", ns=envns) env.addPrefix(Namespace.xsins[0], Namespace.xsins[1]) env.append(header) env.append(body) return env def header(self, content): """ Build the B{<Body/>} for a SOAP outbound message. @param content: The header content. @type content: L{Element} @return: The SOAP body fragment. @rtype: L{Element} """ header = Element("Header", ns=envns) header.append(content) return header def bodycontent(self, method, args, kwargs): """ Get the content for the SOAP I{body} node. @param method: A service method. @type method: I{service.Method} @param args: method parameter values. @type args: list @param kwargs: Named (keyword) args for the method invoked. @type kwargs: dict @return: The XML content for the <body/>. @rtype: [L{Element},...] """ raise Exception("not implemented") def headercontent(self, method): """ Get the content for the SOAP I{Header} node. @param method: A service method. @type method: I{service.Method} @return: The XML content for the <body/>. @rtype: [L{Element},...] """ content = [] wsse = self.options().wsse if wsse is not None: content.append(wsse.xml()) headers = self.options().soapheaders if not isinstance(headers, (tuple, list, dict)): headers = (headers,) elif not headers: return content pts = self.headpart_types(method) if isinstance(headers, (tuple, list)): n = 0 for header in headers: if isinstance(header, Element): content.append(deepcopy(header)) continue if len(pts) == n: break h = self.mkheader(method, pts[n], header) ns = pts[n][1].namespace("ns0") h.setPrefix(ns[0], ns[1]) content.append(h) n += 1 else: for pt in pts: header = headers.get(pt[0]) if header is None: continue h = self.mkheader(method, pt, header) ns = pt[1].namespace("ns0") h.setPrefix(ns[0], ns[1]) content.append(h) return content def replycontent(self, method, body): """ Get the reply body content. @param method: A service method. @type method: I{service.Method} @param body: The SOAP body. @type body: L{Element} @return: The body content. @rtype: [L{Element},...] """ raise Exception("not implemented") def body(self, content): """ Build the B{<Body/>} for a SOAP outbound message. @param content: The body content. @type content: L{Element} @return: The SOAP body fragment. @rtype: L{Element} """ body = Element("Body", ns=envns) body.append(content) return body def bodypart_types(self, method, input=True): """ Get a list of I{parameter definitions} (pdefs) defined for the specified method. An input I{pdef} is a (I{name}, L{xsd.sxbase.SchemaObject}) tuple, while an output I{pdef} is a L{xsd.sxbase.SchemaObject}. @param method: A service method. @type method: I{service.Method} @param input: Defines input/output message. @type input: boolean @return: A list of parameter definitions @rtype: [I{pdef},...] """ if input: parts = method.soap.input.body.parts else: parts = method.soap.output.body.parts return [self.__part_type(p, input) for p in parts] def headpart_types(self, method, input=True): """ Get a list of header I{parameter definitions} (pdefs) defined for the specified method. An input I{pdef} is a (I{name}, L{xsd.sxbase.SchemaObject}) tuple, while an output I{pdef} is a L{xsd.sxbase.SchemaObject}. @param method: A service method. @type method: I{service.Method} @param input: Defines input/output message. @type input: boolean @return: A list of parameter definitions @rtype: [I{pdef},...] """ if input: headers = method.soap.input.headers else: headers = method.soap.output.headers return [self.__part_type(h.part, input) for h in headers] def returned_types(self, method): """ Get the I{method} return value type(s). @param method: A service method. @type method: I{service.Method} @return: Method return value type. @rtype: [L{xsd.sxbase.SchemaObject},...] """ return self.bodypart_types(method, input=False) def __part_type(self, part, input): """ Get a I{parameter definition} (pdef) defined for a given body or header message part. An input I{pdef} is a (I{name}, L{xsd.sxbase.SchemaObject}) tuple, while an output I{pdef} is a L{xsd.sxbase.SchemaObject}. @param part: A service method input or output part. @type part: I{suds.wsdl.Part} @param input: Defines input/output message. @type input: boolean @return: A list of parameter definitions @rtype: [I{pdef},...] """ if part.element is None: query = TypeQuery(part.type) else: query = ElementQuery(part.element) part_type = query.execute(self.schema()) if part_type is None: raise TypeNotFound(query.ref) if part.type is not None: part_type = PartElement(part.name, part_type) if not input: return part_type if part_type.name is None: return part.name, part_type return part_type.name, part_type