From 5ca78e896f507cfffec9171f0a5a9997ee0e1e09 Mon Sep 17 00:00:00 2001 From: Christophe de Vienne Date: Thu, 22 Sep 2011 17:04:33 +0200 Subject: [PATCH] Start working on the soap protocol --- .hgignore | 5 +++ examples/demo/demo.py | 1 + examples/demo/setup.cfg | 2 ++ examples/demo/setup.py | 1 + wsme/controller.py | 70 ++++++++++++++++++++++++++++++----------- wsme/soap.py | 58 ++++++++++++++++++++++++++++++++-- 6 files changed, 117 insertions(+), 20 deletions(-) create mode 100644 examples/demo/setup.cfg diff --git a/.hgignore b/.hgignore index 5e3e5a7..8ecc22c 100644 --- a/.hgignore +++ b/.hgignore @@ -14,3 +14,8 @@ syntax: regexp ^include ^dist +^examples/.*/bin +^examples/.*/dist +^examples/.*/lib +^examples/.*/include + diff --git a/examples/demo/demo.py b/examples/demo/demo.py index ecbce87..0ebd4cd 100644 --- a/examples/demo/demo.py +++ b/examples/demo/demo.py @@ -16,6 +16,7 @@ from wsme import * import wsme.restjson import wsme.restxml +import wsme.soap class DemoRoot(WSRoot): diff --git a/examples/demo/setup.cfg b/examples/demo/setup.cfg new file mode 100644 index 0000000..e815e43 --- /dev/null +++ b/examples/demo/setup.cfg @@ -0,0 +1,2 @@ +[easy_install] +find_links = http://www.owlfish.com/software/wsgiutils/download.html diff --git a/examples/demo/setup.py b/examples/demo/setup.py index f509c87..4b7d102 100644 --- a/examples/demo/setup.py +++ b/examples/demo/setup.py @@ -6,5 +6,6 @@ setup(name='demo', 'PasteScript', 'PasteDeploy', 'WSGIUtils', + 'Pygments', ], package=['demo']) diff --git a/wsme/controller.py b/wsme/controller.py index 9101ccb..420d89c 100644 --- a/wsme/controller.py +++ b/wsme/controller.py @@ -54,6 +54,8 @@ class FunctionDefinition(object): self.name = func.__name__ self.return_type = None self.arguments = [] + self.protocol_specific = False + self.contenttype = None @classmethod def get(cls, func): @@ -80,6 +82,19 @@ class expose(object): return func +class pexpose(object): + def __init__(self, return_type=None, contenttype=None): + self.return_type = return_type + self.contenttype = contenttype + register_type(return_type) + + def __call__(self, func): + fd = FunctionDefinition.get(func) + fd.return_type = self.return_type + fd.protocol_specific = True + fd.contenttype = self.contenttype + return func + class validate(object): def __init__(self, *args, **kw): self.param_types = args @@ -124,40 +139,47 @@ class WSRoot(object): def _handle_request(self, request): res = webob.Response() + res_content_type = None try: protocol = self._select_protocol(request) if protocol is None: msg = ("None of the following protocols can handle this " - "request : %s" % ','.join(self.protocols.keys())) + "request : %s" % ','.join(self.protocols.keys())) res.status = 500 res.text = msg log.error(msg) 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 and funcdef.arguments or None) result = func(**kw) - # TODO make sure result type == a._wsme_definition.return_type res.status = 200 - res.body = protocol.encode_result(result, funcdef.return_type) + + if funcdef.protocol_specific and funcdef.return_type is None: + res.body = result + else: + # TODO make sure result type == a._wsme_definition.return_type + res.body = protocol.encode_result(result, funcdef.return_type) + res_content_type = funcdef.contenttype except Exception, e: + infos = self._format_exception(sys.exc_info()) + log.error(str(infos)) res.status = 500 - res.body = protocol.encode_error( - self._format_exception(sys.exc_info())) + res.body = protocol.encode_error(infos) - # Attempt to correctly guess what content-type we should return. - res_content_type = None - - last_q = 0 - if hasattr(request.accept, '_parsed'): - for mimetype, q in request.accept._parsed: - if mimetype in protocol.content_types and last_q < q: - res_content_type = mimetype - else: - res_content_type = request.accept.best_match([ - ct for ct in protocol.content_types if ct]) + if res_content_type is None: + # Attempt to correctly guess what content-type we should return. + last_q = 0 + if hasattr(request.accept, '_parsed'): + for mimetype, q in request.accept._parsed: + if mimetype in protocol.content_types and last_q < q: + res_content_type = mimetype + else: + res_content_type = request.accept.best_match([ + ct for ct in protocol.content_types if ct]) # If not we will attempt to convert the body to an accepted # output format. @@ -175,15 +197,27 @@ class WSRoot(object): def _lookup_function(self, path): a = self + isprotocol_specific = path[0] == '_protocol' + + if isprotocol_specific: + a = self.protocols[path[1]] + path = path[2:] + + print path, a, a.api_wsdl + for name in path: a = getattr(a, name, None) if a is None: break + print a + if not hasattr(a, '_wsme_definition'): raise exc.UnknownFunction('/'.join(path)) - return a, a._wsme_definition + definition = a._wsme_definition + + return a, definition def _format_exception(self, excinfo): """Extract informations that can be sent to the client.""" diff --git a/wsme/soap.py b/wsme/soap.py index aeef20e..ca1bd6f 100644 --- a/wsme/soap.py +++ b/wsme/soap.py @@ -1,9 +1,63 @@ +from wsme.controller import register_protocol, pexpose + +from xml.etree import ElementTree as et + + + class SoapProtocol(object): name = 'soap' - accept = '' + content_types = ['application/soap+xml'] + + ns = { + "soap": "http://www.w3.org/2001/12/soap-envelope" + } def __init__(self): pass + def accept(self, root, req): + if req.headers['Content-Type'] in self.content_types: + return True + if req.path.endswith('.wsdl'): + return True + return False -controller.register_protocol(SoapProtocol) + def extract_path(self, request): + if request.path.endswith('.wsdl'): + print "Here !!" + return ['_protocol', 'soap', 'api_wsdl'] + + def read_arguments(self, request, arguments): + if arguments is None: + return {} + return {} + + def encode_result(self, result, return_type): + return "" + + def make_header(self): + header = et.Element('{%(soap)s}Header' % self.ns) + return header + + 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 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) + + @pexpose(contenttype="text/xml") + def api_wsdl(self): + return """""" + + +register_protocol(SoapProtocol)