136

I want to use a WSDL SOAP based web service in Python. I have looked at the Dive Into Python code but the SOAPpy module does not work under Python 2.5.

I have tried using suds which works partly, but breaks with certain types (suds.TypeNotFound: Type not found: 'item').

I have also looked at Client but this does not appear to support WSDL.

And I have looked at ZSI but it looks very complex. Does anyone have any sample code for it?

The WSDL is https://ws.pingdom.com/soap/PingdomAPI.wsdl and works fine with the PHP 5 SOAP client.

Csa77
  • 649
  • 13
  • 19
davidmytton
  • 38,604
  • 37
  • 87
  • 93
  • 4
    Would you consider changing your accepted answer? The currently accepted answer is -1, and there's another answer with +19. I know this is from 2008; I'm just suggesting. – Mark E. Haase Oct 17 '12 at 15:17
  • SUDS didn't work as it couldn't parse the WSDL properly but would be a good choice otherwise. So I changed the answer to a tutorial from Dive Into Python which has some alternatives. As a side note, Pingdom now has a REST API https://www.pingdom.com/services/api-documentation-rest/ with client libraries at http://blog.pingdom.com/2011/04/11/pingdom-rest-api-wrappers/ – davidmytton Oct 23 '12 at 22:06

10 Answers10

50

I would recommend that you have a look at SUDS

"Suds is a lightweight SOAP python client for consuming Web Services."

Yusufk
  • 1,055
  • 2
  • 10
  • 15
  • Seconded. Suds made immediate sense to me, no class generation, it loads the WSDL live and creates an object you can immediately use from it. – EnigmaCurry Feb 23 '11 at 15:43
  • 20
    Suds has an infinite recursion problem when opening WSDL with recursive imports. This is considered a blocking bug by Suds, and the issue was created over 3 years ago, but it hasn't been fixed yet. https://fedorahosted.org/suds/ticket/239 It makes me wonder if Suds is suitable for use in 2012? – Buttons840 Feb 27 '12 at 22:31
  • 3
    [suds](https://pypi.python.org/pypi/suds) seems dead. Long live [SUDS](https://github.com/heroku/sf-suds/tree/master/suds) - this seems to be the active Fork. – nerdoc Jun 22 '17 at 15:43
  • 7
    This is the top answer, but if anyone's looking for an answer that works today, consider [Zeep](https://python-zeep.readthedocs.io/en/master/), as the newer answers suggest, too. – Tobias Feil Mar 14 '19 at 16:14
32

There is a relatively new library which is very promising and albeit still poorly documented, seems very clean and pythonic: python zeep.

See also this answer for an example.

Community
  • 1
  • 1
lorenzog
  • 3,483
  • 4
  • 29
  • 50
19

I recently stumbled up on the same problem. Here is the synopsis of my solution:

Basic constituent code blocks needed

The following are the required basic code blocks of your client application

  1. Session request section: request a session with the provider
  2. Session authentication section: provide credentials to the provider
  3. Client section: create the Client
  4. Security Header section: add the WS-Security Header to the Client
  5. Consumption section: consume available operations (or methods) as needed

What modules do you need?

Many suggested to use Python modules such as urllib2 ; however, none of the modules work-at least for this particular project.

So, here is the list of the modules you need to get. First of all, you need to download and install the latest version of suds from the following link:

pypi.python.org/pypi/suds-jurko/0.4.1.jurko.2

Additionally, you need to download and install requests and suds_requests modules from the following links respectively ( disclaimer: I am new to post in here, so I can't post more than one link for now).

pypi.python.org/pypi/requests

pypi.python.org/pypi/suds_requests/0.1

Once you successfully download and install these modules, you are good to go.

The code

Following the steps outlined earlier, the code looks like the following: Imports:

import logging
from suds.client import Client
from suds.wsse import *
from datetime import timedelta,date,datetime,tzinfo
import requests
from requests.auth import HTTPBasicAuth
import suds_requests

Session request and authentication:

username=input('Username:')
password=input('password:')
session = requests.session()
session.auth=(username, password)

Create the Client:

client = Client(WSDL_URL, faults=False, cachingpolicy=1, location=WSDL_URL, transport=suds_requests.RequestsTransport(session))

Add WS-Security Header:

...
addSecurityHeader(client,username,password)
....

def addSecurityHeader(client,username,password):
    security=Security()
    userNameToken=UsernameToken(username,password)
    timeStampToken=Timestamp(validity=600)
    security.tokens.append(userNameToken)
    security.tokens.append(timeStampToken)
    client.set_options(wsse=security)

Please note that this method creates the security header depicted in Fig.1. So, your implementation may vary depending on the correct security header format provided by the owner of the service you are consuming.

Consume the relevant method (or operation) :

result=client.service.methodName(Inputs)

Logging:

One of the best practices in such implementations as this one is logging to see how the communication is executed. In case there is some issue, it makes debugging easy. The following code does basic logging. However, you can log many aspects of the communication in addition to the ones depicted in the code.

logging.basicConfig(level=logging.INFO) 
logging.getLogger('suds.client').setLevel(logging.DEBUG) 
logging.getLogger('suds.transport').setLevel(logging.DEBUG)

Result:

Here is the result in my case. Note that the server returned HTTP 200. This is the standard success code for HTTP request-response.

(200, (collectionNodeLmp){
   timestamp = 2014-12-03 00:00:00-05:00
   nodeLmp[] = 
      (nodeLmp){
         pnodeId = 35010357
         name = "YADKIN"
         mccValue = -0.19
         mlcValue = -0.13
         price = 36.46
         type = "500 KV"
         timestamp = 2014-12-03 01:00:00-05:00
         errorCodeId = 0
      },
      (nodeLmp){
         pnodeId = 33138769
         name = "ZION 1"
         mccValue = -0.18
         mlcValue = -1.86
         price = 34.75
         type = "Aggregate"
         timestamp = 2014-12-03 01:00:00-05:00
         errorCodeId = 0
      },
 })
Teddy Belay
  • 1,525
  • 14
  • 12
  • 1
    Might be worth of saying that `suds_request` will fail while installing, so if you are using `suds-jurko` fork, you can install `suds_request` which was adapted to work with jurko's version of suds: `pip install git+https://github.com/chrcoe/suds_requests.git@feature/python3_suds_jurko` – errata Feb 18 '16 at 10:28
10

Zeep is a decent SOAP library for Python that matches what you're asking for: http://docs.python-zeep.org

Al Sweigart
  • 11,566
  • 10
  • 64
  • 92
Hanni Ali
  • 379
  • 4
  • 6
  • 1
    Duplicate answer (please close this one and upvote https://stackoverflow.com/a/36910649/948581) –  Aug 24 '17 at 08:48
7

Right now (as of 2008), all the SOAP libraries available for Python suck. I recommend avoiding SOAP if possible. The last time we where forced to use a SOAP web service from Python, we wrote a wrapper in C# that handled the SOAP on one side and spoke COM out the other.

the Tin Man
  • 158,662
  • 42
  • 215
  • 303
Matthew Scouten
  • 15,303
  • 9
  • 33
  • 50
  • 16
    That sounds like an insanely complicated way to use a simple protocol based on xml and http. – ddaa Jan 12 '12 at 12:22
  • 2
    At the time, 2008, this was the method that sucked the least for our needs. I seem to remember that that particular web service was extremely picky about something that all the python libraries were getting wrong. – Matthew Scouten Jan 16 '12 at 18:14
  • 1
    2019, python zeep, suds, still prone to many parsing incompatibility issues. Poorly maintain wsdl documents will make those modules throw exception like non-stop firecracker. – mootmoot May 10 '19 at 15:01
6

I periodically search for a satisfactory answer to this, but no luck so far. I use soapUI + requests + manual labour.

I gave up and used Java the last time I needed to do this, and simply gave up a few times the last time I wanted to do this, but it wasn't essential.

Having successfully used the requests library last year with Project Place's RESTful API, it occurred to me that maybe I could just hand-roll the SOAP requests I want to send in a similar way.

Turns out that's not too difficult, but it is time consuming and prone to error, especially if fields are inconsistently named (the one I'm currently working on today has 'jobId', JobId' and 'JobID'. I use soapUI to load the WSDL to make it easier to extract endpoints etc and perform some manual testing. So far I've been lucky not to have been affected by changes to any WSDL that I'm using.

Hywel Thomas
  • 799
  • 9
  • 5
3

It's not true SOAPpy does not work with Python 2.5 - it works, although it's very simple and really, really basic. If you want to talk to any more complicated webservice, ZSI is your only friend.

The really useful demo I found is at http://www.ebi.ac.uk/Tools/webservices/tutorials/python - this really helped me to understand how ZSI works.

zgoda
  • 12,775
  • 4
  • 37
  • 46
  • 1
    python setup.py install gives errors with the latest release. The latest dev copy might work but that's a pain to do. – davidmytton Sep 22 '08 at 20:41
1

If you're rolling your own I'd highly recommend looking at http://effbot.org/zone/element-soap.htm.

sj26
  • 6,725
  • 2
  • 27
  • 24
1

SOAPpy is now obsolete, AFAIK, replaced by ZSL. It's a moot point, because I can't get either one to work, much less compile, on either Python 2.5 or Python 2.6

the Tin Man
  • 158,662
  • 42
  • 215
  • 303
1
#!/usr/bin/python
# -*- coding: utf-8 -*-
# consume_wsdl_soap_ws_pss.py
import logging.config
from pysimplesoap.client import SoapClient

logging.config.dictConfig({
    'version': 1,
    'formatters': {
        'verbose': {
            'format': '%(name)s: %(message)s'
        }
    },
    'handlers': {
        'console': {
            'level': 'DEBUG',
            'class': 'logging.StreamHandler',
            'formatter': 'verbose',
        },
    },
    'loggers': {
        'pysimplesoap.helpers': {
            'level': 'DEBUG',
            'propagate': True,
            'handlers': ['console'],
        },
    }
})

WSDL_URL = 'http://www.webservicex.net/stockquote.asmx?WSDL'
client = SoapClient(wsdl=WSDL_URL, ns="web", trace=True)
client['AuthHeaderElement'] = {'username': 'someone', 'password': 'nottelling'}

#Discover operations
list_of_services = [service for service in client.services]
print(list_of_services)

#Discover params
method = client.services['StockQuote']

response = client.GetQuote(symbol='GOOG')
print('GetQuote: {}'.format(response['GetQuoteResult']))
Down the Stream
  • 639
  • 7
  • 10
  • the lib is listed here: https://code.google.com/archive/p/pysimplesoap/ – Down the Stream Mar 23 '17 at 16:09
  • sample output: ... DEBUG:pysimplesoap.helpers:complexContent/simpleType/element string = string [u'StockQuote'] GetQuote: GOOG816.133/23/2017-13.46820.01822.57812.261973140564.29B829.59-1.62%663.28 - 853.5027.8829.28Alphabet Inc. – Down the Stream Mar 23 '17 at 16:11
  • fails on Python3 in pysimplesoap/client.py:757 -- 'dict' object has no attribute 'iteritems' – ierdna Jun 14 '17 at 17:28
  • apparently version that comes with PIP is broken. have to install it manually from GIT - it fixes things – ierdna Jun 14 '17 at 17:39
  • Good point: see this link:https://stackoverflow.com/questions/13998492/iteritems-in-python "dict.iteritems was removed because dict.items now does the thing dict.iteritems did in python 2..." – Down the Stream Jun 14 '17 at 17:59