9

I'm looking for a simple way to programmatically invoke a SOAP/RPC call via Python. Something like:

method_to_invoke, args = parse_user_input()
outbound_xml = library.call_remote_method(method_to_invoke, args)
result = requests.post(... data=outbound_xml)

I know there are several Python libraries that support SOAP/RPC calls; however they all do some "magic" and allow for things like:

result = client.service.getPercentBodyFat('jeff', 68, 170)

(previous example taken from suds documentation but the basic principles are the same). This assumes I know the name of the method ahead of time and can't determine it at runtime.

Looking for solutions they are either no longer maintained, or try to do too much "magic". For example see this over-complicated soution or this solution which is basically "Build your own XML and send it over".

Is there any library that can build the "outbound" XML for me without having to go through hoops? I already have a HTTP server which would receive the inbound RPC and want to use requests to properly handle things like SSL certificate validation.

Community
  • 1
  • 1
lorenzog
  • 3,483
  • 4
  • 29
  • 50
  • is there a reason you can't use something like suds and pick the method using reflection (e.g. getattr)? Does something else also need to by dynamic other than the method name? – Charlie Apr 27 '16 at 13:27
  • @Charlie care to provide an example in the answers? Reflection might work it just seems an unnecessary complication I'd rather avoid. I understand RPC libraries are meant to simplify life, but the lack of a pythonic, simple one that's easily extensible seems ridiculous. – lorenzog Apr 27 '16 at 13:50
  • OK sorry I don't have a solution. In my experience SOAP is meant to be brittle - you establish a "contract" with a service and then if it changes there's a big waterfall process to make the updates. – Charlie Apr 27 '16 at 14:07

1 Answers1

22

You can give python-zeep a chance (http://docs.python-zeep.org). It can easily generate the xml which you want to send via the following code:

client = zeep.Client(
    wsdl='http://www.webservicex.net/ConvertSpeed.asmx?WSDL')
doc = client.service._binding.create_message('ConvertSpeed', 100, 
      'kilometersPerhour', 'milesPerhour'))    
print(etree.tostring(doc, pretty_print=True))

(I'm the author so let me know if you have any issues with this)

lorenzog
  • 3,483
  • 4
  • 29
  • 50
mvantellingen
  • 1,229
  • 10
  • 6
  • Looks perfect. Thanks for doing this. May I recommend you get it posted here https://wiki.python.org/moin/WebServices like, on the top in bold and font size 250pt or something :) – lorenzog Apr 27 '16 at 15:31
  • Also - it would be nice to see a few more examples of use, such as - if I want to do the opposite e.g. feed an XML into zeep, does it support "server" side generation of methods from a WSDL? – lorenzog Apr 27 '16 at 15:51
  • It's only a client and cant act currently as a server. I have good experience with http://spyne.io/docs/2.10/index.html for that – mvantellingen Apr 27 '16 at 16:12
  • Did something change in recent versions? The example you posted doesn't seem to work any more. I have 0.13.0 at the moment – lorenzog Aug 03 '16 at 07:56
  • Yeah that is changed to:: client.service._binding.create_message('ConvertSpeed', 100, 'kilometersPerhour', 'milesPerhour')) – mvantellingen Aug 03 '16 at 15:22
  • thanks, I've updated the answer (needs to be approved but it's there) – lorenzog Aug 03 '16 at 15:50
  • How can I pass raw xml as a request using zeep @mvantellingen – Raj Kumar May 17 '21 at 16:54