diff --git a/wsme/controller.py b/wsme/controller.py index 3f63158..e53f34a 100644 --- a/wsme/controller.py +++ b/wsme/controller.py @@ -36,9 +36,11 @@ def scan_api(controller, path=[]): a = getattr(controller, name) if inspect.ismethod(a): if hasattr(a, '_wsme_definition'): - yield path, a._wsme_definition + a._wsme_definition.path = path + yield a._wsme_definition else: - if len(path) > 10: raise ValueError(str(path)) + if len(path) > 10: + raise ValueError(str(path)) for i in scan_api(a, path + [name]): yield i @@ -59,6 +61,7 @@ class FunctionDefinition(object): self.arguments = [] self.protocol_specific = False self.contenttype = None + self.path = None @classmethod def get(cls, func): @@ -98,6 +101,7 @@ class pexpose(object): fd.contenttype = self.contenttype return func + class validate(object): def __init__(self, *args, **kw): self.param_types = args @@ -129,6 +133,13 @@ class WSRoot(object): protocol = registered_protocols[protocol]() self.protocols[protocol.name] = protocol + self._api = None + + def getapi(self): + if self._api is None: + self._api = [i for i in scan_api(self)] + return self._api + def _select_protocol(self, request): protocol = None if 'wsmeproto' in request.params: @@ -154,7 +165,7 @@ class WSRoot(object): return res path = protocol.extract_path(request) func, funcdef = self._lookup_function(path) - kw = protocol.read_arguments(request, funcdef.arguments) + kw = protocol.read_arguments(request, funcdef) if funcdef.protocol_specific: kw['root'] = self @@ -167,7 +178,7 @@ class WSRoot(object): res.body = result else: # TODO make sure result type == a._wsme_definition.return_type - res.body = protocol.encode_result(result, funcdef.return_type) + res.body = protocol.encode_result(result, funcdef) res_content_type = funcdef.contenttype except Exception, e: infos = self._format_exception(sys.exc_info()) @@ -203,7 +214,7 @@ class WSRoot(object): a = self isprotocol_specific = path[0] == '_protocol' - + if isprotocol_specific: a = self.protocols[path[1]] path = path[2:] diff --git a/wsme/soap.py b/wsme/soap.py index fc5ab91..b8e6660 100644 --- a/wsme/soap.py +++ b/wsme/soap.py @@ -2,7 +2,7 @@ import pkg_resources from xml.etree import ElementTree as et from genshi.template import MarkupTemplate -from wsme.controller import register_protocol, pexpose, scan_api +from wsme.controller import register_protocol, pexpose import wsme.types nativetypes = { @@ -29,64 +29,62 @@ class SoapProtocol(object): def accept(self, root, req): if req.path.endswith('.wsdl'): return True - if req.headers['Content-Type'] in self.content_types: - return True + for ct in self.content_types: + if req.headers['Content-Type'].startswith(ct): + return True return False def extract_path(self, request): if request.path.endswith('.wsdl'): print "Here !!" return ['_protocol', self.name, 'api_wsdl'] + el = et.fromstring(request.body) + body = el.find('{http://schemas.xmlsoap.org/soap/envelope/}Body') + fname = list(body)[0].tag + print fname + return [fname] - def read_arguments(self, request, arguments): - if arguments is None: - return {} + def read_arguments(self, request, funcdef): return {} - def encode_result(self, result, return_type): - return "" + def encode_result(self, result, funcdef): + envelope = self.render_template('soap') + print envelope + return envelope - def make_header(self): - header = et.Element('{%(soap)s}Header' % self.ns) - return header + def get_template(self, name): + return pkg_resources.resource_string( + __name__, 'templates/%s.html' % name) - def make_body(self): - body = et.Element('{%(soap)s}Body' % self.ns) - return body - - def make_envelope(self): - env = et.Element('{%(soap)s}Envelope' % self.ns) - env.append(self.make_header()) - env.append(self.make_body()) - return env + def render_template(self, name, **kw): + tmpl = MarkupTemplate(self.get_template(name)) + stream = tmpl.generate(**kw) + return stream.render('xml') def encode_error(self, infos): - env = self.make_envelope() - fault = et.Element('{%(soap)s}Fault' % self.ns) - env.find('{%(soap)s}Body' % self.ns).append(fault) - return et.tostring(env) - + return self.render_template('fault', + typenamespace=self.typenamespace, + **infos) + @pexpose(contenttype="text/xml") 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( + return self.render_template('wsdl', 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)], + funclist = root.getapi(), arrays = [], list_attributes = wsme.types.list_attributes, baseURL = service, soap_type = self.soap_type, - ) - return stream.render('xml') + soap_fname = self.soap_fname, + ) def soap_type(self, datatype): if datatype in nativetypes: @@ -94,4 +92,9 @@ class SoapProtocol(object): if wsme.types.iscomplex(datatype): return "types:%s" % datatype.__name__ + def soap_fname(self, funcdef): + return "%s%s" % ( + "".join((i.capitalize() for i in funcdef.path)), + funcdef.name.capitalize()) + register_protocol(SoapProtocol) diff --git a/wsme/templates/fault.html b/wsme/templates/fault.html new file mode 100644 index 0000000..62084ea --- /dev/null +++ b/wsme/templates/fault.html @@ -0,0 +1,14 @@ + + + + ${faultcode} + ${faultstring} + ${debuginfo} + + + diff --git a/wsme/templates/soap.html b/wsme/templates/soap.html new file mode 100644 index 0000000..d4114ed --- /dev/null +++ b/wsme/templates/soap.html @@ -0,0 +1,10 @@ + + + ${soap_body(methodname, function_info, output)} + + diff --git a/wsme/templates/wsdl.html b/wsme/templates/wsdl.html index 8bbd957..289d2a7 100644 --- a/wsme/templates/wsdl.html +++ b/wsme/templates/wsdl.html @@ -22,8 +22,8 @@ - - + + - + - - - + + + - - + + - + ${funcdef.doc} - - + + @@ -79,8 +79,8 @@ - - + + diff --git a/wsme/tests/test_soap.py b/wsme/tests/test_soap.py index a4ebc43..6204c16 100644 --- a/wsme/tests/test_soap.py +++ b/wsme/tests/test_soap.py @@ -11,6 +11,24 @@ except: import wsme.soap +def build_soap_message(method, params=""): + message = """ + + + + <%(method)s> + %(params)s + + + + +""" % dict(method=method, params=params) + return message + + def dumpxml(key, obj): el = et.Element(key) if isinstance(obj, basestring): @@ -38,7 +56,19 @@ def loadxml(el): class TestSOAP(wsme.tests.protocol.ProtocolTestCase): protocol = 'SOAP' + def test_simple_call(self): + message = build_soap_message('Touch') + print message + res = self.app.post('/', message, + headers={ + "Content-Type": "application/soap+xml; charset=utf-8" + }, expect_errors=True) + print res.body + assert res.status.startswith('200') + def call(self, fpath, **kw): + # get the actual definition so we can build the adequate request + el = dumpxml('parameters', kw) content = et.tostring(el) res = self.app.post( @@ -63,5 +93,4 @@ class TestSOAP(wsme.tests.protocol.ProtocolTestCase): def test_wsdl(self): res = self.app.get('/api.wsdl') print res.body - assert 'returntypes' in res.body - assert False + assert 'ReturntypesGetunicode' in res.body