Python suds wrong namespace prefix in SOAP request


I use python/suds to implement a client and I get wrong namespace prefixes in the sent SOAP header for a spefic type of parameters defined by element ref= in the wsdl.

The .wsdl is referencing a data types .xsd file, see below. The issue is with the function GetRecordAttributes and its first argument of type gbt:recordReferences.

File: browse2.wsdl

<xsd:schema targetNamespace="" xmlns="" xmlns:gbt="" elementFormDefault="qualified" attributeFormDefault="qualified">
<xsd:import schemaLocation="grantabasetypes2.xsd" namespace=""/>
<xsd:element name="GetRecordAttributes">
              <xsd:element ref="gbt:recordReferences">

Referenced File : grantabasetypes2.xsd

<element name="recordReferences">
      <element name="record" minOccurs="0" maxOccurs="unbounded" type="gbt:MIRecordReference"/>

SOAP Request sent by suds:

<SOAP-ENV:Envelope xmlns:ns0="" xmlns:ns1="" xmlns:ns2="" xmlns:xsi="" xmlns:SOAP-ENV="">

Problem : <ns2:recordReferences> has wrong prefix, should be <ns0:recordReferences> since it belongs to the namespace ...GrantaBaseTypes defined in the .xsd.

This happens for all arguments defined by ref= in the wsdl. How can this be automatically fixed?

Note: I checked that the "good" prefix is accepted by the service by manually sending the xml SOAP request via curl.


I meddled with SUDS source code and the following empirical fix forces all elements with ref= attribute to assume the ref-ed namespace (previously, they take on the schema root namespace or whatever tns is):

File: /suds/xsd/

class SchemaObject(object):
    def namespace(self, prefix=None):

        ns = self.schema.tns

        if self.ref and self.ref in self.schema.elements.keys():
            ns = self.ref

Works with my service, but I'm not sure if it'll break other things. I would prefer a smarter solution that does not change SUDS source code.



Best Solution

Write a Suds plugin to modify the XML before it is sent.

from suds.client import Client
from suds.plugin import MessagePlugin

class MyPlugin(MessagePlugin):
    def marshalled(self, context):
        #modify this line to reliably find the "recordReferences" element

client = Client(WSDL_URL, plugins=[MyPlugin()])

Quoting Suds documentation:

Provides the plugin with the opportunity to inspect/modify the envelope Document before it is sent.

Related Question