144 lines
5.6 KiB
Python
144 lines
5.6 KiB
Python
# This program is free software; you can redistribute it and/or modify it under
|
|
# the terms of the (LGPL) GNU Lesser General Public License as published by the
|
|
# Free Software Foundation; either version 3 of the License, or (at your
|
|
# option) any later version.
|
|
#
|
|
# This program is distributed in the hope that it will be useful, but WITHOUT
|
|
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
|
# FOR A PARTICULAR PURPOSE. See the GNU Library Lesser General Public License
|
|
# for more details at ( http://www.gnu.org/licenses/lgpl.html ).
|
|
#
|
|
# You should have received a copy of the GNU Lesser General Public License
|
|
# along with this program; if not, write to the Free Software Foundation, Inc.,
|
|
# 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
|
# written by: Jeff Ortel ( jortel@redhat.com )
|
|
|
|
"""
|
|
Classes for the (WS) SOAP I{document/literal} binding.
|
|
|
|
"""
|
|
|
|
from suds import *
|
|
from suds.argparser import parse_args
|
|
from suds.bindings.binding import Binding
|
|
from suds.sax.element import Element
|
|
|
|
|
|
class Document(Binding):
|
|
"""
|
|
The document/literal style. Literal is the only (@use) supported since
|
|
document/encoded is pretty much dead.
|
|
|
|
Although the SOAP specification supports multiple documents within the SOAP
|
|
<body/>, it is very uncommon. As such, suds library supports presenting an
|
|
I{RPC} view of service methods defined with only a single document
|
|
parameter. To support the complete specification, service methods defined
|
|
with multiple documents (multiple message parts), are still presented using
|
|
a full I{document} view.
|
|
|
|
More detailed description:
|
|
|
|
An interface is considered I{wrapped} if:
|
|
- There is exactly one message part in that interface.
|
|
- The message part resolves to an element of a non-builtin type.
|
|
Otherwise it is considered I{bare}.
|
|
|
|
I{Bare} interface is interpreted directly as specified in the WSDL schema,
|
|
with each message part represented by a single parameter in the suds
|
|
library web service operation proxy interface (input or output).
|
|
|
|
I{Wrapped} interface is interpreted without the external wrapping document
|
|
structure, with each of its contained elements passed through suds
|
|
library's web service operation proxy interface (input or output)
|
|
individually instead of as a single I{document} object.
|
|
|
|
"""
|
|
def bodycontent(self, method, args, kwargs):
|
|
wrapped = method.soap.input.body.wrapped
|
|
if wrapped:
|
|
pts = self.bodypart_types(method)
|
|
root = self.document(pts[0])
|
|
else:
|
|
root = []
|
|
|
|
def add_param(param_name, param_type, in_choice_context, value):
|
|
"""
|
|
Construct request data for the given input parameter.
|
|
|
|
Called by our argument parser for every input parameter, in order.
|
|
|
|
A parameter's type is identified by its corresponding XSD schema
|
|
element.
|
|
|
|
"""
|
|
# Do not construct request data for undefined input parameters
|
|
# defined inside a choice order indicator. An empty choice
|
|
# parameter can still be included in the constructed request by
|
|
# explicitly providing an empty string value for it.
|
|
#TODO: This functionality might be better placed inside the
|
|
# mkparam() function but to do that we would first need to better
|
|
# understand how different Binding subclasses in suds work and how
|
|
# they would be affected by this change.
|
|
if in_choice_context and value is None:
|
|
return
|
|
|
|
# Construct request data for the current input parameter.
|
|
pdef = (param_name, param_type)
|
|
p = self.mkparam(method, pdef, value)
|
|
if p is None:
|
|
return
|
|
if not wrapped:
|
|
ns = param_type.namespace("ns0")
|
|
p.setPrefix(ns[0], ns[1])
|
|
root.append(p)
|
|
|
|
parse_args(method.name, self.param_defs(method), args, kwargs,
|
|
add_param, self.options().extraArgumentErrors)
|
|
|
|
return root
|
|
|
|
def replycontent(self, method, body):
|
|
if method.soap.output.body.wrapped:
|
|
return body[0].children
|
|
return body.children
|
|
|
|
def document(self, wrapper):
|
|
"""
|
|
Get the document root. For I{document/literal}, this is the name of the
|
|
wrapper element qualified by the schema's target namespace.
|
|
|
|
@param wrapper: The method name.
|
|
@type wrapper: L{xsd.sxbase.SchemaObject}
|
|
@return: A root element.
|
|
@rtype: L{Element}
|
|
|
|
"""
|
|
tag = wrapper[1].name
|
|
ns = wrapper[1].namespace("ns0")
|
|
return Element(tag, ns=ns)
|
|
|
|
def mkparam(self, method, pdef, object):
|
|
"""
|
|
Expand list parameters into individual parameters each with the type
|
|
information. This is because in document arrays are simply
|
|
multi-occurrence elements.
|
|
|
|
"""
|
|
if isinstance(object, (list, tuple)):
|
|
return [self.mkparam(method, pdef, item) for item in object]
|
|
return super(Document, self).mkparam(method, pdef, object)
|
|
|
|
def param_defs(self, method):
|
|
"""Get parameter definitions for document literal."""
|
|
pts = self.bodypart_types(method)
|
|
if not method.soap.input.body.wrapped:
|
|
return pts
|
|
pt = pts[0][1].resolve()
|
|
return [(c.name, c, a) for c, a in pt if not c.isattr()]
|
|
|
|
def returned_types(self, method):
|
|
rts = super(Document, self).returned_types(method)
|
|
if not method.soap.output.body.wrapped:
|
|
return rts
|
|
return [child for child, ancestry in rts[0].resolve(nobuiltin=True)]
|