Worked on the wsdl generation. It looks like it should although it lacks the basic types handling and arrays definitions

This commit is contained in:
Christophe de Vienne
2011-09-22 23:29:57 +02:00
parent 2f08df38b9
commit b5eaa27a9a
6 changed files with 71 additions and 38 deletions

View File

@@ -34,9 +34,11 @@ def scan_api(controller, path=[]):
if name.startswith('_'):
continue
a = getattr(controller, name)
if hasattr(a, '_wsme_definition'):
yield path, a._wsme_definition
if inspect.ismethod(a):
if hasattr(a, '_wsme_definition'):
yield path, a._wsme_definition
else:
if len(path) > 10: raise ValueError(str(path))
for i in scan_api(a, path + [name]):
yield i
@@ -52,6 +54,7 @@ class FunctionArgument(object):
class FunctionDefinition(object):
def __init__(self, func):
self.name = func.__name__
self.doc = func.__doc__
self.return_type = None
self.arguments = []
self.protocol_specific = False
@@ -154,6 +157,9 @@ class WSRoot(object):
kw = protocol.read_arguments(request,
funcdef and funcdef.arguments or None)
if funcdef.protocol_specific:
kw['root'] = self
result = func(**kw)
res.status = 200

View File

@@ -2,7 +2,13 @@ import pkg_resources
from xml.etree import ElementTree as et
from genshi.template import MarkupTemplate
from wsme.controller import register_protocol, pexpose
from wsme.controller import register_protocol, pexpose, scan_api
import wsme.types
nativetypes = {
str: 'xsd:string',
int: 'xsd:int',
}
class SoapProtocol(object):
name = 'SOAP'
@@ -12,8 +18,13 @@ class SoapProtocol(object):
"soap": "http://www.w3.org/2001/12/soap-envelope"
}
def __init__(self):
pass
def __init__(self, tns=None,
typenamespace=None,
baseURL=None
):
self.tns = tns
self.typenamespace = typenamespace
self.servicename = 'MyApp'
def accept(self, root, req):
if req.path.endswith('.wsdl'):
@@ -56,20 +67,31 @@ class SoapProtocol(object):
return et.tostring(env)
@pexpose(contenttype="text/xml")
def api_wsdl(self):
def api_wsdl(self, root, service=None):
if service is None:
servicename = self.servicename
else:
servicename = self.servicename + service.capitalize()
tmpl = MarkupTemplate(
pkg_resources.resource_string(__name__, 'templates/wsdl.html'))
stream = tmpl.generate(
tns = 'test',
typenamespace = 'tset',
soapenc = 'enc',
service_name = 'sn',
complex_types = [],
funclist = [],
tns = self.tns,
typenamespace = self.typenamespace,
soapenc = 'http://schemas.xmlsoap.org/soap/encoding/',
service_name = servicename,
complex_types = (t() for t in wsme.types.complex_types),
funclist = [i for i in scan_api(root)],
arrays = [],
baseURL = '',
list_attributes = wsme.types.list_attributes,
baseURL = service,
soap_type = self.soap_type,
)
return stream.render('xml')
def soap_type(self, datatype):
if datatype in nativetypes:
return nativetypes[datatype]
if wsme.types.iscomplex(datatype):
return "types:%s" % datatype.__name__
register_protocol(SoapProtocol)

View File

@@ -14,26 +14,30 @@
<xsd:complexType py:for="cls in complex_types"
name="${cls.__name__}">
<xsd:sequence>
<xsd:element py:for="attr in ctvalues(cls)" name="${attr}"
type="${soap_type(getattr(cls, attr))}"/>
<xsd:element py:for="attr, attrdef in list_attributes(cls)" name="${attr}"
type="${soap_type(attrdef.datatype)}"
minOccurs="${attrdef.mandatory and 1 or 0}"
maxOccurs="1"/>
</xsd:sequence>
</xsd:complexType>
<!-- !Declare the request/response pairs for each function -->
<py:for each="func in funclist" py:with="fi=registry[func]._ws_func_info">
<xsd:element name="${func}">
<py:for each="path, funcdef in funclist">
<xsd:element name="${funcdef.name}">
<xsd:complexType>
<xsd:sequence>
<xsd:element py:for="param in fi.params" name="${param}"
type="${soap_type(fi.input_types.get(param, None))}" py:attrs="{'minOccurs':param in fi.optional and '0' or None}"/>
<xsd:element py:for="farg in funcdef.arguments"
name="${farg.name}"
type="${soap_type(farg.datatype)}"
py:attrs="{'minOccurs': not farg.mandatory and '0' or None}"/>
</xsd:sequence>
</xsd:complexType>
</xsd:element>
<xsd:element name="${func}Response">
<xsd:element name="${funcdef.name}Response">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="result"
type="${soap_type(fi.return_type)}"/>
type="${soap_type(funcdef.return_type)}"/>
</xsd:sequence>
</xsd:complexType>
</xsd:element>
@@ -50,23 +54,23 @@
</wsdl:types>
<!-- !Declare the request and response messages used for each func. -->
<py:for each="func in funclist">
<wsdl:message name="${func}Request" py:attrs="{'xmlns':typenamespace}">
<wsdl:part name="parameters" element="types:${func}"/>
<py:for each="path, funcdef in funclist">
<wsdl:message name="${funcdef.name}Request" py:attrs="{'xmlns':typenamespace}">
<wsdl:part name="parameters" element="types:${funcdef.name}"/>
</wsdl:message>
<wsdl:message name="${func}Response" py:attrs="{'xmlns':typenamespace}">
<wsdl:part name="parameters" element="types:${func}Response"/>
<wsdl:message name="${funcdef.name}Response" py:attrs="{'xmlns':typenamespace}">
<wsdl:part name="parameters" element="types:${funcdef.name}Response"/>
</wsdl:message>
</py:for>
<!-- !Define the PortType for the service and all of the operations
(functions) declared in the service. -->
<wsdl:portType name="${service_name}_PortType">
<wsdl:operation py:for="func in funclist" name="${func}" py:with="funcdoc=registry[func].__doc__">
<wsdl:documentation py:if="funcdoc">${funcdoc}</wsdl:documentation>
<wsdl:input message="tns:${func}Request"/>
<wsdl:output message="tns:${func}Response"/>
<wsdl:operation py:for="path, funcdef in funclist" name="${funcdef.name}">
<wsdl:documentation py:if="funcdef.doc">${funcdef.doc}</wsdl:documentation>
<wsdl:input message="tns:${funcdef.name}Request"/>
<wsdl:output message="tns:${funcdef.name}Response"/>
</wsdl:operation>
</wsdl:portType>
@@ -75,8 +79,8 @@
<wsdl:binding name="${service_name}_Binding" type="tns:${service_name}_PortType">
<soap:binding style="document"
transport="http://schemas.xmlsoap.org/soap/http"/>
<wsdl:operation py:for="func in funclist" name="${func}">
<soap:operation soapAction="${func}"/>
<wsdl:operation py:for="path, funcdef in funclist" name="${funcdef.name}">
<soap:operation soapAction="${funcdef.name}"/>
<wsdl:input>
<soap:body use="literal"/>
</wsdl:input>
@@ -91,7 +95,7 @@
<wsdl:documentation>WSDL File for ${service_name}</wsdl:documentation>
<wsdl:port binding="tns:${service_name}_Binding" name="${service_name}_PortType">
<soap:address
location="${baseURL}soap/"/>
location="${baseURL}/"/>
</wsdl:port>
</wsdl:service>
</wsdl:definitions>

View File

@@ -176,11 +176,11 @@ class WSTestRoot(WSRoot):
witherrors = WithErrors()
def reset(self):
self.touched = False
self._touched = False
@expose()
def touch(self):
self.touched = True
self._touched = True
class ProtocolTestCase(unittest.TestCase):

View File

@@ -64,3 +64,4 @@ class TestSOAP(wsme.tests.protocol.ProtocolTestCase):
res = self.app.get('/api.wsdl')
print res.body
assert 'returntypes' in res.body
assert False

View File

@@ -10,10 +10,10 @@ dt_types = [datetime.date, datetime.time, datetime.datetime]
extra_types = [binary, decimal.Decimal]
native_types = pod_types + dt_types + extra_types
structured_types = []
complex_types = []
def isstructured(datatype):
def iscomplex(datatype):
return hasattr(datatype, '_wsme_attributes')
@@ -106,7 +106,7 @@ def register_type(class_):
class_._wsme_attributes = inspect_class(class_)
structured_types.append(weakref.ref(class_))
complex_types.append(weakref.ref(class_))
def list_attributes(class_):