Most of the return types now works with soap

This commit is contained in:
Christophe de Vienne
2011-09-23 20:32:54 +02:00
parent 0125de0a79
commit 95a48f4596
4 changed files with 70 additions and 19 deletions

View File

@@ -184,7 +184,6 @@ class WSRoot(object):
res_content_type = funcdef.contenttype
except Exception, e:
infos = self._format_exception(sys.exc_info())
log.error(str(infos))
if isinstance(e, exc.ClientSideError):
res.status = 400
else:

View File

@@ -6,10 +6,16 @@ Parts of the code were taken from the tgwebservices soap implmentation.
import pkg_resources
import datetime
import decimal
import base64
from simplegeneric import generic
from xml.etree import ElementTree as et
try:
from xml.etree import cElementTree as et
except ImportError:
import cElementTree as et
from genshi.builder import tag, Element, Namespace
from genshi.template import MarkupTemplate
from wsme.controller import register_protocol, pexpose
import wsme.types
@@ -31,12 +37,16 @@ type_registry = {
def make_soap_element(datatype, tag, value):
el = et.Element(tag)
el = Element(tag)
if value is None:
el.set('xsi:nil', 'true')
el(**{'xsi:nil': 'true'})
elif wsme.types.iscomplex(datatype):
el(**{'xsi:type': datatype.__name__})
for name, attrdef in wsme.types.list_attributes(datatype):
el.append(
tosoap(attrdef.datatype, name, getattr(value, name)))
else:
el.set('xsi:type', type_registry.get(datatype))
el.text = str(value)
el(value, **{'xsi:type': type_registry.get(datatype)})
return el
@@ -46,6 +56,17 @@ def tosoap(datatype, tag, value):
response output"""
return make_soap_element(datatype, tag, value)
@tosoap.when_object(datetime.datetime)
def datetime_tosoap(datatype, tag, value):
return make_soap_element(datatype, tag,
value is not None and value.isoformat() or None)
@tosoap.when_object(wsme.types.binary)
def binary_tosoap(datatype, tag, value):
return make_soap_element(datatype, tag,
value is not None and base64.encodestring(value)
or None)
@tosoap.when_object(None)
def None_tosoap(datatype, tag, value):
return make_soap_element(datatype, tag, None)
@@ -94,8 +115,9 @@ class SoapProtocol(object):
body = el.find('{%(soapenv)s}Body' % self.ns)
# Extract the service name from the tns
fname = list(body)[0].tag
if fname.startswith('{%s}' % self.tns):
fname = fname[len(self.tns)+2:]
if fname.startswith('{%s}' % self.typenamespace):
fname = fname[len(self.typenamespace)+2:]
print fname
return self.get_name_mapping()[fname]
return None
@@ -103,9 +125,9 @@ class SoapProtocol(object):
return {}
def soap_response(self, funcdef, result):
r = et.Element('{' + self.tns + '}' + self.soap_fname(funcdef) + 'Response')
r = Element(self.soap_fname(funcdef) + 'Response')
r.append(tosoap(funcdef.return_type, 'result', result))
return et.tostring(r)
return r
def encode_result(self, funcdef, result):
envelope = self.render_template('soap',

View File

@@ -5,6 +5,6 @@
xmlns:py="http://genshi.edgewall.org/"
py:attrs="{'xmlns' : typenamespace}">
<soapenv:Body>
${Markup(soap_response(funcdef, result))}
${soap_response(funcdef, result)}
</soapenv:Body>
</soapenv:Envelope>

View File

@@ -1,5 +1,6 @@
import decimal
import datetime
import base64
import wsme.tests.protocol
@@ -9,11 +10,15 @@ except:
import cElementTree as et
import wsme.soap
import wsme.utils
tns = "http://foo.bar.baz/soap/"
typenamespace = "http://foo.bar.baz/types/"
soapenv_ns = 'http://schemas.xmlsoap.org/soap/envelope/'
xsi_ns = 'http://www.w3.org/2001/XMLSchema-instance'
body_qn = '{%s}Body' % soapenv_ns
type_qn = '{%s}type' % xsi_ns
def build_soap_message(method, params=""):
message = """<?xml version="1.0"?>
@@ -22,14 +27,16 @@ xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
soap:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
<soap:Body xmlns="%(tns)s">
<soap:Body xmlns="%(typenamespace)s">
<%(method)s>
%(params)s
</%(method)s>
</soap:Body>
</soap:Envelope>
""" % dict(method=method, params=params, tns=tns)
""" % dict(method=method,
params=params,
typenamespace=typenamespace)
return message
@@ -56,20 +63,42 @@ def loadxml(el):
else:
return el.text
def read_bool(value):
return value == 'true'
soap_types = {
'xsi:int': int
'xsd:string': unicode,
'xsd:int': int,
'xsd:long': long,
'xsd:float': float,
'xsd:decimal': decimal.Decimal,
'xsd:boolean': read_bool,
'xsd:date': wsme.utils.parse_isodate,
'xsd:time': wsme.utils.parse_isotime,
'xsd:dateTime': wsme.utils.parse_isodatetime,
'xsd:base64Binary': base64.decodestring,
}
def fromsoap(el):
t = el.get('type')
t = el.get(type_qn)
print t
if t in soap_types:
print t, el.text
return soap_types[t](el.text)
return None
else:
d = {}
for child in el:
name = child.tag
assert name.startswith('{%s}' % typenamespace)
name = name[len(typenamespace)+2:]
d[name] = fromsoap(child)
print d
return d
class TestSOAP(wsme.tests.protocol.ProtocolTestCase):
protocol = wsme.soap.SoapProtocol(tns=tns)
protocol = wsme.soap.SoapProtocol(
tns=tns, typenamespace=typenamespace)
def test_simple_call(self):
message = build_soap_message('Touch')
@@ -98,8 +127,9 @@ class TestSOAP(wsme.tests.protocol.ProtocolTestCase):
print body
if res.status_int == 200:
r = body.find('{%s}%sResponse' % (tns, methodname))
result = r.find('{%s}result' % tns)
r = body.find('{%s}%sResponse' % (typenamespace, methodname))
result = r.find('{%s}result' % typenamespace)
print result
return fromsoap(result)
elif res.status_int == 400:
pass