Zeep: Python SOAP client

A Python SOAP client

Highlights:
  • Compatible with Python 3.7, 3.8, 3.9, 3.10, 3.11 and PyPy
  • Build on top of lxml and requests
  • Support for Soap 1.1, Soap 1.2 and HTTP bindings
  • Support for WS-Addressing headers
  • Support for WSSE (UserNameToken / x.509 signing)
  • Support for asyncio via httpx
  • Experimental support for XOP messages

A simple example:

from zeep import Client

client = Client('http://www.webservicex.net/ConvertSpeed.asmx?WSDL')
result = client.service.ConvertSpeed(
    100, 'kilometersPerhour', 'milesPerhour')

assert result == 62.137

Quick Introduction

Zeep inspects the WSDL document and generates the corresponding code to use the services and types in the document. This provides an easy to use programmatic interface to a SOAP server.

The emphasis is on SOAP 1.1 and SOAP 1.2, however Zeep also offers support for HTTP Get and Post bindings.

Parsing the XML documents is done by using the lxml library. This is the most performant and compliant Python XML library currently available. This results in major speed benefits when processing large SOAP responses.

The SOAP specifications are unfortunately really vague and leave a lot of things open for interpretation. Due to this there are a lot of WSDL documents available which are invalid or SOAP servers which contain bugs. Zeep tries to be as compatible as possible but there might be cases where you run into problems. Don’t hesitate to submit an issue in this case (but please first read Reporting bugs).

Installation

Zeep is a pure-python module. This means that there is no C code which needs to be compiled. However the lxml dependency does contain C code since it uses libxml2 and libxslt. For linux/bsd this means you need to install libxml2-dev and libxslt-dev packages. For Windows this is unfortunately a bit more complicated. The easiest way is to install lxml via wheel files since that contains already compiled code for your platform.

To install wheel files you need a recent pip client. See https://pip.pypa.io/en/stable/installing/ how to install pip on your platform.

If you have installed pip then run:

pip install zeep

Note that the latest version to support Python 2.7, 3.3, 3.4 and 3.5 is Zeep 3.4, install via pip install zeep==2.4.0

This assumes that there are wheel files available for the latest lxml release. If that is not the case (https://pypi.python.org/pypi/lxml/) then first install lxml 4.2.5 since that release should have the wheel files for all platforms:

pip install lxml==4.2.5 zeep

When you want to use wsse.Signature() you will need to install the python xmlsec module. This can be done by installing the xmlsec extras:

pip install zeep[xmlsec]

For the asyncio support in Python 3.6+ the httpx module is required, this can be installed with the async extras:

pip install zeep[async]

Getting started

The first thing you generally want to do is inspect the wsdl file you need to implement. This can be done with:

python -mzeep <wsdl>

See python -mzeep --help for more information about this command.

Note

Zeep follows semver for versioning, however bugs can always occur. So as always pin the version of zeep you tested with (e.g. zeep==4.2.1’).

A simple use-case

To give you an idea how zeep works a basic example.

import zeep

wsdl = 'http://www.soapclient.com/xml/soapresponder.wsdl'
client = zeep.Client(wsdl=wsdl)
print(client.service.Method1('Zeep', 'is cool'))

The WSDL used above only defines one simple function (Method1) which is made available by zeep via client.service.Method1. It takes two arguments and returns a string. To get an overview of the services available on the endpoint you can run the following command in your terminal.

python -mzeep http://www.soapclient.com/xml/soapresponder.wsdl

Note

Note that unlike suds, zeep doesn’t enable caching of the wsdl documents by default. This means that everytime you initialize the client requests are done to retrieve the wsdl contents.

User guide

Using Zeep

WSDL documents provide a number of operations (functions) per binding. A binding is collection of operations which are called via a specific protocol.

These protocols are generally Soap 1.1 or Soap 1.2. As mentioned before, Zeep also offers experimental support for the Http Get and Http Post bindings. Most of the time this is an implementation detail, Zeep should offer the same API to the user independent of the underlying protocol.

One of the first things you will do if you start developing an interface to a wsdl web service is to get an overview of all available operations and their call signatures. Zeep offers a command line interface to make this easy.

python -mzeep http://www.soapclient.com/xml/soapresponder.wsdl

See python -mzeep --help for more information.

The Client object

The Client is the main interface for interacting with a SOAP server. It provides a service attribute which references the default binding of the client (via a ServiceProxy object). The default binding can be specified when initiating the client by passing the service_name and port_name. Otherwise the first service and first port within that service are used as the default.

Caching of WSDL and XSD files

When the client is initialized it will automatically retrieve the WSDL file passed as argument. This WSDL file generally references various other WSDL and XSD files. By default Zeep doesn’t cache these files but it is however advised to enable this for performance reasons.

Please see Caching how to enable this. To make it easy to use the zeep.CachingClient() automatically creates a Transport object with SqliteCache enabled.

Configuring the client

The Client class accepts a settings argument to configuring the client. You can initialise the object using the following code:

from zeep import Client, Settings

settings = Settings(strict=False, xml_huge_tree=True)
client = Client('http://my-wsdl/wsdl', settings=settings)

The settings object is always accessible via the client using client.settings. For example:

with client.settings(raw_response=True):
    response = client.service.myoperation()

Please see Settings for more information.

The AsyncClient

The AsyncClient allows you to execute operations in an asynchronous fashion. There is one big caveat however: the wsdl documents are still loaded using synchronous methods. The reason for this is that the codebase was originally not written for asynchronous usage and support that is quite a lot of work.

To use async operations you need to use the AsyncClient() and the corresponding AsyncTransport() (this is the default transport for the AsyncClient)

client = zeep.AsyncClient("http://localhost:8000/?wsdl")

response = await client.service.myoperation()

New in version 4.0.0.

Strict mode

By default zeep will operate in ‘strict’ mode. This can be disabled if you are working with a SOAP server which is not standards compliant by using the strict setting. See Settings. Disabling strict mode will change the following behaviour:

  • The XML is parsed with the recover mode enabled
  • Nonoptional elements are allowed to be missing in xsd:sequences

Note that disabling strict mode should be considered a last resort since it might result in data-loss between the XML and the returned response.

The ServiceProxy object

The ServiceProxy object is a simple object which will check if an operation exists for attribute or item requested. If the operation exists then it will return an OperationProxy object (callable) which is responsible for calling the operation on the binding.

from zeep import Client
from zeep import xsd

client = Client('http://my-endpoint.com/production.svc?wsdl')

# service is a ServiceProxy object.  It will check if there
# is an operation with the name `X` defined in the binding
# and if that is the case it will return an OperationProxy
client.service.X()

# The operation can also be called via an __getitem__ call.
# This is useful if the operation name is not a valid
# python attribute name.
client.service['X-Y']()

Using non-default bindings

As mentioned by default Zeep picks the first binding in the WSDL as the default. This binding is available via client.service. To use a specific binding you can use the bind() method on the client object:

from zeep import Client
from zeep import xsd

client = Client('http://my-endpoint.com/production.svc?wsdl')

service2 = client.bind('SecondService', 'Port12')
service2.someOperation(myArg=1)

for example, if your wsdl contains these definitions

<wsdl:service name="ServiceName">
<wsdl:port name="PortName" binding="tns:BasicHttpsBinding_IServiziPartner">
<soap:address location="https://aaa.bbb.ccc/ddd/eee.svc"/>
</wsdl:port>
<wsdl:port name="PortNameAdmin" binding="tns:BasicHttpsBinding_IServiziPartnerAdmin">
<soap:address location="https://aaa.bbb.ccc/ddd/eee.svc/admin"/>
</wsdl:port>
</wsdl:service>

and you need to calls methods defined in https://aaa.bbb.ccc/ddd/eee.svc/admin you can do:

client = Client("https://www.my.wsdl") # this will use default binding
client_admin = client.bind('ServiceName', 'PortNameAdmin')
client_admin.method1() #this will call method1 defined in service name ServiceName and port PortNameAdmin

Creating new ServiceProxy objects

There are situations where you either need to change the SOAP address from the one which is defined within the WSDL or the WSDL doesn’t define any service elements. This can be done by creating a new ServiceProxy using the Client.create_service() method.

from zeep import Client
from zeep import xsd

client = Client('http://my-endpoint.com/production.svc?wsdl')
service = client.create_service(
    '{http://my-target-namespace-here}myBinding',
    'http://my-endpoint.com/acceptance/')

service.submit('something')

Creating the raw XML documents

When you want zeep to build and return the XML instead of sending it to the server you can use the Client.create_message() call. It requires the ServiceProxy as the first argument and the operation name as the second argument.

from zeep import Client

client = Client('http://my-endpoint.com/production.svc?wsdl')
node = client.create_message(client.service, 'myOperation', user='hi')

Settings

New in version 3.0.

Context manager

You can set various options directly as attribute on the client or via a context manager.

For example to let zeep return the raw response directly instead of processing it you can do the following:

from zeep import Client
from zeep import xsd

client = Client('http://my-endpoint.com/production.svc?wsdl')

with client.settings(raw_response=True):
    response = client.service.myoperation()

    # response is now a regular requests.Response object
    assert response.status_code == 200
    assert response.content

API

class zeep.settings.Settings(strict=True, raw_response=False, force_https=True, extra_http_headers=None, xml_huge_tree=False, forbid_dtd=False, forbid_entities=True, forbid_external=True, xsd_ignore_sequence_order=False, tls=NOTHING)
Parameters:
  • strict (boolean) – boolean to indicate if the lxml should be parsed a ‘strict’. If false then the recover mode is enabled which tries to parse invalid XML as best as it can.
  • raw_response – boolean to skip the parsing of the XML response by zeep but instead returning the raw data
  • forbid_dtd (bool) – disallow XML with a <!DOCTYPE> processing instruction
  • forbid_entities (bool) – disallow XML with <!ENTITY> declarations inside the DTD
  • forbid_external (bool) – disallow any access to remote or local resources in external entities or DTD and raising an ExternalReferenceForbidden exception when a DTD or entity references an external resource.
  • xml_huge_tree – disable lxml/libxml2 security restrictions and support very deep trees and very long text content
  • force_https (bool) – Force all connections to HTTPS if the WSDL is also loaded from an HTTPS endpoint. (default: true)
  • extra_http_headers – Additional HTTP headers to be sent to the transport. This can be used in combination with the context manager approach to add http headers for specific calls.
  • xsd_ignore_sequence_order (boolean) – boolean to indicate whether to enforce sequence order when parsing complex types. This is a workaround for servers that don’t respect sequence order.

Transports

If you need to change options like cache, timeout or TLS (or SSL) verification you will need to create an instance of the Transport class yourself.

Note

Secure Sockets Layer (SSL) has been deprecated in favor of Transport Layer Security (TLS). SSL 2.0 was prohibited in 2011 and SSL 3.0 in June 2015.

TLS verification

If you need to verify the TLS connection (in case you have a self-signed certificate for your host), the best way is to create a requests.Session instance and add the information to that Session, so it keeps persistent:

from requests import Session
from zeep import Client
from zeep.transports import Transport

session = Session()
session.verify = 'path/to/my/certificate.pem'
transport = Transport(session=session)
client = Client(
    'http://my.own.sslhost.local/service?WSDL',
    transport=transport)

Hint

Make sure that the certificate you refer to is a CA_BUNDLE, meaning it contains a root CA and an intermediate CA. Accepted are only X.509 ASCII files (file extension .pem, sometimes .crt). If you have two different files, you must combine them manually into one.

Alternatively, instead of using session.verify you can use session.cert if you just want to use an TLS client certificate.

To disable TLS verification (not recommended!) you will need to set verify to False.

session = Session()
session.verify = False

Or even simpler way:

client.transport.session.verify = False

Remember: this should be only done for testing purposes. Python’s urllib3 will warn you with a InsecureRequestWarning.

See requests.Session for further details.

Session timeout

To set a transport timeout for loading wsdl sfn xsd documents, use the timeout option. The default timeout is 300 seconds:

from zeep import Client
from zeep.transports import Transport

transport = Transport(timeout=10)
client = Client(
    'http://www.webservicex.net/ConvertSpeed.asmx?WSDL',
    transport=transport)

To pass a timeout to the underlying POST/GET requests, use operation_timeout. This defaults to None.

Using HTTP or SOCKS Proxy

By default, zeep uses requests as transport layer, which allows to define proxies using the proxies attribute of requests.Session:

from zeep import Client

client = Client(
    'http://my.own.sslhost.local/service?WSDL')

client.transport.session.proxies = {
    # Utilize for all http/https connections
    'http': 'foo.bar:3128',
    'https': 'foo.bar:3128',
    # Utilize for certain URL
    'http://specific.host.example': 'foo.bar:8080',
    # Or use socks5 proxy (requires requests[socks])
    'https://socks5-required.example': 'socks5://foo.bar:8888',
}

In order to use SOCKS proxies, requests needs to be installed with additional packages (for example pip install -U requests[socks]).

Caching

By default zeep doesn’t use a caching backend. For performance benefits it is advised to use the SqliteCache backend. It caches the WSDL and XSD files for 1 hour by default. To use the cache backend init the client with:

from zeep import Client
from zeep.cache import SqliteCache
from zeep.transports import Transport

transport = Transport(cache=SqliteCache())
client = Client(
    'http://www.webservicex.net/ConvertSpeed.asmx?WSDL',
    transport=transport)

Changing the SqliteCache settings can be done via:

from zeep import Client
from zeep.cache import SqliteCache
from zeep.transports import Transport
cache = SqliteCache(path='/tmp/sqlite.db', timeout=60)
transport = Transport(cache=cache)
client = Client(
    'http://www.webservicex.net/ConvertSpeed.asmx?WSDL',
    transport=transport)

Another option is to use the InMemoryCache backend. It internally uses a global dict to store urls with the corresponding content.

HTTP Authentication

While some providers incorporate security features in the header of a SOAP message, others use the HTTP Authentication header. In the latter case, you can just create a requests.Session object with the auth set and pass it to the Transport class.

from requests import Session
from requests.auth import HTTPBasicAuth  # or HTTPDigestAuth, or OAuth1, etc.
from zeep import Client
from zeep.transports import Transport

session = Session()
session.auth = HTTPBasicAuth(user, password)
client = Client('http://my-endpoint.com/production.svc?wsdl',
    transport=Transport(session=session))

Async HTTP Authentication

The Async client for zeep uses a different backend, so the setup is different in this case. You will need to use httpx to create an httpx.AsyncClient object, and pass it to your zeep.AsyncTransport.

import httpx
import zeep
from zeep.transports import AsyncTransport

USER = 'username'
PASSWORD = 'password'

httpx_client = httpx.AsyncClient(auth=(USER, PASSWORD))

aclient = zeep.AsyncClient(
    "http://my-endpoint.com/production.svc?wsdl",
    transport=AsyncTransport(client=httpx_client)
)

Debugging

To see the SOAP XML messages which are sent to the remote server and the response received you can set the Python logger level to DEBUG for the zeep.transports module. Since 0.15 this can also be achieved via the HistoryPlugin.

import logging.config

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

SOAP headers

SOAP headers are generally used for things like authentication. The header elements can be passed to all operations using the _soapheaders kwarg.

There are multiple ways to pass a value to the soapheader.

  1. When the SOAP header expects a complex type you can either pass a dict or an object created via the client.get_element() method.

  2. When the header expects a simple type value you can pass it directly to the _soapheaders kwarg. (e.g.: client.service.Method(_soapheaders=1234))

  3. Creating custom xsd element objects. For example:

    from zeep import xsd
    
    header = xsd.Element(
        '{http://test.python-zeep.org}auth',
        xsd.ComplexType([
            xsd.Element(
                '{http://test.python-zeep.org}username',
                xsd.String()),
        ])
    )
    header_value = header(username='mvantellingen')
    client.service.Method(_soapheaders=[header_value])
    
  4. Another option is to pass an lxml Element object. This is generally useful if the wsdl doesn’t define a soap header but the server does expect it.

Datastructures

Creating objects

Most of the times you need to pass nested data to the soap client. These Complex types can be retrieved using the client.get_type() method.

from zeep import Client

client = Client('http://my-enterprise-endpoint.com')
order_type = client.get_type('ns0:Order')
order = order_type(number='1234', price=99)
client.service.submit_order(user_id=1, order=order)

However instead of creating an object from a type defined in the XSD you can also pass in a dictionary. Zeep will automatically convert this dict to the required object (and nested child objects) during the call.

from zeep import Client

client = Client('http://my-enterprise-endpoint.com')
client.service.submit_order(user_id=1, order={
    'number': '1234',
    'price': 99,
})

Using factories

When you need to create multiple types the Client.get_type() calls to retrieve the type class and then instantiating them can be a bit verbose. To simplify this you can use a factory object.

from zeep import Client

client = Client('http://my-enterprise-endpoint.com')
factory = client.type_factory('ns0')

user = factory.User(id=1, name='John')
order = factory.Order(number='1234', price=99)
client.service.submit_order(user=user, order=order)

New in version 0.22.

xsd:choice

Mapping the semantics of xsd:choice elements to code is unfortunately pretty difficult. Zeep tries to solve this using two methods:

  1. Accepting the elements in the xsd:choice element as kwargs. This only works for simple xsd:choice definitions.
  2. Using the special kwarg _value_N where the N is the number of the choice in the parent type. This method allows you to pass a list of dicts (when maxOccurs != 1) or a dict directly.

The following examples should illustrate this better.

Simple method
<?xml version="1.0"?>
<schema xmlns:tns="http://tests.python-zeep.org/"
        targetNamespace="http://tests.python-zeep.org/">
  <element name='ElementName'>
    <complexType xmlns:xsd="http://www.w3.org/2001/XMLSchema">
      <choice>
        <element name="item_1" type="string"/>
        <element name="item_2" type="string"/>
      </choice>
    </complexType>
  </element>
</schema>
element = client.get_element('ns0:ElementName')
obj = element(item_1='foo')
Nested using _value_1
<?xml version="1.0"?>
<schema xmlns:tns="http://tests.python-zeep.org/"
        targetNamespace="http://tests.python-zeep.org/">
  <element name='ElementName'>
    <complexType xmlns:xsd="http://www.w3.org/2001/XMLSchema">
      <choice maxOccurs="1">
        <sequence>
            <element name="item_1_a" type="string"/>
            <element name="item_1_b" type="string"/>
        </sequence>
      </choice>
    </complexType>
  </element>
</schema>
element = client.get_element('ns0:ElementName')
obj = element(_value_1={'item_1_a': 'foo', 'item_1_b': 'bar'})
Nested list using _value_1
<?xml version="1.0"?>
<schema xmlns:tns="http://tests.python-zeep.org/"
        targetNamespace="http://tests.python-zeep.org/">
  <element name='ElementName'>
    <complexType xmlns:xsd="http://www.w3.org/2001/XMLSchema">
      <choice maxOccurs="unbounded">
        <element name="item_1" type="string"/>
        <element name="item_2" type="string"/>
      </choice>
    </complexType>
  </element>
</schema>
element = client.get_element('ns0:ElementName')
obj = element(_value_1=[{'item_1': 'foo'}, {'item_2': 'bar'}])

Any objects

Zeep offers full support for xsd:any elements. xsd:any elements are used as a kind of wildcard and basically allows any element to be used. Zeep needs to know the element name you want to serialize, so the value needs to be wrapped in a special object. This is the AnyObject. It takes two parameters, the xsd Element first and the value as the second arg.

from zeep import Client
from zeep import xsd

client = Client('http://my-entrprisy-endpoint.com')
order_type = client.get_element('ns0:Order')
order = xsd.AnyObject(
  order_type, order_type(number='1234', price=99))
client.service.submit_something(user_id=1, _value_1=order)

AnyType objects

xsd:anyType is used as a wildcard type. Where the xsd:Any element allows any element the xsd:anyType allows any type for a specific element. The usage from zeep is almost the same. Instead of passing an Element class to the AnyObject an xsd type is passed.

from zeep import Client
from zeep import xsd

client = Client('http://my-entrprisy-endpoint.com')
value = xsd.AnyObject(xsd.String(), 'foobar')
client.service.submit_something(user_id=1, my_string=value)

SkipValue

Zeep will automatically validate that all the required values are set when calling an operation. If you want to force a value to be ignored and left out of the generated XML then you can assign the zeep.xsd.SkipValue constant.

from zeep import Client
from zeep import xsd

client = Client('http://my-entrprisy-endpoint.com')
client.service.submit_something(user_id=1, my_string=xsd.SkipValue)

SOAP Attachments (multipart)

If the server responds with a Content-type: multipart, a MessagePack object will be returned. It contains a root object and some attachments.

Example based on https://www.w3.org/TR/SOAP-attachments

from zeep import Client

client = Client('http://www.risky-stuff.com/claim.svc?wsdl')

pack = client.service.GetClaimDetails('061400a')

ClaimDetails = pack.root
SignedFormTiffImage = pack.attachments[0].content
CrashPhotoJpeg = pack.attachments[1].content

# Or lookup by content_id
pack.get_by_content_id('<claim061400a.tiff@claiming-it.com>').content

WS-Addressing (WSA)

New in version 0.15.

Zeep offers (experimental) support for the ws-addressing specification. The specification defines some soap:Header elements which basically allows advanced routing of the SOAP messages.

If the WSDL document defines that WSA is required then Zeep will automatically add the required headers to the SOAP envelope. In case you want to customize this then you can add the WsAddressPlugin to the Client.plugins list.

For example:

from zeep import Client
from zeep.wsa import WsAddressingPlugin

client = Client(
    'http://examples.python-zeep.org/basic.wsdl',
    plugins=[WsAddressingPlugin()])
client.service.DoSomething()

Note

The support for ws-addressing is experimental. If you encounter any issues then please don’t hesitate to create an issue on the github repository.

WS-Security (WSSE)

WS-Security incorporates security features in the header of a SOAP message.

UsernameToken

The UsernameToken supports both the passwordText and passwordDigest methods:

>>> from zeep import Client
>>> from zeep.wsse.username import UsernameToken
>>> client = Client(
...     'http://www.webservicex.net/ConvertSpeed.asmx?WSDL',
...     wsse=UsernameToken('username', 'password'))

To use the passwordDigest method you need to supply use_digest=True to the UsernameToken class.

Signature (x509)

To use the wsse.Signature() plugin you will need to install the xmlsec module. See the README for xmlsec for the required dependencies on your platform.

To append the security token as BinarySecurityToken, you can use wsse.BinarySignature() plugin.

Example usage A:

>>> from zeep import Client
>>> from zeep.wsse.signature import Signature
>>> client = Client(
...     'http://www.webservicex.net/ConvertSpeed.asmx?WSDL',
...     wsse=Signature(
...         private_key_filename, public_key_filename,
...         optional_password))

Example usage B:

>>> from zeep import Client
>>> from zeep.wsse.signature import Signature
>>> from zeep.transports import Transport
>>> from requests import Session
>>> session = Session()
>>> session.cert = '/path/to/ssl.pem'
>>> transport = Transport(session=session)
>>> client = Client(
...     'http://www.webservicex.net/ConvertSpeed.asmx?WSDL',
...     transport=transport)

UsernameToken and Signature together

To use UsernameToken and Signature together, then you can pass both together to the client in a list

>>> from zeep import Client
>>> from zeep.wsse.username import UsernameToken
>>> from zeep.wsse.signature import Signature
>>> user_name_token = UsernameToken('username', 'password')
>>> signature = Signature(private_key_filename, public_key_filename,
...     optional_password)
>>> client = Client(
...     'http://www.webservicex.net/ConvertSpeed.asmx?WSDL',
...     wsse=[user_name_token, signature])

UsernameToken with Timestamp token

To use UsernameToken with Timestamp token, first you need an instance of WSU.Timestamp(), then extend it with a list containing WSU.Created() and WSU.Expired() elements, finally pass it as timestamp_token keyword argument to UsernameToken().

>>> import datetime
>>> from zeep import Client
>>> from zeep.wsse.username import UsernameToken
>>> from zeep.wsse.utils import WSU
>>> timestamp_token = WSU.Timestamp()
>>> today_datetime = datetime.datetime.today()
>>> expires_datetime = today_datetime + datetime.timedelta(minutes=10)
>>> timestamp_elements = [
...         WSU.Created(today_datetime.strftime("%Y-%m-%dT%H:%M:%SZ")),
...         WSU.Expires(expires_datetime.strftime("%Y-%m-%dT%H:%M:%SZ"))
...]
>>> timestamp_token.extend(timestamp_elements)
>>> user_name_token = UsernameToken('username', 'password', timestamp_token=timestamp_token)
>>> client = Client(
...     'http://www.webservicex.net/ConvertSpeed.asmx?WSDL', wsse=user_name_token
...)

Plugins

New in version 0.15.

You can write plugins for zeep which can be used to process/modify data before it is sent to the server (egress) and after it is received (ingress).

Writing a plugin is really simple and best explained via an example.

from lxml import etree
from zeep import Plugin

class MyLoggingPlugin(Plugin):

    def ingress(self, envelope, http_headers, operation):
        print(etree.tostring(envelope, pretty_print=True))
        return envelope, http_headers

    def egress(self, envelope, http_headers, operation, binding_options):
        print(etree.tostring(envelope, pretty_print=True))
        return envelope, http_headers

The plugin can implement two methods: ingress and egress. Both methods should always return an envelop (lxml element) and the http headers. The envelope in the egress plugin will only contain the body of the soap message. This is important to remember if you want to inspect or do something with the headers.

To register this plugin you need to pass it to the client. Plugins are always executed sequentially.

from zeep import Client

client = Client(..., plugins=[MyLoggingPlugin()])

HistoryPlugin

New in version 0.15.

The history plugin keep a list of sent and received requests. By default at most one transaction (sent/received) is kept. But this can be changed when you create the plugin by passing the maxlen kwarg.

from zeep import Client
from zeep.plugins import HistoryPlugin

history = HistoryPlugin()
client = Client(
    'http://examples.python-zeep.org/basic.wsdl',
    plugins=[history])
client.service.DoSomething()

print(history.last_sent)
print(history.last_received)

Helpers

In the zeep.helpers module the following helper functions are available:

zeep.helpers.Nil()

Return an xsi:nil element

zeep.helpers.create_xml_soap_map(values)

Create an http://xml.apache.org/xml-soap#Map value.

zeep.helpers.guess_xsd_type(obj)

Return the XSD Type for the given object

zeep.helpers.serialize_object(obj, target_cls=<class 'collections.OrderedDict'>)

Serialize zeep objects to native python data structures

Reporting bugs

The SOAP specifications are pretty bad and unclear for a lot of use-cases. This results in a lot of (older) SOAP servers which don’t implement the specifications correctly (or implement them in a way Zeep doesn’t expect). Of course there is also a good chance that Zeep doesn’t implement something correctly ;-) I’m always interested in the latter.

Since Zeep is a module I’ve created and currently maintain mostly in my spare time I need as much information as possible to quickly analyze/fix issues.

There are basically three majors parts where bugs can happen, these are:

  1. Parsing the WSDL
  2. Creating the XML for the request
  3. Parsing the XML from the response

The first one is usually pretty easy to debug if the WSDL is publicly accessible. If that isn’t the case then you might be able to make it anonymous.

Required information

Please provide the following information:

  1. The version of zeep (or if you are running master the commit hash/date)
  2. The WSDL you are using
  3. An example script (please see below)

Errors when creating the request

Create a new python script using the code below. The first argument to the create_message() method is the name of the operation/method and after that the args / kwargs you normally pass.

from lxml import etree
from zeep import Client

client = Client('YOUR-WSDL')

# client.service.OPERATION_NAME(*args, **kwargs) becomes
node = client.create_message(
    client.service, 'OPERATION_NAME', *args, **kwargs)

print(etree.tostring(node, pretty_print=True))

Errors when parsing the response

The first step is to retrieve the XML which is returned from the server, You need to enable debugging for this. Please see Debugging for a detailed description.

The next step is to create a python script which exposes the problem, an example is the following.

import pretend  # pip install pretend

from zeep import Client
from zeep.transports import Transport

# Replace YOUR-WSDL and OPERATION_NAME with the wsdl url
# and the method name you are calling. The response
# needs to be set in the content=""" """ var.

client = Client('YOUR-WSDL')
response = pretend.stub(
    status_code=200,
    headers={},
    content="""
        <!-- The response from the server -->
    """)

operation = client.service._binding._operations['OPERATION_NAME']
result = client.service._binding.process_reply(
    client, operation, response)

print(result)

API Documentation

Public API

Client

class zeep.Client(wsdl, wsse=None, transport=None, service_name=None, port_name=None, plugins=None, settings=None)

The zeep Client.

Parameters:
  • wsdl – Url/local WSDL location or preparsed WSDL Document
  • wsse
  • transport – Custom transport class.
  • service_name – The service name for the service binding. Defaults to the first service in the WSDL document.
  • port_name – The port name for the default binding. Defaults to the first port defined in the service element in the WSDL document.
  • plugins – a list of Plugin instances
  • settings – a zeep.Settings() object
bind(service_name: Optional[str] = None, port_name: Optional[str] = None)

Create a new ServiceProxy for the given service_name and port_name.

The default ServiceProxy instance (self.service) always referes to the first service/port in the wsdl Document. Use this when a specific port is required.

create_message(service, operation_name, *args, **kwargs)

Create the payload for the given operation.

Return type:lxml.etree._Element
create_service(binding_name, address)

Create a new ServiceProxy for the given binding name and address.

Parameters:
  • binding_name – The QName of the binding
  • address – The address of the endpoint
get_element(name)

Return the element for the given qualified name.

Return type:zeep.xsd.Element
get_type(name)

Return the type for the given qualified name.

Return type:zeep.xsd.ComplexType or zeep.xsd.AnySimpleType
service

The default ServiceProxy instance

Return type:ServiceProxy
set_default_soapheaders(headers)

Set the default soap headers which will be automatically used on all calls.

Note that if you pass custom soapheaders using a list then you will also need to use that during the operations. Since mixing these use cases isn’t supported (yet).

set_ns_prefix(prefix, namespace)

Set a shortcut for the given namespace.

type_factory(namespace)

Return a type factory for the given namespace.

Example:

factory = client.type_factory('ns0')
user = factory.User(name='John')
Return type:Factory

Transport

class zeep.Transport(cache=None, timeout=300, operation_timeout=None, session=None)

The transport object handles all communication to the SOAP server.

Parameters:
  • cache – The cache object to be used to cache GET requests
  • timeout – The timeout for loading wsdl and xsd documents.
  • operation_timeout – The timeout for operations (POST/GET). By default this is None (no timeout).
  • session – A request.Session() object (optional)
get(address, params, headers)

Proxy to requests.get()

Parameters:
  • address – The URL for the request
  • params – The query parameters
  • headers – a dictionary with the HTTP headers.
load(url)

Load the content from the given URL

post(address, message, headers)

Proxy to requests.posts()

Parameters:
  • address – The URL for the request
  • message – The content for the body
  • headers – a dictionary with the HTTP headers.
post_xml(address, envelope, headers)

Post the envelope xml element to the given address with the headers.

This method is intended to be overriden if you want to customize the serialization of the xml element. By default the body is formatted and encoded as utf-8. See zeep.wsdl.utils.etree_to_string.

settings(timeout=None)

Context manager to temporarily overrule options.

Example:

transport = zeep.Transport()
with transport.settings(timeout=10):
    client.service.fast_call()
Parameters:timeout – Set the timeout for POST/GET operations (not used for loading external WSDL or XSD documents)

AnyObject

class zeep.AnyObject(xsd_object, value)

Create an any object

Parameters:
  • xsd_object – the xsd type
  • value – The value

Internals

zeep.wsdl

The wsdl module is responsible for parsing the WSDL document. This includes the bindings and messages.

The structure and naming of the modules and classses closely follows the WSDL 1.1 specification.

The serialization and deserialization of the SOAP/HTTP messages is done by the zeep.wsdl.messages modules.

class zeep.wsdl.Document(location, transport: Type[Transport], base=None, settings=None)

A WSDL Document exists out of one or more definitions.

There is always one ‘root’ definition which should be passed as the location to the Document. This definition can import other definitions. These imports are non-transitive, only the definitions defined in the imported document are available in the parent definition. This Document is mostly just a simple interface to the root definition.

After all definitions are loaded the definitions are resolved. This resolves references which were not yet available during the initial parsing phase.

Parameters:
  • location (string) – Location of this WSDL
  • transport (zeep.transports.Transport) – The transport object to be used
  • base (str) – The base location of this document
  • strict (bool) – Indicates if strict mode is enabled

zeep.wsdl.wsdl

class zeep.wsdl.wsdl.Definition(wsdl, doc, location)

The Definition represents one wsdl:definition within a Document.

Parameters:wsdl – The wsdl
parse_binding(doc: lxml.etree._Element) → Dict[str, Type[zeep.wsdl.definitions.Binding]]

Parse the binding elements and return a dict of bindings.

Currently supported bindings are Soap 1.1, Soap 1.2., HTTP Get and HTTP Post. The detection of the type of bindings is done by the bindings themselves using the introspection of the xml nodes.

Definition:

<wsdl:definitions .... >
    <wsdl:binding name="nmtoken" type="qname"> *
        <-- extensibility element (1) --> *
        <wsdl:operation name="nmtoken"> *
           <-- extensibility element (2) --> *
           <wsdl:input name="nmtoken"? > ?
               <-- extensibility element (3) -->
           </wsdl:input>
           <wsdl:output name="nmtoken"? > ?
               <-- extensibility element (4) --> *
           </wsdl:output>
           <wsdl:fault name="nmtoken"> *
               <-- extensibility element (5) --> *
           </wsdl:fault>
        </wsdl:operation>
    </wsdl:binding>
</wsdl:definitions>
Parameters:doc (lxml.etree._Element) – The source document
Returns:Dictionary with binding name as key and Binding instance as value
Return type:dict
parse_imports(doc)

Import other WSDL definitions in this document.

Note that imports are non-transitive, so only import definitions which are defined in the imported document and ignore definitions imported in that document.

This should handle recursive imports though:

A -> B -> A A -> B -> C -> A
Parameters:doc (lxml.etree._Element) – The source document
parse_messages(doc: lxml.etree._Element)

Definition:

<definitions .... >
    <message name="nmtoken"> *
        <part name="nmtoken" element="qname"? type="qname"?/> *
    </message>
</definitions>
Parameters:doc (lxml.etree._Element) – The source document
parse_ports(doc: lxml.etree._Element) → Dict[str, zeep.wsdl.definitions.PortType]

Return dict with PortType instances as values

Definition:

<wsdl:definitions .... >
    <wsdl:portType name="nmtoken">
        <wsdl:operation name="nmtoken" .... /> *
    </wsdl:portType>
</wsdl:definitions>
Parameters:doc (lxml.etree._Element) – The source document
parse_service(doc: lxml.etree._Element) → Dict[str, zeep.wsdl.definitions.Service]

Definition:

<wsdl:definitions .... >
    <wsdl:service .... > *
        <wsdl:port name="nmtoken" binding="qname"> *
           <-- extensibility element (1) -->
        </wsdl:port>
    </wsdl:service>
</wsdl:definitions>
Parameters:doc (lxml.etree._Element) – The source document
parse_types(doc)

Return an xsd.Schema() instance for the given wsdl:types element.

If the wsdl:types contain multiple schema definitions then a new wrapping xsd.Schema is defined with xsd:import statements linking them together.

If the wsdl:types doesn’t container an xml schema then an empty schema is returned instead.

Definition:

<definitions .... >
    <types>
        <xsd:schema .... />*
    </types>
</definitions>
Parameters:doc (lxml.etree._Element) – The source document
resolve_imports() → None

Resolve all root elements (types, messages, etc).

class zeep.wsdl.wsdl.Document(location, transport: Type[Transport], base=None, settings=None)

A WSDL Document exists out of one or more definitions.

There is always one ‘root’ definition which should be passed as the location to the Document. This definition can import other definitions. These imports are non-transitive, only the definitions defined in the imported document are available in the parent definition. This Document is mostly just a simple interface to the root definition.

After all definitions are loaded the definitions are resolved. This resolves references which were not yet available during the initial parsing phase.

Parameters:
  • location (string) – Location of this WSDL
  • transport (zeep.transports.Transport) – The transport object to be used
  • base (str) – The base location of this document
  • strict (bool) – Indicates if strict mode is enabled

zeep.wsdl.definitions

A WSDL document exists out of a number of definitions. There are 6 major definitions, these are:

  • types
  • message
  • portType
  • binding
  • port
  • service

This module defines the definitions which occur within a WSDL document,

class zeep.wsdl.definitions.AbstractMessage(name)

Messages consist of one or more logical parts.

Each part is associated with a type from some type system using a message-typing attribute. The set of message-typing attributes is extensible. WSDL defines several such message-typing attributes for use with XSD:

  • element: Refers to an XSD element using a QName.
  • type: Refers to an XSD simpleType or complexType using a QName.
class zeep.wsdl.definitions.AbstractOperation(name, input_message=None, output_message=None, fault_messages=None, parameter_order=None, wsa_action=None)

Abstract operations are defined in the wsdl’s portType elements.

class zeep.wsdl.definitions.Binding(wsdl, name, port_name)

Base class for the various bindings (SoapBinding / HttpBinding)

class zeep.wsdl.definitions.MessagePart(element, type)
element

Alias for field number 0

type

Alias for field number 1

class zeep.wsdl.definitions.Operation(name, binding)

Concrete operation

Contains references to the concrete messages

classmethod parse(wsdl, xmlelement, binding)

Definition:

<wsdl:operation name="nmtoken"> *
   <-- extensibility element (2) --> *
   <wsdl:input name="nmtoken"? > ?
       <-- extensibility element (3) -->
   </wsdl:input>
   <wsdl:output name="nmtoken"? > ?
       <-- extensibility element (4) --> *
   </wsdl:output>
   <wsdl:fault name="nmtoken"> *
       <-- extensibility element (5) --> *
   </wsdl:fault>
</wsdl:operation>
class zeep.wsdl.definitions.Port(name, binding_name, xmlelement)

Specifies an address for a binding, thus defining a single communication endpoint.

class zeep.wsdl.definitions.Service(name)

Used to aggregate a set of related ports.

zeep.wsdl.parse

zeep.wsdl.parse.parse_abstract_message(wsdl: Definition, xmlelement: lxml.etree._Element) → zeep.wsdl.definitions.AbstractMessage

Create an AbstractMessage object from a xml element.

Definition:

<definitions .... >
    <message name="nmtoken"> *
        <part name="nmtoken" element="qname"? type="qname"?/> *
    </message>
</definitions>
Parameters:
  • wsdl – The parent definition instance
  • xmlelement – The XML node
zeep.wsdl.parse.parse_abstract_operation(wsdl: Definition, xmlelement: lxml.etree._Element) → Optional[zeep.wsdl.definitions.AbstractOperation]

Create an AbstractOperation object from a xml element.

This is called from the parse_port_type function since the abstract operations are part of the port type element.

Definition:

<wsdl:operation name="nmtoken">*
   <wsdl:documentation .... /> ?
   <wsdl:input name="nmtoken"? message="qname">?
       <wsdl:documentation .... /> ?
   </wsdl:input>
   <wsdl:output name="nmtoken"? message="qname">?
       <wsdl:documentation .... /> ?
   </wsdl:output>
   <wsdl:fault name="nmtoken" message="qname"> *
       <wsdl:documentation .... /> ?
   </wsdl:fault>
</wsdl:operation>
Parameters:
  • wsdl – The parent definition instance
  • xmlelement – The XML node
zeep.wsdl.parse.parse_port(wsdl: Definition, xmlelement: lxml.etree._Element) → zeep.wsdl.definitions.Port

Create a Port object from a xml element.

This is called via the parse_service function since ports are part of the service xml elements.

Definition:

<wsdl:port name="nmtoken" binding="qname"> *
   <wsdl:documentation .... /> ?
   <-- extensibility element -->
</wsdl:port>
Parameters:
  • wsdl – The parent definition instance
  • xmlelement – The XML node
zeep.wsdl.parse.parse_port_type(wsdl: Definition, xmlelement: lxml.etree._Element) → zeep.wsdl.definitions.PortType

Create a PortType object from a xml element.

Definition:

<wsdl:definitions .... >
    <wsdl:portType name="nmtoken">
        <wsdl:operation name="nmtoken" .... /> *
    </wsdl:portType>
</wsdl:definitions>
Parameters:
  • wsdl – The parent definition instance
  • xmlelement – The XML node
zeep.wsdl.parse.parse_service(wsdl: Definition, xmlelement: lxml.etree._Element) → zeep.wsdl.definitions.Service

Definition:

<wsdl:service name="nmtoken"> *
    <wsdl:documentation .... />?
    <wsdl:port name="nmtoken" binding="qname"> *
       <wsdl:documentation .... /> ?
       <-- extensibility element -->
    </wsdl:port>
    <-- extensibility element -->
</wsdl:service>

Example:

<service name="StockQuoteService">
  <documentation>My first service</documentation>
  <port name="StockQuotePort" binding="tns:StockQuoteBinding">
    <soap:address location="http://example.com/stockquote"/>
  </port>
</service>
Parameters:
  • wsdl – The parent definition instance
  • xmlelement – The XML node

Basic implementation to support SOAP-Attachments

See https://www.w3.org/TR/SOAP-attachments

class zeep.wsdl.bindings.http.HttpBinding(wsdl, name, port_name)
class zeep.wsdl.bindings.http.HttpGetBinding(wsdl, name, port_name)
classmethod match(node)

Check if this binding instance should be used to parse the given node.

Parameters:node (lxml.etree._Element) – The node to match against
send(client, options, operation, args, kwargs)

Called from the service

class zeep.wsdl.bindings.http.HttpOperation(name, binding, location)
classmethod parse(definitions, xmlelement, binding)
<wsdl:operation name=”GetLastTradePrice”>

<http:operation location=”GetLastTradePrice”/> <wsdl:input>

<mime:content type=”application/x-www-form-urlencoded”/>

</wsdl:input> <wsdl:output>

<mime:mimeXml/>

</wsdl:output>

</wsdl:operation>

class zeep.wsdl.bindings.http.HttpPostBinding(wsdl, name, port_name)
classmethod match(node)

Check if this binding instance should be used to parse the given node.

Parameters:node (lxml.etree._Element) – The node to match against
send(client, options, operation, args, kwargs)

Called from the service

class zeep.wsdl.bindings.soap.Soap11Binding(wsdl, name, port_name, transport, default_style)
class zeep.wsdl.bindings.soap.Soap12Binding(wsdl, name, port_name, transport, default_style)
class zeep.wsdl.bindings.soap.SoapBinding(wsdl, name, port_name, transport, default_style)

Soap 1.1/1.2 binding

classmethod match(node)

Check if this binding instance should be used to parse the given node.

Parameters:node (lxml.etree._Element) – The node to match against
classmethod parse(definitions, xmlelement)

Definition:

<wsdl:binding name="nmtoken" type="qname"> *
    <-- extensibility element (1) --> *
    <wsdl:operation name="nmtoken"> *
       <-- extensibility element (2) --> *
       <wsdl:input name="nmtoken"? > ?
           <-- extensibility element (3) -->
       </wsdl:input>
       <wsdl:output name="nmtoken"? > ?
           <-- extensibility element (4) --> *
       </wsdl:output>
       <wsdl:fault name="nmtoken"> *
           <-- extensibility element (5) --> *
       </wsdl:fault>
    </wsdl:operation>
</wsdl:binding>
process_reply(client, operation, response)

Process the XML reply from the server.

Parameters:
  • client (zeep.client.Client) – The client with which the operation was called
  • operation (zeep.wsdl.definitions.Operation) – The operation object from which this is a reply
  • response (requests.Response) – The response object returned by the remote server
send(client, options, operation, args, kwargs)

Called from the service

Parameters:
  • client (zeep.client.Client) – The client with which the operation was called
  • options (dict) – The binding options
  • operation (zeep.wsdl.definitions.Operation) – The operation object from which this is a reply
  • args (tuple) – The args to pass to the operation
  • kwargs (dict) – The kwargs to pass to the operation
send_async(client, options, operation, args, kwargs)

Called from the async service

Parameters:
  • client (zeep.client.Client) – The client with which the operation was called
  • options (dict) – The binding options
  • operation (zeep.wsdl.definitions.Operation) – The operation object from which this is a reply
  • args (tuple) – The args to pass to the operation
  • kwargs (dict) – The kwargs to pass to the operation
class zeep.wsdl.bindings.soap.SoapOperation(name, binding, nsmap, soapaction, style)

Represent’s an operation within a specific binding.

classmethod parse(definitions, xmlelement, binding, nsmap)

Definition:

<wsdl:operation name="nmtoken"> *
    <soap:operation soapAction="uri"? style="rpc|document"?>?
    <wsdl:input name="nmtoken"? > ?
        <soap:body use="literal"/>
   </wsdl:input>
   <wsdl:output name="nmtoken"? > ?
        <-- extensibility element (4) --> *
   </wsdl:output>
   <wsdl:fault name="nmtoken"> *
        <-- extensibility element (5) --> *
   </wsdl:fault>
</wsdl:operation>

Example:

<wsdl:operation name="GetLastTradePrice">
  <soap:operation soapAction="http://example.com/GetLastTradePrice"/>
  <wsdl:input>
    <soap:body use="literal"/>
  </wsdl:input>
  <wsdl:output>
  </wsdl:output>
  <wsdl:fault name="dataFault">
    <soap:fault name="dataFault" use="literal"/>
  </wsdl:fault>
</operation>

zeep.wsdl.messages

The messages are responsible for serializing and deserializing

Inheritance diagram of zeep.wsdl.messages.soap.DocumentMessage, zeep.wsdl.messages.soap.RpcMessage, zeep.wsdl.messages.http.UrlEncoded, zeep.wsdl.messages.http.UrlReplacement, zeep.wsdl.messages.mime.MimeContent, zeep.wsdl.messages.mime.MimeXML, zeep.wsdl.messages.mime.MimeMultipart

zeep.wsdl.messages.base

class zeep.wsdl.messages.base.ConcreteMessage(wsdl, name, operation)

Represents the wsdl:binding -> wsdl:operation -> input/output node

class zeep.wsdl.messages.base.SerializedMessage(path, headers, content)
content

Alias for field number 2

headers

Alias for field number 1

path

Alias for field number 0

zeep.wsdl.messages.http

class zeep.wsdl.messages.http.UrlEncoded(wsdl, name, operation)

The urlEncoded element indicates that all the message parts are encoded into the HTTP request URI using the standard URI-encoding rules (name1=value&name2=value…).

The names of the parameters correspond to the names of the message parts. Each value contributed by the part is encoded using a name=value pair. This may be used with GET to specify URL encoding, or with POST to specify a FORM-POST. For GET, the “?” character is automatically appended as necessary.

class zeep.wsdl.messages.http.UrlReplacement(wsdl, name, operation)

The http:urlReplacement element indicates that all the message parts are encoded into the HTTP request URI using a replacement algorithm.

  • The relative URI value of http:operation is searched for a set of search patterns.
  • The search occurs before the value of the http:operation is combined with the value of the location attribute from http:address.
  • There is one search pattern for each message part. The search pattern string is the name of the message part surrounded with parenthesis “(” and “)”.
  • For each match, the value of the corresponding message part is substituted for the match at the location of the match.
  • Matches are performed before any values are replaced (replaced values do not trigger additional matches).

Message parts MUST NOT have repeating values. <http:urlReplacement/>

zeep.wsdl.messages.mime

class zeep.wsdl.messages.mime.MimeContent(wsdl, name, operation, content_type, part_name)

WSDL includes a way to bind abstract types to concrete messages in some MIME format.

Bindings for the following MIME types are defined:

  • multipart/related
  • text/xml
  • application/x-www-form-urlencoded
  • Others (by specifying the MIME type string)

The set of defined MIME types is both large and evolving, so it is not a goal for WSDL to exhaustively define XML grammar for each MIME type.

Parameters:
class zeep.wsdl.messages.mime.MimeXML(wsdl, name, operation, part_name)

To specify XML payloads that are not SOAP compliant (do not have a SOAP Envelope), but do have a particular schema, the mime:mimeXml element may be used to specify that concrete schema.

The part attribute refers to a message part defining the concrete schema of the root XML element. The part attribute MAY be omitted if the message has only a single part. The part references a concrete schema using the element attribute for simple parts or type attribute for composite parts

Parameters:
class zeep.wsdl.messages.mime.MimeMultipart(wsdl, name, operation, part_name)

The multipart/related MIME type aggregates an arbitrary set of MIME formatted parts into one message using the MIME type “multipart/related”.

The mime:multipartRelated element describes the concrete format of such a message:

<mime:multipartRelated>
    <mime:part> *
        <-- mime element -->
    </mime:part>
</mime:multipartRelated>

The mime:part element describes each part of a multipart/related message. MIME elements appear within mime:part to specify the concrete MIME type for the part. If more than one MIME element appears inside a mime:part, they are alternatives.

Parameters:

zeep.wsdl.messages.soap

class zeep.wsdl.messages.soap.DocumentMessage(*args, **kwargs)

In the document message there are no additional wrappers, and the message parts appear directly under the SOAP Body element.

Inheritance diagram of zeep.wsdl.messages.soap.DocumentMessage
Parameters:
deserialize(envelope)

Deserialize the SOAP:Envelope and return a CompoundValue with the result.

classmethod parse(definitions, xmlelement, operation, type, nsmap)

Parse a wsdl:binding/wsdl:operation/wsdl:operation for the SOAP implementation.

Each wsdl:operation can contain three child nodes:
  • input
  • output
  • fault

Definition for input/output:

<input>
  <soap:body parts="nmtokens"? use="literal|encoded"
             encodingStyle="uri-list"? namespace="uri"?>

  <soap:header message="qname" part="nmtoken" use="literal|encoded"
               encodingStyle="uri-list"? namespace="uri"?>*
    <soap:headerfault message="qname" part="nmtoken"
                      use="literal|encoded"
                      encodingStyle="uri-list"? namespace="uri"?/>*
  </soap:header>
</input>

And the definition for fault:

<soap:fault name="nmtoken" use="literal|encoded"
            encodingStyle="uri-list"? namespace="uri"?>
resolve(definitions, abstract_message)

Resolve the data in the self._resolve_info dict (set via parse())

This creates three xsd.Element objects:

  • self.header
  • self.body
  • self.envelope (combination of headers and body)

XXX headerfaults are not implemented yet.

serialize(*args, **kwargs)

Create a SerializedMessage for this message

class zeep.wsdl.messages.soap.RpcMessage(wsdl, name, operation, type, nsmap)

In RPC messages each part is a parameter or a return value and appears inside a wrapper element within the body.

The wrapper element is named identically to the operation name and its namespace is the value of the namespace attribute. Each message part (parameter) appears under the wrapper, represented by an accessor named identically to the corresponding parameter of the call. Parts are arranged in the same order as the parameters of the call.

Inheritance diagram of zeep.wsdl.messages.soap.DocumentMessage
Parameters:
deserialize(envelope)

Deserialize the SOAP:Envelope and return a CompoundValue with the result.

classmethod parse(definitions, xmlelement, operation, type, nsmap)

Parse a wsdl:binding/wsdl:operation/wsdl:operation for the SOAP implementation.

Each wsdl:operation can contain three child nodes:
  • input
  • output
  • fault

Definition for input/output:

<input>
  <soap:body parts="nmtokens"? use="literal|encoded"
             encodingStyle="uri-list"? namespace="uri"?>

  <soap:header message="qname" part="nmtoken" use="literal|encoded"
               encodingStyle="uri-list"? namespace="uri"?>*
    <soap:headerfault message="qname" part="nmtoken"
                      use="literal|encoded"
                      encodingStyle="uri-list"? namespace="uri"?/>*
  </soap:header>
</input>

And the definition for fault:

<soap:fault name="nmtoken" use="literal|encoded"
            encodingStyle="uri-list"? namespace="uri"?>
resolve(definitions, abstract_message)

Resolve the data in the self._resolve_info dict (set via parse())

This creates three xsd.Element objects:

  • self.header
  • self.body
  • self.envelope (combination of headers and body)

XXX headerfaults are not implemented yet.

serialize(*args, **kwargs)

Create a SerializedMessage for this message

zeep.wsdl.utils

zeep.xsd

class zeep.xsd.schema.Schema(node=None, transport=None, location=None, settings=None)

A schema is a collection of schema documents.

create_new_document(node, url, base_url=None, target_namespace=None)
Return type:zeep.xsd.schema.SchemaDocument
elements

Yield all globla xsd.Type objects

Return type:Iterable of zeep.xsd.Element
get_attribute(qname) → zeep.xsd.elements.attribute.Attribute

Return a global xsd.attribute object with the given qname

get_attribute_group(qname) → zeep.xsd.elements.attribute.AttributeGroup

Return a global xsd.attributeGroup object with the given qname

get_element(qname) → zeep.xsd.elements.element.Element

Return a global xsd.Element object with the given qname

get_group(qname) → zeep.xsd.elements.indicators.Group

Return a global xsd.Group object with the given qname.

get_type(qname, fail_silently=False)

Return a global xsd.Type object with the given qname

Return type:zeep.xsd.ComplexType or zeep.xsd.AnySimpleType
is_empty

Boolean to indicate if this schema contains any types or elements

merge(schema)

Merge an other XSD schema in this one

types

Yield all global xsd.Type objects

Return type:Iterable of zeep.xsd.ComplexType
class zeep.xsd.schema.SchemaDocument(namespace, location, base_url)

A Schema Document consists of a set of schema components for a specific target namespace.

This represents an xsd:Schema object

get_attribute(qname) → zeep.xsd.elements.attribute.Attribute

Return a xsd.Attribute object from this schema

get_attribute_group(qname) → zeep.xsd.elements.attribute.AttributeGroup

Return a xsd.AttributeGroup object from this schema

get_element(qname) → zeep.xsd.elements.element.Element

Return a xsd.Element object from this schema

get_group(qname) → zeep.xsd.elements.indicators.Group

Return a xsd.Group object from this schema

get_type(qname: lxml.etree.QName)

Return a xsd.Type object from this schema

Return type:zeep.xsd.ComplexType or zeep.xsd.AnySimpleType
load(schema, node)

Load the XML Schema passed in via the node attribute.

register_attribute(qname: str, value: zeep.xsd.elements.attribute.Attribute)

Register a xsd:Attribute in this schema

register_attribute_group(qname: lxml.etree.QName, value: zeep.xsd.elements.attribute.AttributeGroup) → None

Register a xsd:AttributeGroup in this schema

register_element(qname: lxml.etree.QName, value: zeep.xsd.elements.element.Element)

Register a xsd.Element in this schema

register_group(qname: lxml.etree.QName, value: zeep.xsd.elements.indicators.Group)

Register a xsd:Group in this schema

register_import(namespace, schema)

Register an import for an other schema document.

register_type(qname: lxml.etree.QName, value: zeep.xsd.types.base.Type)

Register a xsd.Type in this schema

zeep.xsd.utils.create_prefixed_name(qname, schema)

Convert a QName to a xsd:name (‘ns1:myType’).

Return type:str
class zeep.xsd.valueobjects.AnyObject(xsd_object, value)

Create an any object

Parameters:
  • xsd_object – the xsd type
  • value – The value
class zeep.xsd.valueobjects.CompoundValue(*args, **kwargs)

Represents a data object for a specific xsd:complexType.

class zeep.xsd.visitor.SchemaVisitor(schema, document)

Visitor which processes XSD files and registers global elements and types in the given schema.

Notes:

TODO: include and import statements can reference other nodes. We need to load these first. Always global.

Parameters:
visit_all(node, parent)

Allows the elements in the group to appear (or not appear) in any order in the containing element.

Definition:

<all
  id = ID
  maxOccurs= 1: 1
  minOccurs= (0 | 1): 1
  {any attributes with non-schema Namespace...}>
Content: (annotation?, element*)
</all>
Parameters:
  • node (lxml.etree._Element) – The XML node
  • parent (lxml.etree._Element) – The parent XML node
visit_annotation(node, parent)

Defines an annotation.

Definition:

<annotation
  id = ID
  {any attributes with non-schema Namespace}...>
Content: (appinfo | documentation)*
</annotation>
Parameters:
  • node (lxml.etree._Element) – The XML node
  • parent (lxml.etree._Element) – The parent XML node
visit_any(node, parent)

Definition:

<any
  id = ID
  maxOccurs = (nonNegativeInteger | unbounded) : 1
  minOccurs = nonNegativeInteger : 1
  namespace = "(##any | ##other) |
    List of (anyURI | (##targetNamespace |  ##local))) : ##any
  processContents = (lax | skip | strict) : strict
  {any attributes with non-schema Namespace...}>
Content: (annotation?)
</any>
Parameters:
  • node (lxml.etree._Element) – The XML node
  • parent (lxml.etree._Element) – The parent XML node
visit_any_attribute(node, parent)

Definition:

<anyAttribute
  id = ID
  namespace = ((##any | ##other) |
    List of (anyURI | (##targetNamespace | ##local))) : ##any
  processContents = (lax | skip | strict): strict
  {any attributes with non-schema Namespace...}>
Content: (annotation?)
</anyAttribute>
Parameters:
  • node (lxml.etree._Element) – The XML node
  • parent (lxml.etree._Element) – The parent XML node
visit_attribute(node: lxml.etree._Element, parent: lxml.etree._Element) → Union[zeep.xsd.elements.attribute.Attribute, zeep.xsd.elements.references.RefAttribute]

Declares an attribute.

Definition:

<attribute
  default = string
  fixed = string
  form = (qualified | unqualified)
  id = ID
  name = NCName
  ref = QName
  type = QName
  use = (optional | prohibited | required): optional
  {any attributes with non-schema Namespace...}>
Content: (annotation?, (simpleType?))
</attribute>
Parameters:
  • node (lxml.etree._Element) – The XML node
  • parent (lxml.etree._Element) – The parent XML node
visit_attribute_group(node, parent)

Definition:

<attributeGroup
  id = ID
  name = NCName
  ref = QName
  {any attributes with non-schema Namespace...}>
Content: (annotation?),
         ((attribute | attributeGroup)*, anyAttribute?))
</attributeGroup>
Parameters:
  • node (lxml.etree._Element) – The XML node
  • parent (lxml.etree._Element) – The parent XML node
visit_choice(node, parent)

Definition:

<choice
  id = ID
  maxOccurs= (nonNegativeInteger | unbounded) : 1
  minOccurs= nonNegativeInteger : 1
  {any attributes with non-schema Namespace}...>
Content: (annotation?, (element | group | choice | sequence | any)*)
</choice>
visit_complex_content(node, parent)

The complexContent element defines extensions or restrictions on a complex type that contains mixed content or elements only.

Definition:

<complexContent
  id = ID
  mixed = Boolean
  {any attributes with non-schema Namespace}...>
Content: (annotation?,  (restriction | extension))
</complexContent>
Parameters:
  • node (lxml.etree._Element) – The XML node
  • parent (lxml.etree._Element) – The parent XML node
visit_complex_type(node, parent)

Definition:

<complexType
  abstract = Boolean : false
  block = (#all | List of (extension | restriction))
  final = (#all | List of (extension | restriction))
  id = ID
  mixed = Boolean : false
  name = NCName
  {any attributes with non-schema Namespace...}>
Content: (annotation?, (simpleContent | complexContent |
          ((group | all | choice | sequence)?,
          ((attribute | attributeGroup)*, anyAttribute?))))
</complexType>
Parameters:
  • node (lxml.etree._Element) – The XML node
  • parent (lxml.etree._Element) – The parent XML node
visit_element(node, parent)

Definition:

<element
  abstract = Boolean : false
  block = (#all | List of (extension | restriction | substitution))
  default = string
  final = (#all | List of (extension | restriction))
  fixed = string
  form = (qualified | unqualified)
  id = ID
  maxOccurs = (nonNegativeInteger | unbounded) : 1
  minOccurs = nonNegativeInteger : 1
  name = NCName
  nillable = Boolean : false
  ref = QName
  substitutionGroup = QName
  type = QName
  {any attributes with non-schema Namespace}...>
Content: (annotation?, (
          (simpleType | complexType)?, (unique | key | keyref)*))
</element>
Parameters:
  • node (lxml.etree._Element) – The XML node
  • parent (lxml.etree._Element) – The parent XML node
visit_extension_complex_content(node, parent)

Definition:

<extension
  base = QName
  id = ID
  {any attributes with non-schema Namespace}...>
Content: (annotation?, (
            (group | all | choice | sequence)?,
            ((attribute | attributeGroup)*, anyAttribute?)))
</extension>
Parameters:
  • node (lxml.etree._Element) – The XML node
  • parent (lxml.etree._Element) – The parent XML node
visit_extension_simple_content(node, parent)

Definition:

<extension
  base = QName
  id = ID
  {any attributes with non-schema Namespace}...>
Content: (annotation?, ((attribute | attributeGroup)*, anyAttribute?))
</extension>
visit_group(node, parent)

Groups a set of element declarations so that they can be incorporated as a group into complex type definitions.

Definition:

<group
  name= NCName
  id = ID
  maxOccurs = (nonNegativeInteger | unbounded) : 1
  minOccurs = nonNegativeInteger : 1
  name = NCName
  ref = QName
  {any attributes with non-schema Namespace}...>
Content: (annotation?, (all | choice | sequence))
</group>
Parameters:
  • node (lxml.etree._Element) – The XML node
  • parent (lxml.etree._Element) – The parent XML node
visit_import(node, parent)

Definition:

<import
  id = ID
  namespace = anyURI
  schemaLocation = anyURI
  {any attributes with non-schema Namespace}...>
Content: (annotation?)
</import>
Parameters:
  • node (lxml.etree._Element) – The XML node
  • parent (lxml.etree._Element) – The parent XML node
visit_include(node, parent)

Definition:

<include
  id = ID
  schemaLocation = anyURI
  {any attributes with non-schema Namespace}...>
Content: (annotation?)
</include>
Parameters:
  • node (lxml.etree._Element) – The XML node
  • parent (lxml.etree._Element) – The parent XML node
visit_list(node, parent)

Definition:

<list
  id = ID
  itemType = QName
  {any attributes with non-schema Namespace}...>
Content: (annotation?, (simpleType?))
</list>

The use of the simpleType element child and the itemType attribute is mutually exclusive.

Parameters:
  • node (lxml.etree._Element) – The XML node
  • parent (lxml.etree._Element) – The parent XML node
visit_notation(node, parent)

Contains the definition of a notation to describe the format of non-XML data within an XML document. An XML Schema notation declaration is a reconstruction of XML 1.0 NOTATION declarations.

Definition:

<notation
  id = ID
  name = NCName
  public = Public identifier per ISO 8879
  system = anyURI
  {any attributes with non-schema Namespace}...>
Content: (annotation?)
</notation>
Parameters:
  • node (lxml.etree._Element) – The XML node
  • parent (lxml.etree._Element) – The parent XML node
visit_restriction_complex_content(node, parent)

Definition:

<restriction
  base = QName
  id = ID
  {any attributes with non-schema Namespace}...>
Content: (annotation?, (group | all | choice | sequence)?,
        ((attribute | attributeGroup)*, anyAttribute?))
</restriction>
Parameters:
  • node (lxml.etree._Element) – The XML node
  • parent (lxml.etree._Element) – The parent XML node
visit_restriction_simple_content(node, parent)

Definition:

<restriction
  base = QName
  id = ID
  {any attributes with non-schema Namespace}...>
Content: (annotation?,
    (simpleType?, (
        minExclusive | minInclusive | maxExclusive | maxInclusive |
        totalDigits |fractionDigits | length | minLength |
        maxLength | enumeration | whiteSpace | pattern)*
    )?, ((attribute | attributeGroup)*, anyAttribute?))
</restriction>
Parameters:
  • node (lxml.etree._Element) – The XML node
  • parent (lxml.etree._Element) – The parent XML node
visit_restriction_simple_type(node, parent)

Definition:

<restriction
  base = QName
  id = ID
  {any attributes with non-schema Namespace}...>
Content: (annotation?,
    (simpleType?, (
        minExclusive | minInclusive | maxExclusive | maxInclusive |
        totalDigits |fractionDigits | length | minLength |
        maxLength | enumeration | whiteSpace | pattern)*))
</restriction>
Parameters:
  • node (lxml.etree._Element) – The XML node
  • parent (lxml.etree._Element) – The parent XML node
visit_schema(node)

Visit the xsd:schema element and process all the child elements

Definition:

<schema
  attributeFormDefault = (qualified | unqualified): unqualified
  blockDefault = (#all | List of (extension | restriction | substitution) : ''
  elementFormDefault = (qualified | unqualified): unqualified
  finalDefault = (#all | List of (extension | restriction | list | union): ''
  id = ID
  targetNamespace = anyURI
  version = token
  xml:lang = language
  {any attributes with non-schema Namespace}...>
Content: (
    (include | import | redefine | annotation)*,
    (((simpleType | complexType | group | attributeGroup) |
      element | attribute | notation),
     annotation*)*)
</schema>
Parameters:node (lxml.etree._Element) – The XML node
visit_sequence(node, parent)

Definition:

<sequence
  id = ID
  maxOccurs = (nonNegativeInteger | unbounded) : 1
  minOccurs = nonNegativeInteger : 1
  {any attributes with non-schema Namespace}...>
Content: (annotation?,
          (element | group | choice | sequence | any)*)
</sequence>
Parameters:
  • node (lxml.etree._Element) – The XML node
  • parent (lxml.etree._Element) – The parent XML node
visit_simple_content(node, parent)

Contains extensions or restrictions on a complexType element with character data or a simpleType element as content and contains no elements.

Definition:

<simpleContent
  id = ID
  {any attributes with non-schema Namespace}...>
Content: (annotation?, (restriction | extension))
</simpleContent>
Parameters:
  • node (lxml.etree._Element) – The XML node
  • parent (lxml.etree._Element) – The parent XML node
visit_simple_type(node, parent)

Definition:

<simpleType
  final = (#all | (list | union | restriction))
  id = ID
  name = NCName
  {any attributes with non-schema Namespace}...>
Content: (annotation?, (restriction | list | union))
</simpleType>
Parameters:
  • node (lxml.etree._Element) – The XML node
  • parent (lxml.etree._Element) – The parent XML node
visit_union(node, parent)

Defines a collection of multiple simpleType definitions.

Definition:

<union
  id = ID
  memberTypes = List of QNames
  {any attributes with non-schema Namespace}...>
Content: (annotation?, (simpleType*))
</union>
Parameters:
  • node (lxml.etree._Element) – The XML node
  • parent (lxml.etree._Element) – The parent XML node
visit_unique(node, parent)

Specifies that an attribute or element value (or a combination of attribute or element values) must be unique within the specified scope. The value must be unique or nil.

Definition:

<unique
  id = ID
  name = NCName
  {any attributes with non-schema Namespace}...>
Content: (annotation?, (selector, field+))
</unique>
Parameters:
  • node (lxml.etree._Element) – The XML node
  • parent (lxml.etree._Element) – The parent XML node

Changelog

Changelog

4.2.1 (2022-11-10)

  • Fix error regarding closing session in async transport (#1347)

4.2.0 (2022-11-03)

  • Drop support for Python 3.6
  • Allow embedding CDATA elements in simple types (#1339)
  • Allow to pass in a pre parsed Document (#1330)
  • Fix httpx DeprecationWarning for post data (#1326)
  • Add BinaryMemorySignature (#1300)
  • Fix IndexError when empty body response (#1287)
  • Add support for context manager on Client (#1166)
  • Allow Ws Addressing plugin to use a different URL (#1328)
  • Accept strings for xsd base64Binary (#1072)

4.1.0 (2021-08-15)

  • Remove last dependency on six (#1250)
  • Use platformdirs instead of the appsdirs dependency (#1244)
  • Pass digest method when signing timestamp node(#1201)
  • Fix settings context manager when an exception is raised (#1193)
  • Don’t render decimals using scientific notation (#1191)
  • Remove dependency on defusedxml (deprecated) (#1179)
  • Improve handling of str values for Duration (#1165)

4.0.0 (2020-10-12)

  • Drop support for Python 2.7, 3.3, 3.4 and 3.5
  • Remove both the aiohttp and the tornado transport class from Zeep. These can be moved to their own Python package if anyone is interested.
  • Add zeep.transports.AsyncTransport which is based on httpx. Note that loading wsdl files is still a sync process but operations can be executed via async.
  • Start adding more typehints to the package

3.4.0 (2019-06-05)

  • Allow passing xsd.Nil to sequences (#959, smilingDima)
  • Add support for passing custom digest and signature methods during WSSE signing (#957, Florian Apolloner)
  • Fix path resolving during XSD imports (#962, adambogocz)

3.3.1 (2019-03-10)

  • Fix issue with empty xsd:import statements on Python 2.7 (#930)

3.3.0 (2019-03-08)

  • Extend the force_https flag to also force loading xsd files from https when a http url is encountered from a https domain
  • Fix handling recursive xsd imports when the url’s are enforced from http to https.
  • Fix reference attribute when using the Binary Security Token (#873, tpazderka)
  • Add support for the WSAM namespace (#890, David Adam)

3.2.0 (2018-12-17)

  • Fix abstract message check for NoneType before attempting to access parts
  • Improve support for ‘Chameleon’ XSD schemas (#879, #888)
  • Fix resolving qualified references (#879)
  • Fix issue with duplicate soap:body tags when multiple parts used (#879)
  • Fix Choice with unbound Any element (#871)
  • Add xsd_ignore_sequence_order flag (#880)
  • Add support for timestamp token in WSS headers (#817)
  • Accept strings for xsd.DateTime (#886)

3.1.0 (2018-07-28)

  • Fix SSL issue on with TornadoAsyncTransport (#792)
  • Fix passing strict keyword in XML loader (#787)
  • Update documentation

3.0.0 (2018-06-16)

This is a major release, and contains a number of backwards incompatible changes to the API.

  • Refactor the settings logic in Zeep. All settings are now configured using the zeep.settings.Settings() class.
  • Allow control of defusedxml settings via zeep.Settings (see #567, #391)
  • Add ability to set specific http headers for each call (#758)
  • Skip the xsd:annotation element in the all:element (#737)
  • Add Settings.force_https as option so that it can be disabled (#605)
  • Strip spaces from QName’s when parsing xsd’s (#719)
  • Fix DateTime parsing when only a date is returned (#672)
  • Fix handling of nested optional any elements (#556)
  • Check if part exists before trying to delete it (#659)

2.5.0 (2018-01-06)

  • Fix AnyType value rendering by guessing the xsd type for the value (#552)
  • Fix AnySimpleType.xmlvalue() not implemented exception (#644)
  • Add __dir__ method to value objects returned by Zeep
  • Don’t require content for 201 and 202 status codes (#613)
  • Fix wheel package by cleaning the build directory correctly (#634)
  • Handle Nil values on complexType with SimpleContent elements (#604)
  • Add Client.namespaces method to list all namespaces available
  • Improve support for auto-completion (#537)

2.4.0 (2017-08-26)

  • Add support for tornado async transport via gen.coroutine (#530, Kateryna Burda)
  • Check if soap:address is defined in the service port instead of raising an exception (#527)
  • Update packaging (stop using find_packages()) (#529)
  • Properly handle None values when rendering complex types (#526)
  • Fix generating signature for empty wsdl messages (#542)
  • Support passing strings to xsd:Time objects (#540)

2.3.0 (2017-08-06)

  • The XML send to the server is no longer using pretty_print=True (#484)
  • Refactor of the multiref support to fix issues with child elements (#489)
  • Add workaround to support negative durations (#486)
  • Fix creating XML documents for operations without aguments (#479)
  • Fix xsd:extension on xsd:group elements (#523)

2.2.0 (2017-06-19)

  • Automatically import the soap-encoding schema if it is required (#473)
  • Add support for XOP messages (this is a rewrite of #325 by vashek)

2.1.1 (2017-06-11)

  • Fix previous release, it contained an incorrect dependency (Mock 2.1.) due to bumpversion :-(

2.1.0 (2017-06-11)

  • Fix recursion error while creating the signature for a global element when it references itself (via ref attribute).
  • Update Client.create_message() to apply plugins and wsse (#465)
  • Fix handling unknown xsi types when parsing elements using xsd:anyType (#455)

2.0.0 (2017-05-22)

This is a major release, and contains a number of backwards incompatible changes to the API.

  • Default values of optional elements are not set by default anymore (#423)

  • Refactor the implementation of wsdl:arrayType too make the API more pythonic (backwards incompatible).

  • The call signature for Client.create_message() was changed. It now requires the service argument:

    Client.create_message(service, operation_name, *args, **kwargs)

  • Choice elements now only work with keyword arguments and raise an exception if positional arguments are passed (#439)

  • Implement initial multiref support for SOAP RPC (#326). This was done using really good real-world tests from vstoykov (thanks!)

  • Fix exception on empty SOAP response (#442)

  • Fix XSD default values for boolean types (Bartek Wójcicki, #386)

1.6.0 (2017-04-27)

  • Implement ValueObject.__json__ for json serialization (#258)
  • Improve handling of unexpected elements for soap:header (#378)
  • Accept unexpected elements in complexTypes when strict is False
  • Fix elementFormDefault/attributeFormDefault for xsd:includes (#426)

1.5.0 (2017-04-22)

  • Fix issue where values of indicators (sequence/choice/all) would write to the same internal dict. (#425)
  • Set default XML parse mode to strict as was intended (#332)
  • Add support for pickling value objects (#417)
  • Add explicit Nil value via zeep.xsd.Nil (#424)
  • Add xml_huge_tree kwarg to the Client() to enable lxml’s huge_tree mode, this is disabled by default (#332)
  • Add support to pass base-types to type extensions (#416)
  • Handle wsdl errors more gracefully by disabling the invalid operations instead of raising an exception (#407, #387)

1.4.1 (2017-04-01)

  • The previous release (1.4.0) contained an incorrect dependency due to bumpversion moving all 1.3.0 versions to 1.4.0. This fixes it.

1.4.0 (2017-04-01)

  • Hardcode the xml prefix to the xml namespace as defined in the specs (#367)
  • Fix parsing of unbound sequences within xsd choices (#380)
  • Use logger.debug() for debug related logging (#369)
  • Add the Client.raw_response option to let zeep return the raw transport response (requests.Response) instead of trying to parse it.
  • Handle minOccurs/maxOccurs properlhy for xsd:Group elements. This also fixes a bug in the xsd:Choice handling for multiple elements (#374, #410)
  • Fix raising XMLSyntaxError when loading invalid XML (Antanas Sinica, #396)

1.3.0 (2017-03-14)

  • Add support for nested xsd:choice elements (#370)
  • Fix unresolved elements for xsd:extension, this was a regression introduced in 1.2.0 (#377)

1.2.0 (2017-03-12)

  • Add flag to disable strict mode in the Client. This allows zeep to better work with non standard compliant SOAP Servers. See the documentation for usage and potential downsides.
  • Minor refactor of resolving of elements for improved performance
  • Support the SOAP 1.2 ‘http://www.w3.org/2003/05/soap/bindings/HTTP/’ transport uri (#355)
  • Fallback to matching wsdl lookups to matching when the target namespace is empty (#356)
  • Improve the handling of xsd:includes, the default namespace of the parent schema is now also used during resolving of the included schema. (#360)
  • Properly propagate the global flag for complex types when an xsd:restriction is used (#360)
  • Filter out duplicate types and elements when dump the wsdl schema (#360)
  • Add zeep.CachingClient() which enables the SqliteCache by default

1.1.0 (2017-02-18)

  • Fix an attribute error when an complexType used xsd:anyType as base restriction (#352)
  • Update asyncio transport to return requests.Response objects (#335)

1.0.0 (2017-01-31)

  • Use cgi.parse_header() to extract media_type for multipart/related checks (#327)
  • Don’t ignore nil elements, instead return None when parsing xml (#328)
  • Fix regression when using WSA with an older lxml version (#197)

0.27.0 (2017-01-28)

  • Add support for SOAP attachments (multipart responses). (Dave Wapstra, #302)
  • Update xsd:anyType to return the xml elements when no type is given via the xsi:type attribute (#284)
  • Fix parsing Any elements when a restriction is used (soap-enc:array) (#322)

0.26.0 (2017-01-26)

This release again introduces some backwords incompatibilties. The next release will hopefully be 1.0 which will introduce semver.

  • backwards-incompatible: The Transport class now accepts a requests.Session() object instead of http_auth and verify. This allows for more flexibility.
  • backwards-incompatible: Zeep no longer sets a default cache backend. Please see http://docs.python-zeep.org/en/master/transport.html#caching for information about how to configure a cache.
  • Add zeep.xsd.SkipValue which instructs the serialize to ignore the element.
  • Support duplicate target namespaces in the wsdl definition (#320)
  • Fix resolving element/types for xsd schema’s with duplicate tns (#319)

0.25.0 (2017-01-23)

  • Important: Add basic validation against the xsd. It currently will only validate the minOccurs/maxOccurs but this will be extended in the future.
  • Add support for duplicate namespace definitions. Previously imports for namespaces which were already imported were ignored. It will now search through all matching schemas with the tns to find a specific object (#204)
  • Fix xsd:extension for sequence -> choice. (#257)
  • Improve serializing attributes when the values were passed as a dict (#125)

0.24.0 (2016-12-16)

  • Don’t fail the parsing of responses if an xsi:type references an non-existing type. Instead log a message (#273)
  • Fix serializing etree.Element instances in the helpers.serialize function (#255)
  • Fix infinite loop during parsing of xsd.Sequence where max_occurs is unbounded (#256)
  • Make the xsd.Element name kwarg required
  • Improve handling of the xsd:anyType element when passed instances of complexType’s (#252)
  • Silently ignore unsupported binding transports instead of an hard error (#277)
  • Support microseconds for xsd.dateTime and xsd.Time (#280)
  • Don’t mutate passed values to the zeep operations (#280)

0.23.0 (2016-11-24)

0.22.1 (2016-11-22)

  • Fix reversed() error (jaceksnet) (#260)
  • Better error message when unexpected xml elements are encountered in sequences.

0.22.0 (2016-11-13)

  • Force the soap:address / http:address to HTTPS when the wsdl is loaded from a https url (#228)
  • Improvements to the xsd:union handling. The matching base class is now used for serializing/deserializing the values. If there is no matching base class then the raw value is returned. (#195)
  • Fix handling of xsd:any with maxOccurs > 1 in xsd:choice elements (#253)
  • Add workaround for schema’s importing the xsd from http://www.w3.org/XML/1998/namespace (#220)
  • Add new Client.type_factory(namespace) method which returns a factory to simplify creation of types.

0.21.0 (2016-11-02)

  • Don’t error on empty xml namespaces declarations in inline schema’s (#186)
  • Wrap importing of sqlite3 in try..except for Google App Engine (#243)
  • Don’t use pkg_resources to determine the zeep version, use __version__ instead (#243).
  • Fix SOAP arrays by wrapping children in the appropriate element (joeribekker, #236)
  • Add operation_timeout kwarg to the Transport class to set timeouts for operations. The default is still no timeout (#140)
  • Introduce client.options context manager to temporarily override various options (only timeout for now) (#140)
  • Wrap the parsing of xml values in a try..except block and log an error instead of throwing an exception (#137)
  • Fix xsd:choice xml rendering with nested choice/sequence structure (#221)
  • Correctly resolve header elements of which the message part defines the type instead of element. (#199)

0.20.0 (2016-10-24)

  • Major performance improvements / lower memory usage. Zeep now no longer copies data and alters it in place but instead uses a set to keep track of modified data.
  • Fix parsing empty soap response (#223)
  • Major refactor of the xsd:extension / xsd:restriction implementation.
  • Better support for xsd:anyType, by re-using the xsd.AnyObject (#229)
  • Deserialize SOAP response without message elements correctly (#237)

0.19.0 (2016-10-18)

  • backwards-incompatible: If the WSDL defines that the endpoint returns soap:header elements and/or multple soap:body messages then the return signature of the operation is changed. You can now explcitly access the body and header elements.
  • Fix parsing HTTP bindings when there are no message elements (#185)
  • Fix deserializing RPC responses (#219
  • Add support for SOAP 1.2 Fault subcodes (#210, vashek)
  • Don’t alter the _soapheaders elements during rendering, instead create a deepcopy first. (#188)
  • Add the SOAPAction to the Content-Type header in SOAP 1.2 bindings (#211)
  • Fix issue when mixing elements and any elements in a choice type (#192)
  • Improving parsing of results for union types (#192)
  • Make ws-addressing work with lxml < 3.5 (#209)
  • Fix recursion error when xsi:type=’anyType’ is given. (#198)

0.18.1 (2016-09-23)

  • PyPi release error

0.18.0 (2016-09-23)

  • Fix parsing Any elements by using the namespace map of the response node instead of the namespace map of the wsdl. (#184, #164)
  • Improve handling of nested choice elements (choice>sequence>choice)

0.17.0 (2016-09-12)

  • Add support for xsd:notation (#183)
  • Add improvements to resolving phase so that all objects are resolved.
  • Improve implementation of xsd.attributeGroup and xsd.UniqueType
  • Create a deepcopy of the args and kwargs passed to objects so that the original are unmodified.
  • Improve handling of wsdl:arrayType

0.16.0 (2016-09-06)

  • Fix error when rendering choice elements with have sequences as children, see #150
  • Re-use credentials passed to python -mzeep <wsdl> (#130)
  • Workaround invalid usage of qualified vs non-qualified element tags in the response handling (#176)
  • Fix regression when importing xsd:schema’s via wsdl:import statements (#179)

0.15.0 (2016-09-04)

  • All wsdl documents and xsd schemas are now globally available for eachother. While this is not correct according to the (messy) soap specifications, it does make zeep more compatible with all the invalid wsdl documents out there. (#159)
  • Implement support for attributeGroup (#160)
  • Add experimental support for ws-addressing (#92)
  • Fix handling of Mime messages with no parts (#168)
  • Workaround an issue where soap servers don’t qualify references (#170)
  • Correctly process attributes which are passed as a dictionary. (#125)
  • Add support for plugins, see documentation for examples.
  • Fix helpers.serialize_object for lists of objects (#123).
  • Add HistoryPlugin which ofers last_sent and last_received properties (#93).

0.14.0 (2016-08-03)

  • Global attributes are now always correctly handled as qualified. (#129)
  • Fix parsing xml data containing simpleContent types (#136).
  • Set xsi:nil attribute when serializing objects to xml (#141)
  • Fix rendering choice elements when the element is mixed with other elements in a sequence (#150)
  • Fix maximum recursion error for recursive xsd:include elements
  • Make wsdl:import statements transitive. (#149)
  • Merge xsd:schema’s which are spread around imported wsdl objects. (#146)
  • Don’t raise exception when no value is given for AnyAttribute (#152)

0.13.0 (2016-07-17)

  • Use warnings.warn() for duplicate target namespaces instead of raising an exception. This better matches with what lxml does.
  • backwards-incompatible: The persistent kwarg is removed from the SqliteCache.__init__() call. Use the new InMemoryCache() instead when you don’t want to persist data. This was required to make the SqliteCache backend thread-safe since we now open/close the db when writing/reading from it (with an additional lock).
  • Fix zeep.helpers.serialize_object() for nested objects (#123)
  • Remove fallback between soap 1.1 and soap 1.2 namespaces during the parsing of the wsdl. This should not be required.

0.12.0 (2016-07-09)

  • backwards-incompatible: Choice elements are now unwrapped if maxOccurs=1. This results in easier operation definitions when choices are used.
  • backwards-incompatible: The _soapheader kwarg is renamed to _soapheaders and now requires a nested dictionary with the header name as key or a list of values (value object or lxml.etree.Element object). Please see the call signature of the function using python -mzeep <wsdl>.
  • Support the element ref’s to xsd:schema elements.
  • Improve the signature() output of element and type definitions
  • Accept lxml.etree.Element objects as value for Any elements.
  • And various other fixes

0.11.0 (2016-07-03)

  • backwards-incompatible: The kwarg name for Any and Choice elements are renamed to generic _value_N names.
  • backwards-incompatible: Client.set_address() is replaced with the Client.create_service() call
  • Auto-load the http://schemas.xmlsoap.org/soap/encoding/ schema if it is referenced but not imported. Too many XSD’s assume that the schema is always available.
  • Major refactoring of the XSD handling to correctly support nested xsd:sequence elements.
  • Add logger.debug() calls around Transport.post() to allow capturing the content send/received from the server
  • Add proper support for default values on attributes and elements.

0.10.0 (2016-06-22)

  • Make global elements / types truly global by refactoring the Schema parsing. Previously the lookups where non-transitive, but this should only be the case during parsing of the xml schema.
  • Properly unwrap XML responses in soap.DocumentMessage when a choice is the root element. (#80)
  • Update exceptions structure, all zeep exceptions are now using zeep.exceptions.Error() as base class.

0.9.1 (2016-06-17)

  • Quote the SOAPAction header value (Derek Harland)
  • Undo fallback for SOAPAction if it is empty (#83)

0.9.0 (2016-06-14)

  • Use the appdirs module to retrieve the OS cache path. Note that this results in an other default cache path then previous releases! See https://github.com/ActiveState/appdirs for more information.
  • Fix regression when initializing soap objects with invalid kwargs.
  • Update wsse.UsernameToken to set encoding type on nonce (Antonio Cuni)
  • Remove assert statement in soap error handling (Eric Waller)
  • Add ‘–no-verify’ to the command line interface. (#63)
  • Correctly xsi:type attributes on unbounded elements. (nicholjy) (#68)
  • Re-implement xsd:list handling
  • Refactor logic to open files from filesystem.
  • Refactor the xsd:choice implementation (serializing/deserializing)
  • Implement parsing of xsd:any elements.

0.8.1 (2016-06-08)

  • Use the operation name for the xml element which wraps the parameters in for soap RPC messages (#60)

0.8.0 (2016-06-07)

  • Add ability to override the soap endpoint via Client.set_address()
  • Fix parsing ComplexTypes which have no child elements (#50)
  • Handle xsi:type attributes on anyType’s correctly when deserializing responses (#17)
  • Fix xsd:restriction on xsd:simpleType’s when the base type wasn’t defined yet. (#59)
  • Add xml declaration to the generate xml strings (#60)
  • Fix xsd:import statements without schemaLocation (#58)

0.7.1 (2016-06-01)

  • Fix regression with handling wsdl:import statements for messages (#47)

0.7.0 (2016-05-31)

  • Add support HTTP authentication (mcordes). This adds a new attribute to the Transport client() which passes the http_auth value to requests. (#31)
  • Fix issue where setting cache=None to Transport class didn’t disable caching.
  • Refactor handling of wsdl:imports, don’t merge definitions but instead lookup values in child definitions. (#40)
  • Remove unused namespace declarations from the generated SOAP messages.
  • Update requirement of six>=1.0.0 to six>=1.9.0 (#39)
  • Fix handling of xsd:choice, xsd:group and xsd:attribute (#30)
  • Improve error messages
  • Fix generating soap messages when sub types are used via xsd extensions (#36)
  • Improve handling of custom soap headers (#33)

0.6.0 (2016-05-21)

  • Add missing name attributes to xsd.QName and xsd.NOTATION (#15)
  • Various fixes related to the Choice element
  • Support xsd:include
  • Experimental support for HTTP bindings
  • Removed Client.get_port(), use Client.bind().

0.5.0 (2015-05-08)

  • Handle attributes during parsing of the response values>
  • Don’t create empty soap objects when the root element is empty.
  • Implement support for WSSE usernameToken profile including passwordText/passwordDigest.
  • Improve XSD date/time related builtins.
  • Various minor XSD handling fixes
  • Use the correct soap-envelope XML namespace for the Soap 1.2 binding
  • Use application/soap+xml as content-type in the Soap 1.2 binding
  • backwards incompatible: Make cache part of the transport object instead of the client. This changes the call signature of the Client() class. (Marek Wywiał)
  • Add the verify kwarg to the Transport object to disable ssl certificate verification. (Marek Wywiał)

0.4.0 (2016-04-17)

  • Add defusedxml module for XML security issues
  • Add support for choice elements
  • Fix documentation example for complex types (Falk Schuetzenmeister)

0.3.0 (2016-04-10)

  • Correctly handle recursion in WSDL and XSD files
  • Add support for the XSD Any element
  • Allow usage of shorthand prefixes when creating elements and types
  • And more various improvements

0.2.5 (2016-04-05)

  • Temporarily disable the HTTP binding support until it works properly
  • Fix an issue with parsing SOAP responses with optional elements

0.2.4 (2016-04-03)

  • Improve xsd.DateTime, xsd.Date and xsd.Time implementations by using the isodate module.
  • Implement xsd.Duration

0.2.3 (2016-04-03)

  • Fix xsd.DateTime, xsd.Date and xsd.Time implementations
  • Handle NIL values correctly for simpletypes

0.2.2 (2016-04-03)

  • Fix issue with initializing value objects (ListElements)
  • Add new zeep.helpers.serialize_object() method
  • Rename type attribute on value objects to _xsd_type to remove potential attribute conflicts

0.2.1 (2016-04-03)

  • Support minOccurs 0 (optional elements)
  • Automatically convert python datastructures to zeep objects for requests.
  • Set default values for new zeep objects to None / [] (Element, ListElement)
  • Add Client.get_element() to create custom objects

0.2.0 (2016-04-03)

  • Proper support for XSD element and attribute forms (qualified/unqualified)
  • Improved XSD handling
  • Separate bindings for Soap 1.1 and Soap 1.2
  • And again various other fixes

0.1.1 (2016-03-20)

  • Various fixes to make the HttpBinding not throw errors during parsing
  • More built-in xsd types
  • Add support for python -mzeep <wsdl>
  • Various other fixes

0.1.0 (2016-03-20)

Preview / Proof-of-concept release. Probably not suitable for production use :)