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:
@@ -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
|
||||
|
||||
44
wsme/soap.py
44
wsme/soap.py
@@ -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)
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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):
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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_):
|
||||
|
||||
Reference in New Issue
Block a user