[Soap-Python] rpclib -> spyne: multiple MethodDescriptor to a single proxy function
C Anthony Risinger
anthony.risinger at corvisa.com
Mon Jun 25 19:29:08 CEST 2012
hello,
while briefly trying to update to the spyne codebase, i am encountering
an AssertionError due to spyne enforcing a 1-to-1 mapping between
MethodDescriptor and the function it wraps:
File "/path/to/spyne/interface/_base.py", line 224, in populate_interface
assert not s.get_method_id(method) in self.method_id_map
AssertionError
... the problem is that i am currently building the MethodDescriptors
dynamically, and mapping to a single _proxy function; this SOAP service
is really proxying/exposing another JSON service (no JSON support in
rpclib/spyne during development).
service definition (disregard custom json functions, unrelated):
-----------------------------------------------
from rpclib import MethodDescriptor
from rpclib.interface.wsdl import Wsdl11
from rpclib.service import ServiceBase
from requests import request
import json
from awesome import models
API_VERISION_JSON = 1
API_VERISION_SOAP = 1
METHODS = [('method_one', 'put', 'some method two'),
('method_two', 'post', 'some method two')]
def _bind(udp):
m, verb, doc = udp
def f(*args, **kwds):
name = kwds['_default_function_name']
in_message = getattr(models, m)
out_message = getattr(models, m+'Response', None)
if out_message is None:
out_message = getattr(models, m+'_response')
desc = MethodDescriptor(function=_proxy,
in_message=in_message,
out_message=out_message,
doc=doc,
is_callback=False,
is_async=False,
mtom=False,
in_header=None,
out_header=None,
faults=None,
port_type=None,
no_ctx=False,
udp=udp,
class_key=name)
return desc
f.__doc__ = doc
f._is_rpc = True
return f
def _proxy(ctx, req):
res = None
ret = None
method, verb, doc = ctx.descriptor.udp
host = 'http://%(SERVER_NAME)s:%(SERVER_PORT)s' % \
ctx.transport.req_env
endpoint = '%s/api/v%s/%s/' % (host, API_VERISION_JSON, method)
headers = {'content-type': 'application/json'}
try:
res = request(verb, endpoint, headers=headers,
data=json.dumps(req.json(req)))
res_json = json.loads(res.text)
except Exception, e:
import traceback
if res:
print res.text
traceback.print_exc()
raise e
out_message = ctx.descriptor.out_message
if len(out_message._type_info) == 1:
out_message = out_message._type_info[0]
return out_message.json(res_json)
MyService = type('MyService', (ServiceBase,),
dict([(udp[0], _bind(udp)) for udp in METHODS]))
-----------------------------------------------
... thats's the complete -- working -- service definition, with only the
method list truncated and some names changed to protect the innocent. in
short: i store the method name, HTTP verb, and __doc__ in udp, then use
that and the transport context to rebuild the real request.
i haven't spent much time investigating, but why is this restriction
necessary? the solution ATM means needlessly wrapping _proxy for each
method with a module level function, since lambdas probably wouldn't
work either (albeit, i didn't try :-)
how can i solve this cleanly, or better, patch spyne to not care what
callable actually implements the method (since the pattern was working
rather nicely)?
thanks!
--
C Anthony
-----------------------------------------
CONFIDENTIALITY: The information contained in this communication may be confidential and is intended only for the use of the intended recipient(s). If the reader of this message is not the intended recipient(s), you are hereby notified that
any dissemination, distribution, or copying of this communication, or any of its contents, is strictly prohibited. If you have received this communication in error, please return it to the sender immediately and delete any copy of it from your computer system.
More information about the Soap
mailing list