soap with urllib2 in python

Easiest way to call do a SOAP call in Python. Tested against webMethods IntegrationServer. Expects hand-written SOAP message, but I personally really prefer writing short XML instead of learning about bloated generators.

import urllib2, base64
def invoke(host, port, username, password, service_path, service_name, xml=''):
    url = "http://{host}:{port}/soap/rpc".format(host=host, port=port)
    data = ("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" +
                "<SOAP-ENV:Envelope\n" +
                " xmlns:SOAP-ENV=\"http://schemas.xmlsoap.org/soap/envelope/\"\n" +
                "   xmlns:SOAP-ENC=\"http://schemas.xmlsoap.org/soap/encoding/\"\n" +
                "   xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\"\n" +
                "   xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n" +
                "   SOAP-ENV:encodingStyle=\"http://schemas.xmlsoap.org/soap/encoding/\">\n" +
                "<SOAP-ENV:Body>\n" +
                "   <ns1:" + service_name + "\n" +
                "       SOAP-ENV:encodingStyle=\"http://schemas.xmlsoap.org/soap/encoding/\"\n" +
                "       xmlns:ns1=\"http://" + host  +  "/" + service_path + "\">\n" +
                xml +
                "   </ns1:" + service_name + ">\n" +
                "</SOAP-ENV:Body>\n" +
                "</SOAP-ENV:Envelope>\n\n");
    data = data.replace('\n', '\r\n')
    headers = {
            'Authorization': "Basic {0}".format(base64.encodestring("{0}:{1}".format(username, password))),
            'Content-Type': 'text/xml',
            'Content-Length': len(data),
        }
    req = urllib2.Request(url, data, headers)
    xml = urllib2.urlopen(req, data).read()
    return xml


def main():
    print(invoke('127.0.0.1', 5555, 'Administrator', 'EvTyecalkAt8', 'foo.bar.baz', 'xyzzy'))


if __name__ == '__main__':
    main()

$Id: simple-soap-python.html,v 1.2 2009/03/09 17:04:31 maciej Exp $