wiki:TipsAndTricks
Last modified 4 years ago Last modified on 11/19/09 17:30:13

Tips & Tricks

Types Names Containing (.)

The suds Factory uses a (.) dot notation the parsing the path parameter for create(). The path is designed to provide access to nested types. However, this can cause problems because (.) is legal in XML particle names. Some schema(s) define elements and types with names containing (.) dots.

To mitigate this, the Factory separator() method can be used to specify a different path separator as follows:

client = Client(url)
client.factory.separator('/')
first = client.factory.create('name.first')

Including Literal XML

To include literal (not escaped) XML as a parameter value of object attribute, you need to set the value of the parameter of the object attribute to be a sax Element. The marshaller is designed to simply attach and append content that is already XML.

For example, you want to pass the following XML as a parameter:

<query>
  <name>Elmer Fudd</name>
  <age unit="years">33</age>
  <job>Wabbit Hunter</job>
</query>

The can be done as follows:

from suds.sax.element import Element
query = Element('query')
name = Element('name').setText('Elmer Fudd')
age = Element('age').setText('33')
age.set('units', 'years')
job = Element('job').setText('Wabbit Hunter')
query.append(name)
query.append(age)
query.append(job)
client.service.runQuery(query)

See also: Custom Headers

Performance

Cache the suds Client because reading and digesting the WSDL can be expensive
because some servers generate them on demand.

As of 0.3.5 r473, suds provides some URL caching. By default, http get(s) such as getting the WSDL and importing XSDs are cached.

The default cache is a FileCache with an expiration of (1) day.

This duration may be adjusted as follows:

cache = client.options.cache
cache.setduration(days=10)

OR

cache.setduration(seconds=90)

The duration my be (months, weeks, days, hours, seconds ).

The default location (directory) is /tmp/suds so Windows users will need to set the location to something that makes sense on windows.

The cache is an option and can be set with any kind of Cache object. So, uses may plug-in any kind of cache they want.

from suds.transport import Cache

class MyCache(Cache)
...     pass

client.set_options(cache=MyCache())

To disable caching:

client.set_options(cache=None)

Schema - TypeNotFound

  • Some WSDL(s) schemas import as: <import namespace="http://schemas.xmlsoap.org/soap/encoding/"/> without schemaLocation="" and expect processor to use the namespace URI as the schema location for the namespace. The specifications for processing <import/> leave the resolution of the imported namespace to a schema to the descession of the processor (in this case suds) when @schemaLocation is not specified. Suds always looks within the WSDL for a schema but does not look outside unless:
    • A schemaLocation is specified, or
    • A static binding is specified using the following syntax:
      from suds.xsd.sxbasic import Import
      ns = 'http://schemas.xmlsoap.org/soap/encoding/'
      location = 'http://schemas.xmlsoap.org/soap/encoding/'
      Import.bind(ns, location)
      
      Or, the shorthand (when location is the same as the namespace URI)
      Import.bind(ns)
      

note: http://schemas.xmlsoap.org/soap/encoding/' automatically bound in 0.3.4 as of (r420).

In some cases, binding the schemaLocation isn't enough. Many times the problem is that the schema references a named object in another schema but fails to import it. To help with cases like this, the schema doctor was introduced in r512, ( 0.3.6 beta ).

See: https://fedorahosted.org/suds/wiki/Documentation#FIXINGBROKENSCHEMAs for details.

SAX Parser

  • SAX Parser Exceptions

Sometimes web service providers (servers) include characters (such as control-chars) in the reply that cause the suds sax parser to raise an exception. As of release 0.3.2+ (and r313+), you can plug-in a filter function or lambda to pre-process the reply before it is processed by the sax parser. Here is an example of how to install the function and how you might clean the reply. This only needs to be done once in your application before you use the suds client.

import string
from suds.bindings.binding import Binding
Binding.replyfilter = (lambda s,r: ''.join([c for c in r if c in string.printable]))

Passing Explicit NULL values

If you have a service that takes NULL values for required parameters or you want to pass NULL for optional object attributes, you simply need to set the value to null. How do you do this? As of 0.3.8 (r599), you can do the following:

from suds import null
client.service.foo(null())

And the soap message will contain an empty (and xsi:nil="true" if node defined as nillable).

You need to use null instead of None because None is interpreted by the marshaller as not having a value.

Client API

  • Namespace Prefixes

The suds Client provides an RPC like interface to the service defined in the WSDL. Many WSDLs include and import many schema (xsd) files. When many namespaces are involved there are also many namespace prefixes. Namespace prefixes are a necessary tool for referencing schema objects by qualified name. Since prefixes are usually locally defined, there is no expectation or guarantee of uniqueness. In exposing these types to be created by the Factory, Suds must provide unique for all the namespaces defined in any/all schemas. These are the ns0-ns(N) prefixes seen when printing the Client. These prefixes are generated by first finding all relevant namespaces (URIs). Then, they are sorted alphabetically. Last, each namespace is assigned the next available prefix. So, if a new namespace is introduced or the URI of a namespace is changed, the assignment of prefixes may also change. For most WSDL and schema files, this rarely causes a problem. But, if you are using a big complex WSDL and/or schema file(s), you may find yourself getting errors on programs that worked just yesterday.

There are (2) solutions. The first (and best), is to statically defined your own prefixes.

client.addprefix('x', 'http://xx...')
client.addprefix('y', 'http://yy...')
...
client.factory.create('x:Thing')

Where x is mapped to the http://xx... namespace and y is mapped to the http://yy... namespace.

Second, is to use the alternate qualification syntax defined in the README.

client.factory.create('{http://xx...}Thing')

Examples & Articles

Attachments