SOAPpy-0.12.0/0040755001604000501700000000000010206655324012535 5ustar warnegclinicalSOAPpy-0.12.0/SOAPpy/0040755001604000501700000000000010206655324013650 5ustar warnegclinicalSOAPpy-0.12.0/SOAPpy/wstools/0040755001604000501700000000000010206655324015362 5ustar warnegclinicalSOAPpy-0.12.0/SOAPpy/wstools/test/0040755001604000501700000000000010206655324016341 5ustar warnegclinicalSOAPpy-0.12.0/SOAPpy/wstools/test/__init__.py0100644001604000501700000000013210202425137020434 0ustar warnegclinical#! /usr/bin/env python """wstools.WSDLTools.WSDLReader tests directory.""" import utils SOAPpy-0.12.0/SOAPpy/wstools/test/test_t1.py0100644001604000501700000000114010202425137020260 0ustar warnegclinical############################################################################ # Joshua R. Boverhof, David W. Robertson, LBNL # See LBNLCopyright for copyright notice! ########################################################################### import unittest import test_wsdl import utils def makeTestSuite(): suite = unittest.TestSuite() suite.addTest(test_wsdl.makeTestSuite("services_by_file")) return suite def main(): loader = utils.MatchTestLoader(True, None, "makeTestSuite") unittest.main(defaultTest="makeTestSuite", testLoader=loader) if __name__ == "__main__" : main() SOAPpy-0.12.0/SOAPpy/wstools/test/test_wsdl.py0100644001604000501700000001257410202425137020722 0ustar warnegclinical#!/usr/bin/env python ############################################################################ # Joshua R. Boverhof, David W. Robertson, LBNL # See LBNLCopyright for copyright notice! ########################################################################### import sys, unittest import ConfigParser from ZSI.wstools.Utility import DOM from ZSI.wstools.WSDLTools import WSDLReader from ZSI.wstools.TimeoutSocket import TimeoutError class WSDLToolsTestCase(unittest.TestCase): def __init__(self, methodName='runTest'): unittest.TestCase.__init__(self, methodName) def setUp(self): self.path = nameGenerator.next() print self.path sys.stdout.flush() def __str__(self): teststr = unittest.TestCase.__str__(self) if hasattr(self, "path"): return "%s: %s" % (teststr, self.path ) else: return "%s" % (teststr) def checkWSDLCollection(self, tag_name, component, key='name'): if self.wsdl is None: return definition = self.wsdl.document.documentElement version = DOM.WSDLUriToVersion(definition.namespaceURI) nspname = DOM.GetWSDLUri(version) for node in DOM.getElements(definition, tag_name, nspname): name = DOM.getAttr(node, key) comp = component[name] self.failUnlessEqual(eval('comp.%s' %key), name) def checkXSDCollection(self, tag_name, component, node, key='name'): for cnode in DOM.getElements(node, tag_name): name = DOM.getAttr(cnode, key) component[name] def test_all(self): try: if self.path[:7] == 'http://': self.wsdl = WSDLReader().loadFromURL(self.path) else: self.wsdl = WSDLReader().loadFromFile(self.path) except TimeoutError: print "connection timed out" sys.stdout.flush() return except: self.path = self.path + ": load failed, unable to start" raise try: self.checkWSDLCollection('service', self.wsdl.services) except: self.path = self.path + ": wsdl.services" raise try: self.checkWSDLCollection('message', self.wsdl.messages) except: self.path = self.path + ": wsdl.messages" raise try: self.checkWSDLCollection('portType', self.wsdl.portTypes) except: self.path = self.path + ": wsdl.portTypes" raise try: self.checkWSDLCollection('binding', self.wsdl.bindings) except: self.path = self.path + ": wsdl.bindings" raise try: self.checkWSDLCollection('import', self.wsdl.imports, key='namespace') except: self.path = self.path + ": wsdl.imports" raise try: for key in self.wsdl.types.keys(): schema = self.wsdl.types[key] self.failUnlessEqual(key, schema.getTargetNamespace()) definition = self.wsdl.document.documentElement version = DOM.WSDLUriToVersion(definition.namespaceURI) nspname = DOM.GetWSDLUri(version) for node in DOM.getElements(definition, 'types', nspname): for snode in DOM.getElements(node, 'schema'): tns = DOM.findTargetNS(snode) schema = self.wsdl.types[tns] self.schemaAttributesDeclarations(schema, snode) self.schemaAttributeGroupDeclarations(schema, snode) self.schemaElementDeclarations(schema, snode) self.schemaTypeDefinitions(schema, snode) except: self.path = self.path + ": wsdl.types" raise if self.wsdl.extensions: print 'No check for WSDLTools(%s) Extensions:' %(self.wsdl.name) for ext in self.wsdl.extensions: print '\t', ext def schemaAttributesDeclarations(self, schema, node): self.checkXSDCollection('attribute', schema.attr_decl, node) def schemaAttributeGroupDeclarations(self, schema, node): self.checkXSDCollection('group', schema.attr_groups, node) def schemaElementDeclarations(self, schema, node): self.checkXSDCollection('element', schema.elements, node) def schemaTypeDefinitions(self, schema, node): self.checkXSDCollection('complexType', schema.types, node) self.checkXSDCollection('simpleType', schema.types, node) def setUpOptions(section): cp = ConfigParser.ConfigParser() cp.read('config.txt') if not cp.sections(): print 'fatal error: configuration file config.txt not present' sys.exit(0) if not cp.has_section(section): print '%s section not present in configuration file, exiting' % section sys.exit(0) return cp, len(cp.options(section)) def getOption(cp, section): for name, value in cp.items(section): yield value def makeTestSuite(section='services_by_file'): global nameGenerator cp, numTests = setUpOptions(section) nameGenerator = getOption(cp, section) suite = unittest.TestSuite() for i in range(0, numTests): suite.addTest(unittest.makeSuite(WSDLToolsTestCase, 'test_')) return suite def main(): unittest.main(defaultTest="makeTestSuite") if __name__ == "__main__" : main() SOAPpy-0.12.0/SOAPpy/wstools/test/test_wstools.py0100644001604000501700000000176010202425137021456 0ustar warnegclinical#!/usr/bin/env python ############################################################################ # Joshua R. Boverhof, David W. Robertson, LBNL # See LBNLCopyright for copyright notice! ########################################################################### import unittest, tarfile, os, ConfigParser import test_wsdl SECTION='files' CONFIG_FILE = 'config.txt' def extractFiles(section, option): config = ConfigParser.ConfigParser() config.read(CONFIG_FILE) archives = config.get(section, option) archives = eval(archives) for file in archives: tar = tarfile.open(file) if not os.access(tar.membernames[0], os.R_OK): for i in tar.getnames(): tar.extract(i) def makeTestSuite(): suite = unittest.TestSuite() suite.addTest(test_wsdl.makeTestSuite("services_by_file")) return suite def main(): extractFiles(SECTION, 'archives') unittest.main(defaultTest="makeTestSuite") if __name__ == "__main__" : main() SOAPpy-0.12.0/SOAPpy/wstools/test/test_wstools_net.py0100644001604000501700000000102710202425137022320 0ustar warnegclinical#!/usr/bin/env python ############################################################################ # Joshua R. Boverhof, David W. Robertson, LBNL # See LBNLCopyright for copyright notice! ########################################################################### import unittest import test_wsdl def makeTestSuite(): suite = unittest.TestSuite() suite.addTest(test_wsdl.makeTestSuite("services_by_http")) return suite def main(): unittest.main(defaultTest="makeTestSuite") if __name__ == "__main__" : main() SOAPpy-0.12.0/SOAPpy/wstools/Namespaces.py0100755001604000501700000001273110202425137020010 0ustar warnegclinical#! /usr/bin/env python """Namespace module, so you don't need PyXML """ try: from xml.ns import SOAP, SCHEMA, WSDL, XMLNS, DSIG, ENCRYPTION DSIG.C14N = "http://www.w3.org/TR/2001/REC-xml-c14n-20010315" except: class SOAP: ENV = "http://schemas.xmlsoap.org/soap/envelope/" ENC = "http://schemas.xmlsoap.org/soap/encoding/" ACTOR_NEXT = "http://schemas.xmlsoap.org/soap/actor/next" class SCHEMA: XSD1 = "http://www.w3.org/1999/XMLSchema" XSD2 = "http://www.w3.org/2000/10/XMLSchema" XSD3 = "http://www.w3.org/2001/XMLSchema" XSD_LIST = [ XSD1, XSD2, XSD3 ] XSI1 = "http://www.w3.org/1999/XMLSchema-instance" XSI2 = "http://www.w3.org/2000/10/XMLSchema-instance" XSI3 = "http://www.w3.org/2001/XMLSchema-instance" XSI_LIST = [ XSI1, XSI2, XSI3 ] BASE = XSD3 class WSDL: BASE = "http://schemas.xmlsoap.org/wsdl/" BIND_HTTP = "http://schemas.xmlsoap.org/wsdl/http/" BIND_MIME = "http://schemas.xmlsoap.org/wsdl/mime/" BIND_SOAP = "http://schemas.xmlsoap.org/wsdl/soap/" BIND_SOAP12 = "http://schemas.xmlsoap.org/wsdl/soap12/" class XMLNS: BASE = "http://www.w3.org/2000/xmlns/" XML = "http://www.w3.org/XML/1998/namespace" HTML = "http://www.w3.org/TR/REC-html40" class DSIG: BASE = "http://www.w3.org/2000/09/xmldsig#" C14N = "http://www.w3.org/TR/2001/REC-xml-c14n-20010315" C14N_COMM = "http://www.w3.org/TR/2000/CR-xml-c14n-20010315#WithComments" C14N_EXCL = "http://www.w3.org/2001/10/xml-exc-c14n#" DIGEST_MD2 = "http://www.w3.org/2000/09/xmldsig#md2" DIGEST_MD5 = "http://www.w3.org/2000/09/xmldsig#md5" DIGEST_SHA1 = "http://www.w3.org/2000/09/xmldsig#sha1" ENC_BASE64 = "http://www.w3.org/2000/09/xmldsig#base64" ENVELOPED = "http://www.w3.org/2000/09/xmldsig#enveloped-signature" HMAC_SHA1 = "http://www.w3.org/2000/09/xmldsig#hmac-sha1" SIG_DSA_SHA1 = "http://www.w3.org/2000/09/xmldsig#dsa-sha1" SIG_RSA_SHA1 = "http://www.w3.org/2000/09/xmldsig#rsa-sha1" XPATH = "http://www.w3.org/TR/1999/REC-xpath-19991116" XSLT = "http://www.w3.org/TR/1999/REC-xslt-19991116" class ENCRYPTION: BASE = "http://www.w3.org/2001/04/xmlenc#" BLOCK_3DES = "http://www.w3.org/2001/04/xmlenc#des-cbc" BLOCK_AES128 = "http://www.w3.org/2001/04/xmlenc#aes128-cbc" BLOCK_AES192 = "http://www.w3.org/2001/04/xmlenc#aes192-cbc" BLOCK_AES256 = "http://www.w3.org/2001/04/xmlenc#aes256-cbc" DIGEST_RIPEMD160 = "http://www.w3.org/2001/04/xmlenc#ripemd160" DIGEST_SHA256 = "http://www.w3.org/2001/04/xmlenc#sha256" DIGEST_SHA512 = "http://www.w3.org/2001/04/xmlenc#sha512" KA_DH = "http://www.w3.org/2001/04/xmlenc#dh" KT_RSA_1_5 = "http://www.w3.org/2001/04/xmlenc#rsa-1_5" KT_RSA_OAEP = "http://www.w3.org/2001/04/xmlenc#rsa-oaep-mgf1p" STREAM_ARCFOUR = "http://www.w3.org/2001/04/xmlenc#arcfour" WRAP_3DES = "http://www.w3.org/2001/04/xmlenc#kw-3des" WRAP_AES128 = "http://www.w3.org/2001/04/xmlenc#kw-aes128" WRAP_AES192 = "http://www.w3.org/2001/04/xmlenc#kw-aes192" WRAP_AES256 = "http://www.w3.org/2001/04/xmlenc#kw-aes256" class OASIS: '''URLs for Oasis specifications ''' WSSE = "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd" UTILITY = "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd" LIFETIME = "http://docs.oasis-open.org/wsrf/2004/06/wsrf-WS-ResourceLifetime-1.2-draft-01.xsd" PROPERTIES = "http://docs.oasis-open.org/wsrf/2004/06/wsrf-WS-ResourceProperties-1.2-draft-01.xsd" BASENOTIFICATION = "http://docs.oasis-open.org/wsn/2004/06/wsn-WS-BaseNotification-1.2-draft-01.xsd" BASEFAULTS = "http://docs.oasis-open.org/wsrf/2004/06/wsrf-WS-BaseFaults-1.2-draft-01.xsd" class WSSE: BASE = "http://schemas.xmlsoap.org/ws/2002/04/secext" TRUST = "http://schemas.xmlsoap.org/ws/2004/04/trust" class WSU: BASE = "http://schemas.xmlsoap.org/ws/2002/04/utility" UTILITY = "http://schemas.xmlsoap.org/ws/2002/07/utility" class WSR: PROPERTIES = "http://www.ibm.com/xmlns/stdwip/web-services/WS-ResourceProperties" LIFETIME = "http://www.ibm.com/xmlns/stdwip/web-services/WS-ResourceLifetime" class WSA200408: ADDRESS = "http://schemas.xmlsoap.org/ws/2004/08/addressing" ANONYMOUS = "%s/role/anonymous" %ADDRESS FAULT = "%s/fault" %ADDRESS WSA = WSA200408 class WSA200403: ADDRESS = "http://schemas.xmlsoap.org/ws/2004/03/addressing" ANONYMOUS = "%s/role/anonymous" %ADDRESS FAULT = "%s/fault" %ADDRESS class WSA200303: ADDRESS = "http://schemas.xmlsoap.org/ws/2003/03/addressing" ANONYMOUS = "%s/role/anonymous" %ADDRESS FAULT = None class WSP: POLICY = "http://schemas.xmlsoap.org/ws/2002/12/policy" class BEA: SECCONV = "http://schemas.xmlsoap.org/ws/2004/04/sc" class GLOBUS: SECCONV = "http://wsrf.globus.org/core/2004/07/security/secconv" CORE = "http://www.globus.org/namespaces/2004/06/core" SIG = "http://www.globus.org/2002/04/xmlenc#gssapi-sign" ZSI_SCHEMA_URI = 'http://www.zolera.com/schemas/ZSI/' SOAPpy-0.12.0/SOAPpy/wstools/TimeoutSocket.py0100755001604001300100000001234510202425136020574 0ustar warnegcompstat"""Based on code from timeout_socket.py, with some tweaks for compatibility. These tweaks should really be rolled back into timeout_socket, but it's not totally clear who is maintaining it at this point. In the meantime, we'll use a different module name for our tweaked version to avoid any confusion. The original timeout_socket is by: Scott Cotton Lloyd Zusman Phil Mayes Piers Lauder Radovan Garabik """ ident = "$Id: TimeoutSocket.py,v 1.2 2003/05/20 21:10:12 warnes Exp $" import string, socket, select, errno WSAEINVAL = getattr(errno, 'WSAEINVAL', 10022) class TimeoutSocket: """A socket imposter that supports timeout limits.""" def __init__(self, timeout=20, sock=None): self.timeout = float(timeout) self.inbuf = '' if sock is None: sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) self.sock = sock self.sock.setblocking(0) self._rbuf = '' self._wbuf = '' def __getattr__(self, name): # Delegate to real socket attributes. return getattr(self.sock, name) def connect(self, *addr): timeout = self.timeout sock = self.sock try: # Non-blocking mode sock.setblocking(0) apply(sock.connect, addr) sock.setblocking(timeout != 0) return 1 except socket.error,why: if not timeout: raise sock.setblocking(1) if len(why.args) == 1: code = 0 else: code, why = why if code not in ( errno.EINPROGRESS, errno.EALREADY, errno.EWOULDBLOCK ): raise r,w,e = select.select([],[sock],[],timeout) if w: try: apply(sock.connect, addr) return 1 except socket.error,why: if len(why.args) == 1: code = 0 else: code, why = why if code in (errno.EISCONN, WSAEINVAL): return 1 raise raise TimeoutError('socket connect() timeout.') def send(self, data, flags=0): total = len(data) next = 0 while 1: r, w, e = select.select([],[self.sock], [], self.timeout) if w: buff = data[next:next + 8192] sent = self.sock.send(buff, flags) next = next + sent if next == total: return total continue raise TimeoutError('socket send() timeout.') def recv(self, amt, flags=0): if select.select([self.sock], [], [], self.timeout)[0]: return self.sock.recv(amt, flags) raise TimeoutError('socket recv() timeout.') buffsize = 4096 handles = 1 def makefile(self, mode="r", buffsize=-1): self.handles = self.handles + 1 self.mode = mode return self def close(self): self.handles = self.handles - 1 if self.handles == 0 and self.sock.fileno() >= 0: self.sock.close() def read(self, n=-1): if not isinstance(n, type(1)): n = -1 if n >= 0: k = len(self._rbuf) if n <= k: data = self._rbuf[:n] self._rbuf = self._rbuf[n:] return data n = n - k L = [self._rbuf] self._rbuf = "" while n > 0: new = self.recv(max(n, self.buffsize)) if not new: break k = len(new) if k > n: L.append(new[:n]) self._rbuf = new[n:] break L.append(new) n = n - k return "".join(L) k = max(4096, self.buffsize) L = [self._rbuf] self._rbuf = "" while 1: new = self.recv(k) if not new: break L.append(new) k = min(k*2, 1024**2) return "".join(L) def readline(self, limit=-1): data = "" i = self._rbuf.find('\n') while i < 0 and not (0 < limit <= len(self._rbuf)): new = self.recv(self.buffsize) if not new: break i = new.find('\n') if i >= 0: i = i + len(self._rbuf) self._rbuf = self._rbuf + new if i < 0: i = len(self._rbuf) else: i = i+1 if 0 <= limit < len(self._rbuf): i = limit data, self._rbuf = self._rbuf[:i], self._rbuf[i:] return data def readlines(self, sizehint = 0): total = 0 list = [] while 1: line = self.readline() if not line: break list.append(line) total += len(line) if sizehint and total >= sizehint: break return list def writelines(self, list): self.send(''.join(list)) def write(self, data): self.send(data) def flush(self): pass class TimeoutError(Exception): pass SOAPpy-0.12.0/SOAPpy/wstools/UserTuple.py0100755001604000501700000001000310202425137017647 0ustar warnegclinical""" A more or less complete user-defined wrapper around tuple objects. Adapted version of the standard library's UserList. Taken from Stefan Schwarzer's ftputil library, available at , and used under this license: Copyright (C) 1999, Stefan Schwarzer All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: - Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. - Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. - Neither the name of the above author nor the names of the contributors to the software may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. """ # $Id: UserTuple.py,v 1.1 2003/07/21 14:18:54 warnes Exp $ #XXX tuple instances (in Python 2.2) contain also: # __class__, __delattr__, __getattribute__, __hash__, __new__, # __reduce__, __setattr__, __str__ # What about these? class UserTuple: def __init__(self, inittuple=None): self.data = () if inittuple is not None: # XXX should this accept an arbitrary sequence? if type(inittuple) == type(self.data): self.data = inittuple elif isinstance(inittuple, UserTuple): # this results in # self.data is inittuple.data # but that's ok for tuples because they are # immutable. (Builtin tuples behave the same.) self.data = inittuple.data[:] else: # the same applies here; (t is tuple(t)) == 1 self.data = tuple(inittuple) def __repr__(self): return repr(self.data) def __lt__(self, other): return self.data < self.__cast(other) def __le__(self, other): return self.data <= self.__cast(other) def __eq__(self, other): return self.data == self.__cast(other) def __ne__(self, other): return self.data != self.__cast(other) def __gt__(self, other): return self.data > self.__cast(other) def __ge__(self, other): return self.data >= self.__cast(other) def __cast(self, other): if isinstance(other, UserTuple): return other.data else: return other def __cmp__(self, other): return cmp(self.data, self.__cast(other)) def __contains__(self, item): return item in self.data def __len__(self): return len(self.data) def __getitem__(self, i): return self.data[i] def __getslice__(self, i, j): i = max(i, 0); j = max(j, 0) return self.__class__(self.data[i:j]) def __add__(self, other): if isinstance(other, UserTuple): return self.__class__(self.data + other.data) elif isinstance(other, type(self.data)): return self.__class__(self.data + other) else: return self.__class__(self.data + tuple(other)) # dir( () ) contains no __radd__ (at least in Python 2.2) def __mul__(self, n): return self.__class__(self.data*n) __rmul__ = __mul__ SOAPpy-0.12.0/SOAPpy/wstools/Utility.py0100755001604000501700000013713610204421702017377 0ustar warnegclinical# Copyright (c) 2001 Zope Corporation and Contributors. All Rights Reserved. # # This software is subject to the provisions of the Zope Public License, # Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. # THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED # WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED # WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS # FOR A PARTICULAR PURPOSE. ident = "$Id: Utility.py,v 1.20 2005/02/09 18:33:05 boverhof Exp $" import types import string, httplib, smtplib, urllib, socket, weakref from os.path import isfile from string import join, strip, split from UserDict import UserDict from cStringIO import StringIO from TimeoutSocket import TimeoutSocket, TimeoutError from urlparse import urlparse from httplib import HTTPConnection, HTTPSConnection from exceptions import Exception import xml.dom.minidom from xml.dom import Node import logging from c14n import Canonicalize from Namespaces import SCHEMA, SOAP, XMLNS, ZSI_SCHEMA_URI try: from xml.dom.ext import SplitQName except: def SplitQName(qname): '''SplitQName(qname) -> (string, string) Split Qualified Name into a tuple of len 2, consisting of the prefix and the local name. (prefix, localName) Special Cases: xmlns -- (localName, 'xmlns') None -- (None, localName) ''' l = qname.split(':') if len(l) == 1: l.insert(0, None) elif len(l) == 2: if l[0] == 'xmlns': l.reverse() else: return return tuple(l) class NamespaceError(Exception): """Used to indicate a Namespace Error.""" class RecursionError(Exception): """Used to indicate a HTTP redirect recursion.""" class ParseError(Exception): """Used to indicate a XML parsing error.""" class DOMException(Exception): """Used to indicate a problem processing DOM.""" class Base: """Base class for instance level Logging""" def __init__(self, module=__name__): self.logger = logging.getLogger('%s-%s(%x)' %(module, self.__class__, id(self))) class HTTPResponse: """Captures the information in an HTTP response message.""" def __init__(self, response): self.status = response.status self.reason = response.reason self.headers = response.msg self.body = response.read() or None response.close() class TimeoutHTTP(HTTPConnection): """A custom http connection object that supports socket timeout.""" def __init__(self, host, port=None, timeout=20): HTTPConnection.__init__(self, host, port) self.timeout = timeout def connect(self): self.sock = TimeoutSocket(self.timeout) self.sock.connect((self.host, self.port)) class TimeoutHTTPS(HTTPSConnection): """A custom https object that supports socket timeout. Note that this is not really complete. The builtin SSL support in the Python socket module requires a real socket (type) to be passed in to be hooked to SSL. That means our fake socket won't work and our timeout hacks are bypassed for send and recv calls. Since our hack _is_ in place at connect() time, it should at least provide some timeout protection.""" def __init__(self, host, port=None, timeout=20, **kwargs): HTTPSConnection.__init__(self, str(host), port, **kwargs) self.timeout = timeout def connect(self): sock = TimeoutSocket(self.timeout) sock.connect((self.host, self.port)) realsock = getattr(sock.sock, '_sock', sock.sock) ssl = socket.ssl(realsock, self.key_file, self.cert_file) self.sock = httplib.FakeSocket(sock, ssl) def urlopen(url, timeout=20, redirects=None): """A minimal urlopen replacement hack that supports timeouts for http. Note that this supports GET only.""" scheme, host, path, params, query, frag = urlparse(url) if not scheme in ('http', 'https'): return urllib.urlopen(url) if params: path = '%s;%s' % (path, params) if query: path = '%s?%s' % (path, query) if frag: path = '%s#%s' % (path, frag) if scheme == 'https': # If ssl is not compiled into Python, you will not get an exception # until a conn.endheaders() call. We need to know sooner, so use # getattr. if hasattr(socket, 'ssl'): conn = TimeoutHTTPS(host, None, timeout) else: import M2Crypto ctx = M2Crypto.SSL.Context() ctx.set_session_timeout(timeout) conn = M2Crypto.httpslib.HTTPSConnection(host, ssl_context=ctx) #conn.set_debuglevel(1) else: conn = TimeoutHTTP(host, None, timeout) conn.putrequest('GET', path) conn.putheader('Connection', 'close') conn.endheaders() response = None while 1: response = conn.getresponse() if response.status != 100: break conn._HTTPConnection__state = httplib._CS_REQ_SENT conn._HTTPConnection__response = None status = response.status # If we get an HTTP redirect, we will follow it automatically. if status >= 300 and status < 400: location = response.msg.getheader('location') if location is not None: response.close() if redirects is not None and redirects.has_key(location): raise RecursionError( 'Circular HTTP redirection detected.' ) if redirects is None: redirects = {} redirects[location] = 1 return urlopen(location, timeout, redirects) raise HTTPResponse(response) if not (status >= 200 and status < 300): raise HTTPResponse(response) body = StringIO(response.read()) response.close() return body class DOM: """The DOM singleton defines a number of XML related constants and provides a number of utility methods for DOM related tasks. It also provides some basic abstractions so that the rest of the package need not care about actual DOM implementation in use.""" # Namespace stuff related to the SOAP specification. NS_SOAP_ENV_1_1 = 'http://schemas.xmlsoap.org/soap/envelope/' NS_SOAP_ENC_1_1 = 'http://schemas.xmlsoap.org/soap/encoding/' NS_SOAP_ENV_1_2 = 'http://www.w3.org/2001/06/soap-envelope' NS_SOAP_ENC_1_2 = 'http://www.w3.org/2001/06/soap-encoding' NS_SOAP_ENV_ALL = (NS_SOAP_ENV_1_1, NS_SOAP_ENV_1_2) NS_SOAP_ENC_ALL = (NS_SOAP_ENC_1_1, NS_SOAP_ENC_1_2) NS_SOAP_ENV = NS_SOAP_ENV_1_1 NS_SOAP_ENC = NS_SOAP_ENC_1_1 _soap_uri_mapping = { NS_SOAP_ENV_1_1 : '1.1', NS_SOAP_ENV_1_2 : '1.2', } SOAP_ACTOR_NEXT_1_1 = 'http://schemas.xmlsoap.org/soap/actor/next' SOAP_ACTOR_NEXT_1_2 = 'http://www.w3.org/2001/06/soap-envelope/actor/next' SOAP_ACTOR_NEXT_ALL = (SOAP_ACTOR_NEXT_1_1, SOAP_ACTOR_NEXT_1_2) def SOAPUriToVersion(self, uri): """Return the SOAP version related to an envelope uri.""" value = self._soap_uri_mapping.get(uri) if value is not None: return value raise ValueError( 'Unsupported SOAP envelope uri: %s' % uri ) def GetSOAPEnvUri(self, version): """Return the appropriate SOAP envelope uri for a given human-friendly SOAP version string (e.g. '1.1').""" attrname = 'NS_SOAP_ENV_%s' % join(split(version, '.'), '_') value = getattr(self, attrname, None) if value is not None: return value raise ValueError( 'Unsupported SOAP version: %s' % version ) def GetSOAPEncUri(self, version): """Return the appropriate SOAP encoding uri for a given human-friendly SOAP version string (e.g. '1.1').""" attrname = 'NS_SOAP_ENC_%s' % join(split(version, '.'), '_') value = getattr(self, attrname, None) if value is not None: return value raise ValueError( 'Unsupported SOAP version: %s' % version ) def GetSOAPActorNextUri(self, version): """Return the right special next-actor uri for a given human-friendly SOAP version string (e.g. '1.1').""" attrname = 'SOAP_ACTOR_NEXT_%s' % join(split(version, '.'), '_') value = getattr(self, attrname, None) if value is not None: return value raise ValueError( 'Unsupported SOAP version: %s' % version ) # Namespace stuff related to XML Schema. NS_XSD_99 = 'http://www.w3.org/1999/XMLSchema' NS_XSI_99 = 'http://www.w3.org/1999/XMLSchema-instance' NS_XSD_00 = 'http://www.w3.org/2000/10/XMLSchema' NS_XSI_00 = 'http://www.w3.org/2000/10/XMLSchema-instance' NS_XSD_01 = 'http://www.w3.org/2001/XMLSchema' NS_XSI_01 = 'http://www.w3.org/2001/XMLSchema-instance' NS_XSD_ALL = (NS_XSD_99, NS_XSD_00, NS_XSD_01) NS_XSI_ALL = (NS_XSI_99, NS_XSI_00, NS_XSI_01) NS_XSD = NS_XSD_01 NS_XSI = NS_XSI_01 _xsd_uri_mapping = { NS_XSD_99 : NS_XSI_99, NS_XSD_00 : NS_XSI_00, NS_XSD_01 : NS_XSI_01, } for key, value in _xsd_uri_mapping.items(): _xsd_uri_mapping[value] = key def InstanceUriForSchemaUri(self, uri): """Return the appropriate matching XML Schema instance uri for the given XML Schema namespace uri.""" return self._xsd_uri_mapping.get(uri) def SchemaUriForInstanceUri(self, uri): """Return the appropriate matching XML Schema namespace uri for the given XML Schema instance namespace uri.""" return self._xsd_uri_mapping.get(uri) # Namespace stuff related to WSDL. NS_WSDL_1_1 = 'http://schemas.xmlsoap.org/wsdl/' NS_WSDL_ALL = (NS_WSDL_1_1,) NS_WSDL = NS_WSDL_1_1 NS_SOAP_BINDING_1_1 = 'http://schemas.xmlsoap.org/wsdl/soap/' NS_HTTP_BINDING_1_1 = 'http://schemas.xmlsoap.org/wsdl/http/' NS_MIME_BINDING_1_1 = 'http://schemas.xmlsoap.org/wsdl/mime/' NS_SOAP_BINDING_ALL = (NS_SOAP_BINDING_1_1,) NS_HTTP_BINDING_ALL = (NS_HTTP_BINDING_1_1,) NS_MIME_BINDING_ALL = (NS_MIME_BINDING_1_1,) NS_SOAP_BINDING = NS_SOAP_BINDING_1_1 NS_HTTP_BINDING = NS_HTTP_BINDING_1_1 NS_MIME_BINDING = NS_MIME_BINDING_1_1 NS_SOAP_HTTP_1_1 = 'http://schemas.xmlsoap.org/soap/http' NS_SOAP_HTTP_ALL = (NS_SOAP_HTTP_1_1,) NS_SOAP_HTTP = NS_SOAP_HTTP_1_1 _wsdl_uri_mapping = { NS_WSDL_1_1 : '1.1', } def WSDLUriToVersion(self, uri): """Return the WSDL version related to a WSDL namespace uri.""" value = self._wsdl_uri_mapping.get(uri) if value is not None: return value raise ValueError( 'Unsupported SOAP envelope uri: %s' % uri ) def GetWSDLUri(self, version): attr = 'NS_WSDL_%s' % join(split(version, '.'), '_') value = getattr(self, attr, None) if value is not None: return value raise ValueError( 'Unsupported WSDL version: %s' % version ) def GetWSDLSoapBindingUri(self, version): attr = 'NS_SOAP_BINDING_%s' % join(split(version, '.'), '_') value = getattr(self, attr, None) if value is not None: return value raise ValueError( 'Unsupported WSDL version: %s' % version ) def GetWSDLHttpBindingUri(self, version): attr = 'NS_HTTP_BINDING_%s' % join(split(version, '.'), '_') value = getattr(self, attr, None) if value is not None: return value raise ValueError( 'Unsupported WSDL version: %s' % version ) def GetWSDLMimeBindingUri(self, version): attr = 'NS_MIME_BINDING_%s' % join(split(version, '.'), '_') value = getattr(self, attr, None) if value is not None: return value raise ValueError( 'Unsupported WSDL version: %s' % version ) def GetWSDLHttpTransportUri(self, version): attr = 'NS_SOAP_HTTP_%s' % join(split(version, '.'), '_') value = getattr(self, attr, None) if value is not None: return value raise ValueError( 'Unsupported WSDL version: %s' % version ) # Other xml namespace constants. NS_XMLNS = 'http://www.w3.org/2000/xmlns/' def isElement(self, node, name, nsuri=None): """Return true if the given node is an element with the given name and optional namespace uri.""" if node.nodeType != node.ELEMENT_NODE: return 0 return node.localName == name and \ (nsuri is None or self.nsUriMatch(node.namespaceURI, nsuri)) def getElement(self, node, name, nsuri=None, default=join): """Return the first child of node with a matching name and namespace uri, or the default if one is provided.""" nsmatch = self.nsUriMatch ELEMENT_NODE = node.ELEMENT_NODE for child in node.childNodes: if child.nodeType == ELEMENT_NODE: if ((child.localName == name or name is None) and (nsuri is None or nsmatch(child.namespaceURI, nsuri)) ): return child if default is not join: return default raise KeyError, name def getElementById(self, node, id, default=join): """Return the first child of node matching an id reference.""" attrget = self.getAttr ELEMENT_NODE = node.ELEMENT_NODE for child in node.childNodes: if child.nodeType == ELEMENT_NODE: if attrget(child, 'id') == id: return child if default is not join: return default raise KeyError, name def getMappingById(self, document, depth=None, element=None, mapping=None, level=1): """Create an id -> element mapping of those elements within a document that define an id attribute. The depth of the search may be controlled by using the (1-based) depth argument.""" if document is not None: element = document.documentElement mapping = {} attr = element._attrs.get('id', None) if attr is not None: mapping[attr.value] = element if depth is None or depth > level: level = level + 1 ELEMENT_NODE = element.ELEMENT_NODE for child in element.childNodes: if child.nodeType == ELEMENT_NODE: self.getMappingById(None, depth, child, mapping, level) return mapping def getElements(self, node, name, nsuri=None): """Return a sequence of the child elements of the given node that match the given name and optional namespace uri.""" nsmatch = self.nsUriMatch result = [] ELEMENT_NODE = node.ELEMENT_NODE for child in node.childNodes: if child.nodeType == ELEMENT_NODE: if ((child.localName == name or name is None) and ( (nsuri is None) or nsmatch(child.namespaceURI, nsuri))): result.append(child) return result def hasAttr(self, node, name, nsuri=None): """Return true if element has attribute with the given name and optional nsuri. If nsuri is not specified, returns true if an attribute exists with the given name with any namespace.""" if nsuri is None: if node.hasAttribute(name): return True return False return node.hasAttributeNS(nsuri, name) def getAttr(self, node, name, nsuri=None, default=join): """Return the value of the attribute named 'name' with the optional nsuri, or the default if one is specified. If nsuri is not specified, an attribute that matches the given name will be returned regardless of namespace.""" if nsuri is None: result = node._attrs.get(name, None) if result is None: for item in node._attrsNS.keys(): if item[1] == name: result = node._attrsNS[item] break else: result = node._attrsNS.get((nsuri, name), None) if result is not None: return result.value if default is not join: return default return '' def getAttrs(self, node): """Return a Collection of all attributes """ attrs = {} for k,v in node._attrs.items(): attrs[k] = v.value return attrs def getElementText(self, node, preserve_ws=None): """Return the text value of an xml element node. Leading and trailing whitespace is stripped from the value unless the preserve_ws flag is passed with a true value.""" result = [] for child in node.childNodes: nodetype = child.nodeType if nodetype == child.TEXT_NODE or \ nodetype == child.CDATA_SECTION_NODE: result.append(child.nodeValue) value = join(result, '') if preserve_ws is None: value = strip(value) return value def findNamespaceURI(self, prefix, node): """Find a namespace uri given a prefix and a context node.""" attrkey = (self.NS_XMLNS, prefix) DOCUMENT_NODE = node.DOCUMENT_NODE ELEMENT_NODE = node.ELEMENT_NODE while 1: if node is None: raise DOMException('Value for prefix %s not found.' % prefix) if node.nodeType != ELEMENT_NODE: node = node.parentNode continue result = node._attrsNS.get(attrkey, None) if result is not None: return result.value if hasattr(node, '__imported__'): raise DOMException('Value for prefix %s not found.' % prefix) node = node.parentNode if node.nodeType == DOCUMENT_NODE: raise DOMException('Value for prefix %s not found.' % prefix) def findDefaultNS(self, node): """Return the current default namespace uri for the given node.""" attrkey = (self.NS_XMLNS, 'xmlns') DOCUMENT_NODE = node.DOCUMENT_NODE ELEMENT_NODE = node.ELEMENT_NODE while 1: if node.nodeType != ELEMENT_NODE: node = node.parentNode continue result = node._attrsNS.get(attrkey, None) if result is not None: return result.value if hasattr(node, '__imported__'): raise DOMException('Cannot determine default namespace.') node = node.parentNode if node.nodeType == DOCUMENT_NODE: raise DOMException('Cannot determine default namespace.') def findTargetNS(self, node): """Return the defined target namespace uri for the given node.""" attrget = self.getAttr attrkey = (self.NS_XMLNS, 'xmlns') DOCUMENT_NODE = node.DOCUMENT_NODE ELEMENT_NODE = node.ELEMENT_NODE while 1: if node.nodeType != ELEMENT_NODE: node = node.parentNode continue result = attrget(node, 'targetNamespace', default=None) if result is not None: return result node = node.parentNode if node.nodeType == DOCUMENT_NODE: raise DOMException('Cannot determine target namespace.') def getTypeRef(self, element): """Return (namespaceURI, name) for a type attribue of the given element, or None if the element does not have a type attribute.""" typeattr = self.getAttr(element, 'type', default=None) if typeattr is None: return None parts = typeattr.split(':', 1) if len(parts) == 2: nsuri = self.findNamespaceURI(parts[0], element) else: nsuri = self.findDefaultNS(element) return (nsuri, parts[1]) def importNode(self, document, node, deep=0): """Implements (well enough for our purposes) DOM node import.""" nodetype = node.nodeType if nodetype in (node.DOCUMENT_NODE, node.DOCUMENT_TYPE_NODE): raise DOMException('Illegal node type for importNode') if nodetype == node.ENTITY_REFERENCE_NODE: deep = 0 clone = node.cloneNode(deep) self._setOwnerDoc(document, clone) clone.__imported__ = 1 return clone def _setOwnerDoc(self, document, node): node.ownerDocument = document for child in node.childNodes: self._setOwnerDoc(document, child) def nsUriMatch(self, value, wanted, strict=0, tt=type(())): """Return a true value if two namespace uri values match.""" if value == wanted or (type(wanted) is tt) and value in wanted: return 1 if not strict: wanted = type(wanted) is tt and wanted or (wanted,) value = value[-1:] != '/' and value or value[:-1] for item in wanted: if item == value or item[:-1] == value: return 1 return 0 def createDocument(self, nsuri, qname, doctype=None): """Create a new writable DOM document object.""" impl = xml.dom.minidom.getDOMImplementation() return impl.createDocument(nsuri, qname, doctype) def loadDocument(self, data): """Load an xml file from a file-like object and return a DOM document instance.""" return xml.dom.minidom.parse(data) def loadFromURL(self, url): """Load an xml file from a URL and return a DOM document.""" if isfile(url) is True: file = open(url, 'r') else: file = urlopen(url) try: result = self.loadDocument(file) except Exception, ex: file.close() raise ParseError(('Failed to load document %s' %url,) + ex.args) else: file.close() return result DOM = DOM() class MessageInterface: '''Higher Level Interface, delegates to DOM singleton, must be subclassed and implement all methods that throw NotImplementedError. ''' def __init__(self, sw): '''Constructor, May be extended, do not override. sw -- soapWriter instance ''' self.sw = None if type(sw) != weakref.ReferenceType and sw is not None: self.sw = weakref.ref(sw) else: self.sw = sw def AddCallback(self, func, *arglist): self.sw().AddCallback(func, *arglist) def Known(self, obj): return self.sw().Known(obj) def Forget(self, obj): return self.sw().Forget(obj) def canonicalize(self): '''canonicalize the underlying DOM, and return as string. ''' raise NotImplementedError, '' def createDocument(self, namespaceURI=SOAP.ENV, localName='Envelope'): '''create Document ''' raise NotImplementedError, '' def createAppendElement(self, namespaceURI, localName): '''create and append element(namespaceURI,localName), and return the node. ''' raise NotImplementedError, '' def findNamespaceURI(self, qualifiedName): raise NotImplementedError, '' def resolvePrefix(self, prefix): raise NotImplementedError, '' def setAttributeNS(self, namespaceURI, localName, value): '''set attribute (namespaceURI, localName)=value ''' raise NotImplementedError, '' def setAttributeType(self, namespaceURI, localName): '''set attribute xsi:type=(namespaceURI, localName) ''' raise NotImplementedError, '' def setNamespaceAttribute(self, namespaceURI, prefix): '''set namespace attribute xmlns:prefix=namespaceURI ''' raise NotImplementedError, '' class ElementProxy(Base, MessageInterface): ''' ''' _soap_env_prefix = 'SOAP-ENV' _soap_enc_prefix = 'SOAP-ENC' _zsi_prefix = 'ZSI' _xsd_prefix = 'xsd' _xsi_prefix = 'xsi' _xml_prefix = 'xml' _xmlns_prefix = 'xmlns' _soap_env_nsuri = SOAP.ENV _soap_enc_nsuri = SOAP.ENC _zsi_nsuri = ZSI_SCHEMA_URI _xsd_nsuri = SCHEMA.XSD3 _xsi_nsuri = SCHEMA.XSI3 _xml_nsuri = XMLNS.XML _xmlns_nsuri = XMLNS.BASE standard_ns = {\ _xml_prefix:_xml_nsuri, _xmlns_prefix:_xmlns_nsuri } reserved_ns = {\ _soap_env_prefix:_soap_env_nsuri, _soap_enc_prefix:_soap_enc_nsuri, _zsi_prefix:_zsi_nsuri, _xsd_prefix:_xsd_nsuri, _xsi_prefix:_xsi_nsuri, } name = None namespaceURI = None def __init__(self, sw, message=None): '''Initialize. sw -- SoapWriter ''' self._indx = 0 MessageInterface.__init__(self, sw) Base.__init__(self) self._dom = DOM self.node = None if type(message) in (types.StringType,types.UnicodeType): self.loadFromString(message) elif isinstance(message, ElementProxy): self.node = message._getNode() else: self.node = message self.processorNss = self.standard_ns.copy() self.processorNss.update(self.reserved_ns) def __str__(self): return self.toString() def evaluate(self, expression, processorNss=None): '''expression -- XPath compiled expression ''' from Ft.Xml import XPath if not processorNss: context = XPath.Context.Context(self.node, processorNss=self.processorNss) else: context = XPath.Context.Context(self.node, processorNss=processorNss) nodes = expression.evaluate(context) return map(lambda node: ElementProxy(self.sw,node), nodes) ############################################# # Methods for checking/setting the # classes (namespaceURI,name) node. ############################################# def checkNode(self, namespaceURI=None, localName=None): ''' namespaceURI -- namespace of element localName -- local name of element ''' namespaceURI = namespaceURI or self.namespaceURI localName = localName or self.name check = False if localName and self.node: check = self._dom.isElement(self.node, localName, namespaceURI) if not check: raise NamespaceError, 'unexpected node type %s, expecting %s' %(self.node, localName) def setNode(self, node=None): if node: if isinstance(node, ElementProxy): self.node = node._getNode() else: self.node = node elif self.node: node = self._dom.getElement(self.node, self.name, self.namespaceURI, default=None) if not node: raise NamespaceError, 'cant find element (%s,%s)' %(self.namespaceURI,self.name) self.node = node else: #self.node = self._dom.create(self.node, self.name, self.namespaceURI, default=None) self.createDocument(self.namespaceURI, localName=self.name, doctype=None) self.checkNode() ############################################# # Wrapper Methods for direct DOM Element Node access ############################################# def _getNode(self): return self.node def _getElements(self): return self._dom.getElements(self.node, name=None) def _getOwnerDocument(self): return self.node.ownerDocument or self.node def _getUniquePrefix(self): '''I guess we need to resolve all potential prefixes because when the current node is attached it copies the namespaces into the parent node. ''' while 1: self._indx += 1 prefix = 'ns%d' %self._indx try: self._dom.findNamespaceURI(prefix, self._getNode()) except DOMException, ex: break return prefix def _getPrefix(self, node, nsuri): ''' Keyword arguments: node -- DOM Element Node nsuri -- namespace of attribute value ''' try: if node and (node.nodeType == node.ELEMENT_NODE) and \ (nsuri == self._dom.findDefaultNS(node)): return None except DOMException, ex: pass if nsuri == XMLNS.XML: return self._xml_prefix if node.nodeType == Node.ELEMENT_NODE: for attr in node.attributes.values(): if attr.namespaceURI == XMLNS.BASE \ and nsuri == attr.value: return attr.localName else: if node.parentNode: return self._getPrefix(node.parentNode, nsuri) raise NamespaceError, 'namespaceURI "%s" is not defined' %nsuri def _appendChild(self, node): ''' Keyword arguments: node -- DOM Element Node ''' if node is None: raise TypeError, 'node is None' self.node.appendChild(node) def _insertBefore(self, newChild, refChild): ''' Keyword arguments: child -- DOM Element Node to insert refChild -- DOM Element Node ''' self.node.insertBefore(newChild, refChild) def _setAttributeNS(self, namespaceURI, qualifiedName, value): ''' Keyword arguments: namespaceURI -- namespace of attribute qualifiedName -- qualified name of new attribute value value -- value of attribute ''' self.node.setAttributeNS(namespaceURI, qualifiedName, value) ############################################# #General Methods ############################################# def isFault(self): '''check to see if this is a soap:fault message. ''' return False def getPrefix(self, namespaceURI): try: prefix = self._getPrefix(node=self.node, nsuri=namespaceURI) except NamespaceError, ex: prefix = self._getUniquePrefix() self.setNamespaceAttribute(prefix, namespaceURI) return prefix def getDocument(self): return self._getOwnerDocument() def setDocument(self, document): self.node = document def importFromString(self, xmlString): doc = self._dom.loadDocument(StringIO(xmlString)) node = self._dom.getElement(doc, name=None) clone = self.importNode(node) self._appendChild(clone) def importNode(self, node): if isinstance(node, ElementProxy): node = node._getNode() return self._dom.importNode(self._getOwnerDocument(), node, deep=1) def loadFromString(self, data): self.node = self._dom.loadDocument(StringIO(data)) def canonicalize(self): return Canonicalize(self.node) def toString(self): return self.canonicalize() def createDocument(self, namespaceURI, localName, doctype=None): '''If specified must be a SOAP envelope, else may contruct an empty document. ''' prefix = self._soap_env_prefix if namespaceURI == self.reserved_ns[prefix]: qualifiedName = '%s:%s' %(prefix,localName) elif namespaceURI is localName is None: self.node = self._dom.createDocument(None,None,None) return else: raise KeyError, 'only support creation of document in %s' %self.reserved_ns[prefix] document = self._dom.createDocument(nsuri=namespaceURI, qname=qualifiedName, doctype=doctype) self.node = document.childNodes[0] #set up reserved namespace attributes for prefix,nsuri in self.reserved_ns.items(): self._setAttributeNS(namespaceURI=self._xmlns_nsuri, qualifiedName='%s:%s' %(self._xmlns_prefix,prefix), value=nsuri) ############################################# #Methods for attributes ############################################# def hasAttribute(self, namespaceURI, localName): return self._dom.hasAttr(self._getNode(), name=localName, nsuri=namespaceURI) def setAttributeType(self, namespaceURI, localName): '''set xsi:type Keyword arguments: namespaceURI -- namespace of attribute value localName -- name of new attribute value ''' self.logger.debug('setAttributeType: (%s,%s)', namespaceURI, localName) value = localName if namespaceURI: value = '%s:%s' %(self.getPrefix(namespaceURI),localName) xsi_prefix = self.getPrefix(self._xsi_nsuri) self._setAttributeNS(self._xsi_nsuri, '%s:type' %xsi_prefix, value) def createAttributeNS(self, namespace, name, value): document = self._getOwnerDocument() attrNode = document.createAttributeNS(namespace, name, value) def setAttributeNS(self, namespaceURI, localName, value): ''' Keyword arguments: namespaceURI -- namespace of attribute to create, None is for attributes in no namespace. localName -- local name of new attribute value -- value of new attribute ''' prefix = None if namespaceURI: try: prefix = self.getPrefix(namespaceURI) except KeyError, ex: prefix = 'ns2' self.setNamespaceAttribute(prefix, namespaceURI) qualifiedName = localName if prefix: qualifiedName = '%s:%s' %(prefix, localName) self._setAttributeNS(namespaceURI, qualifiedName, value) def setNamespaceAttribute(self, prefix, namespaceURI): ''' Keyword arguments: prefix -- xmlns prefix namespaceURI -- value of prefix ''' self._setAttributeNS(XMLNS.BASE, 'xmlns:%s' %prefix, namespaceURI) ############################################# #Methods for elements ############################################# def createElementNS(self, namespace, qname): ''' Keyword arguments: namespace -- namespace of element to create qname -- qualified name of new element ''' document = self._getOwnerDocument() node = document.createElementNS(namespace, qname) return ElementProxy(self.sw, node) def createAppendSetElement(self, namespaceURI, localName, prefix=None): '''Create a new element (namespaceURI,name), append it to current node, then set it to be the current node. Keyword arguments: namespaceURI -- namespace of element to create localName -- local name of new element prefix -- if namespaceURI is not defined, declare prefix. defaults to 'ns1' if left unspecified. ''' node = self.createAppendElement(namespaceURI, localName, prefix=None) node=node._getNode() self._setNode(node._getNode()) def createAppendElement(self, namespaceURI, localName, prefix=None): '''Create a new element (namespaceURI,name), append it to current node, and return the newly created node. Keyword arguments: namespaceURI -- namespace of element to create localName -- local name of new element prefix -- if namespaceURI is not defined, declare prefix. defaults to 'ns1' if left unspecified. ''' declare = False qualifiedName = localName if namespaceURI: try: prefix = self.getPrefix(namespaceURI) except: declare = True prefix = prefix or self._getUniquePrefix() if prefix: qualifiedName = '%s:%s' %(prefix, localName) node = self.createElementNS(namespaceURI, qualifiedName) if declare: node._setAttributeNS(XMLNS.BASE, 'xmlns:%s' %prefix, namespaceURI) self._appendChild(node=node._getNode()) return node def createInsertBefore(self, namespaceURI, localName, refChild): qualifiedName = localName prefix = self.getPrefix(namespaceURI) if prefix: qualifiedName = '%s:%s' %(prefix, localName) node = self.createElementNS(namespaceURI, qualifiedName) self._insertBefore(newChild=node._getNode(), refChild=refChild._getNode()) return node def getElement(self, namespaceURI, localName): ''' Keyword arguments: namespaceURI -- namespace of element localName -- local name of element ''' node = self._dom.getElement(self.node, localName, namespaceURI, default=None) if node: return ElementProxy(self.sw, node) return None def getAttributeValue(self, namespaceURI, localName): ''' Keyword arguments: namespaceURI -- namespace of attribute localName -- local name of attribute ''' if self.hasAttribute(namespaceURI, localName): attr = self.node.getAttributeNodeNS(namespaceURI,localName) return attr.value return None def getValue(self): return self._dom.getElementText(self.node, preserve_ws=True) ############################################# #Methods for text nodes ############################################# def createAppendTextNode(self, pyobj): node = self.createTextNode(pyobj) self._appendChild(node=node._getNode()) return node def createTextNode(self, pyobj): document = self._getOwnerDocument() node = document.createTextNode(pyobj) return ElementProxy(self.sw, node) ############################################# #Methods for retrieving namespaceURI's ############################################# def findNamespaceURI(self, qualifiedName): parts = SplitQName(qualifiedName) element = self._getNode() if len(parts) == 1: return (self._dom.findTargetNS(element), value) return self._dom.findNamespaceURI(parts[0], element) def resolvePrefix(self, prefix): element = self._getNode() return self._dom.findNamespaceURI(prefix, element) def getSOAPEnvURI(self): return self._soap_env_nsuri def isEmpty(self): return not self.node class Collection(UserDict): """Helper class for maintaining ordered named collections.""" default = lambda self,k: k.name def __init__(self, parent, key=None): UserDict.__init__(self) self.parent = weakref.ref(parent) self.list = [] self._func = key or self.default def __getitem__(self, key): if type(key) is type(1): return self.list[key] return self.data[key] def __setitem__(self, key, item): item.parent = weakref.ref(self) self.list.append(item) self.data[key] = item def keys(self): return map(lambda i: self._func(i), self.list) def items(self): return map(lambda i: (self._func(i), i), self.list) def values(self): return self.list class CollectionNS(UserDict): """Helper class for maintaining ordered named collections.""" default = lambda self,k: k.name def __init__(self, parent, key=None): UserDict.__init__(self) self.parent = weakref.ref(parent) self.targetNamespace = None self.list = [] self._func = key or self.default def __getitem__(self, key): self.targetNamespace = self.parent().targetNamespace if type(key) is types.IntType: return self.list[key] elif self.__isSequence(key): nsuri,name = key return self.data[nsuri][name] return self.data[self.parent().targetNamespace][key] def __setitem__(self, key, item): item.parent = weakref.ref(self) self.list.append(item) targetNamespace = getattr(item, 'targetNamespace', self.parent().targetNamespace) if not self.data.has_key(targetNamespace): self.data[targetNamespace] = {} self.data[targetNamespace][key] = item def __isSequence(self, key): return (type(key) in (types.TupleType,types.ListType) and len(key) == 2) def keys(self): keys = [] for tns in self.data.keys(): keys.append(map(lambda i: (tns,self._func(i)), self.data[tns].values())) return keys def items(self): return map(lambda i: (self._func(i), i), self.list) def values(self): return self.list # This is a runtime guerilla patch for pulldom (used by minidom) so # that xml namespace declaration attributes are not lost in parsing. # We need them to do correct QName linking for XML Schema and WSDL. # The patch has been submitted to SF for the next Python version. from xml.dom.pulldom import PullDOM, START_ELEMENT if 1: def startPrefixMapping(self, prefix, uri): if not hasattr(self, '_xmlns_attrs'): self._xmlns_attrs = [] self._xmlns_attrs.append((prefix or 'xmlns', uri)) self._ns_contexts.append(self._current_context.copy()) self._current_context[uri] = prefix or '' PullDOM.startPrefixMapping = startPrefixMapping def startElementNS(self, name, tagName , attrs): # Retrieve xml namespace declaration attributes. xmlns_uri = 'http://www.w3.org/2000/xmlns/' xmlns_attrs = getattr(self, '_xmlns_attrs', None) if xmlns_attrs is not None: for aname, value in xmlns_attrs: attrs._attrs[(xmlns_uri, aname)] = value self._xmlns_attrs = [] uri, localname = name if uri: # When using namespaces, the reader may or may not # provide us with the original name. If not, create # *a* valid tagName from the current context. if tagName is None: prefix = self._current_context[uri] if prefix: tagName = prefix + ":" + localname else: tagName = localname if self.document: node = self.document.createElementNS(uri, tagName) else: node = self.buildDocument(uri, tagName) else: # When the tagname is not prefixed, it just appears as # localname if self.document: node = self.document.createElement(localname) else: node = self.buildDocument(None, localname) for aname,value in attrs.items(): a_uri, a_localname = aname if a_uri == xmlns_uri: if a_localname == 'xmlns': qname = a_localname else: qname = 'xmlns:' + a_localname attr = self.document.createAttributeNS(a_uri, qname) node.setAttributeNodeNS(attr) elif a_uri: prefix = self._current_context[a_uri] if prefix: qname = prefix + ":" + a_localname else: qname = a_localname attr = self.document.createAttributeNS(a_uri, qname) node.setAttributeNodeNS(attr) else: attr = self.document.createAttribute(a_localname) node.setAttributeNode(attr) attr.value = value self.lastEvent[1] = [(START_ELEMENT, node), None] self.lastEvent = self.lastEvent[1] self.push(node) PullDOM.startElementNS = startElementNS # # This is a runtime guerilla patch for minidom so # that xmlns prefixed attributes dont raise AttributeErrors # during cloning. # # Namespace declarations can appear in any start-tag, must look for xmlns # prefixed attribute names during cloning. # # key (attr.namespaceURI, tag) # ('http://www.w3.org/2000/xmlns/', u'xsd') # ('http://www.w3.org/2000/xmlns/', 'xmlns') # # xml.dom.minidom.Attr.nodeName = xmlns:xsd # xml.dom.minidom.Attr.value = = http://www.w3.org/2001/XMLSchema if 1: def _clone_node(node, deep, newOwnerDocument): """ Clone a node and give it the new owner document. Called by Node.cloneNode and Document.importNode """ if node.ownerDocument.isSameNode(newOwnerDocument): operation = xml.dom.UserDataHandler.NODE_CLONED else: operation = xml.dom.UserDataHandler.NODE_IMPORTED if node.nodeType == xml.dom.minidom.Node.ELEMENT_NODE: clone = newOwnerDocument.createElementNS(node.namespaceURI, node.nodeName) for attr in node.attributes.values(): clone.setAttributeNS(attr.namespaceURI, attr.nodeName, attr.value) prefix, tag = xml.dom.minidom._nssplit(attr.nodeName) if prefix == 'xmlns': a = clone.getAttributeNodeNS(attr.namespaceURI, tag) elif prefix: a = clone.getAttributeNodeNS(attr.namespaceURI, tag) else: a = clone.getAttributeNodeNS(attr.namespaceURI, attr.nodeName) a.specified = attr.specified if deep: for child in node.childNodes: c = xml.dom.minidom._clone_node(child, deep, newOwnerDocument) clone.appendChild(c) elif node.nodeType == xml.dom.minidom.Node.DOCUMENT_FRAGMENT_NODE: clone = newOwnerDocument.createDocumentFragment() if deep: for child in node.childNodes: c = xml.dom.minidom._clone_node(child, deep, newOwnerDocument) clone.appendChild(c) elif node.nodeType == xml.dom.minidom.Node.TEXT_NODE: clone = newOwnerDocument.createTextNode(node.data) elif node.nodeType == xml.dom.minidom.Node.CDATA_SECTION_NODE: clone = newOwnerDocument.createCDATASection(node.data) elif node.nodeType == xml.dom.minidom.Node.PROCESSING_INSTRUCTION_NODE: clone = newOwnerDocument.createProcessingInstruction(node.target, node.data) elif node.nodeType == xml.dom.minidom.Node.COMMENT_NODE: clone = newOwnerDocument.createComment(node.data) elif node.nodeType == xml.dom.minidom.Node.ATTRIBUTE_NODE: clone = newOwnerDocument.createAttributeNS(node.namespaceURI, node.nodeName) clone.specified = True clone.value = node.value elif node.nodeType == xml.dom.minidom.Node.DOCUMENT_TYPE_NODE: assert node.ownerDocument is not newOwnerDocument operation = xml.dom.UserDataHandler.NODE_IMPORTED clone = newOwnerDocument.implementation.createDocumentType( node.name, node.publicId, node.systemId) clone.ownerDocument = newOwnerDocument if deep: clone.entities._seq = [] clone.notations._seq = [] for n in node.notations._seq: notation = xml.dom.minidom.Notation(n.nodeName, n.publicId, n.systemId) notation.ownerDocument = newOwnerDocument clone.notations._seq.append(notation) if hasattr(n, '_call_user_data_handler'): n._call_user_data_handler(operation, n, notation) for e in node.entities._seq: entity = xml.dom.minidom.Entity(e.nodeName, e.publicId, e.systemId, e.notationName) entity.actualEncoding = e.actualEncoding entity.encoding = e.encoding entity.version = e.version entity.ownerDocument = newOwnerDocument clone.entities._seq.append(entity) if hasattr(e, '_call_user_data_handler'): e._call_user_data_handler(operation, n, entity) else: # Note the cloning of Document and DocumentType nodes is # implemenetation specific. minidom handles those cases # directly in the cloneNode() methods. raise xml.dom.NotSupportedErr("Cannot clone node %s" % repr(node)) # Check for _call_user_data_handler() since this could conceivably # used with other DOM implementations (one of the FourThought # DOMs, perhaps?). if hasattr(node, '_call_user_data_handler'): node._call_user_data_handler(operation, node, clone) return clone xml.dom.minidom._clone_node = _clone_node SOAPpy-0.12.0/SOAPpy/wstools/WSDLTools.py0100755001604000501700000016200110202425136017516 0ustar warnegclinical# Copyright (c) 2001 Zope Corporation and Contributors. All Rights Reserved. # # This software is subject to the provisions of the Zope Public License, # Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. # THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED # WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED # WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS # FOR A PARTICULAR PURPOSE. ident = "$Id: WSDLTools.py,v 1.32 2005/02/07 17:07:31 irjudson Exp $" import urllib, weakref from cStringIO import StringIO from Namespaces import OASIS, XMLNS, WSA200408, WSA200403, WSA200303 from Utility import Collection, CollectionNS, DOM, ElementProxy from XMLSchema import XMLSchema, SchemaReader, WSDLToolsAdapter class WSDLReader: """A WSDLReader creates WSDL instances from urls and xml data.""" # Custom subclasses of WSDLReader may wish to implement a caching # strategy or other optimizations. Because application needs vary # so widely, we don't try to provide any caching by default. def loadFromStream(self, stream, name=None): """Return a WSDL instance loaded from a stream object.""" document = DOM.loadDocument(stream) wsdl = WSDL() if name: wsdl.location = name elif hasattr(stream, 'name'): wsdl.location = stream.name wsdl.load(document) return wsdl def loadFromURL(self, url): """Return a WSDL instance loaded from the given url.""" document = DOM.loadFromURL(url) wsdl = WSDL() wsdl.location = url wsdl.load(document) return wsdl def loadFromString(self, data): """Return a WSDL instance loaded from an xml string.""" return self.loadFromStream(StringIO(data)) def loadFromFile(self, filename): """Return a WSDL instance loaded from the given file.""" file = open(filename, 'rb') try: wsdl = self.loadFromStream(file) finally: file.close() return wsdl class WSDL: """A WSDL object models a WSDL service description. WSDL objects may be created manually or loaded from an xml representation using a WSDLReader instance.""" def __init__(self, targetNamespace=None, strict=1): self.targetNamespace = targetNamespace or 'urn:this-document.wsdl' self.documentation = '' self.location = None self.document = None self.name = None self.services = CollectionNS(self) self.messages = CollectionNS(self) self.portTypes = CollectionNS(self) self.bindings = CollectionNS(self) self.imports = Collection(self) self.types = Types(self) self.extensions = [] self.strict = strict def __del__(self): if self.document is not None: self.document.unlink() version = '1.1' def addService(self, name, documentation='', targetNamespace=None): if self.services.has_key(name): raise WSDLError( 'Duplicate service element: %s' % name ) item = Service(name, documentation) if targetNamespace: item.targetNamespace = targetNamespace self.services[name] = item return item def addMessage(self, name, documentation='', targetNamespace=None): if self.messages.has_key(name): raise WSDLError( 'Duplicate message element: %s.' % name ) item = Message(name, documentation) if targetNamespace: item.targetNamespace = targetNamespace self.messages[name] = item return item def addPortType(self, name, documentation='', targetNamespace=None): if self.portTypes.has_key(name): raise WSDLError( 'Duplicate portType element: name' ) item = PortType(name, documentation) if targetNamespace: item.targetNamespace = targetNamespace self.portTypes[name] = item return item def addBinding(self, name, type, documentation='', targetNamespace=None): if self.bindings.has_key(name): raise WSDLError( 'Duplicate binding element: %s' % name ) item = Binding(name, type, documentation) if targetNamespace: item.targetNamespace = targetNamespace self.bindings[name] = item return item def addImport(self, namespace, location): item = ImportElement(namespace, location) self.imports[namespace] = item return item def toDom(self): """ Generate a DOM representation of the WSDL instance. Not dealing with generating XML Schema, thus the targetNamespace of all XML Schema elements or types used by WSDL message parts needs to be specified via import information items. """ namespaceURI = DOM.GetWSDLUri(self.version) self.document = DOM.createDocument(namespaceURI ,'wsdl:definitions') # Set up a couple prefixes for easy reading. child = DOM.getElement(self.document, None) child.setAttributeNS(None, 'targetNamespace', self.targetNamespace) child.setAttributeNS(XMLNS.BASE, 'xmlns:wsdl', namespaceURI) child.setAttributeNS(XMLNS.BASE, 'xmlns:xsd', 'http://www.w3.org/1999/XMLSchema') child.setAttributeNS(XMLNS.BASE, 'xmlns:soap', 'http://schemas.xmlsoap.org/wsdl/soap/') child.setAttributeNS(XMLNS.BASE, 'xmlns:tns', self.targetNamespace) # wsdl:import for item in self.imports: item.toDom() # wsdl:message for item in self.messages: item.toDom() # wsdl:portType for item in self.portTypes: item.toDom() # wsdl:binding for item in self.bindings: item.toDom() # wsdl:service for item in self.services: item.toDom() def load(self, document): # We save a reference to the DOM document to ensure that elements # saved as "extensions" will continue to have a meaningful context # for things like namespace references. The lifetime of the DOM # document is bound to the lifetime of the WSDL instance. self.document = document definitions = DOM.getElement(document, 'definitions', None, None) if definitions is None: raise WSDLError( 'Missing element.' ) self.version = DOM.WSDLUriToVersion(definitions.namespaceURI) NS_WSDL = DOM.GetWSDLUri(self.version) self.targetNamespace = DOM.getAttr(definitions, 'targetNamespace', None, None) self.name = DOM.getAttr(definitions, 'name', None, None) self.documentation = GetDocumentation(definitions) # Resolve (recursively) any import elements in the document. imported = {} base_location = self.location while len(DOM.getElements(definitions, 'import', NS_WSDL)): for element in DOM.getElements(definitions, 'import', NS_WSDL): location = DOM.getAttr(element, 'location') location = urllib.basejoin(base_location, location) self._import(self.document, element, base_location) #reader = SchemaReader(base_url=self.location) for element in DOM.getElements(definitions, None, None): targetNamespace = DOM.getAttr(element, 'targetNamespace') localName = element.localName if not DOM.nsUriMatch(element.namespaceURI, NS_WSDL): if localName == 'schema': reader = SchemaReader(base_url=self.location) schema = reader.loadFromNode(WSDLToolsAdapter(self), element) schema.setBaseUrl(self.location) self.types.addSchema(schema) else: self.extensions.append(element) continue elif localName == 'message': name = DOM.getAttr(element, 'name') docs = GetDocumentation(element) message = self.addMessage(name, docs, targetNamespace) parts = DOM.getElements(element, 'part', NS_WSDL) message.load(parts) continue elif localName == 'portType': name = DOM.getAttr(element, 'name') docs = GetDocumentation(element) ptype = self.addPortType(name, docs, targetNamespace) #operations = DOM.getElements(element, 'operation', NS_WSDL) #ptype.load(operations) ptype.load(element) continue elif localName == 'binding': name = DOM.getAttr(element, 'name') type = DOM.getAttr(element, 'type', default=None) if type is None: raise WSDLError( 'Missing type attribute for binding %s.' % name ) type = ParseQName(type, element) docs = GetDocumentation(element) binding = self.addBinding(name, type, docs, targetNamespace) operations = DOM.getElements(element, 'operation', NS_WSDL) binding.load(operations) binding.load_ex(GetExtensions(element)) continue elif localName == 'service': name = DOM.getAttr(element, 'name') docs = GetDocumentation(element) service = self.addService(name, docs, targetNamespace) ports = DOM.getElements(element, 'port', NS_WSDL) service.load(ports) service.load_ex(GetExtensions(element)) continue elif localName == 'types': self.types.documentation = GetDocumentation(element) base_location = DOM.getAttr(element, 'base-location') if base_location: element.removeAttribute('base-location') base_location = base_location or self.location reader = SchemaReader(base_url=base_location) for item in DOM.getElements(element, None, None): if item.localName == 'schema': schema = reader.loadFromNode(WSDLToolsAdapter(self), item) # XXX could have been imported #schema.setBaseUrl(self.location) schema.setBaseUrl(base_location) self.types.addSchema(schema) else: self.types.addExtension(item) # XXX remove the attribute # element.removeAttribute('base-location') continue def _import(self, document, element, base_location=None): '''Algo take element's children, clone them, and add them to the main document. Support for relative locations is a bit complicated. The orig document context is lost, so we need to store base location in DOM elements representing , by creating a special temporary "base-location" attribute, and , by resolving the relative "location" and storing it as "location". document -- document we are loading element -- DOM Element representing base_location -- location of document from which this was gleaned. ''' namespace = DOM.getAttr(element, 'namespace', default=None) location = DOM.getAttr(element, 'location', default=None) if namespace is None or location is None: raise WSDLError( 'Invalid import element (missing namespace or location).' ) if base_location: location = urllib.basejoin(base_location, location) element.setAttributeNS(None, 'location', location) obimport = self.addImport(namespace, location) obimport._loaded = 1 importdoc = DOM.loadFromURL(location) try: if location.find('#') > -1: idref = location.split('#')[-1] imported = DOM.getElementById(importdoc, idref) else: imported = importdoc.documentElement if imported is None: raise WSDLError( 'Import target element not found for: %s' % location ) imported_tns = DOM.findTargetNS(imported) if imported_tns != namespace: return if imported.localName == 'definitions': imported_nodes = imported.childNodes else: imported_nodes = [imported] parent = element.parentNode parent.removeChild(element) for node in imported_nodes: if node.nodeType != node.ELEMENT_NODE: continue child = DOM.importNode(document, node, 1) parent.appendChild(child) child.setAttribute('targetNamespace', namespace) attrsNS = imported._attrsNS for attrkey in attrsNS.keys(): if attrkey[0] == DOM.NS_XMLNS: attr = attrsNS[attrkey].cloneNode(1) child.setAttributeNode(attr) #XXX Quick Hack, should be in WSDL Namespace. if child.localName == 'import': rlocation = child.getAttributeNS(None, 'location') alocation = urllib.basejoin(location, rlocation) child.setAttribute('location', alocation) elif child.localName == 'types': child.setAttribute('base-location', location) finally: importdoc.unlink() return location class Element: """A class that provides common functions for WSDL element classes.""" def __init__(self, name=None, documentation=''): self.name = name self.documentation = documentation self.extensions = [] def addExtension(self, item): item.parent = weakref.ref(self) self.extensions.append(item) class ImportElement(Element): def __init__(self, namespace, location): self.namespace = namespace self.location = location def getWSDL(self): """Return the WSDL object that contains this Message Part.""" return self.parent().parent() def toDom(self): wsdl = self.getWSDL() ep = ElementProxy(None, DOM.getElement(wsdl.document, None)) epc = ep.createAppendElement(DOM.GetWSDLUri(wsdl.version), 'import') epc.setAttributeNS(None, 'namespace', self.namespace) epc.setAttributeNS(None, 'location', self.location) _loaded = None class Types(Collection): default = lambda self,k: k.targetNamespace def __init__(self, parent): Collection.__init__(self, parent) self.documentation = '' self.extensions = [] def addSchema(self, schema): name = schema.targetNamespace self[name] = schema return schema def addExtension(self, item): self.extensions.append(item) class Message(Element): def __init__(self, name, documentation=''): Element.__init__(self, name, documentation) self.parts = Collection(self) def addPart(self, name, type=None, element=None): if self.parts.has_key(name): raise WSDLError( 'Duplicate message part element: %s' % name ) if type is None and element is None: raise WSDLError( 'Missing type or element attribute for part: %s' % name ) item = MessagePart(name) item.element = element item.type = type self.parts[name] = item return item def load(self, elements): for element in elements: name = DOM.getAttr(element, 'name') part = MessagePart(name) self.parts[name] = part elemref = DOM.getAttr(element, 'element', default=None) typeref = DOM.getAttr(element, 'type', default=None) if typeref is None and elemref is None: raise WSDLError( 'No type or element attribute for part: %s' % name ) if typeref is not None: part.type = ParseTypeRef(typeref, element) if elemref is not None: part.element = ParseTypeRef(elemref, element) def getElementDeclaration(self): """Return the XMLSchema.ElementDeclaration instance or None""" element = None if self.element: nsuri,name = self.element wsdl = self.getWSDL() if wsdl.types.has_key(nsuri) and wsdl.types[nsuri].elements.has_key(name): element = wsdl.types[nsuri].elements[name] return element def getTypeDefinition(self): """Return the XMLSchema.TypeDefinition instance or None""" type = None if self.type: nsuri,name = self.type wsdl = self.getWSDL() if wsdl.types.has_key(nsuri) and wsdl.types[nsuri].types.has_key(name): type = wsdl.types[nsuri].types[name] return type def getWSDL(self): """Return the WSDL object that contains this Message Part.""" return self.parent().parent() def toDom(self): wsdl = self.getWSDL() ep = ElementProxy(None, DOM.getElement(wsdl.document, None)) epc = ep.createAppendElement(DOM.GetWSDLUri(wsdl.version), 'message') epc.setAttributeNS(None, 'name', self.name) for part in self.parts: part.toDom(epc._getNode()) class MessagePart(Element): def __init__(self, name): Element.__init__(self, name, '') self.element = None self.type = None def getWSDL(self): """Return the WSDL object that contains this Message Part.""" return self.parent().parent().parent().parent() def getTypeDefinition(self): wsdl = self.getWSDL() nsuri,name = self.type schema = wsdl.types.get(nsuri, {}) return schema.get(name) def getElementDeclaration(self): wsdl = self.getWSDL() nsuri,name = self.element schema = wsdl.types.get(nsuri, {}) return schema.get(name) def toDom(self, node): """node -- node representing message""" wsdl = self.getWSDL() ep = ElementProxy(None, node) epc = ep.createAppendElement(DOM.GetWSDLUri(wsdl.version), 'part') epc.setAttributeNS(None, 'name', self.name) if self.element is not None: ns,name = self.element prefix = epc.getPrefix(ns) epc.setAttributeNS(None, 'element', '%s:%s'%(prefix,name)) elif self.type is not None: ns,name = self.type prefix = epc.getPrefix(ns) epc.setAttributeNS(None, 'type', '%s:%s'%(prefix,name)) class PortType(Element): '''PortType has a anyAttribute, thus must provide for an extensible mechanism for supporting such attributes. ResourceProperties is specified in WS-ResourceProperties. wsa:Action is specified in WS-Address. Instance Data: name -- name attribute resourceProperties -- optional. wsr:ResourceProperties attribute, value is a QName this is Parsed into a (namespaceURI, name) that represents a Global Element Declaration. operations ''' def __init__(self, name, documentation=''): Element.__init__(self, name, documentation) self.operations = Collection(self) self.resourceProperties = None def getWSDL(self): return self.parent().parent() def getTargetNamespace(self): return self.targetNamespace or self.getWSDL().targetNamespace def getResourceProperties(self): return self.resourceProperties def addOperation(self, name, documentation='', parameterOrder=None): item = Operation(name, documentation, parameterOrder) self.operations[name] = item return item def load(self, element): self.name = DOM.getAttr(element, 'name') self.documentation = GetDocumentation(element) self.targetNamespace = DOM.getAttr(element, 'targetNamespace') if DOM.hasAttr(element, 'ResourceProperties', OASIS.PROPERTIES): rpref = DOM.getAttr(element, 'ResourceProperties', OASIS.PROPERTIES) self.resourceProperties = ParseQName(rpref, element) lookfor = (WSA200408, WSA200403, WSA200303,) NS_WSDL = DOM.GetWSDLUri(self.getWSDL().version) elements = DOM.getElements(element, 'operation', NS_WSDL) for element in elements: name = DOM.getAttr(element, 'name') docs = GetDocumentation(element) param_order = DOM.getAttr(element, 'parameterOrder', default=None) if param_order is not None: param_order = param_order.split(' ') operation = self.addOperation(name, docs, param_order) item = DOM.getElement(element, 'input', None, None) if item is not None: name = DOM.getAttr(item, 'name') docs = GetDocumentation(item) msgref = DOM.getAttr(item, 'message') message = ParseQName(msgref, item) for WSA in lookfor: action = DOM.getAttr(item, 'Action', WSA.ADDRESS, None) if action: break operation.setInput(message, name, docs, action) item = DOM.getElement(element, 'output', None, None) if item is not None: name = DOM.getAttr(item, 'name') docs = GetDocumentation(item) msgref = DOM.getAttr(item, 'message') message = ParseQName(msgref, item) for WSA in lookfor: action = DOM.getAttr(item, 'Action', WSA.ADDRESS, None) if action: break operation.setOutput(message, name, docs, action) for item in DOM.getElements(element, 'fault', None): name = DOM.getAttr(item, 'name') docs = GetDocumentation(item) msgref = DOM.getAttr(item, 'message') message = ParseQName(msgref, item) for WSA in lookfor: action = DOM.getAttr(item, 'Action', WSA.ADDRESS, None) if action: break operation.addFault(message, name, docs, action) def toDom(self): wsdl = self.getWSDL() ep = ElementProxy(None, DOM.getElement(wsdl.document, None)) epc = ep.createAppendElement(DOM.GetWSDLUri(wsdl.version), 'portType') epc.setAttributeNS(None, 'name', self.name) if self.resourceProperties: ns,name = self.resourceProperties prefix = epc.getPrefix(ns) epc.setAttributeNS(OASIS.PROPERTIES, 'ResourceProperties', '%s:%s'%(prefix,name)) for op in self.operations: op.toDom(epc._getNode()) class Operation(Element): def __init__(self, name, documentation='', parameterOrder=None): Element.__init__(self, name, documentation) self.parameterOrder = parameterOrder self.faults = Collection(self) self.input = None self.output = None def getWSDL(self): """Return the WSDL object that contains this Operation.""" return self.parent().parent().parent().parent() def getPortType(self): return self.parent().parent() def getInputAction(self): """wsa:Action attribute""" return GetWSAActionInput(self) def getInputMessage(self): if self.input is None: return None wsdl = self.getPortType().getWSDL() return wsdl.messages[self.input.message] def getOutputAction(self): """wsa:Action attribute""" return GetWSAActionOutput(self) def getOutputMessage(self): if self.output is None: return None wsdl = self.getPortType().getWSDL() return wsdl.messages[self.output.message] def getFaultAction(self, name): """wsa:Action attribute""" return GetWSAActionFault(self, name) def getFaultMessage(self, name): wsdl = self.getPortType().getWSDL() return wsdl.messages[self.faults[name].message] def addFault(self, message, name, documentation='', action=None): if self.faults.has_key(name): raise WSDLError( 'Duplicate fault element: %s' % name ) item = MessageRole('fault', message, name, documentation, action) self.faults[name] = item return item def setInput(self, message, name='', documentation='', action=None): self.input = MessageRole('input', message, name, documentation, action) self.input.parent = weakref.ref(self) return self.input def setOutput(self, message, name='', documentation='', action=None): self.output = MessageRole('output', message, name, documentation, action) self.output.parent = weakref.ref(self) return self.output def toDom(self, node): wsdl = self.getWSDL() ep = ElementProxy(None, node) epc = ep.createAppendElement(DOM.GetWSDLUri(wsdl.version), 'operation') epc.setAttributeNS(None, 'name', self.name) node = epc._getNode() if self.input: self.input.toDom(node) if self.output: self.output.toDom(node) for fault in self.faults: fault.toDom(node) class MessageRole(Element): def __init__(self, type, message, name='', documentation='', action=None): Element.__init__(self, name, documentation) self.message = message self.type = type self.action = action def getWSDL(self): """Return the WSDL object that contains this MessageRole.""" if self.parent().getWSDL() == 'fault': return self.parent().parent().getWSDL() return self.parent().getWSDL() def getMessage(self): """Return the WSDL object that represents the attribute message (namespaceURI, name) tuple """ wsdl = self.getWSDL() return wsdl.messages[self.message] def toDom(self, node): wsdl = self.getWSDL() ep = ElementProxy(None, node) epc = ep.createAppendElement(DOM.GetWSDLUri(wsdl.version), self.type) epc.setAttributeNS(None, 'message', self.message) if self.action: epc.setAttributeNS(WSA200408.ADDRESS, 'Action', self.action) class Binding(Element): def __init__(self, name, type, documentation=''): Element.__init__(self, name, documentation) self.operations = Collection(self) self.type = type def getWSDL(self): """Return the WSDL object that contains this binding.""" return self.parent().parent() def getPortType(self): """Return the PortType object associated with this binding.""" return self.getWSDL().portTypes[self.type] def findBinding(self, kind): for item in self.extensions: if isinstance(item, kind): return item return None def findBindings(self, kind): return [ item for item in self.extensions if isinstance(item, kind) ] def addOperationBinding(self, name, documentation=''): item = OperationBinding(name, documentation) self.operations[name] = item return item def load(self, elements): for element in elements: name = DOM.getAttr(element, 'name') docs = GetDocumentation(element) opbinding = self.addOperationBinding(name, docs) opbinding.load_ex(GetExtensions(element)) item = DOM.getElement(element, 'input', None, None) if item is not None: mbinding = MessageRoleBinding('input') mbinding.documentation = GetDocumentation(item) opbinding.input = mbinding mbinding.load_ex(GetExtensions(item)) item = DOM.getElement(element, 'output', None, None) if item is not None: mbinding = MessageRoleBinding('output') mbinding.documentation = GetDocumentation(item) opbinding.output = mbinding mbinding.load_ex(GetExtensions(item)) for item in DOM.getElements(element, 'fault', None): name = DOM.getAttr(item, 'name') mbinding = MessageRoleBinding('fault', name) mbinding.documentation = GetDocumentation(item) opbinding.faults[name] = mbinding mbinding.load_ex(GetExtensions(item)) def load_ex(self, elements): for e in elements: ns, name = e.namespaceURI, e.localName if ns in DOM.NS_SOAP_BINDING_ALL and name == 'binding': transport = DOM.getAttr(e, 'transport', default=None) style = DOM.getAttr(e, 'style', default='document') ob = SoapBinding(transport, style) self.addExtension(ob) continue elif ns in DOM.NS_HTTP_BINDING_ALL and name == 'binding': verb = DOM.getAttr(e, 'verb') ob = HttpBinding(verb) self.addExtension(ob) continue else: self.addExtension(e) def toDom(self): wsdl = self.getWSDL() ep = ElementProxy(None, DOM.getElement(wsdl.document, None)) epc = ep.createAppendElement(DOM.GetWSDLUri(wsdl.version), 'binding') epc.setAttributeNS(None, 'name', self.name) ns,name = self.type prefix = epc.getPrefix(ns) epc.setAttributeNS(None, 'type', '%s:%s' %(prefix,name)) node = epc._getNode() for ext in self.extensions: ext.toDom(node) for op_binding in self.operations: op_binding.toDom(node) class OperationBinding(Element): def __init__(self, name, documentation=''): Element.__init__(self, name, documentation) self.input = None self.output = None self.faults = Collection(self) def getWSDL(self): """Return the WSDL object that contains this binding.""" return self.parent().parent().parent().parent() def getBinding(self): """Return the parent Binding object of the operation binding.""" return self.parent().parent() def getOperation(self): """Return the abstract Operation associated with this binding.""" return self.getBinding().getPortType().operations[self.name] def findBinding(self, kind): for item in self.extensions: if isinstance(item, kind): return item return None def findBindings(self, kind): return [ item for item in self.extensions if isinstance(item, kind) ] def addInputBinding(self, binding): if self.input is None: self.input = MessageRoleBinding('input') self.input.parent = weakref.ref(self) self.input.addExtension(binding) return binding def addOutputBinding(self, binding): if self.output is None: self.output = MessageRoleBinding('output') self.output.parent = weakref.ref(self) self.output.addExtension(binding) return binding def addFaultBinding(self, name, binding): fault = self.get(name, None) if fault is None: fault = MessageRoleBinding('fault', name) fault.addExtension(binding) return binding def load_ex(self, elements): for e in elements: ns, name = e.namespaceURI, e.localName if ns in DOM.NS_SOAP_BINDING_ALL and name == 'operation': soapaction = DOM.getAttr(e, 'soapAction', default=None) style = DOM.getAttr(e, 'style', default=None) ob = SoapOperationBinding(soapaction, style) self.addExtension(ob) continue elif ns in DOM.NS_HTTP_BINDING_ALL and name == 'operation': location = DOM.getAttr(e, 'location') ob = HttpOperationBinding(location) self.addExtension(ob) continue else: self.addExtension(e) def toDom(self, node): wsdl = self.getWSDL() ep = ElementProxy(None, node) epc = ep.createAppendElement(DOM.GetWSDLUri(wsdl.version), 'operation') epc.setAttributeNS(None, 'name', self.name) node = epc._getNode() for ext in self.extensions: ext.toDom(node) if self.input: self.input.toDom(node) if self.output: self.output.toDom(node) for fault in self.faults: fault.toDom(node) class MessageRoleBinding(Element): def __init__(self, type, name='', documentation=''): Element.__init__(self, name, documentation) self.type = type def getWSDL(self): """Return the WSDL object that contains this MessageRole.""" if self.type == 'fault': return self.parent().parent().getWSDL() return self.parent().getWSDL() def findBinding(self, kind): for item in self.extensions: if isinstance(item, kind): return item return None def findBindings(self, kind): return [ item for item in self.extensions if isinstance(item, kind) ] def load_ex(self, elements): for e in elements: ns, name = e.namespaceURI, e.localName if ns in DOM.NS_SOAP_BINDING_ALL and name == 'body': encstyle = DOM.getAttr(e, 'encodingStyle', default=None) namespace = DOM.getAttr(e, 'namespace', default=None) parts = DOM.getAttr(e, 'parts', default=None) use = DOM.getAttr(e, 'use', default=None) if use is None: raise WSDLError( 'Invalid soap:body binding element.' ) ob = SoapBodyBinding(use, namespace, encstyle, parts) self.addExtension(ob) continue elif ns in DOM.NS_SOAP_BINDING_ALL and name == 'fault': encstyle = DOM.getAttr(e, 'encodingStyle', default=None) namespace = DOM.getAttr(e, 'namespace', default=None) name = DOM.getAttr(e, 'name', default=None) use = DOM.getAttr(e, 'use', default=None) if use is None or name is None: raise WSDLError( 'Invalid soap:fault binding element.' ) ob = SoapFaultBinding(name, use, namespace, encstyle) self.addExtension(ob) continue elif ns in DOM.NS_SOAP_BINDING_ALL and name in ( 'header', 'headerfault' ): encstyle = DOM.getAttr(e, 'encodingStyle', default=None) namespace = DOM.getAttr(e, 'namespace', default=None) message = DOM.getAttr(e, 'message') part = DOM.getAttr(e, 'part') use = DOM.getAttr(e, 'use') if name == 'header': _class = SoapHeaderBinding else: _class = SoapHeaderFaultBinding message = ParseQName(message, e) ob = _class(message, part, use, namespace, encstyle) self.addExtension(ob) continue elif ns in DOM.NS_HTTP_BINDING_ALL and name == 'urlReplacement': ob = HttpUrlReplacementBinding() self.addExtension(ob) continue elif ns in DOM.NS_HTTP_BINDING_ALL and name == 'urlEncoded': ob = HttpUrlEncodedBinding() self.addExtension(ob) continue elif ns in DOM.NS_MIME_BINDING_ALL and name == 'multipartRelated': ob = MimeMultipartRelatedBinding() self.addExtension(ob) ob.load_ex(GetExtensions(e)) continue elif ns in DOM.NS_MIME_BINDING_ALL and name == 'content': part = DOM.getAttr(e, 'part', default=None) type = DOM.getAttr(e, 'type', default=None) ob = MimeContentBinding(part, type) self.addExtension(ob) continue elif ns in DOM.NS_MIME_BINDING_ALL and name == 'mimeXml': part = DOM.getAttr(e, 'part', default=None) ob = MimeXmlBinding(part) self.addExtension(ob) continue else: self.addExtension(e) def toDom(self, node): wsdl = self.getWSDL() ep = ElementProxy(None, node) epc = ep.createAppendElement(DOM.GetWSDLUri(wsdl.version), self.type) node = epc._getNode() for item in self.extensions: if item: item.toDom(node) class Service(Element): def __init__(self, name, documentation=''): Element.__init__(self, name, documentation) self.ports = Collection(self) def getWSDL(self): return self.parent().parent() def addPort(self, name, binding, documentation=''): item = Port(name, binding, documentation) self.ports[name] = item return item def load(self, elements): for element in elements: name = DOM.getAttr(element, 'name', default=None) docs = GetDocumentation(element) binding = DOM.getAttr(element, 'binding', default=None) if name is None or binding is None: raise WSDLError( 'Invalid port element.' ) binding = ParseQName(binding, element) port = self.addPort(name, binding, docs) port.load_ex(GetExtensions(element)) def load_ex(self, elements): for e in elements: self.addExtension(e) def toDom(self): wsdl = self.getWSDL() ep = ElementProxy(None, DOM.getElement(wsdl.document, None)) epc = ep.createAppendElement(DOM.GetWSDLUri(wsdl.version), "service") epc.setAttributeNS(None, "name", self.name) node = epc._getNode() for port in self.ports: port.toDom(node) class Port(Element): def __init__(self, name, binding, documentation=''): Element.__init__(self, name, documentation) self.binding = binding def getWSDL(self): return self.parent().parent().getWSDL() def getService(self): """Return the Service object associated with this port.""" return self.parent().parent() def getBinding(self): """Return the Binding object that is referenced by this port.""" wsdl = self.getService().getWSDL() return wsdl.bindings[self.binding] def getPortType(self): """Return the PortType object that is referenced by this port.""" wsdl = self.getService().getWSDL() binding = wsdl.bindings[self.binding] return wsdl.portTypes[binding.type] def getAddressBinding(self): """A convenience method to obtain the extension element used as the address binding for the port.""" for item in self.extensions: if isinstance(item, SoapAddressBinding) or \ isinstance(item, HttpAddressBinding): return item raise WSDLError( 'No address binding found in port.' ) def load_ex(self, elements): for e in elements: ns, name = e.namespaceURI, e.localName if ns in DOM.NS_SOAP_BINDING_ALL and name == 'address': location = DOM.getAttr(e, 'location', default=None) ob = SoapAddressBinding(location) self.addExtension(ob) continue elif ns in DOM.NS_HTTP_BINDING_ALL and name == 'address': location = DOM.getAttr(e, 'location', default=None) ob = HttpAddressBinding(location) self.addExtension(ob) continue else: self.addExtension(e) def toDom(self, node): wsdl = self.getWSDL() ep = ElementProxy(None, node) epc = ep.createAppendElement(DOM.GetWSDLUri(wsdl.version), "port") epc.setAttributeNS(None, "name", self.name) ns,name = self.binding prefix = epc.getPrefix(ns) epc.setAttributeNS(None, "binding", "%s:%s" %(prefix,name)) node = epc._getNode() for ext in self.extensions: ext.toDom(node) class SoapBinding: def __init__(self, transport, style='rpc'): self.transport = transport self.style = style def getWSDL(self): return self.parent().getWSDL() def toDom(self, node): wsdl = self.getWSDL() ep = ElementProxy(None, node) epc = ep.createAppendElement(DOM.GetWSDLSoapBindingUri(wsdl.version), 'binding') if self.transport: epc.setAttributeNS(None, "transport", self.transport) if self.style: epc.setAttributeNS(None, "style", self.style) class SoapAddressBinding: def __init__(self, location): self.location = location def getWSDL(self): return self.parent().getWSDL() def toDom(self, node): wsdl = self.getWSDL() ep = ElementProxy(None, node) epc = ep.createAppendElement(DOM.GetWSDLSoapBindingUri(wsdl.version), 'address') epc.setAttributeNS(None, "location", self.location) class SoapOperationBinding: def __init__(self, soapAction=None, style=None): self.soapAction = soapAction self.style = style def getWSDL(self): return self.parent().getWSDL() def toDom(self, node): wsdl = self.getWSDL() ep = ElementProxy(None, node) epc = ep.createAppendElement(DOM.GetWSDLSoapBindingUri(wsdl.version), 'operation') if self.soapAction: epc.setAttributeNS(None, 'soapAction', self.soapAction) if self.style: epc.setAttributeNS(None, 'style', self.style) class SoapBodyBinding: def __init__(self, use, namespace=None, encodingStyle=None, parts=None): if not use in ('literal', 'encoded'): raise WSDLError( 'Invalid use attribute value: %s' % use ) self.encodingStyle = encodingStyle self.namespace = namespace if type(parts) in (type(''), type(u'')): parts = parts.split() self.parts = parts self.use = use def getWSDL(self): return self.parent().getWSDL() def toDom(self, node): wsdl = self.getWSDL() ep = ElementProxy(None, node) epc = ep.createAppendElement(DOM.GetWSDLSoapBindingUri(wsdl.version), 'body') epc.setAttributeNS(None, "use", self.use) epc.setAttributeNS(None, "namespace", self.namespace) class SoapFaultBinding: def __init__(self, name, use, namespace=None, encodingStyle=None): if not use in ('literal', 'encoded'): raise WSDLError( 'Invalid use attribute value: %s' % use ) self.encodingStyle = encodingStyle self.namespace = namespace self.name = name self.use = use class SoapHeaderBinding: def __init__(self, message, part, use, namespace=None, encodingStyle=None): if not use in ('literal', 'encoded'): raise WSDLError( 'Invalid use attribute value: %s' % use ) self.encodingStyle = encodingStyle self.namespace = namespace self.message = message self.part = part self.use = use tagname = 'header' class SoapHeaderFaultBinding(SoapHeaderBinding): tagname = 'headerfault' class HttpBinding: def __init__(self, verb): self.verb = verb class HttpAddressBinding: def __init__(self, location): self.location = location class HttpOperationBinding: def __init__(self, location): self.location = location class HttpUrlReplacementBinding: pass class HttpUrlEncodedBinding: pass class MimeContentBinding: def __init__(self, part=None, type=None): self.part = part self.type = type class MimeXmlBinding: def __init__(self, part=None): self.part = part class MimeMultipartRelatedBinding: def __init__(self): self.parts = [] def load_ex(self, elements): for e in elements: ns, name = e.namespaceURI, e.localName if ns in DOM.NS_MIME_BINDING_ALL and name == 'part': self.parts.append(MimePartBinding()) continue class MimePartBinding: def __init__(self): self.items = [] def load_ex(self, elements): for e in elements: ns, name = e.namespaceURI, e.localName if ns in DOM.NS_MIME_BINDING_ALL and name == 'content': part = DOM.getAttr(e, 'part', default=None) type = DOM.getAttr(e, 'type', default=None) ob = MimeContentBinding(part, type) self.items.append(ob) continue elif ns in DOM.NS_MIME_BINDING_ALL and name == 'mimeXml': part = DOM.getAttr(e, 'part', default=None) ob = MimeXmlBinding(part) self.items.append(ob) continue elif ns in DOM.NS_SOAP_BINDING_ALL and name == 'body': encstyle = DOM.getAttr(e, 'encodingStyle', default=None) namespace = DOM.getAttr(e, 'namespace', default=None) parts = DOM.getAttr(e, 'parts', default=None) use = DOM.getAttr(e, 'use', default=None) if use is None: raise WSDLError( 'Invalid soap:body binding element.' ) ob = SoapBodyBinding(use, namespace, encstyle, parts) self.items.append(ob) continue class WSDLError(Exception): pass def DeclareNSPrefix(writer, prefix, nsuri): if writer.hasNSPrefix(nsuri): return writer.declareNSPrefix(prefix, nsuri) def ParseTypeRef(value, element): parts = value.split(':', 1) if len(parts) == 1: return (DOM.findTargetNS(element), value) nsuri = DOM.findNamespaceURI(parts[0], element) return (nsuri, parts[1]) def ParseQName(value, element): nameref = value.split(':', 1) if len(nameref) == 2: nsuri = DOM.findNamespaceURI(nameref[0], element) name = nameref[-1] else: nsuri = DOM.findTargetNS(element) name = nameref[-1] return nsuri, name def GetDocumentation(element): docnode = DOM.getElement(element, 'documentation', None, None) if docnode is not None: return DOM.getElementText(docnode) return '' def GetExtensions(element): return [ item for item in DOM.getElements(element, None, None) if item.namespaceURI != DOM.NS_WSDL ] def GetWSAActionFault(operation, name): """Find wsa:Action attribute, and return value or WSA.FAULT for the default. """ attr = operation.faults[name].action if attr is not None: return attr return WSA.FAULT def GetWSAActionInput(operation): """Find wsa:Action attribute, and return value or the default.""" attr = operation.input.action if attr is not None: return attr portType = operation.getPortType() targetNamespace = portType.getTargetNamespace() ptName = portType.name msgName = operation.input.name if not msgName: msgName = operation.name + 'Request' if targetNamespace.endswith('/'): return '%s%s/%s' %(targetNamespace, ptName, msgName) return '%s/%s/%s' %(targetNamespace, ptName, msgName) def GetWSAActionOutput(operation): """Find wsa:Action attribute, and return value or the default.""" attr = operation.output.action if attr is not None: return attr targetNamespace = operation.getPortType().getTargetNamespace() ptName = operation.getPortType().name msgName = operation.output.name if not msgName: msgName = operation.name + 'Response' if targetNamespace.endswith('/'): return '%s%s/%s' %(targetNamespace, ptName, msgName) return '%s/%s/%s' %(targetNamespace, ptName, msgName) def FindExtensions(object, kind, t_type=type(())): if isinstance(kind, t_type): result = [] namespaceURI, name = kind return [ item for item in object.extensions if hasattr(item, 'nodeType') \ and DOM.nsUriMatch(namespaceURI, item.namespaceURI) \ and item.name == name ] return [ item for item in object.extensions if isinstance(item, kind) ] def FindExtension(object, kind, t_type=type(())): if isinstance(kind, t_type): namespaceURI, name = kind for item in object.extensions: if hasattr(item, 'nodeType') \ and DOM.nsUriMatch(namespaceURI, item.namespaceURI) \ and item.name == name: return item else: for item in object.extensions: if isinstance(item, kind): return item return None class SOAPCallInfo: """SOAPCallInfo captures the important binding information about a SOAP operation, in a structure that is easier to work with than raw WSDL structures.""" def __init__(self, methodName): self.methodName = methodName self.inheaders = [] self.outheaders = [] self.inparams = [] self.outparams = [] self.retval = None encodingStyle = DOM.NS_SOAP_ENC documentation = '' soapAction = None transport = None namespace = None location = None use = 'encoded' style = 'rpc' def addInParameter(self, name, type, namespace=None, element_type=0): """Add an input parameter description to the call info.""" parameter = ParameterInfo(name, type, namespace, element_type) self.inparams.append(parameter) return parameter def addOutParameter(self, name, type, namespace=None, element_type=0): """Add an output parameter description to the call info.""" parameter = ParameterInfo(name, type, namespace, element_type) self.outparams.append(parameter) return parameter def setReturnParameter(self, name, type, namespace=None, element_type=0): """Set the return parameter description for the call info.""" parameter = ParameterInfo(name, type, namespace, element_type) self.retval = parameter return parameter def addInHeaderInfo(self, name, type, namespace, element_type=0, mustUnderstand=0): """Add an input SOAP header description to the call info.""" headerinfo = HeaderInfo(name, type, namespace, element_type) if mustUnderstand: headerinfo.mustUnderstand = 1 self.inheaders.append(headerinfo) return headerinfo def addOutHeaderInfo(self, name, type, namespace, element_type=0, mustUnderstand=0): """Add an output SOAP header description to the call info.""" headerinfo = HeaderInfo(name, type, namespace, element_type) if mustUnderstand: headerinfo.mustUnderstand = 1 self.outheaders.append(headerinfo) return headerinfo def getInParameters(self): """Return a sequence of the in parameters of the method.""" return self.inparams def getOutParameters(self): """Return a sequence of the out parameters of the method.""" return self.outparams def getReturnParameter(self): """Return param info about the return value of the method.""" return self.retval def getInHeaders(self): """Return a sequence of the in headers of the method.""" return self.inheaders def getOutHeaders(self): """Return a sequence of the out headers of the method.""" return self.outheaders class ParameterInfo: """A ParameterInfo object captures parameter binding information.""" def __init__(self, name, type, namespace=None, element_type=0): if element_type: self.element_type = 1 if namespace is not None: self.namespace = namespace self.name = name self.type = type element_type = 0 namespace = None default = None class HeaderInfo(ParameterInfo): """A HeaderInfo object captures SOAP header binding information.""" def __init__(self, name, type, namespace, element_type=None): ParameterInfo.__init__(self, name, type, namespace, element_type) mustUnderstand = 0 actor = None def callInfoFromWSDL(port, name): """Return a SOAPCallInfo given a WSDL port and operation name.""" wsdl = port.getService().getWSDL() binding = port.getBinding() portType = binding.getPortType() operation = portType.operations[name] opbinding = binding.operations[name] messages = wsdl.messages callinfo = SOAPCallInfo(name) addrbinding = port.getAddressBinding() if not isinstance(addrbinding, SoapAddressBinding): raise ValueError, 'Unsupported binding type.' callinfo.location = addrbinding.location soapbinding = binding.findBinding(SoapBinding) if soapbinding is None: raise ValueError, 'Missing soap:binding element.' callinfo.transport = soapbinding.transport callinfo.style = soapbinding.style or 'document' soap_op_binding = opbinding.findBinding(SoapOperationBinding) if soap_op_binding is not None: callinfo.soapAction = soap_op_binding.soapAction callinfo.style = soap_op_binding.style or callinfo.style parameterOrder = operation.parameterOrder if operation.input is not None: message = messages[operation.input.message] msgrole = opbinding.input mime = msgrole.findBinding(MimeMultipartRelatedBinding) if mime is not None: raise ValueError, 'Mime bindings are not supported.' else: for item in msgrole.findBindings(SoapHeaderBinding): part = messages[item.message].parts[item.part] header = callinfo.addInHeaderInfo( part.name, part.element or part.type, item.namespace, element_type = part.element and 1 or 0 ) header.encodingStyle = item.encodingStyle body = msgrole.findBinding(SoapBodyBinding) if body is None: raise ValueError, 'Missing soap:body binding.' callinfo.encodingStyle = body.encodingStyle callinfo.namespace = body.namespace callinfo.use = body.use if body.parts is not None: parts = [] for name in body.parts: parts.append(message.parts[name]) else: parts = message.parts.values() for part in parts: callinfo.addInParameter( part.name, part.element or part.type, element_type = part.element and 1 or 0 ) if operation.output is not None: try: message = messages[operation.output.message] except KeyError: if self.strict: raise RuntimeError( "Recieved message not defined in the WSDL schema: %s" % operation.output.message) else: message = wsdl.addMessage(operation.output.message) print "Warning:", \ "Recieved message not defined in the WSDL schema.", \ "Adding it." print "Message:", operation.output.message msgrole = opbinding.output mime = msgrole.findBinding(MimeMultipartRelatedBinding) if mime is not None: raise ValueError, 'Mime bindings are not supported.' else: for item in msgrole.findBindings(SoapHeaderBinding): part = messages[item.message].parts[item.part] header = callinfo.addOutHeaderInfo( part.name, part.element or part.type, item.namespace, element_type = part.element and 1 or 0 ) header.encodingStyle = item.encodingStyle body = msgrole.findBinding(SoapBodyBinding) if body is None: raise ValueError, 'Missing soap:body binding.' callinfo.encodingStyle = body.encodingStyle callinfo.namespace = body.namespace callinfo.use = body.use if body.parts is not None: parts = [] for name in body.parts: parts.append(message.parts[name]) else: parts = message.parts.values() if parts: for part in parts: callinfo.addOutParameter( part.name, part.element or part.type, element_type = part.element and 1 or 0 ) return callinfo SOAPpy-0.12.0/SOAPpy/wstools/XMLSchema.py0100755001604000501700000030604210205371226017515 0ustar warnegclinical# Copyright (c) 2003, The Regents of the University of California, # through Lawrence Berkeley National Laboratory (subject to receipt of # any required approvals from the U.S. Dept. of Energy). All rights # reserved. # # Copyright (c) 2001 Zope Corporation and Contributors. All Rights Reserved. # # This software is subject to the provisions of the Zope Public License, # Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. # THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED # WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED # WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS # FOR A PARTICULAR PURPOSE. ident = "$Id: XMLSchema.py,v 1.53 2005/02/18 13:50:14 warnes Exp $" import types, weakref, urllib, sys from threading import RLock from Namespaces import XMLNS from Utility import DOM, DOMException, Collection, SplitQName from StringIO import StringIO def GetSchema(component): """convience function for finding the parent XMLSchema instance. """ parent = component while not isinstance(parent, XMLSchema): parent = parent._parent() return parent class SchemaReader: """A SchemaReader creates XMLSchema objects from urls and xml data. """ def __init__(self, domReader=None, base_url=None): """domReader -- class must implement DOMAdapterInterface base_url -- base url string """ self.__base_url = base_url self.__readerClass = domReader if not self.__readerClass: self.__readerClass = DOMAdapter self._includes = {} self._imports = {} def __setImports(self, schema): """Add dictionary of imports to schema instance. schema -- XMLSchema instance """ for ns,val in schema.imports.items(): if self._imports.has_key(ns): schema.addImportSchema(self._imports[ns]) def __setIncludes(self, schema): """Add dictionary of includes to schema instance. schema -- XMLSchema instance """ for schemaLocation, val in schema.includes.items(): if self._includes.has_key(schemaLocation): schema.addIncludeSchema(self._imports[schemaLocation]) def addSchemaByLocation(self, location, schema): """provide reader with schema document for a location. """ self._includes[location] = schema def addSchemaByNamespace(self, schema): """provide reader with schema document for a targetNamespace. """ self._imports[schema.targetNamespace] = schema def loadFromNode(self, parent, element): """element -- DOM node or document parent -- WSDLAdapter instance """ reader = self.__readerClass(element) schema = XMLSchema(parent) #HACK to keep a reference schema.wsdl = parent schema.setBaseUrl(self.__base_url) schema.load(reader) return schema def loadFromStream(self, file, url=None): """Return an XMLSchema instance loaded from a file object. file -- file object url -- base location for resolving imports/includes. """ reader = self.__readerClass() reader.loadDocument(file) schema = XMLSchema() if url is not None: schema.setBaseUrl(url) schema.load(reader) self.__setIncludes(schema) self.__setImports(schema) return schema def loadFromString(self, data): """Return an XMLSchema instance loaded from an XML string. data -- XML string """ return self.loadFromStream(StringIO(data)) def loadFromURL(self, url): """Return an XMLSchema instance loaded from the given url. url -- URL to dereference """ reader = self.__readerClass() if self.__base_url: url = urllib.basejoin(self.__base_url,url) reader.loadFromURL(url) schema = XMLSchema() schema.setBaseUrl(url) schema.load(reader) self.__setIncludes(schema) self.__setImports(schema) return schema def loadFromFile(self, filename): """Return an XMLSchema instance loaded from the given file. filename -- name of file to open """ if self.__base_url: filename = urllib.basejoin(self.__base_url,filename) file = open(filename, 'rb') try: schema = self.loadFromStream(file, filename) finally: file.close() return schema class SchemaError(Exception): pass ########################### # DOM Utility Adapters ########################## class DOMAdapterInterface: def hasattr(self, attr, ns=None): """return true if node has attribute attr -- attribute to check for ns -- namespace of attribute, by default None """ raise NotImplementedError, 'adapter method not implemented' def getContentList(self, *contents): """returns an ordered list of child nodes *contents -- list of node names to return """ raise NotImplementedError, 'adapter method not implemented' def setAttributeDictionary(self, attributes): """set attribute dictionary """ raise NotImplementedError, 'adapter method not implemented' def getAttributeDictionary(self): """returns a dict of node's attributes """ raise NotImplementedError, 'adapter method not implemented' def getNamespace(self, prefix): """returns namespace referenced by prefix. """ raise NotImplementedError, 'adapter method not implemented' def getTagName(self): """returns tagName of node """ raise NotImplementedError, 'adapter method not implemented' def getParentNode(self): """returns parent element in DOMAdapter or None """ raise NotImplementedError, 'adapter method not implemented' def loadDocument(self, file): """load a Document from a file object file -- """ raise NotImplementedError, 'adapter method not implemented' def loadFromURL(self, url): """load a Document from an url url -- URL to dereference """ raise NotImplementedError, 'adapter method not implemented' class DOMAdapter(DOMAdapterInterface): """Adapter for ZSI.Utility.DOM """ def __init__(self, node=None): """Reset all instance variables. element -- DOM document, node, or None """ if hasattr(node, 'documentElement'): self.__node = node.documentElement else: self.__node = node self.__attributes = None def hasattr(self, attr, ns=None): """attr -- attribute ns -- optional namespace, None means unprefixed attribute. """ if not self.__attributes: self.setAttributeDictionary() if ns: return self.__attributes.get(ns,{}).has_key(attr) return self.__attributes.has_key(attr) def getContentList(self, *contents): nodes = [] ELEMENT_NODE = self.__node.ELEMENT_NODE for child in DOM.getElements(self.__node, None): if child.nodeType == ELEMENT_NODE and\ SplitQName(child.tagName)[1] in contents: nodes.append(child) return map(self.__class__, nodes) def setAttributeDictionary(self): self.__attributes = {} for v in self.__node._attrs.values(): self.__attributes[v.nodeName] = v.nodeValue def getAttributeDictionary(self): if not self.__attributes: self.setAttributeDictionary() return self.__attributes def getTagName(self): return self.__node.tagName def getParentNode(self): if self.__node.parentNode.nodeType == self.__node.ELEMENT_NODE: return DOMAdapter(self.__node.parentNode) return None def getNamespace(self, prefix): """prefix -- deference namespace prefix in node's context. Ascends parent nodes until found. """ namespace = None if prefix == 'xmlns': namespace = DOM.findDefaultNS(prefix, self.__node) else: try: namespace = DOM.findNamespaceURI(prefix, self.__node) except DOMException, ex: if prefix != 'xml': raise SchemaError, '%s namespace not declared for %s'\ %(prefix, self.__node._get_tagName()) namespace = XMLNS.XML return namespace def loadDocument(self, file): self.__node = DOM.loadDocument(file) if hasattr(self.__node, 'documentElement'): self.__node = self.__node.documentElement def loadFromURL(self, url): self.__node = DOM.loadFromURL(url) if hasattr(self.__node, 'documentElement'): self.__node = self.__node.documentElement class XMLBase: """ These class variables are for string indentation. """ tag = None __indent = 0 __rlock = RLock() def __str__(self): XMLBase.__rlock.acquire() XMLBase.__indent += 1 tmp = "<" + str(self.__class__) + '>\n' for k,v in self.__dict__.items(): tmp += "%s* %s = %s\n" %(XMLBase.__indent*' ', k, v) XMLBase.__indent -= 1 XMLBase.__rlock.release() return tmp """Marker Interface: can determine something about an instances properties by using the provided convenience functions. """ class DefinitionMarker: """marker for definitions """ pass class DeclarationMarker: """marker for declarations """ pass class AttributeMarker: """marker for attributes """ pass class AttributeGroupMarker: """marker for attribute groups """ pass class WildCardMarker: """marker for wildcards """ pass class ElementMarker: """marker for wildcards """ pass class ReferenceMarker: """marker for references """ pass class ModelGroupMarker: """marker for model groups """ pass class AllMarker(ModelGroupMarker): """marker for all model group """ pass class ChoiceMarker(ModelGroupMarker): """marker for choice model group """ pass class SequenceMarker(ModelGroupMarker): """marker for sequence model group """ pass class ExtensionMarker: """marker for extensions """ pass class RestrictionMarker: """marker for restrictions """ facets = ['enumeration', 'length', 'maxExclusive', 'maxInclusive',\ 'maxLength', 'minExclusive', 'minInclusive', 'minLength',\ 'pattern', 'fractionDigits', 'totalDigits', 'whiteSpace'] class SimpleMarker: """marker for simple type information """ pass class ListMarker: """marker for simple type list """ pass class UnionMarker: """marker for simple type Union """ pass class ComplexMarker: """marker for complex type information """ pass class LocalMarker: """marker for complex type information """ pass class MarkerInterface: def isDefinition(self): return isinstance(self, DefinitionMarker) def isDeclaration(self): return isinstance(self, DeclarationMarker) def isAttribute(self): return isinstance(self, AttributeMarker) def isAttributeGroup(self): return isinstance(self, AttributeGroupMarker) def isElement(self): return isinstance(self, ElementMarker) def isReference(self): return isinstance(self, ReferenceMarker) def isWildCard(self): return isinstance(self, WildCardMarker) def isModelGroup(self): return isinstance(self, ModelGroupMarker) def isAll(self): return isinstance(self, AllMarker) def isChoice(self): return isinstance(self, ChoiceMarker) def isSequence(self): return isinstance(self, SequenceMarker) def isExtension(self): return isinstance(self, ExtensionMarker) def isRestriction(self): return isinstance(self, RestrictionMarker) def isSimple(self): return isinstance(self, SimpleMarker) def isComplex(self): return isinstance(self, ComplexMarker) def isLocal(self): return isinstance(self, LocalMarker) def isList(self): return isinstance(self, ListMarker) def isUnion(self): return isinstance(self, UnionMarker) ########################################################## # Schema Components ######################################################### class XMLSchemaComponent(XMLBase, MarkerInterface): """ class variables: required -- list of required attributes attributes -- dict of default attribute values, including None. Value can be a function for runtime dependencies. contents -- dict of namespace keyed content lists. 'xsd' content of xsd namespace. xmlns_key -- key for declared xmlns namespace. xmlns -- xmlns is special prefix for namespace dictionary xml -- special xml prefix for xml namespace. """ required = [] attributes = {} contents = {} xmlns_key = '' xmlns = 'xmlns' xml = 'xml' def __init__(self, parent=None): """parent -- parent instance instance variables: attributes -- dictionary of node's attributes """ self.attributes = None self._parent = parent if self._parent: self._parent = weakref.ref(parent) if not self.__class__ == XMLSchemaComponent\ and not (type(self.__class__.required) == type(XMLSchemaComponent.required)\ and type(self.__class__.attributes) == type(XMLSchemaComponent.attributes)\ and type(self.__class__.contents) == type(XMLSchemaComponent.contents)): raise RuntimeError, 'Bad type for a class variable in %s' %self.__class__ def getItemTrace(self): """Returns a node trace up to the item. """ item, path, name, ref = self, [], 'name', 'ref' while not isinstance(item,XMLSchema) and not isinstance(item,WSDLToolsAdapter): attr = item.getAttribute(name) if attr is None: attr = item.getAttribute(ref) if attr is None: path.append('<%s>' %(item.tag)) else: path.append('<%s ref="%s">' %(item.tag, attr)) else: path.append('<%s name="%s">' %(item.tag,attr)) item = item._parent() try: tns = item.getTargetNamespace() except: tns = '' path.append('<%s targetNamespace="%s">' %(item.tag, tns)) path.reverse() return ''.join(path) def getTargetNamespace(self): """return targetNamespace """ parent = self targetNamespace = 'targetNamespace' tns = self.attributes.get(targetNamespace) while not tns: parent = parent._parent() tns = parent.attributes.get(targetNamespace) return tns def getAttributeDeclaration(self, attribute): """attribute -- attribute with a QName value (eg. type). collection -- check types collection in parent Schema instance """ return self.getQNameAttribute('attr_decl', attribute) def getAttributeGroup(self, attribute): """attribute -- attribute with a QName value (eg. type). collection -- check types collection in parent Schema instance """ return self.getQNameAttribute('attr_groups', attribute) def getTypeDefinition(self, attribute): """attribute -- attribute with a QName value (eg. type). collection -- check types collection in parent Schema instance """ return self.getQNameAttribute('types', attribute) def getElementDeclaration(self, attribute): """attribute -- attribute with a QName value (eg. element). collection -- check elements collection in parent Schema instance. """ return self.getQNameAttribute('elements', attribute) def getModelGroup(self, attribute): """attribute -- attribute with a QName value (eg. ref). collection -- check model_group collection in parent Schema instance. """ return self.getQNameAttribute('model_groups', attribute) def getQNameAttribute(self, collection, attribute): """returns object instance representing QName --> (namespace,name), or if does not exist return None. attribute -- an information item attribute, with a QName value. collection -- collection in parent Schema instance to search. """ obj = None tdc = self.attributes.get(attribute) if tdc: parent = GetSchema(self) targetNamespace = tdc.getTargetNamespace() if parent.targetNamespace == targetNamespace: item = tdc.getName() try: obj = getattr(parent, collection)[item] except KeyError, ex: raise KeyError, "targetNamespace(%s) collection(%s) has no item(%s)"\ %(targetNamespace, collection, item) elif parent.imports.has_key(targetNamespace): schema = parent.imports[targetNamespace].getSchema() item = tdc.getName() try: obj = getattr(schema, collection)[item] except KeyError, ex: raise KeyError, "targetNamespace(%s) collection(%s) has no item(%s)"\ %(targetNamespace, collection, item) return obj def getXMLNS(self, prefix=None): """deference prefix or by default xmlns, returns namespace. """ if prefix == XMLSchemaComponent.xml: return XMLNS.XML parent = self ns = self.attributes[XMLSchemaComponent.xmlns].get(prefix or\ XMLSchemaComponent.xmlns_key) while not ns: parent = parent._parent() ns = parent.attributes[XMLSchemaComponent.xmlns].get(prefix or\ XMLSchemaComponent.xmlns_key) if not ns and isinstance(parent, WSDLToolsAdapter): raise SchemaError, 'unknown prefix %s' %prefix return ns def getAttribute(self, attribute): """return requested attribute or None """ return self.attributes.get(attribute) def setAttributes(self, node): """Sets up attribute dictionary, checks for required attributes and sets default attribute values. attr is for default attribute values determined at runtime. structure of attributes dictionary ['xmlns'][xmlns_key] -- xmlns namespace ['xmlns'][prefix] -- declared namespace prefix [namespace][prefix] -- attributes declared in a namespace [attribute] -- attributes w/o prefix, default namespaces do not directly apply to attributes, ie Name can't collide with QName. """ self.attributes = {XMLSchemaComponent.xmlns:{}} for k,v in node.getAttributeDictionary().items(): prefix,value = SplitQName(k) if value == XMLSchemaComponent.xmlns: self.attributes[value][prefix or XMLSchemaComponent.xmlns_key] = v elif prefix: ns = node.getNamespace(prefix) if not ns: raise SchemaError, 'no namespace for attribute prefix %s'\ %prefix if not self.attributes.has_key(ns): self.attributes[ns] = {} elif self.attributes[ns].has_key(value): raise SchemaError, 'attribute %s declared multiple times in %s'\ %(value, ns) self.attributes[ns][value] = v elif not self.attributes.has_key(value): self.attributes[value] = v else: raise SchemaError, 'attribute %s declared multiple times' %value if not isinstance(self, WSDLToolsAdapter): self.__checkAttributes() self.__setAttributeDefaults() #set QNames for k in ['type', 'element', 'base', 'ref', 'substitutionGroup', 'itemType']: if self.attributes.has_key(k): prefix, value = SplitQName(self.attributes.get(k)) self.attributes[k] = \ TypeDescriptionComponent((self.getXMLNS(prefix), value)) #Union, memberTypes is a whitespace separated list of QNames for k in ['memberTypes']: if self.attributes.has_key(k): qnames = self.attributes[k] self.attributes[k] = [] for qname in qnames.split(): prefix, value = SplitQName(qname) self.attributes['memberTypes'].append(\ TypeDescriptionComponent(\ (self.getXMLNS(prefix), value))) def getContents(self, node): """retrieve xsd contents """ return node.getContentList(*self.__class__.contents['xsd']) def __setAttributeDefaults(self): """Looks for default values for unset attributes. If class variable representing attribute is None, then it must be defined as an instance variable. """ for k,v in self.__class__.attributes.items(): if v and not self.attributes.has_key(k): if isinstance(v, types.FunctionType): self.attributes[k] = v(self) else: self.attributes[k] = v def __checkAttributes(self): """Checks that required attributes have been defined, attributes w/default cannot be required. Checks all defined attributes are legal, attribute references are not subject to this test. """ for a in self.__class__.required: if not self.attributes.has_key(a): raise SchemaError,\ 'class instance %s, missing required attribute %s'\ %(self.__class__, a) for a in self.attributes.keys(): if (a not in (XMLSchemaComponent.xmlns, XMLNS.XML)) and\ (a not in self.__class__.attributes.keys()) and not\ (self.isAttribute() and self.isReference()): raise SchemaError, '%s, unknown attribute(%s,%s)' \ %(self.getItemTrace(), a, self.attributes[a]) class WSDLToolsAdapter(XMLSchemaComponent): """WSDL Adapter to grab the attributes from the wsdl document node. """ attributes = {'name':None, 'targetNamespace':None} tag = 'definitions' def __init__(self, wsdl): XMLSchemaComponent.__init__(self, parent=wsdl) self.setAttributes(DOMAdapter(wsdl.document)) def getImportSchemas(self): """returns WSDLTools.WSDL types Collection """ return self._parent().types class Notation(XMLSchemaComponent): """ parent: schema attributes: id -- ID name -- NCName, Required public -- token, Required system -- anyURI contents: annotation? """ required = ['name', 'public'] attributes = {'id':None, 'name':None, 'public':None, 'system':None} contents = {'xsd':('annotation')} tag = 'notation' def __init__(self, parent): XMLSchemaComponent.__init__(self, parent) self.annotation = None def fromDom(self, node): self.setAttributes(node) contents = self.getContents(node) for i in contents: component = SplitQName(i.getTagName())[1] if component == 'annotation' and not self.annotation: self.annotation = Annotation(self) self.annotation.fromDom(i) else: raise SchemaError, 'Unknown component (%s)' %(i.getTagName()) class Annotation(XMLSchemaComponent): """ parent: all,any,anyAttribute,attribute,attributeGroup,choice,complexContent, complexType,element,extension,field,group,import,include,key,keyref, list,notation,redefine,restriction,schema,selector,simpleContent, simpleType,union,unique attributes: id -- ID contents: (documentation | appinfo)* """ attributes = {'id':None} contents = {'xsd':('documentation', 'appinfo')} tag = 'annotation' def __init__(self, parent): XMLSchemaComponent.__init__(self, parent) self.content = None def fromDom(self, node): self.setAttributes(node) contents = self.getContents(node) content = [] for i in contents: component = SplitQName(i.getTagName())[1] if component == 'documentation': #print_debug('class %s, documentation skipped' %self.__class__, 5) continue elif component == 'appinfo': #print_debug('class %s, appinfo skipped' %self.__class__, 5) continue else: raise SchemaError, 'Unknown component (%s)' %(i.getTagName()) self.content = tuple(content) class Documentation(XMLSchemaComponent): """ parent: annotation attributes: source, anyURI xml:lang, language contents: mixed, any """ attributes = {'source':None, 'xml:lang':None} contents = {'xsd':('mixed', 'any')} tag = 'documentation' def __init__(self, parent): XMLSchemaComponent.__init__(self, parent) self.content = None def fromDom(self, node): self.setAttributes(node) contents = self.getContents(node) content = [] for i in contents: component = SplitQName(i.getTagName())[1] if component == 'mixed': #print_debug('class %s, mixed skipped' %self.__class__, 5) continue elif component == 'any': #print_debug('class %s, any skipped' %self.__class__, 5) continue else: raise SchemaError, 'Unknown component (%s)' %(i.getTagName()) self.content = tuple(content) class Appinfo(XMLSchemaComponent): """ parent: annotation attributes: source, anyURI contents: mixed, any """ attributes = {'source':None, 'anyURI':None} contents = {'xsd':('mixed', 'any')} tag = 'appinfo' def __init__(self, parent): XMLSchemaComponent.__init__(self, parent) self.content = None def fromDom(self, node): self.setAttributes(node) contents = self.getContents(node) content = [] for i in contents: component = SplitQName(i.getTagName())[1] if component == 'mixed': #print_debug('class %s, mixed skipped' %self.__class__, 5) continue elif component == 'any': #print_debug('class %s, any skipped' %self.__class__, 5) continue else: raise SchemaError, 'Unknown component (%s)' %(i.getTagName()) self.content = tuple(content) class XMLSchemaFake: # This is temporary, for the benefit of WSDL until the real thing works. def __init__(self, element): self.targetNamespace = DOM.getAttr(element, 'targetNamespace') self.element = element class XMLSchema(XMLSchemaComponent): """A schema is a collection of schema components derived from one or more schema documents, that is, one or more element information items. It represents the abstract notion of a schema rather than a single schema document (or other representation). parent: ROOT attributes: id -- ID version -- token xml:lang -- language targetNamespace -- anyURI attributeFormDefault -- 'qualified' | 'unqualified', 'unqualified' elementFormDefault -- 'qualified' | 'unqualified', 'unqualified' blockDefault -- '#all' | list of ('substitution | 'extension' | 'restriction') finalDefault -- '#all' | list of ('extension' | 'restriction' | 'list' | 'union') contents: ((include | import | redefine | annotation)*, (attribute, attributeGroup, complexType, element, group, notation, simpleType)*, annotation*)* attributes -- schema attributes imports -- import statements includes -- include statements redefines -- types -- global simpleType, complexType definitions elements -- global element declarations attr_decl -- global attribute declarations attr_groups -- attribute Groups model_groups -- model Groups notations -- global notations """ attributes = {'id':None, 'version':None, 'xml:lang':None, 'targetNamespace':None, 'attributeFormDefault':'unqualified', 'elementFormDefault':'unqualified', 'blockDefault':None, 'finalDefault':None} contents = {'xsd':('include', 'import', 'redefine', 'annotation', 'attribute',\ 'attributeGroup', 'complexType', 'element', 'group',\ 'notation', 'simpleType', 'annotation')} empty_namespace = '' tag = 'schema' def __init__(self, parent=None): """parent -- instance variables: targetNamespace -- schema's declared targetNamespace, or empty string. _imported_schemas -- namespace keyed dict of schema dependencies, if a schema is provided instance will not resolve import statement. _included_schemas -- schemaLocation keyed dict of component schemas, if schema is provided instance will not resolve include statement. _base_url -- needed for relative URLs support, only works with URLs relative to initial document. includes -- collection of include statements imports -- collection of import statements elements -- collection of global element declarations types -- collection of global type definitions attr_decl -- collection of global attribute declarations attr_groups -- collection of global attribute group definitions model_groups -- collection of model group definitions notations -- collection of notations """ self.targetNamespace = None XMLSchemaComponent.__init__(self, parent) f = lambda k: k.attributes['name'] ns = lambda k: k.attributes['namespace'] sl = lambda k: k.attributes['schemaLocation'] self.includes = Collection(self, key=sl) self.imports = Collection(self, key=ns) self.elements = Collection(self, key=f) self.types = Collection(self, key=f) self.attr_decl = Collection(self, key=f) self.attr_groups = Collection(self, key=f) self.model_groups = Collection(self, key=f) self.notations = Collection(self, key=f) self._imported_schemas = {} self._included_schemas = {} self._base_url = None def addImportSchema(self, schema): """for resolving import statements in Schema instance schema -- schema instance _imported_schemas """ if not isinstance(schema, XMLSchema): raise TypeError, 'expecting a Schema instance' if schema.targetNamespace != self.targetNamespace: self._imported_schemas[schema.targetNamespace] = schema else: raise SchemaError, 'import schema bad targetNamespace' def addIncludeSchema(self, schemaLocation, schema): """for resolving include statements in Schema instance schemaLocation -- schema location schema -- schema instance _included_schemas """ if not isinstance(schema, XMLSchema): raise TypeError, 'expecting a Schema instance' if not schema.targetNamespace or\ schema.targetNamespace == self.targetNamespace: self._included_schemas[schemaLocation] = schema else: raise SchemaError, 'include schema bad targetNamespace' def setImportSchemas(self, schema_dict): """set the import schema dictionary, which is used to reference depedent schemas. """ self._imported_schemas = schema_dict def getImportSchemas(self): """get the import schema dictionary, which is used to reference depedent schemas. """ return self._imported_schemas def getSchemaNamespacesToImport(self): """returns tuple of namespaces the schema instance has declared itself to be depedent upon. """ return tuple(self.includes.keys()) def setIncludeSchemas(self, schema_dict): """set the include schema dictionary, which is keyed with schemaLocation (uri). This is a means of providing schemas to the current schema for content inclusion. """ self._included_schemas = schema_dict def getIncludeSchemas(self): """get the include schema dictionary, which is keyed with schemaLocation (uri). """ return self._included_schemas def getBaseUrl(self): """get base url, used for normalizing all relative uri's """ return self._base_url def setBaseUrl(self, url): """set base url, used for normalizing all relative uri's """ self._base_url = url def getElementFormDefault(self): """return elementFormDefault attribute """ return self.attributes.get('elementFormDefault') def isElementFormDefaultQualified(self): return self.attributes.get('elementFormDefault') == 'qualified' def getAttributeFormDefault(self): """return attributeFormDefault attribute """ return self.attributes.get('attributeFormDefault') def getBlockDefault(self): """return blockDefault attribute """ return self.attributes.get('blockDefault') def getFinalDefault(self): """return finalDefault attribute """ return self.attributes.get('finalDefault') def load(self, node): pnode = node.getParentNode() if pnode: pname = SplitQName(pnode.getTagName())[1] if pname == 'types': attributes = {} self.setAttributes(pnode) attributes.update(self.attributes) self.setAttributes(node) for k,v in attributes['xmlns'].items(): if not self.attributes['xmlns'].has_key(k): self.attributes['xmlns'][k] = v else: self.setAttributes(node) else: self.setAttributes(node) self.targetNamespace = self.getTargetNamespace() contents = self.getContents(node) indx = 0 num = len(contents) while indx < num: while indx < num: node = contents[indx] component = SplitQName(node.getTagName())[1] if component == 'include': tp = self.__class__.Include(self) tp.fromDom(node) self.includes[tp.attributes['schemaLocation']] = tp schema = tp.getSchema() if schema.targetNamespace and \ schema.targetNamespace != self.targetNamespace: raise SchemaError, 'included schema bad targetNamespace' for collection in ['imports','elements','types',\ 'attr_decl','attr_groups','model_groups','notations']: for k,v in getattr(schema,collection).items(): if not getattr(self,collection).has_key(k): v._parent = weakref.ref(self) getattr(self,collection)[k] = v elif component == 'import': tp = self.__class__.Import(self) tp.fromDom(node) import_ns = tp.getAttribute('namespace') if import_ns: if import_ns == self.targetNamespace: raise SchemaError,\ 'import and schema have same targetNamespace' self.imports[import_ns] = tp else: self.imports[self.__class__.empty_namespace] = tp if not self.getImportSchemas().has_key(import_ns) and\ tp.getAttribute('schemaLocation'): self.addImportSchema(tp.getSchema()) elif component == 'redefine': #print_debug('class %s, redefine skipped' %self.__class__, 5) pass elif component == 'annotation': #print_debug('class %s, annotation skipped' %self.__class__, 5) pass else: break indx += 1 # (attribute, attributeGroup, complexType, element, group, # notation, simpleType)*, annotation*)* while indx < num: node = contents[indx] component = SplitQName(node.getTagName())[1] if component == 'attribute': tp = AttributeDeclaration(self) tp.fromDom(node) self.attr_decl[tp.getAttribute('name')] = tp elif component == 'attributeGroup': tp = AttributeGroupDefinition(self) tp.fromDom(node) self.attr_groups[tp.getAttribute('name')] = tp elif component == 'complexType': tp = ComplexType(self) tp.fromDom(node) self.types[tp.getAttribute('name')] = tp elif component == 'element': tp = ElementDeclaration(self) tp.fromDom(node) self.elements[tp.getAttribute('name')] = tp elif component == 'group': tp = ModelGroupDefinition(self) tp.fromDom(node) self.model_groups[tp.getAttribute('name')] = tp elif component == 'notation': tp = Notation(self) tp.fromDom(node) self.notations[tp.getAttribute('name')] = tp elif component == 'simpleType': tp = SimpleType(self) tp.fromDom(node) self.types[tp.getAttribute('name')] = tp else: break indx += 1 while indx < num: node = contents[indx] component = SplitQName(node.getTagName())[1] if component == 'annotation': #print_debug('class %s, annotation 2 skipped' %self.__class__, 5) pass else: break indx += 1 class Import(XMLSchemaComponent): """ parent: schema attributes: id -- ID namespace -- anyURI schemaLocation -- anyURI contents: annotation? """ attributes = {'id':None, 'namespace':None, 'schemaLocation':None} contents = {'xsd':['annotation']} tag = 'import' def __init__(self, parent): XMLSchemaComponent.__init__(self, parent) self.annotation = None self._schema = None def fromDom(self, node): self.setAttributes(node) contents = self.getContents(node) if self.attributes['namespace'] == self.getTargetNamespace(): raise SchemaError, 'namespace of schema and import match' for i in contents: component = SplitQName(i.getTagName())[1] if component == 'annotation' and not self.annotation: self.annotation = Annotation(self) self.annotation.fromDom(i) else: raise SchemaError, 'Unknown component (%s)' %(i.getTagName()) def getSchema(self): """if schema is not defined, first look for a Schema class instance in parent Schema. Else if not defined resolve schemaLocation and create a new Schema class instance, and keep a hard reference. """ if not self._schema: ns = self.attributes['namespace'] schema = self._parent().getImportSchemas().get(ns) if not schema and self._parent()._parent: schema = self._parent()._parent().getImportSchemas().get(ns) if not schema: url = self.attributes.get('schemaLocation') if not url: raise SchemaError, 'namespace(%s) is unknown' %ns base_url = self._parent().getBaseUrl() reader = SchemaReader(base_url=base_url) reader._imports = self._parent().getImportSchemas() reader._includes = self._parent().getIncludeSchemas() self._schema = reader.loadFromURL(url) return self._schema or schema class Include(XMLSchemaComponent): """ parent: schema attributes: id -- ID schemaLocation -- anyURI, required contents: annotation? """ required = ['schemaLocation'] attributes = {'id':None, 'schemaLocation':None} contents = {'xsd':['annotation']} tag = 'include' def __init__(self, parent): XMLSchemaComponent.__init__(self, parent) self.annotation = None self._schema = None def fromDom(self, node): self.setAttributes(node) contents = self.getContents(node) for i in contents: component = SplitQName(i.getTagName())[1] if component == 'annotation' and not self.annotation: self.annotation = Annotation(self) self.annotation.fromDom(i) else: raise SchemaError, 'Unknown component (%s)' %(i.getTagName()) def getSchema(self): """if schema is not defined, first look for a Schema class instance in parent Schema. Else if not defined resolve schemaLocation and create a new Schema class instance. """ if not self._schema: schema = self._parent() self._schema = schema.getIncludeSchemas().get(\ self.attributes['schemaLocation'] ) if not self._schema: url = self.attributes['schemaLocation'] reader = SchemaReader(base_url=schema.getBaseUrl()) reader._imports = schema.getImportSchemas() reader._includes = schema.getIncludeSchemas() self._schema = reader.loadFromURL(url) return self._schema class AttributeDeclaration(XMLSchemaComponent,\ AttributeMarker,\ DeclarationMarker): """ parent: schema attributes: id -- ID name -- NCName, required type -- QName default -- string fixed -- string contents: annotation?, simpleType? """ required = ['name'] attributes = {'id':None, 'name':None, 'type':None, 'default':None, 'fixed':None} contents = {'xsd':['annotation','simpleType']} tag = 'attribute' def __init__(self, parent): XMLSchemaComponent.__init__(self, parent) self.annotation = None self.content = None def fromDom(self, node): """ No list or union support """ self.setAttributes(node) contents = self.getContents(node) for i in contents: component = SplitQName(i.getTagName())[1] if component == 'annotation' and not self.annotation: self.annotation = Annotation(self) self.annotation.fromDom(i) elif component == 'simpleType': self.content = AnonymousSimpleType(self) self.content.fromDom(i) else: raise SchemaError, 'Unknown component (%s)' %(i.getTagName()) class LocalAttributeDeclaration(AttributeDeclaration,\ AttributeMarker,\ LocalMarker,\ DeclarationMarker): """ parent: complexType, restriction, extension, attributeGroup attributes: id -- ID name -- NCName, required type -- QName form -- ('qualified' | 'unqualified'), schema.attributeFormDefault use -- ('optional' | 'prohibited' | 'required'), optional default -- string fixed -- string contents: annotation?, simpleType? """ required = ['name'] attributes = {'id':None, 'name':None, 'type':None, 'form':lambda self: GetSchema(self).getAttributeFormDefault(), 'use':'optional', 'default':None, 'fixed':None} contents = {'xsd':['annotation','simpleType']} def __init__(self, parent): AttributeDeclaration.__init__(self, parent) self.annotation = None self.content = None def fromDom(self, node): self.setAttributes(node) contents = self.getContents(node) for i in contents: component = SplitQName(i.getTagName())[1] if component == 'annotation' and not self.annotation: self.annotation = Annotation(self) self.annotation.fromDom(i) elif component == 'simpleType': self.content = AnonymousSimpleType(self) self.content.fromDom(i) else: raise SchemaError, 'Unknown component (%s)' %(i.getTagName()) class AttributeWildCard(XMLSchemaComponent,\ AttributeMarker,\ DeclarationMarker,\ WildCardMarker): """ parents: complexType, restriction, extension, attributeGroup attributes: id -- ID namespace -- '##any' | '##other' | (anyURI* | '##targetNamespace' | '##local'), ##any processContents -- 'lax' | 'skip' | 'strict', strict contents: annotation? """ attributes = {'id':None, 'namespace':'##any', 'processContents':'strict'} contents = {'xsd':['annotation']} tag = 'anyAttribute' def __init__(self, parent): XMLSchemaComponent.__init__(self, parent) self.annotation = None def fromDom(self, node): self.setAttributes(node) contents = self.getContents(node) for i in contents: component = SplitQName(i.getTagName())[1] if component == 'annotation' and not self.annotation: self.annotation = Annotation(self) self.annotation.fromDom(i) else: raise SchemaError, 'Unknown component (%s)' %(i.getTagName()) class AttributeReference(XMLSchemaComponent,\ AttributeMarker,\ ReferenceMarker): """ parents: complexType, restriction, extension, attributeGroup attributes: id -- ID ref -- QName, required use -- ('optional' | 'prohibited' | 'required'), optional default -- string fixed -- string contents: annotation? """ required = ['ref'] attributes = {'id':None, 'ref':None, 'use':'optional', 'default':None, 'fixed':None} contents = {'xsd':['annotation']} tag = 'attribute' def __init__(self, parent): XMLSchemaComponent.__init__(self, parent) self.annotation = None def getAttributeDeclaration(self, attribute='ref'): return XMLSchemaComponent.getAttributeDeclaration(self, attribute) def fromDom(self, node): self.setAttributes(node) contents = self.getContents(node) for i in contents: component = SplitQName(i.getTagName())[1] if component == 'annotation' and not self.annotation: self.annotation = Annotation(self) self.annotation.fromDom(i) else: raise SchemaError, 'Unknown component (%s)' %(i.getTagName()) class AttributeGroupDefinition(XMLSchemaComponent,\ AttributeGroupMarker,\ DefinitionMarker): """ parents: schema, redefine attributes: id -- ID name -- NCName, required contents: annotation?, (attribute | attributeGroup)*, anyAttribute? """ required = ['name'] attributes = {'id':None, 'name':None} contents = {'xsd':['annotation', 'attribute', 'attributeGroup', 'anyAttribute']} tag = 'attributeGroup' def __init__(self, parent): XMLSchemaComponent.__init__(self, parent) self.annotation = None self.attr_content = None def getAttributeContent(self): return self.attr_content def fromDom(self, node): self.setAttributes(node) contents = self.getContents(node) content = [] for indx in range(len(contents)): component = SplitQName(contents[indx].getTagName())[1] if (component == 'annotation') and (not indx): self.annotation = Annotation(self) self.annotation.fromDom(contents[indx]) elif component == 'attribute': if contents[indx].hasattr('name'): content.append(LocalAttributeDeclaration(self)) elif contents[indx].hasattr('ref'): content.append(AttributeReference(self)) else: raise SchemaError, 'Unknown attribute type' content[-1].fromDom(contents[indx]) elif component == 'attributeGroup': content.append(AttributeGroupReference(self)) content[-1].fromDom(contents[indx]) elif component == 'anyAttribute': if len(contents) != indx+1: raise SchemaError, 'anyAttribute is out of order in %s' %self.getItemTrace() content.append(AttributeWildCard(self)) content[-1].fromDom(contents[indx]) else: raise SchemaError, 'Unknown component (%s)' %(contents[indx].getTagName()) self.attr_content = tuple(content) class AttributeGroupReference(XMLSchemaComponent,\ AttributeGroupMarker,\ ReferenceMarker): """ parents: complexType, restriction, extension, attributeGroup attributes: id -- ID ref -- QName, required contents: annotation? """ required = ['ref'] attributes = {'id':None, 'ref':None} contents = {'xsd':['annotation']} tag = 'attributeGroup' def __init__(self, parent): XMLSchemaComponent.__init__(self, parent) self.annotation = None def getAttributeGroup(self, attribute='ref'): """attribute -- attribute with a QName value (eg. type). collection -- check types collection in parent Schema instance """ return XMLSchemaComponent.getQNameAttribute(self, 'attr_groups', attribute) def fromDom(self, node): self.setAttributes(node) contents = self.getContents(node) for i in contents: component = SplitQName(i.getTagName())[1] if component == 'annotation' and not self.annotation: self.annotation = Annotation(self) self.annotation.fromDom(i) else: raise SchemaError, 'Unknown component (%s)' %(i.getTagName()) ###################################################### # Elements ##################################################### class IdentityConstrants(XMLSchemaComponent): """Allow one to uniquely identify nodes in a document and ensure the integrity of references between them. attributes -- dictionary of attributes selector -- XPath to selected nodes fields -- list of XPath to key field """ def __init__(self, parent): XMLSchemaComponent.__init__(self, parent) self.selector = None self.fields = None self.annotation = None def fromDom(self, node): self.setAttributes(node) contents = self.getContents(node) fields = [] for i in contents: component = SplitQName(i.getTagName())[1] if component in self.__class__.contents['xsd']: if component == 'annotation' and not self.annotation: self.annotation = Annotation(self) self.annotation.fromDom(i) elif component == 'selector': self.selector = self.Selector(self) self.selector.fromDom(i) continue elif component == 'field': fields.append(self.Field(self)) fields[-1].fromDom(i) continue else: raise SchemaError, 'Unknown component (%s)' %(i.getTagName()) else: raise SchemaError, 'Unknown component (%s)' %(i.getTagName()) self.fields = tuple(fields) class Constraint(XMLSchemaComponent): def __init__(self, parent): XMLSchemaComponent.__init__(self, parent) self.annotation = None def fromDom(self, node): self.setAttributes(node) contents = self.getContents(node) for i in contents: component = SplitQName(i.getTagName())[1] if component in self.__class__.contents['xsd']: if component == 'annotation' and not self.annotation: self.annotation = Annotation(self) self.annotation.fromDom(i) else: raise SchemaError, 'Unknown component (%s)' %(i.getTagName()) else: raise SchemaError, 'Unknown component (%s)' %(i.getTagName()) class Selector(Constraint): """ parent: unique, key, keyref attributes: id -- ID xpath -- XPath subset, required contents: annotation? """ required = ['xpath'] attributes = {'id':None, 'xpath':None} contents = {'xsd':['annotation']} tag = 'selector' class Field(Constraint): """ parent: unique, key, keyref attributes: id -- ID xpath -- XPath subset, required contents: annotation? """ required = ['xpath'] attributes = {'id':None, 'xpath':None} contents = {'xsd':['annotation']} tag = 'field' class Unique(IdentityConstrants): """ Enforce fields are unique w/i a specified scope. parent: element attributes: id -- ID name -- NCName, required contents: annotation?, selector, field+ """ required = ['name'] attributes = {'id':None, 'name':None} contents = {'xsd':['annotation', 'selector', 'field']} tag = 'unique' class Key(IdentityConstrants): """ Enforce fields are unique w/i a specified scope, and all field values are present w/i document. Fields cannot be nillable. parent: element attributes: id -- ID name -- NCName, required contents: annotation?, selector, field+ """ required = ['name'] attributes = {'id':None, 'name':None} contents = {'xsd':['annotation', 'selector', 'field']} tag = 'key' class KeyRef(IdentityConstrants): """ Ensure a match between two sets of values in an instance. parent: element attributes: id -- ID name -- NCName, required refer -- QName, required contents: annotation?, selector, field+ """ required = ['name', 'refer'] attributes = {'id':None, 'name':None, 'refer':None} contents = {'xsd':['annotation', 'selector', 'field']} tag = 'keyref' class ElementDeclaration(XMLSchemaComponent,\ ElementMarker,\ DeclarationMarker): """ parents: schema attributes: id -- ID name -- NCName, required type -- QName default -- string fixed -- string nillable -- boolean, false abstract -- boolean, false substitutionGroup -- QName block -- ('#all' | ('substition' | 'extension' | 'restriction')*), schema.blockDefault final -- ('#all' | ('extension' | 'restriction')*), schema.finalDefault contents: annotation?, (simpleType,complexType)?, (key | keyref | unique)* """ required = ['name'] attributes = {'id':None, 'name':None, 'type':None, 'default':None, 'fixed':None, 'nillable':0, 'abstract':0, 'substitutionGroup':None, 'block':lambda self: self._parent().getBlockDefault(), 'final':lambda self: self._parent().getFinalDefault()} contents = {'xsd':['annotation', 'simpleType', 'complexType', 'key',\ 'keyref', 'unique']} tag = 'element' def __init__(self, parent): XMLSchemaComponent.__init__(self, parent) self.annotation = None self.content = None self.constraints = () def isQualified(self): '''Global elements are always qualified. ''' return True def getElementDeclaration(self, attribute): raise Warning, 'invalid operation for <%s>' %self.tag def getTypeDefinition(self, attribute=None): '''If attribute is None, "type" is assumed, return the corresponding representation of the global type definition (TypeDefinition), or the local definition if don't find "type". To maintain backwards compat, if attribute is provided call base class method. ''' if attribute: return XMLSchemaComponent.getTypeDefinition(self, attribute) gt = XMLSchemaComponent.getTypeDefinition(self, 'type') if gt: return gt return self.content def getConstraints(self): return self._constraints def setConstraints(self, constraints): self._constraints = tuple(constraints) constraints = property(getConstraints, setConstraints, None, "tuple of key, keyref, unique constraints") def fromDom(self, node): self.setAttributes(node) contents = self.getContents(node) constraints = [] for i in contents: component = SplitQName(i.getTagName())[1] if component in self.__class__.contents['xsd']: if component == 'annotation' and not self.annotation: self.annotation = Annotation(self) self.annotation.fromDom(i) elif component == 'simpleType' and not self.content: self.content = AnonymousSimpleType(self) self.content.fromDom(i) elif component == 'complexType' and not self.content: self.content = LocalComplexType(self) self.content.fromDom(i) elif component == 'key': constraints.append(Key(self)) constraints[-1].fromDom(i) elif component == 'keyref': constraints.append(KeyRef(self)) constraints[-1].fromDom(i) elif component == 'unique': constraints.append(Unique(self)) constraints[-1].fromDom(i) else: raise SchemaError, 'Unknown component (%s)' %(i.getTagName()) else: raise SchemaError, 'Unknown component (%s)' %(i.getTagName()) self.constraints = constraints class LocalElementDeclaration(ElementDeclaration,\ LocalMarker): """ parents: all, choice, sequence attributes: id -- ID name -- NCName, required form -- ('qualified' | 'unqualified'), schema.elementFormDefault type -- QName minOccurs -- Whole Number, 1 maxOccurs -- (Whole Number | 'unbounded'), 1 default -- string fixed -- string nillable -- boolean, false block -- ('#all' | ('extension' | 'restriction')*), schema.blockDefault contents: annotation?, (simpleType,complexType)?, (key | keyref | unique)* """ required = ['name'] attributes = {'id':None, 'name':None, 'form':lambda self: GetSchema(self).getElementFormDefault(), 'type':None, 'minOccurs':'1', 'maxOccurs':'1', 'default':None, 'fixed':None, 'nillable':0, 'abstract':0, 'block':lambda self: GetSchema(self).getBlockDefault()} contents = {'xsd':['annotation', 'simpleType', 'complexType', 'key',\ 'keyref', 'unique']} def isQualified(self): '''Local elements can be qualified or unqualifed according to the attribute form, or the elementFormDefault. By default local elements are unqualified. ''' form = self.getAttribute('form') if form == 'qualified': return True if form == 'unqualified': return False raise SchemaError, 'Bad form (%s) for element: %s' %(form, self.getItemTrace()) class ElementReference(XMLSchemaComponent,\ ElementMarker,\ ReferenceMarker): """ parents: all, choice, sequence attributes: id -- ID ref -- QName, required minOccurs -- Whole Number, 1 maxOccurs -- (Whole Number | 'unbounded'), 1 contents: annotation? """ required = ['ref'] attributes = {'id':None, 'ref':None, 'minOccurs':'1', 'maxOccurs':'1'} contents = {'xsd':['annotation']} tag = 'element' def __init__(self, parent): XMLSchemaComponent.__init__(self, parent) self.annotation = None def getElementDeclaration(self, attribute=None): '''If attribute is None, "ref" is assumed, return the corresponding representation of the global element declaration (ElementDeclaration), To maintain backwards compat, if attribute is provided call base class method. ''' if attribute: return XMLSchemaComponent.getElementDeclaration(self, attribute) return XMLSchemaComponent.getElementDeclaration(self, 'ref') def fromDom(self, node): self.annotation = None self.setAttributes(node) for i in self.getContents(node): component = SplitQName(i.getTagName())[1] if component in self.__class__.contents['xsd']: if component == 'annotation' and not self.annotation: self.annotation = Annotation(self) self.annotation.fromDom(i) else: raise SchemaError, 'Unknown component (%s)' %(i.getTagName()) class ElementWildCard(LocalElementDeclaration,\ WildCardMarker): """ parents: choice, sequence attributes: id -- ID minOccurs -- Whole Number, 1 maxOccurs -- (Whole Number | 'unbounded'), 1 namespace -- '##any' | '##other' | (anyURI* | '##targetNamespace' | '##local'), ##any processContents -- 'lax' | 'skip' | 'strict', strict contents: annotation? """ required = [] attributes = {'id':None, 'minOccurs':'1', 'maxOccurs':'1', 'namespace':'##any', 'processContents':'strict'} contents = {'xsd':['annotation']} tag = 'any' def __init__(self, parent): XMLSchemaComponent.__init__(self, parent) self.annotation = None def isQualified(self): '''Global elements are always qualified, but if processContents are not strict could have dynamically generated local elements. ''' return GetSchema(self).isElementFormDefaultQualified() def getTypeDefinition(self, attribute): raise Warning, 'invalid operation for <%s>' %self.tag def fromDom(self, node): self.annotation = None self.setAttributes(node) for i in self.getContents(node): component = SplitQName(i.getTagName())[1] if component in self.__class__.contents['xsd']: if component == 'annotation' and not self.annotation: self.annotation = Annotation(self) self.annotation.fromDom(i) else: raise SchemaError, 'Unknown component (%s)' %(i.getTagName()) ###################################################### # Model Groups ##################################################### class Sequence(XMLSchemaComponent,\ SequenceMarker): """ parents: complexType, extension, restriction, group, choice, sequence attributes: id -- ID minOccurs -- Whole Number, 1 maxOccurs -- (Whole Number | 'unbounded'), 1 contents: annotation?, (element | group | choice | sequence | any)* """ attributes = {'id':None, 'minOccurs':'1', 'maxOccurs':'1'} contents = {'xsd':['annotation', 'element', 'group', 'choice', 'sequence',\ 'any']} tag = 'sequence' def __init__(self, parent): XMLSchemaComponent.__init__(self, parent) self.annotation = None self.content = None def fromDom(self, node): self.setAttributes(node) contents = self.getContents(node) content = [] for i in contents: component = SplitQName(i.getTagName())[1] if component in self.__class__.contents['xsd']: if component == 'annotation' and not self.annotation: self.annotation = Annotation(self) self.annotation.fromDom(i) continue elif component == 'element': if i.hasattr('ref'): content.append(ElementReference(self)) else: content.append(LocalElementDeclaration(self)) elif component == 'group': content.append(ModelGroupReference(self)) elif component == 'choice': content.append(Choice(self)) elif component == 'sequence': content.append(Sequence(self)) elif component == 'any': content.append(ElementWildCard(self)) else: raise SchemaError, 'Unknown component (%s)' %(i.getTagName()) content[-1].fromDom(i) else: raise SchemaError, 'Unknown component (%s)' %(i.getTagName()) self.content = tuple(content) class All(XMLSchemaComponent,\ AllMarker): """ parents: complexType, extension, restriction, group attributes: id -- ID minOccurs -- '0' | '1', 1 maxOccurs -- '1', 1 contents: annotation?, element* """ attributes = {'id':None, 'minOccurs':'1', 'maxOccurs':'1'} contents = {'xsd':['annotation', 'element']} tag = 'all' def __init__(self, parent): XMLSchemaComponent.__init__(self, parent) self.annotation = None self.content = None def fromDom(self, node): self.setAttributes(node) contents = self.getContents(node) content = [] for i in contents: component = SplitQName(i.getTagName())[1] if component in self.__class__.contents['xsd']: if component == 'annotation' and not self.annotation: self.annotation = Annotation(self) self.annotation.fromDom(i) continue elif component == 'element': if i.hasattr('ref'): content.append(ElementReference(self)) else: content.append(LocalElementDeclaration(self)) else: raise SchemaError, 'Unknown component (%s)' %(i.getTagName()) content[-1].fromDom(i) else: raise SchemaError, 'Unknown component (%s)' %(i.getTagName()) self.content = tuple(content) class Choice(XMLSchemaComponent,\ ChoiceMarker): """ parents: complexType, extension, restriction, group, choice, sequence attributes: id -- ID minOccurs -- Whole Number, 1 maxOccurs -- (Whole Number | 'unbounded'), 1 contents: annotation?, (element | group | choice | sequence | any)* """ attributes = {'id':None, 'minOccurs':'1', 'maxOccurs':'1'} contents = {'xsd':['annotation', 'element', 'group', 'choice', 'sequence',\ 'any']} tag = 'choice' def __init__(self, parent): XMLSchemaComponent.__init__(self, parent) self.annotation = None self.content = None def fromDom(self, node): self.setAttributes(node) contents = self.getContents(node) content = [] for i in contents: component = SplitQName(i.getTagName())[1] if component in self.__class__.contents['xsd']: if component == 'annotation' and not self.annotation: self.annotation = Annotation(self) self.annotation.fromDom(i) continue elif component == 'element': if i.hasattr('ref'): content.append(ElementReference(self)) else: content.append(LocalElementDeclaration(self)) elif component == 'group': content.append(ModelGroupReference(self)) elif component == 'choice': content.append(Choice(self)) elif component == 'sequence': content.append(Sequence(self)) elif component == 'any': content.append(ElementWildCard(self)) else: raise SchemaError, 'Unknown component (%s)' %(i.getTagName()) content[-1].fromDom(i) else: raise SchemaError, 'Unknown component (%s)' %(i.getTagName()) self.content = tuple(content) class ModelGroupDefinition(XMLSchemaComponent,\ ModelGroupMarker,\ DefinitionMarker): """ parents: redefine, schema attributes: id -- ID name -- NCName, required contents: annotation?, (all | choice | sequence)? """ required = ['name'] attributes = {'id':None, 'name':None} contents = {'xsd':['annotation', 'all', 'choice', 'sequence']} tag = 'group' def __init__(self, parent): XMLSchemaComponent.__init__(self, parent) self.annotation = None self.content = None def fromDom(self, node): self.setAttributes(node) contents = self.getContents(node) for i in contents: component = SplitQName(i.getTagName())[1] if component in self.__class__.contents['xsd']: if component == 'annotation' and not self.annotation: self.annotation = Annotation(self) self.annotation.fromDom(i) continue elif component == 'all' and not self.content: self.content = All(self) elif component == 'choice' and not self.content: self.content = Choice(self) elif component == 'sequence' and not self.content: self.content = Sequence(self) else: raise SchemaError, 'Unknown component (%s)' %(i.getTagName()) self.content.fromDom(i) else: raise SchemaError, 'Unknown component (%s)' %(i.getTagName()) class ModelGroupReference(XMLSchemaComponent,\ ModelGroupMarker,\ ReferenceMarker): """ parents: choice, complexType, extension, restriction, sequence attributes: id -- ID ref -- NCName, required minOccurs -- Whole Number, 1 maxOccurs -- (Whole Number | 'unbounded'), 1 contents: annotation? """ required = ['ref'] attributes = {'id':None, 'ref':None, 'minOccurs':'1', 'maxOccurs':'1'} contents = {'xsd':['annotation']} tag = 'group' def __init__(self, parent): XMLSchemaComponent.__init__(self, parent) self.annotation = None def getModelGroupReference(self): return self.getModelGroup('ref') def fromDom(self, node): self.setAttributes(node) contents = self.getContents(node) for i in contents: component = SplitQName(i.getTagName())[1] if component in self.__class__.contents['xsd']: if component == 'annotation' and not self.annotation: self.annotation = Annotation(self) self.annotation.fromDom(i) else: raise SchemaError, 'Unknown component (%s)' %(i.getTagName()) else: raise SchemaError, 'Unknown component (%s)' %(i.getTagName()) class ComplexType(XMLSchemaComponent,\ DefinitionMarker,\ ComplexMarker): """ parents: redefine, schema attributes: id -- ID name -- NCName, required mixed -- boolean, false abstract -- boolean, false block -- ('#all' | ('extension' | 'restriction')*), schema.blockDefault final -- ('#all' | ('extension' | 'restriction')*), schema.finalDefault contents: annotation?, (simpleContent | complexContent | ((group | all | choice | sequence)?, (attribute | attributeGroup)*, anyAttribute?)) """ required = ['name'] attributes = {'id':None, 'name':None, 'mixed':0, 'abstract':0, 'block':lambda self: self._parent().getBlockDefault(), 'final':lambda self: self._parent().getFinalDefault()} contents = {'xsd':['annotation', 'simpleContent', 'complexContent',\ 'group', 'all', 'choice', 'sequence', 'attribute', 'attributeGroup',\ 'anyAttribute', 'any']} tag = 'complexType' def __init__(self, parent): XMLSchemaComponent.__init__(self, parent) self.annotation = None self.content = None self.attr_content = None def getAttributeContent(self): return self.attr_content def getElementDeclaration(self, attribute): raise Warning, 'invalid operation for <%s>' %self.tag def getTypeDefinition(self, attribute): raise Warning, 'invalid operation for <%s>' %self.tag def fromDom(self, node): self.setAttributes(node) contents = self.getContents(node) indx = 0 num = len(contents) #XXX ugly if not num: return component = SplitQName(contents[indx].getTagName())[1] if component == 'annotation': self.annotation = Annotation(self) self.annotation.fromDom(contents[indx]) indx += 1 component = SplitQName(contents[indx].getTagName())[1] self.content = None if component == 'simpleContent': self.content = self.__class__.SimpleContent(self) self.content.fromDom(contents[indx]) elif component == 'complexContent': self.content = self.__class__.ComplexContent(self) self.content.fromDom(contents[indx]) else: if component == 'all': self.content = All(self) elif component == 'choice': self.content = Choice(self) elif component == 'sequence': self.content = Sequence(self) elif component == 'group': self.content = ModelGroupReference(self) if self.content: self.content.fromDom(contents[indx]) indx += 1 self.attr_content = [] while indx < num: component = SplitQName(contents[indx].getTagName())[1] if component == 'attribute': if contents[indx].hasattr('ref'): self.attr_content.append(AttributeReference(self)) else: self.attr_content.append(LocalAttributeDeclaration(self)) elif component == 'attributeGroup': self.attr_content.append(AttributeGroupReference(self)) elif component == 'anyAttribute': self.attr_content.append(AttributeWildCard(self)) else: raise SchemaError, 'Unknown component (%s): %s' \ %(contents[indx].getTagName(),self.getItemTrace()) self.attr_content[-1].fromDom(contents[indx]) indx += 1 class _DerivedType(XMLSchemaComponent): def __init__(self, parent): XMLSchemaComponent.__init__(self, parent) self.annotation = None self.derivation = None def fromDom(self, node): self.setAttributes(node) contents = self.getContents(node) for i in contents: component = SplitQName(i.getTagName())[1] if component in self.__class__.contents['xsd']: if component == 'annotation' and not self.annotation: self.annotation = Annotation(self) self.annotation.fromDom(i) continue elif component == 'restriction' and not self.derivation: self.derivation = self.__class__.Restriction(self) elif component == 'extension' and not self.derivation: self.derivation = self.__class__.Extension(self) else: raise SchemaError, 'Unknown component (%s)' %(i.getTagName()) else: raise SchemaError, 'Unknown component (%s)' %(i.getTagName()) self.derivation.fromDom(i) class ComplexContent(_DerivedType,\ ComplexMarker): """ parents: complexType attributes: id -- ID mixed -- boolean, false contents: annotation?, (restriction | extension) """ attributes = {'id':None, 'mixed':0 } contents = {'xsd':['annotation', 'restriction', 'extension']} tag = 'complexContent' class _DerivationBase(XMLSchemaComponent): """, parents: complexContent attributes: id -- ID base -- QName, required contents: annotation?, (group | all | choice | sequence)?, (attribute | attributeGroup)*, anyAttribute? """ required = ['base'] attributes = {'id':None, 'base':None } contents = {'xsd':['annotation', 'group', 'all', 'choice',\ 'sequence', 'attribute', 'attributeGroup', 'anyAttribute']} def __init__(self, parent): XMLSchemaComponent.__init__(self, parent) self.annotation = None self.content = None self.attr_content = None def getAttributeContent(self): return self.attr_content def fromDom(self, node): self.setAttributes(node) contents = self.getContents(node) indx = 0 num = len(contents) #XXX ugly if not num: return component = SplitQName(contents[indx].getTagName())[1] if component == 'annotation': self.annotation = Annotation(self) self.annotation.fromDom(contents[indx]) indx += 1 component = SplitQName(contents[indx].getTagName())[1] if component == 'all': self.content = All(self) self.content.fromDom(contents[indx]) indx += 1 elif component == 'choice': self.content = Choice(self) self.content.fromDom(contents[indx]) indx += 1 elif component == 'sequence': self.content = Sequence(self) self.content.fromDom(contents[indx]) indx += 1 elif component == 'group': self.content = ModelGroupReference(self) self.content.fromDom(contents[indx]) indx += 1 else: self.content = None self.attr_content = [] while indx < num: component = SplitQName(contents[indx].getTagName())[1] if component == 'attribute': if contents[indx].hasattr('ref'): self.attr_content.append(AttributeReference(self)) else: self.attr_content.append(LocalAttributeDeclaration(self)) elif component == 'attributeGroup': if contents[indx].hasattr('ref'): self.attr_content.append(AttributeGroupReference(self)) else: self.attr_content.append(AttributeGroupDefinition(self)) elif component == 'anyAttribute': self.attr_content.append(AttributeWildCard(self)) else: raise SchemaError, 'Unknown component (%s)' %(contents[indx].getTagName()) self.attr_content[-1].fromDom(contents[indx]) indx += 1 class Extension(_DerivationBase, ExtensionMarker): """ parents: complexContent attributes: id -- ID base -- QName, required contents: annotation?, (group | all | choice | sequence)?, (attribute | attributeGroup)*, anyAttribute? """ tag = 'extension' class Restriction(_DerivationBase,\ RestrictionMarker): """ parents: complexContent attributes: id -- ID base -- QName, required contents: annotation?, (group | all | choice | sequence)?, (attribute | attributeGroup)*, anyAttribute? """ tag = 'restriction' class SimpleContent(_DerivedType,\ SimpleMarker): """ parents: complexType attributes: id -- ID contents: annotation?, (restriction | extension) """ attributes = {'id':None} contents = {'xsd':['annotation', 'restriction', 'extension']} tag = 'simpleContent' class Extension(XMLSchemaComponent,\ ExtensionMarker): """ parents: simpleContent attributes: id -- ID base -- QName, required contents: annotation?, (attribute | attributeGroup)*, anyAttribute? """ required = ['base'] attributes = {'id':None, 'base':None } contents = {'xsd':['annotation', 'attribute', 'attributeGroup', 'anyAttribute']} tag = 'extension' def __init__(self, parent): XMLSchemaComponent.__init__(self, parent) self.annotation = None self.attr_content = None def getAttributeContent(self): return self.attr_content def fromDom(self, node): self.setAttributes(node) contents = self.getContents(node) indx = 0 num = len(contents) if num: component = SplitQName(contents[indx].getTagName())[1] if component == 'annotation': self.annotation = Annotation(self) self.annotation.fromDom(contents[indx]) indx += 1 component = SplitQName(contents[indx].getTagName())[1] content = [] while indx < num: component = SplitQName(contents[indx].getTagName())[1] if component == 'attribute': if contents[indx].hasattr('ref'): content.append(AttributeReference(self)) else: content.append(LocalAttributeDeclaration(self)) elif component == 'attributeGroup': content.append(AttributeGroupReference(self)) elif component == 'anyAttribute': content.append(AttributeWildCard(self)) else: raise SchemaError, 'Unknown component (%s)'\ %(contents[indx].getTagName()) content[-1].fromDom(contents[indx]) indx += 1 self.attr_content = tuple(content) class Restriction(XMLSchemaComponent,\ RestrictionMarker): """ parents: simpleContent attributes: id -- ID base -- QName, required contents: annotation?, simpleType?, (enumeration | length | maxExclusive | maxInclusive | maxLength | minExclusive | minInclusive | minLength | pattern | fractionDigits | totalDigits | whiteSpace)*, (attribute | attributeGroup)*, anyAttribute? """ required = ['base'] attributes = {'id':None, 'base':None } contents = {'xsd':['annotation', 'simpleType', 'attribute',\ 'attributeGroup', 'anyAttribute'] + RestrictionMarker.facets} tag = 'restriction' def __init__(self, parent): XMLSchemaComponent.__init__(self, parent) self.annotation = None self.content = None self.attr_content = None def getAttributeContent(self): return self.attr_content def fromDom(self, node): self.content = [] self.setAttributes(node) contents = self.getContents(node) indx = 0 num = len(contents) component = SplitQName(contents[indx].getTagName())[1] if component == 'annotation': self.annotation = Annotation(self) self.annotation.fromDom(contents[indx]) indx += 1 component = SplitQName(contents[indx].getTagName())[1] content = [] while indx < num: component = SplitQName(contents[indx].getTagName())[1] if component == 'attribute': if contents[indx].hasattr('ref'): content.append(AttributeReference(self)) else: content.append(LocalAttributeDeclaration(self)) elif component == 'attributeGroup': content.append(AttributeGroupReference(self)) elif component == 'anyAttribute': content.append(AttributeWildCard(self)) elif component == 'simpleType': self.content.append(LocalSimpleType(self)) self.content[-1].fromDom(contents[indx]) else: raise SchemaError, 'Unknown component (%s)'\ %(contents[indx].getTagName()) content[-1].fromDom(contents[indx]) indx += 1 self.attr_content = tuple(content) class LocalComplexType(ComplexType,\ LocalMarker): """ parents: element attributes: id -- ID mixed -- boolean, false contents: annotation?, (simpleContent | complexContent | ((group | all | choice | sequence)?, (attribute | attributeGroup)*, anyAttribute?)) """ required = [] attributes = {'id':None, 'mixed':0} tag = 'complexType' class SimpleType(XMLSchemaComponent,\ DefinitionMarker,\ SimpleMarker): """ parents: redefine, schema attributes: id -- ID name -- NCName, required final -- ('#all' | ('extension' | 'restriction' | 'list' | 'union')*), schema.finalDefault contents: annotation?, (restriction | list | union) """ required = ['name'] attributes = {'id':None, 'name':None, 'final':lambda self: self._parent().getFinalDefault()} contents = {'xsd':['annotation', 'restriction', 'list', 'union']} tag = 'simpleType' def __init__(self, parent): XMLSchemaComponent.__init__(self, parent) self.annotation = None self.content = None def getElementDeclaration(self, attribute): raise Warning, 'invalid operation for <%s>' %self.tag def getTypeDefinition(self, attribute): raise Warning, 'invalid operation for <%s>' %self.tag def fromDom(self, node): self.setAttributes(node) contents = self.getContents(node) for child in contents: component = SplitQName(child.getTagName())[1] if component == 'annotation': self.annotation = Annotation(self) self.annotation.fromDom(child) continue break else: return if component == 'restriction': self.content = self.__class__.Restriction(self) elif component == 'list': self.content = self.__class__.List(self) elif component == 'union': self.content = self.__class__.Union(self) else: raise SchemaError, 'Unknown component (%s)' %(component) self.content.fromDom(child) class Restriction(XMLSchemaComponent,\ RestrictionMarker): """ parents: simpleType attributes: id -- ID base -- QName, required or simpleType child contents: annotation?, simpleType?, (enumeration | length | maxExclusive | maxInclusive | maxLength | minExclusive | minInclusive | minLength | pattern | fractionDigits | totalDigits | whiteSpace)* """ attributes = {'id':None, 'base':None } contents = {'xsd':['annotation', 'simpleType']+RestrictionMarker.facets} tag = 'restriction' def __init__(self, parent): XMLSchemaComponent.__init__(self, parent) self.annotation = None self.content = None def getSimpleTypeContent(self): for el in self.content: if el.isSimple(): return el return None def fromDom(self, node): self.setAttributes(node) contents = self.getContents(node) content = [] for indx in range(len(contents)): component = SplitQName(contents[indx].getTagName())[1] if (component == 'annotation') and (not indx): self.annotation = Annotation(self) self.annotation.fromDom(contents[indx]) continue elif (component == 'simpleType') and (not indx or indx == 1): content.append(AnonymousSimpleType(self)) content[-1].fromDom(contents[indx]) elif component in RestrictionMarker.facets: #print_debug('%s class instance, skipping %s' %(self.__class__, component)) pass else: raise SchemaError, 'Unknown component (%s)' %(i.getTagName()) self.content = tuple(content) class Union(XMLSchemaComponent, UnionMarker): """ parents: simpleType attributes: id -- ID memberTypes -- list of QNames, required or simpleType child. contents: annotation?, simpleType* """ attributes = {'id':None, 'memberTypes':None } contents = {'xsd':['annotation', 'simpleType']} tag = 'union' def __init__(self, parent): XMLSchemaComponent.__init__(self, parent) self.annotation = None self.content = None def fromDom(self, node): self.setAttributes(node) contents = self.getContents(node) content = [] for indx in range(len(contents)): component = SplitQName(contents[indx].getTagName())[1] if (component == 'annotation') and (not indx): self.annotation = Annotation(self) self.annotation.fromDom(contents[indx]) elif (component == 'simpleType'): content.append(AnonymousSimpleType(self)) content[-1].fromDom(contents[indx]) else: raise SchemaError, 'Unknown component (%s)' %(i.getTagName()) self.content = tuple(content) class List(XMLSchemaComponent, ListMarker): """ parents: simpleType attributes: id -- ID itemType -- QName, required or simpleType child. contents: annotation?, simpleType? """ attributes = {'id':None, 'itemType':None } contents = {'xsd':['annotation', 'simpleType']} tag = 'list' def __init__(self, parent): XMLSchemaComponent.__init__(self, parent) self.annotation = None self.content = None def getItemType(self): return self.attributes.get('itemType') def getTypeDefinition(self, attribute='itemType'): '''return the type refered to by itemType attribute or the simpleType content. If returns None, then the type refered to by itemType is primitive. ''' tp = XMLSchemaComponent.getTypeDefinition(self, attribute) return tp or self.content def fromDom(self, node): self.annotation = None self.content = None self.setAttributes(node) contents = self.getContents(node) for indx in range(len(contents)): component = SplitQName(contents[indx].getTagName())[1] if (component == 'annotation') and (not indx): self.annotation = Annotation(self) self.annotation.fromDom(contents[indx]) elif (component == 'simpleType'): self.content = AnonymousSimpleType(self) self.content.fromDom(contents[indx]) break else: raise SchemaError, 'Unknown component (%s)' %(i.getTagName()) class AnonymousSimpleType(SimpleType,\ SimpleMarker): """ parents: attribute, element, list, restriction, union attributes: id -- ID contents: annotation?, (restriction | list | union) """ required = [] attributes = {'id':None} tag = 'simpleType' class Redefine: """ parents: attributes: contents: """ tag = 'redefine' ########################### ########################### if sys.version_info[:2] >= (2, 2): tupleClass = tuple else: import UserTuple tupleClass = UserTuple.UserTuple class TypeDescriptionComponent(tupleClass): """Tuple of length 2, consisting of a namespace and unprefixed name. """ def __init__(self, args): """args -- (namespace, name) Remove the name's prefix, irrelevant. """ if len(args) != 2: raise TypeError, 'expecting tuple (namespace, name), got %s' %args elif args[1].find(':') >= 0: args = (args[0], SplitQName(args[1])[1]) tuple.__init__(self, args) return def getTargetNamespace(self): return self[0] def getName(self): return self[1] SOAPpy-0.12.0/SOAPpy/wstools/XMLname.py0100644001604000501700000000474110204656221017233 0ustar warnegclinical"""Translate strings to and from SOAP 1.2 XML name encoding Implements rules for mapping application defined name to XML names specified by the w3 SOAP working group for SOAP version 1.2 in Appendix A of "SOAP Version 1.2 Part 2: Adjuncts", W3C Working Draft 17, December 2001, Also see . Author: Gregory R. Warnes Date:: 2002-04-25 Version 0.9.0 """ ident = "$Id: XMLname.py,v 1.4 2005/02/16 14:45:37 warnes Exp $" from re import * def _NCNameChar(x): return x.isalpha() or x.isdigit() or x=="." or x=='-' or x=="_" def _NCNameStartChar(x): return x.isalpha() or x=="_" def _toUnicodeHex(x): hexval = hex(ord(x[0]))[2:] hexlen = len(hexval) # Make hexval have either 4 or 8 digits by prepending 0's if (hexlen==1): hexval = "000" + hexval elif (hexlen==2): hexval = "00" + hexval elif (hexlen==3): hexval = "0" + hexval elif (hexlen==4): hexval = "" + hexval elif (hexlen==5): hexval = "000" + hexval elif (hexlen==6): hexval = "00" + hexval elif (hexlen==7): hexval = "0" + hexval elif (hexlen==8): hexval = "" + hexval else: raise Exception, "Illegal Value returned from hex(ord(x))" return "_x"+ hexval + "_" def _fromUnicodeHex(x): return eval( r'u"\u'+x[2:-1]+'"' ) def toXMLname(string): """Convert string to a XML name.""" if string.find(':') != -1 : (prefix, localname) = string.split(':',1) else: prefix = None localname = string T = unicode(localname) N = len(localname) X = []; for i in range(N) : if i< N-1 and T[i]==u'_' and T[i+1]==u'x': X.append(u'_x005F_') elif i==0 and N >= 3 and \ ( T[0]==u'x' or T[0]==u'X' ) and \ ( T[1]==u'm' or T[1]==u'M' ) and \ ( T[2]==u'l' or T[2]==u'L' ): X.append(u'_xFFFF_' + T[0]) elif (not _NCNameChar(T[i])) or (i==0 and not _NCNameStartChar(T[i])): X.append(_toUnicodeHex(T[i])) else: X.append(T[i]) if prefix: return "%s:%s" % (prefix, u''.join(X)) return u''.join(X) def fromXMLname(string): """Convert XML name to unicode string.""" retval = sub(r'_xFFFF_','', string ) def fun( matchobj ): return _fromUnicodeHex( matchobj.group(0) ) retval = sub(r'_x[0-9A-Za-z]+_', fun, retval ) return retval SOAPpy-0.12.0/SOAPpy/wstools/__init__.py0100644001604000501700000000031610202425136017460 0ustar warnegclinical#! /usr/bin/env python """WSDL parsing services package for Web Services for Python.""" ident = "$Id: __init__.py,v 1.11 2004/12/07 15:54:53 blunck2 Exp $" import WSDLTools import XMLname import logging SOAPpy-0.12.0/SOAPpy/wstools/c14n.py0100755001604000501700000005141210202425137016475 0ustar warnegclinical#! /usr/bin/env python """Compatibility module, imported by ZSI if you don't have PyXML 0.7. No copyright violations -- we're only using parts of PyXML that we wrote. """ _copyright = '''ZSI: Zolera Soap Infrastructure. Copyright 2001, Zolera Systems, Inc. All Rights Reserved. Copyright 2002-2003, Rich Salz. All Rights Reserved. Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, provided that the above copyright notice(s) and this permission notice appear in all copies of the Software and that both the above copyright notice(s) and this permission notice appear in supporting documentation. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. Except as contained in this notice, the name of a copyright holder shall not be used in advertising or otherwise to promote the sale, use or other dealings in this Software without prior written authorization of the copyright holder. ''' _copyright += "\n\nPortions are also: " _copyright += '''Copyright 2001, Zolera Systems Inc. All Rights Reserved. Copyright 2001, MIT. All Rights Reserved. Distributed under the terms of: Python 2.0 License or later. http://www.python.org/2.0.1/license.html or W3C Software License http://www.w3.org/Consortium/Legal/copyright-software-19980720 ''' from xml.dom import Node from Namespaces import XMLNS import cStringIO as StringIO try: from xml.dom.ext import c14n except ImportError, ex: _implementation2 = None _attrs = lambda E: (E.attributes and E.attributes.values()) or [] _children = lambda E: E.childNodes or [] else: class _implementation2(c14n._implementation): """Patch for exclusive c14n """ def __init__(self, node, write, **kw): self.unsuppressedPrefixes = kw.get('unsuppressedPrefixes') self._exclusive = None if node.nodeType == Node.ELEMENT_NODE: if not c14n._inclusive(self): self._exclusive = self._inherit_context(node) c14n._implementation.__init__(self, node, write, **kw) def _do_element(self, node, initial_other_attrs = []): """Patch for the xml.dom.ext.c14n implemenation _do_element method. This fixes a problem with sorting of namespaces. """ # Get state (from the stack) make local copies. # ns_parent -- NS declarations in parent # ns_rendered -- NS nodes rendered by ancestors # ns_local -- NS declarations relevant to this element # xml_attrs -- Attributes in XML namespace from parent # xml_attrs_local -- Local attributes in XML namespace. ns_parent, ns_rendered, xml_attrs = \ self.state[0], self.state[1].copy(), self.state[2].copy() #0422 ns_local = ns_parent.copy() xml_attrs_local = {} # Divide attributes into NS, XML, and others. #other_attrs = initial_other_attrs[:] other_attrs = [] sort_these_attrs = initial_other_attrs[:] in_subset = c14n._in_subset(self.subset, node) #for a in _attrs(node): sort_these_attrs +=c14n._attrs(node) for a in sort_these_attrs: if a.namespaceURI == c14n.XMLNS.BASE: n = a.nodeName if n == "xmlns:": n = "xmlns" # DOM bug workaround ns_local[n] = a.nodeValue elif a.namespaceURI == c14n.XMLNS.XML: if c14n._inclusive(self) or (in_subset and c14n._in_subset(self.subset, a)): #020925 Test to see if attribute node in subset xml_attrs_local[a.nodeName] = a #0426 else: if c14n._in_subset(self.subset, a): #020925 Test to see if attribute node in subset other_attrs.append(a) #add local xml:foo attributes to ancestor's xml:foo attributes xml_attrs.update(xml_attrs_local) # Render the node W, name = self.write, None if in_subset: name = node.nodeName W('<') W(name) # Create list of NS attributes to render. ns_to_render = [] for n,v in ns_local.items(): # If default namespace is XMLNS.BASE or empty, # and if an ancestor was the same if n == "xmlns" and v in [ c14n.XMLNS.BASE, '' ] \ and ns_rendered.get('xmlns') in [ c14n.XMLNS.BASE, '', None ]: continue # "omit namespace node with local name xml, which defines # the xml prefix, if its string value is # http://www.w3.org/XML/1998/namespace." if n in ["xmlns:xml", "xml"] \ and v in [ 'http://www.w3.org/XML/1998/namespace' ]: continue # If not previously rendered # and it's inclusive or utilized if (n,v) not in ns_rendered.items() \ and (c14n._inclusive(self) or \ c14n._utilized(n, node, other_attrs, self.unsuppressedPrefixes)): ns_to_render.append((n, v)) ##################################### # JRB ##################################### if not c14n._inclusive(self): if node.prefix is None: look_for = [('xmlns', node.namespaceURI),] else: look_for = [('xmlns:%s' %node.prefix, node.namespaceURI),] for a in c14n._attrs(node): if a.namespaceURI != XMLNS.BASE: #print "ATTRIBUTE: ", (a.namespaceURI, a.prefix) if a.prefix: #print "APREFIX: ", a.prefix look_for.append(('xmlns:%s' %a.prefix, a.namespaceURI)) for key,namespaceURI in look_for: if ns_rendered.has_key(key): if ns_rendered[key] == namespaceURI: # Dont write out pass else: #ns_to_render += [(key, namespaceURI)] pass elif (key,namespaceURI) in ns_to_render: # Dont write out pass else: # Unique write out, rewrite to render ns_local[key] = namespaceURI for a in self._exclusive: if a.nodeName == key: #self._do_attr(a.nodeName, a.value) #ns_rendered[key] = namespaceURI #break ns_to_render += [(a.nodeName, a.value)] break elif key is None and a.nodeName == 'xmlns': #print "DEFAULT: ", (a.nodeName, a.value) ns_to_render += [(a.nodeName, a.value)] break #print "KEY: ", key else: #print "Look for: ", look_for #print "NS_TO_RENDER: ", ns_to_render #print "EXCLUSIVE NS: ", map(lambda f: (f.nodeName,f.value),self._exclusive) raise RuntimeError, \ 'can not find namespace (%s="%s") for exclusive canonicalization'\ %(key, namespaceURI) ##################################### # Sort and render the ns, marking what was rendered. ns_to_render.sort(c14n._sorter_ns) for n,v in ns_to_render: #XXX JRB, getting 'xmlns,None' here when xmlns='' if v: self._do_attr(n, v) else: v = '' self._do_attr(n, v) ns_rendered[n]=v #0417 # If exclusive or the parent is in the subset, add the local xml attributes # Else, add all local and ancestor xml attributes # Sort and render the attributes. if not c14n._inclusive(self) or c14n._in_subset(self.subset,node.parentNode): #0426 other_attrs.extend(xml_attrs_local.values()) else: other_attrs.extend(xml_attrs.values()) #print "OTHER: ", other_attrs other_attrs.sort(c14n._sorter) for a in other_attrs: self._do_attr(a.nodeName, a.value) W('>') # Push state, recurse, pop state. state, self.state = self.state, (ns_local, ns_rendered, xml_attrs) for c in c14n._children(node): c14n._implementation.handlers[c.nodeType](self, c) self.state = state if name: W('' % name) c14n._implementation.handlers[c14n.Node.ELEMENT_NODE] = _do_element _IN_XML_NS = lambda n: n.namespaceURI == XMLNS.XML # Does a document/PI has lesser/greater document order than the # first element? _LesserElement, _Element, _GreaterElement = range(3) def _sorter(n1,n2): '''_sorter(n1,n2) -> int Sorting predicate for non-NS attributes.''' i = cmp(n1.namespaceURI, n2.namespaceURI) if i: return i return cmp(n1.localName, n2.localName) def _sorter_ns(n1,n2): '''_sorter_ns((n,v),(n,v)) -> int "(an empty namespace URI is lexicographically least)."''' if n1[0] == 'xmlns': return -1 if n2[0] == 'xmlns': return 1 return cmp(n1[0], n2[0]) def _utilized(n, node, other_attrs, unsuppressedPrefixes): '''_utilized(n, node, other_attrs, unsuppressedPrefixes) -> boolean Return true if that nodespace is utilized within the node''' if n.startswith('xmlns:'): n = n[6:] elif n.startswith('xmlns'): n = n[5:] if n == node.prefix or n in unsuppressedPrefixes: return 1 for attr in other_attrs: if n == attr.prefix: return 1 return 0 _in_subset = lambda subset, node: not subset or node in subset # # JRB. Currently there is a bug in do_element, but since the underlying # Data Structures in c14n have changed I can't just apply the # _implementation2 patch above. But this will work OK for most uses, # just not XML Signatures. # class _implementation: '''Implementation class for C14N. This accompanies a node during it's processing and includes the parameters and processing state.''' # Handler for each node type; populated during module instantiation. handlers = {} def __init__(self, node, write, **kw): '''Create and run the implementation.''' self.write = write self.subset = kw.get('subset') if self.subset: self.comments = kw.get('comments', 1) else: self.comments = kw.get('comments', 0) self.unsuppressedPrefixes = kw.get('unsuppressedPrefixes') nsdict = kw.get('nsdict', { 'xml': XMLNS.XML, 'xmlns': XMLNS.BASE }) # Processing state. self.state = (nsdict, ['xml'], []) if node.nodeType == Node.DOCUMENT_NODE: self._do_document(node) elif node.nodeType == Node.ELEMENT_NODE: self.documentOrder = _Element # At document element if self.unsuppressedPrefixes is not None: self._do_element(node) else: inherited = self._inherit_context(node) self._do_element(node, inherited) elif node.nodeType == Node.DOCUMENT_TYPE_NODE: pass else: raise TypeError, str(node) def _inherit_context(self, node): '''_inherit_context(self, node) -> list Scan ancestors of attribute and namespace context. Used only for single element node canonicalization, not for subset canonicalization.''' # Collect the initial list of xml:foo attributes. xmlattrs = filter(_IN_XML_NS, _attrs(node)) # Walk up and get all xml:XXX attributes we inherit. inherited, parent = [], node.parentNode while parent and parent.nodeType == Node.ELEMENT_NODE: for a in filter(_IN_XML_NS, _attrs(parent)): n = a.localName if n not in xmlattrs: xmlattrs.append(n) inherited.append(a) parent = parent.parentNode return inherited def _do_document(self, node): '''_do_document(self, node) -> None Process a document node. documentOrder holds whether the document element has been encountered such that PIs/comments can be written as specified.''' self.documentOrder = _LesserElement for child in node.childNodes: if child.nodeType == Node.ELEMENT_NODE: self.documentOrder = _Element # At document element self._do_element(child) self.documentOrder = _GreaterElement # After document element elif child.nodeType == Node.PROCESSING_INSTRUCTION_NODE: self._do_pi(child) elif child.nodeType == Node.COMMENT_NODE: self._do_comment(child) elif child.nodeType == Node.DOCUMENT_TYPE_NODE: pass else: raise TypeError, str(child) handlers[Node.DOCUMENT_NODE] = _do_document def _do_text(self, node): '''_do_text(self, node) -> None Process a text or CDATA node. Render various special characters as their C14N entity representations.''' if not _in_subset(self.subset, node): return s = node.data \ .replace("&", "&") \ .replace("<", "<") \ .replace(">", ">") \ .replace("\015", " ") if s: self.write(s) handlers[Node.TEXT_NODE] = _do_text handlers[Node.CDATA_SECTION_NODE] = _do_text def _do_pi(self, node): '''_do_pi(self, node) -> None Process a PI node. Render a leading or trailing #xA if the document order of the PI is greater or lesser (respectively) than the document element. ''' if not _in_subset(self.subset, node): return W = self.write if self.documentOrder == _GreaterElement: W('\n') W('') if self.documentOrder == _LesserElement: W('\n') handlers[Node.PROCESSING_INSTRUCTION_NODE] = _do_pi def _do_comment(self, node): '''_do_comment(self, node) -> None Process a comment node. Render a leading or trailing #xA if the document order of the comment is greater or lesser (respectively) than the document element. ''' if not _in_subset(self.subset, node): return if self.comments: W = self.write if self.documentOrder == _GreaterElement: W('\n') W('') if self.documentOrder == _LesserElement: W('\n') handlers[Node.COMMENT_NODE] = _do_comment def _do_attr(self, n, value): ''''_do_attr(self, node) -> None Process an attribute.''' W = self.write W(' ') W(n) W('="') s = value \ .replace("&", "&") \ .replace("<", "<") \ .replace('"', '"') \ .replace('\011', ' ') \ .replace('\012', ' ') \ .replace('\015', ' ') W(s) W('"') def _do_element(self, node, initial_other_attrs = []): '''_do_element(self, node, initial_other_attrs = []) -> None Process an element (and its children).''' # Get state (from the stack) make local copies. # ns_parent -- NS declarations in parent # ns_rendered -- NS nodes rendered by ancestors # xml_attrs -- Attributes in XML namespace from parent # ns_local -- NS declarations relevant to this element ns_parent, ns_rendered, xml_attrs = \ self.state[0], self.state[1][:], self.state[2][:] ns_local = ns_parent.copy() # Divide attributes into NS, XML, and others. other_attrs = initial_other_attrs[:] in_subset = _in_subset(self.subset, node) for a in _attrs(node): if a.namespaceURI == XMLNS.BASE: n = a.nodeName if n == "xmlns:": n = "xmlns" # DOM bug workaround ns_local[n] = a.nodeValue elif a.namespaceURI == XMLNS.XML: if self.unsuppressedPrefixes is None or in_subset: xml_attrs.append(a) else: other_attrs.append(a) # Render the node W, name = self.write, None if in_subset: name = node.nodeName W('<') W(name) # Create list of NS attributes to render. ns_to_render = [] for n,v in ns_local.items(): pval = ns_parent.get(n) # If default namespace is XMLNS.BASE or empty, skip if n == "xmlns" \ and v in [ XMLNS.BASE, '' ] and pval in [ XMLNS.BASE, '' ]: continue # "omit namespace node with local name xml, which defines # the xml prefix, if its string value is # http://www.w3.org/XML/1998/namespace." if n == "xmlns:xml" \ and v in [ 'http://www.w3.org/XML/1998/namespace' ]: continue # If different from parent, or parent didn't render # and if not exclusive, or this prefix is needed or # not suppressed if (v != pval or n not in ns_rendered) \ and (self.unsuppressedPrefixes is None or \ _utilized(n, node, other_attrs, self.unsuppressedPrefixes)): ns_to_render.append((n, v)) # Sort and render the ns, marking what was rendered. ns_to_render.sort(_sorter_ns) for n,v in ns_to_render: self._do_attr(n, v) ns_rendered.append(n) # Add in the XML attributes (don't pass to children, since # we're rendering them), sort, and render. other_attrs.extend(xml_attrs) xml_attrs = [] other_attrs.sort(_sorter) for a in other_attrs: self._do_attr(a.nodeName, a.value) W('>') # Push state, recurse, pop state. state, self.state = self.state, (ns_local, ns_rendered, xml_attrs) for c in _children(node): _implementation.handlers[c.nodeType](self, c) self.state = state if name: W('' % name) handlers[Node.ELEMENT_NODE] = _do_element def Canonicalize(node, output=None, **kw): '''Canonicalize(node, output=None, **kw) -> UTF-8 Canonicalize a DOM document/element node and all descendents. Return the text; if output is specified then output.write will be called to output the text and None will be returned Keyword parameters: nsdict: a dictionary of prefix:uri namespace entries assumed to exist in the surrounding context comments: keep comments if non-zero (default is 0) subset: Canonical XML subsetting resulting from XPath (default is []) unsuppressedPrefixes: do exclusive C14N, and this specifies the prefixes that should be inherited. ''' if output: if _implementation2 is None: _implementation(node, output.write, **kw) else: apply(_implementation2, (node, output.write), kw) else: s = StringIO.StringIO() if _implementation2 is None: _implementation(node, s.write, **kw) else: apply(_implementation2, (node, s.write), kw) return s.getvalue() if __name__ == '__main__': print _copyright SOAPpy-0.12.0/SOAPpy/wstools/logging.py0100644001604000501700000000362010202425137017351 0ustar warnegclinical#! /usr/bin/env python """Logging""" import sys class ILogger: '''Logger interface, by default this class will be used and logging calls are no-ops. ''' level = 0 def __init__(self, msg): return def warning(self, *args): return def debug(self, *args): return def error(self, *args): return def setLevel(cls, level): cls.level = level setLevel = classmethod(setLevel) _LoggerClass = ILogger class BasicLogger(ILogger): def __init__(self, msg, out=sys.stdout): self.msg, self.out = msg, out def warning(self, msg, *args): if self.level < 1: return print >>self, self.WARN, self.msg, print >>self, msg %args WARN = 'WARN' def debug(self, msg, *args): if self.level < 2: return print >>self, self.DEBUG, self.msg, print >>self, msg %args DEBUG = 'DEBUG' def error(self, msg, *args): print >>self, self.ERROR, self.msg, print >>self, msg %args ERROR = 'ERROR' def write(self, *args): '''Write convenience function; writes strings. ''' for s in args: self.out.write(s) def setBasicLogger(): '''Use Basic Logger. ''' setLoggerClass(BasicLogger) BasicLogger.setLevel(0) def setBasicLoggerWARN(): '''Use Basic Logger. ''' setLoggerClass(BasicLogger) BasicLogger.setLevel(1) def setBasicLoggerDEBUG(): '''Use Basic Logger. ''' setLoggerClass(BasicLogger) BasicLogger.setLevel(2) def setLoggerClass(loggingClass): '''Set Logging Class. ''' assert issubclass(loggingClass, ILogger), 'loggingClass must subclass ILogger' global _LoggerClass _LoggerClass = loggingClass def setLevel(level=0): '''Set Global Logging Level. ''' ILogger.level = level def getLogger(msg): '''Return instance of Logging class. ''' return _LoggerClass(msg) SOAPpy-0.12.0/SOAPpy/Client.py0100644001604000501700000004123610206442035015434 0ustar warnegclinical""" ################################################################################ # # SOAPpy - Cayce Ullman (cayce@actzero.com) # Brian Matthews (blm@actzero.com) # Gregory Warnes (Gregory.R.Warnes@Pfizer.com) # Christopher Blunck (blunck@gst.com) # ################################################################################ # Copyright (c) 2003, Pfizer # Copyright (c) 2001, Cayce Ullman. # Copyright (c) 2001, Brian Matthews. # # All rights reserved. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions are met: # Redistributions of source code must retain the above copyright notice, this # list of conditions and the following disclaimer. # # Redistributions in binary form must reproduce the above copyright notice, # this list of conditions and the following disclaimer in the documentation # and/or other materials provided with the distribution. # # Neither the name of actzero, inc. nor the names of its contributors may # be used to endorse or promote products derived from this software without # specific prior written permission. # # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE # ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR # ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES # (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; # LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND # ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS # SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. # ################################################################################ """ ident = '$Id: Client.py,v 1.27 2005/02/21 20:27:09 warnes Exp $' from version import __version__ from __future__ import nested_scopes #import xml.sax import urllib from types import * import re import base64 # SOAPpy modules from Errors import * from Config import Config from Parser import parseSOAPRPC from SOAPBuilder import buildSOAP from Utilities import * from Types import faultType, simplify ################################################################################ # Client ################################################################################ def SOAPUserAgent(): return "SOAPpy " + __version__ + " (pywebsvcs.sf.net)" class SOAPAddress: def __init__(self, url, config = Config): proto, uri = urllib.splittype(url) # apply some defaults if uri[0:2] != '//': if proto != None: uri = proto + ':' + uri uri = '//' + uri proto = 'http' host, path = urllib.splithost(uri) try: int(host) host = 'localhost:' + host except: pass if not path: path = '/' if proto not in ('http', 'https', 'httpg'): raise IOError, "unsupported SOAP protocol" if proto == 'httpg' and not config.GSIclient: raise AttributeError, \ "GSI client not supported by this Python installation" if proto == 'https' and not config.SSLclient: raise AttributeError, \ "SSL client not supported by this Python installation" self.user,host = urllib.splituser(host) self.proto = proto self.host = host self.path = path def __str__(self): return "%(proto)s://%(host)s%(path)s" % self.__dict__ __repr__ = __str__ class HTTPTransport: def getNS(self, original_namespace, data): """Extract the (possibly extended) namespace from the returned SOAP message.""" if type(original_namespace) == StringType: pattern="xmlns:\w+=['\"](" + original_namespace + "[^'\"]*)['\"]" match = re.search(pattern, data) if match: return match.group(1) else: return original_namespace else: return original_namespace # Need a Timeout someday? def call(self, addr, data, namespace, soapaction = None, encoding = None, http_proxy = None, config = Config): import httplib if not isinstance(addr, SOAPAddress): addr = SOAPAddress(addr, config) # Build a request if http_proxy: real_addr = http_proxy real_path = addr.proto + "://" + addr.host + addr.path else: real_addr = addr.host real_path = addr.path if addr.proto == 'httpg': from pyGlobus.io import GSIHTTP r = GSIHTTP(real_addr, tcpAttr = config.tcpAttr) elif addr.proto == 'https': r = httplib.HTTPS(real_addr) else: r = httplib.HTTP(real_addr) r.putrequest("POST", real_path) r.putheader("Host", addr.host) r.putheader("User-agent", SOAPUserAgent()) t = 'text/xml'; if encoding != None: t += '; charset="%s"' % encoding r.putheader("Content-type", t) r.putheader("Content-length", str(len(data))) # if user is not a user:passwd format # we'll receive a failure from the server. . .I guess (??) if addr.user != None: val = base64.encodestring(addr.user) r.putheader('Authorization','Basic ' + val.replace('\012','')) # This fixes sending either "" or "None" if soapaction == None or len(soapaction) == 0: r.putheader("SOAPAction", "") else: r.putheader("SOAPAction", '"%s"' % soapaction) if config.dumpHeadersOut: s = 'Outgoing HTTP headers' debugHeader(s) print "POST %s %s" % (real_path, r._http_vsn_str) print "Host:", addr.host print "User-agent: SOAPpy " + __version__ + " (http://pywebsvcs.sf.net)" print "Content-type:", t print "Content-length:", len(data) print 'SOAPAction: "%s"' % soapaction debugFooter(s) r.endheaders() if config.dumpSOAPOut: s = 'Outgoing SOAP' debugHeader(s) print data, if data[-1] != '\n': print debugFooter(s) # send the payload r.send(data) # read response line code, msg, headers = r.getreply() if headers: content_type = headers.get("content-type","text/xml") content_length = headers.get("Content-length") else: content_type=None content_length=None # work around OC4J bug which does ', ' for some reaason if content_length: comma=content_length.find(',') if comma>0: content_length = content_length[:comma] # attempt to extract integer message size try: message_len = int(content_length) except: message_len = -1 if message_len < 0: # Content-Length missing or invalid; just read the whole socket # This won't work with HTTP/1.1 chunked encoding data = r.getfile().read() message_len = len(data) else: data = r.getfile().read(message_len) if(config.debug): print "code=",code print "msg=", msg print "headers=", headers print "content-type=", content_type print "data=", data if config.dumpHeadersIn: s = 'Incoming HTTP headers' debugHeader(s) if headers.headers: print "HTTP/1.? %d %s" % (code, msg) print "\n".join(map (lambda x: x.strip(), headers.headers)) else: print "HTTP/0.9 %d %s" % (code, msg) debugFooter(s) def startswith(string, val): return string[0:len(val)] == val if code == 500 and not \ ( startswith(content_type, "text/xml") and message_len > 0 ): raise HTTPError(code, msg) if config.dumpSOAPIn: s = 'Incoming SOAP' debugHeader(s) print data, if (len(data)>0) and (data[-1] != '\n'): print debugFooter(s) if code not in (200, 500): raise HTTPError(code, msg) # get the new namespace if namespace is None: new_ns = None else: new_ns = self.getNS(namespace, data) # return response payload return data, new_ns ################################################################################ # SOAP Proxy ################################################################################ class SOAPProxy: def __init__(self, proxy, namespace = None, soapaction = None, header = None, methodattrs = None, transport = HTTPTransport, encoding = 'UTF-8', throw_faults = 1, unwrap_results = None, http_proxy=None, config = Config, noroot = 0, simplify_objects=None): # Test the encoding, raising an exception if it's not known if encoding != None: ''.encode(encoding) # get default values for unwrap_results and simplify_objects # from config if unwrap_results is None: self.unwrap_results=config.unwrap_results else: self.unwrap_results=unwrap_results if simplify_objects is None: self.simplify_objects=config.simplify_objects else: self.simplify_objects=simplify_objects self.proxy = SOAPAddress(proxy, config) self.namespace = namespace self.soapaction = soapaction self.header = header self.methodattrs = methodattrs self.transport = transport() self.encoding = encoding self.throw_faults = throw_faults self.http_proxy = http_proxy self.config = config self.noroot = noroot # GSI Additions if hasattr(config, "channel_mode") and \ hasattr(config, "delegation_mode"): self.channel_mode = config.channel_mode self.delegation_mode = config.delegation_mode #end GSI Additions def invoke(self, method, args): return self.__call(method, args, {}) def __call(self, name, args, kw, ns = None, sa = None, hd = None, ma = None): ns = ns or self.namespace ma = ma or self.methodattrs if sa: # Get soapaction if type(sa) == TupleType: sa = sa[0] else: if self.soapaction: sa = self.soapaction else: sa = name if hd: # Get header if type(hd) == TupleType: hd = hd[0] else: hd = self.header hd = hd or self.header if ma: # Get methodattrs if type(ma) == TupleType: ma = ma[0] else: ma = self.methodattrs ma = ma or self.methodattrs m = buildSOAP(args = args, kw = kw, method = name, namespace = ns, header = hd, methodattrs = ma, encoding = self.encoding, config = self.config, noroot = self.noroot) call_retry = 0 try: r, self.namespace = self.transport.call(self.proxy, m, ns, sa, encoding = self.encoding, http_proxy = self.http_proxy, config = self.config) except Exception, ex: # # Call failed. # # See if we have a fault handling vector installed in our # config. If we do, invoke it. If it returns a true value, # retry the call. # # In any circumstance other than the fault handler returning # true, reraise the exception. This keeps the semantics of this # code the same as without the faultHandler code. # if hasattr(self.config, "faultHandler"): if callable(self.config.faultHandler): call_retry = self.config.faultHandler(self.proxy, ex) if not call_retry: raise else: raise else: raise if call_retry: r, self.namespace = self.transport.call(self.proxy, m, ns, sa, encoding = self.encoding, http_proxy = self.http_proxy, config = self.config) p, attrs = parseSOAPRPC(r, attrs = 1) try: throw_struct = self.throw_faults and \ isinstance (p, faultType) except: throw_struct = 0 if throw_struct: if Config.debug: print p raise p # If unwrap_results=1 and there is only element in the struct, # SOAPProxy will assume that this element is the result # and return it rather than the struct containing it. # Otherwise SOAPproxy will return the struct with all the # elements as attributes. if self.unwrap_results: try: count = 0 for i in p.__dict__.keys(): if i[0] != "_": # don't count the private stuff count += 1 t = getattr(p, i) if count == 1: # Only one piece of data, bubble it up p = t except: pass # Automatically simplfy SOAP complex types into the # corresponding python types. (structType --> dict, # arrayType --> array, etc.) if self.simplify_objects: p = simplify(p) if self.config.returnAllAttrs: return p, attrs return p def _callWithBody(self, body): return self.__call(None, body, {}) def __getattr__(self, name): # hook to catch method calls if name == '__del__': raise AttributeError, name return self.__Method(self.__call, name, config = self.config) # To handle attribute wierdness class __Method: # Some magic to bind a SOAP method to an RPC server. # Supports "nested" methods (e.g. examples.getStateName) -- concept # borrowed from xmlrpc/soaplib -- www.pythonware.com # Altered (improved?) to let you inline namespaces on a per call # basis ala SOAP::LITE -- www.soaplite.com def __init__(self, call, name, ns = None, sa = None, hd = None, ma = None, config = Config): self.__call = call self.__name = name self.__ns = ns self.__sa = sa self.__hd = hd self.__ma = ma self.__config = config return def __call__(self, *args, **kw): if self.__name[0] == "_": if self.__name in ["__repr__","__str__"]: return self.__repr__() else: return self.__f_call(*args, **kw) else: return self.__r_call(*args, **kw) def __getattr__(self, name): if name == '__del__': raise AttributeError, name if self.__name[0] == "_": # Don't nest method if it is a directive return self.__class__(self.__call, name, self.__ns, self.__sa, self.__hd, self.__ma) return self.__class__(self.__call, "%s.%s" % (self.__name, name), self.__ns, self.__sa, self.__hd, self.__ma) def __f_call(self, *args, **kw): if self.__name == "_ns": self.__ns = args elif self.__name == "_sa": self.__sa = args elif self.__name == "_hd": self.__hd = args elif self.__name == "_ma": self.__ma = args return self def __r_call(self, *args, **kw): return self.__call(self.__name, args, kw, self.__ns, self.__sa, self.__hd, self.__ma) def __repr__(self): return "<%s at %d>" % (self.__class__, id(self)) SOAPpy-0.12.0/SOAPpy/Config.py0100644001604000501700000001637710202425140015425 0ustar warnegclinical""" ################################################################################ # Copyright (c) 2003, Pfizer # Copyright (c) 2001, Cayce Ullman. # Copyright (c) 2001, Brian Matthews. # # All rights reserved. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions are met: # Redistributions of source code must retain the above copyright notice, this # list of conditions and the following disclaimer. # # Redistributions in binary form must reproduce the above copyright notice, # this list of conditions and the following disclaimer in the documentation # and/or other materials provided with the distribution. # # Neither the name of actzero, inc. nor the names of its contributors may # be used to endorse or promote products derived from this software without # specific prior written permission. # # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE # ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR # ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES # (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; # LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND # ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS # SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. # ################################################################################ """ ident = '$Id: Config.py,v 1.9 2004/01/31 04:20:05 warnes Exp $' from version import __version__ import copy, socket from types import * from NS import NS ################################################################################ # Configuration class ################################################################################ class SOAPConfig: __readonly = ('SSLserver', 'SSLclient', 'GSIserver', 'GSIclient') def __init__(self, config = None, **kw): d = self.__dict__ if config: if not isinstance(config, SOAPConfig): raise AttributeError, \ "initializer must be SOAPConfig instance" s = config.__dict__ for k, v in s.items(): if k[0] != '_': d[k] = v else: # Setting debug also sets returnFaultInfo, # dumpHeadersIn, dumpHeadersOut, dumpSOAPIn, and dumpSOAPOut self.debug = 0 self.dumpFaultInfo = 1 # Setting namespaceStyle sets typesNamespace, typesNamespaceURI, # schemaNamespace, and schemaNamespaceURI self.namespaceStyle = '1999' self.strictNamespaces = 0 self.typed = 1 self.buildWithNamespacePrefix = 1 self.returnAllAttrs = 0 # Strict checking of range for floats and doubles self.strict_range = 0 # Default encoding for dictionary keys self.dict_encoding = 'ascii' # New argument name handling mechanism. See # README.MethodParameterNaming for details self.specialArgs = 1 # If unwrap_results=1 and there is only element in the struct, # SOAPProxy will assume that this element is the result # and return it rather than the struct containing it. # Otherwise SOAPproxy will return the struct with all the # elements as attributes. self.unwrap_results = 1 # Automatically convert SOAP complex types, and # (recursively) public contents into the corresponding # python types. (Private subobjects have names that start # with '_'.) # # Conversions: # - faultType --> raise python exception # - arrayType --> array # - compoundType --> dictionary # self.simplify_objects = 0 # Per-class authorization method. If this is set, before # calling a any class method, the specified authorization # method will be called. If it returns 1, the method call # will proceed, otherwise the call will throw with an # authorization error. self.authMethod = None # Globus Support if pyGlobus.io available try: from pyGlobus import io; d['GSIserver'] = 1 d['GSIclient'] = 1 except: d['GSIserver'] = 0 d['GSIclient'] = 0 # Server SSL support if M2Crypto.SSL available try: from M2Crypto import SSL d['SSLserver'] = 1 except: d['SSLserver'] = 0 # Client SSL support if socket.ssl available try: from socket import ssl d['SSLclient'] = 1 except: d['SSLclient'] = 0 for k, v in kw.items(): if k[0] != '_': setattr(self, k, v) def __setattr__(self, name, value): if name in self.__readonly: raise AttributeError, "readonly configuration setting" d = self.__dict__ if name in ('typesNamespace', 'typesNamespaceURI', 'schemaNamespace', 'schemaNamespaceURI'): if name[-3:] == 'URI': base, uri = name[:-3], 1 else: base, uri = name, 0 if type(value) == StringType: if NS.NSMAP.has_key(value): n = (value, NS.NSMAP[value]) elif NS.NSMAP_R.has_key(value): n = (NS.NSMAP_R[value], value) else: raise AttributeError, "unknown namespace" elif type(value) in (ListType, TupleType): if uri: n = (value[1], value[0]) else: n = (value[0], value[1]) else: raise AttributeError, "unknown namespace type" d[base], d[base + 'URI'] = n try: d['namespaceStyle'] = \ NS.STMAP_R[(d['typesNamespace'], d['schemaNamespace'])] except: d['namespaceStyle'] = '' elif name == 'namespaceStyle': value = str(value) if not NS.STMAP.has_key(value): raise AttributeError, "unknown namespace style" d[name] = value n = d['typesNamespace'] = NS.STMAP[value][0] d['typesNamespaceURI'] = NS.NSMAP[n] n = d['schemaNamespace'] = NS.STMAP[value][1] d['schemaNamespaceURI'] = NS.NSMAP[n] elif name == 'debug': d[name] = \ d['returnFaultInfo'] = \ d['dumpHeadersIn'] = \ d['dumpHeadersOut'] = \ d['dumpSOAPIn'] = \ d['dumpSOAPOut'] = value else: d[name] = value Config = SOAPConfig() SOAPpy-0.12.0/SOAPpy/Errors.py0100644001604000501700000000567710204422026015477 0ustar warnegclinical""" ################################################################################ # # SOAPpy - Cayce Ullman (cayce@actzero.com) # Brian Matthews (blm@actzero.com) # Gregory Warnes (Gregory.R.Warnes@Pfizer.com) # Christopher Blunck (blunck@gst.com) # ################################################################################ # Copyright (c) 2003, Pfizer # Copyright (c) 2001, Cayce Ullman. # Copyright (c) 2001, Brian Matthews. # # All rights reserved. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions are met: # Redistributions of source code must retain the above copyright notice, this # list of conditions and the following disclaimer. # # Redistributions in binary form must reproduce the above copyright notice, # this list of conditions and the following disclaimer in the documentation # and/or other materials provided with the distribution. # # Neither the name of actzero, inc. nor the names of its contributors may # be used to endorse or promote products derived from this software without # specific prior written permission. # # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE # ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR # ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES # (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; # LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND # ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS # SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. # ################################################################################ """ ident = '$Id: Errors.py,v 1.5 2005/02/15 16:32:22 warnes Exp $' from version import __version__ import exceptions ################################################################################ # Exceptions ################################################################################ class Error(exceptions.Exception): def __init__(self, msg): self.msg = msg def __str__(self): return "" % self.msg __repr__ = __str__ def __call__(self): return (msg,) class RecursionError(Error): pass class UnknownTypeError(Error): pass class HTTPError(Error): # indicates an HTTP protocol error def __init__(self, code, msg): self.code = code self.msg = msg def __str__(self): return "" % (self.code, self.msg) __repr__ = __str__ def __call___(self): return (self.code, self.msg, ) class UnderflowError(exceptions.ArithmeticError): pass SOAPpy-0.12.0/SOAPpy/GSIServer.py0100644001604000501700000001217210204422026016020 0ustar warnegclinical""" GSIServer - Contributed by Ivan R. Judson ################################################################################ # # SOAPpy - Cayce Ullman (cayce@actzero.com) # Brian Matthews (blm@actzero.com) # Gregory Warnes (Gregory.R.Warnes@Pfizer.com) # Christopher Blunck (blunck@gst.com) # ################################################################################ # Copyright (c) 2003, Pfizer # Copyright (c) 2001, Cayce Ullman. # Copyright (c) 2001, Brian Matthews. # # All rights reserved. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions are met: # Redistributions of source code must retain the above copyright notice, this # list of conditions and the following disclaimer. # # Redistributions in binary form must reproduce the above copyright notice, # this list of conditions and the following disclaimer in the documentation # and/or other materials provided with the distribution. # # Neither the name of actzero, inc. nor the names of its contributors may # be used to endorse or promote products derived from this software without # specific prior written permission. # # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE # ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR # ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES # (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; # LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND # ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS # SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. # ################################################################################ """ ident = '$Id: GSIServer.py,v 1.5 2005/02/15 16:32:22 warnes Exp $' from version import __version__ from __future__ import nested_scopes #import xml.sax import re import socket import sys import SocketServer from types import * import BaseHTTPServer # SOAPpy modules from Parser import parseSOAPRPC from Config import SOAPConfig from Types import faultType, voidType, simplify from NS import NS from SOAPBuilder import buildSOAP from Utilities import debugHeader, debugFooter try: from M2Crypto import SSL except: pass ##### from Server import * from pyGlobus.io import GSITCPSocketServer, ThreadingGSITCPSocketServer from pyGlobus import ioc def GSIConfig(): config = SOAPConfig() config.channel_mode = ioc.GLOBUS_IO_SECURE_CHANNEL_MODE_GSI_WRAP config.delegation_mode = ioc.GLOBUS_IO_SECURE_DELEGATION_MODE_FULL_PROXY config.tcpAttr = None config.authMethod = "_authorize" return config Config = GSIConfig() class GSISOAPServer(GSITCPSocketServer, SOAPServerBase): def __init__(self, addr = ('localhost', 8000), RequestHandler = SOAPRequestHandler, log = 0, encoding = 'UTF-8', config = Config, namespace = None): # Test the encoding, raising an exception if it's not known if encoding != None: ''.encode(encoding) self.namespace = namespace self.objmap = {} self.funcmap = {} self.encoding = encoding self.config = config self.log = log self.allow_reuse_address= 1 GSITCPSocketServer.__init__(self, addr, RequestHandler, self.config.channel_mode, self.config.delegation_mode, tcpAttr = self.config.tcpAttr) def get_request(self): sock, addr = GSITCPSocketServer.get_request(self) return sock, addr class ThreadingGSISOAPServer(ThreadingGSITCPSocketServer, SOAPServerBase): def __init__(self, addr = ('localhost', 8000), RequestHandler = SOAPRequestHandler, log = 0, encoding = 'UTF-8', config = Config, namespace = None): # Test the encoding, raising an exception if it's not known if encoding != None: ''.encode(encoding) self.namespace = namespace self.objmap = {} self.funcmap = {} self.encoding = encoding self.config = config self.log = log self.allow_reuse_address= 1 ThreadingGSITCPSocketServer.__init__(self, addr, RequestHandler, self.config.channel_mode, self.config.delegation_mode, tcpAttr = self.config.tcpAttr) def get_request(self): sock, addr = ThreadingGSITCPSocketServer.get_request(self) return sock, addr SOAPpy-0.12.0/SOAPpy/NS.py0100644001604000501700000000722010204422026014525 0ustar warnegclinical""" ################################################################################ # # SOAPpy - Cayce Ullman (cayce@actzero.com) # Brian Matthews (blm@actzero.com) # Gregory Warnes (Gregory.R.Warnes@Pfizer.com) # Christopher Blunck (blunck@gst.com) # ################################################################################ # Copyright (c) 2003, Pfizer # Copyright (c) 2001, Cayce Ullman. # Copyright (c) 2001, Brian Matthews. # # All rights reserved. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions are met: # Redistributions of source code must retain the above copyright notice, this # list of conditions and the following disclaimer. # # Redistributions in binary form must reproduce the above copyright notice, # this list of conditions and the following disclaimer in the documentation # and/or other materials provided with the distribution. # # Neither the name of actzero, inc. nor the names of its contributors may # be used to endorse or promote products derived from this software without # specific prior written permission. # # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE # ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR # ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES # (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; # LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND # ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS # SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. # ################################################################################ """ from __future__ import nested_scopes ident = '$Id: NS.py,v 1.4 2005/02/15 16:32:22 warnes Exp $' from version import __version__ ############################################################################## # Namespace Class ################################################################################ def invertDict(dict): d = {} for k, v in dict.items(): d[v] = k return d class NS: XML = "http://www.w3.org/XML/1998/namespace" ENV = "http://schemas.xmlsoap.org/soap/envelope/" ENC = "http://schemas.xmlsoap.org/soap/encoding/" XSD = "http://www.w3.org/1999/XMLSchema" XSD2 = "http://www.w3.org/2000/10/XMLSchema" XSD3 = "http://www.w3.org/2001/XMLSchema" XSD_L = [XSD, XSD2, XSD3] EXSD_L= [ENC, XSD, XSD2, XSD3] XSI = "http://www.w3.org/1999/XMLSchema-instance" XSI2 = "http://www.w3.org/2000/10/XMLSchema-instance" XSI3 = "http://www.w3.org/2001/XMLSchema-instance" XSI_L = [XSI, XSI2, XSI3] URN = "http://soapinterop.org/xsd" # For generated messages XML_T = "xml" ENV_T = "SOAP-ENV" ENC_T = "SOAP-ENC" XSD_T = "xsd" XSD2_T= "xsd2" XSD3_T= "xsd3" XSI_T = "xsi" XSI2_T= "xsi2" XSI3_T= "xsi3" URN_T = "urn" NSMAP = {ENV_T: ENV, ENC_T: ENC, XSD_T: XSD, XSD2_T: XSD2, XSD3_T: XSD3, XSI_T: XSI, XSI2_T: XSI2, XSI3_T: XSI3, URN_T: URN} NSMAP_R = invertDict(NSMAP) STMAP = {'1999': (XSD_T, XSI_T), '2000': (XSD2_T, XSI2_T), '2001': (XSD3_T, XSI3_T)} STMAP_R = invertDict(STMAP) def __init__(self): raise Error, "Don't instantiate this" SOAPpy-0.12.0/SOAPpy/Parser.py0100644001604000501700000010507610206532466015465 0ustar warnegclinical# SOAPpy modules from Config import Config from Types import * from NS import NS from Utilities import * import string import fpconst import xml.sax from wstools.XMLname import fromXMLname try: from M2Crypto import SSL except: pass ident = '$Id: Parser.py,v 1.16 2005/02/22 04:29:42 warnes Exp $' from version import __version__ ################################################################################ # SOAP Parser ################################################################################ class RefHolder: def __init__(self, name, frame): self.name = name self.parent = frame self.pos = len(frame) self.subpos = frame.namecounts.get(name, 0) def __repr__(self): return "<%s %s at %d>" % (self.__class__, self.name, id(self)) def __str__(self): return "<%s %s at %d>" % (self.__class__, self.name, id(self)) class SOAPParser(xml.sax.handler.ContentHandler): class Frame: def __init__(self, name, kind = None, attrs = {}, rules = {}): self.name = name self.kind = kind self.attrs = attrs self.rules = rules self.contents = [] self.names = [] self.namecounts = {} self.subattrs = [] def append(self, name, data, attrs): self.names.append(name) self.contents.append(data) self.subattrs.append(attrs) if self.namecounts.has_key(name): self.namecounts[name] += 1 else: self.namecounts[name] = 1 def _placeItem(self, name, value, pos, subpos = 0, attrs = None): self.contents[pos] = value if attrs: self.attrs.update(attrs) def __len__(self): return len(self.contents) def __repr__(self): return "<%s %s at %d>" % (self.__class__, self.name, id(self)) def __init__(self, rules = None): xml.sax.handler.ContentHandler.__init__(self) self.body = None self.header = None self.attrs = {} self._data = None self._next = "E" # Keeping state for message validity self._stack = [self.Frame('SOAP')] # Make two dictionaries to store the prefix <-> URI mappings, and # initialize them with the default self._prem = {NS.XML_T: NS.XML} self._prem_r = {NS.XML: NS.XML_T} self._ids = {} self._refs = {} self._rules = rules def startElementNS(self, name, qname, attrs): # Workaround two sax bugs if name[0] == None and name[1][0] == ' ': name = (None, name[1][1:]) else: name = tuple(name) # First some checking of the layout of the message if self._next == "E": if name[1] != 'Envelope': raise Error, "expected `SOAP-ENV:Envelope', gto `%s:%s'" % \ (self._prem_r[name[0]], name[1]) if name[0] != NS.ENV: raise faultType, ("%s:VersionMismatch" % NS.ENV_T, "Don't understand version `%s' Envelope" % name[0]) else: self._next = "HorB" elif self._next == "HorB": if name[0] == NS.ENV and name[1] in ("Header", "Body"): self._next = None else: raise Error, \ "expected `SOAP-ENV:Header' or `SOAP-ENV:Body', " \ "got `%s'" % self._prem_r[name[0]] + ':' + name[1] elif self._next == "B": if name == (NS.ENV, "Body"): self._next = None else: raise Error, "expected `SOAP-ENV:Body', got `%s'" % \ self._prem_r[name[0]] + ':' + name[1] elif self._next == "": raise Error, "expected nothing, got `%s'" % \ self._prem_r[name[0]] + ':' + name[1] if len(self._stack) == 2: rules = self._rules else: try: rules = self._stack[-1].rules[name[1]] except: rules = None if type(rules) not in (NoneType, DictType): kind = rules else: kind = attrs.get((NS.ENC, 'arrayType')) if kind != None: del attrs._attrs[(NS.ENC, 'arrayType')] i = kind.find(':') if i >= 0: kind = (self._prem[kind[:i]], kind[i + 1:]) else: kind = None self.pushFrame(self.Frame(name[1], kind, attrs._attrs, rules)) self._data = [] # Start accumulating def pushFrame(self, frame): self._stack.append(frame) def popFrame(self): return self._stack.pop() def endElementNS(self, name, qname): # Workaround two sax bugs if name[0] == None and name[1][0] == ' ': ns, name = None, name[1][1:] else: ns, name = tuple(name) name = fromXMLname(name) # convert to SOAP 1.2 XML name encoding if self._next == "E": raise Error, "didn't get SOAP-ENV:Envelope" if self._next in ("HorB", "B"): raise Error, "didn't get SOAP-ENV:Body" cur = self.popFrame() attrs = cur.attrs idval = None if attrs.has_key((None, 'id')): idval = attrs[(None, 'id')] if self._ids.has_key(idval): raise Error, "duplicate id `%s'" % idval del attrs[(None, 'id')] root = 1 if len(self._stack) == 3: if attrs.has_key((NS.ENC, 'root')): root = int(attrs[(NS.ENC, 'root')]) # Do some preliminary checks. First, if root="0" is present, # the element must have an id. Next, if root="n" is present, # n something other than 0 or 1, raise an exception. if root == 0: if idval == None: raise Error, "non-root element must have an id" elif root != 1: raise Error, "SOAP-ENC:root must be `0' or `1'" del attrs[(NS.ENC, 'root')] while 1: href = attrs.get((None, 'href')) if href: if href[0] != '#': raise Error, "Non-local hrefs are not yet suppported." if self._data != None and \ string.join(self._data, "").strip() != '': raise Error, "hrefs can't have data" href = href[1:] if self._ids.has_key(href): data = self._ids[href] else: data = RefHolder(name, self._stack[-1]) if self._refs.has_key(href): self._refs[href].append(data) else: self._refs[href] = [data] del attrs[(None, 'href')] break kind = None if attrs: for i in NS.XSI_L: if attrs.has_key((i, 'type')): kind = attrs[(i, 'type')] del attrs[(i, 'type')] if kind != None: i = kind.find(':') if i >= 0: kind = (self._prem[kind[:i]], kind[i + 1:]) else: # XXX What to do here? (None, kind) is just going to fail in convertType #print "Kind with no NS:", kind kind = (None, kind) null = 0 if attrs: for i in (NS.XSI, NS.XSI2): if attrs.has_key((i, 'null')): null = attrs[(i, 'null')] del attrs[(i, 'null')] if attrs.has_key((NS.XSI3, 'nil')): null = attrs[(NS.XSI3, 'nil')] del attrs[(NS.XSI3, 'nil')] ## Check for nil # check for nil='true' if type(null) in (StringType, UnicodeType): if null.lower() == 'true': null = 1 # check for nil=1, but watch out for string values try: null = int(null) except ValueError, e: if not e[0].startswith("invalid literal for int()"): raise e null = 0 if null: if len(cur) or \ (self._data != None and string.join(self._data, "").strip() != ''): raise Error, "nils can't have data" data = None break if len(self._stack) == 2: if (ns, name) == (NS.ENV, "Header"): self.header = data = headerType(attrs = attrs) self._next = "B" break elif (ns, name) == (NS.ENV, "Body"): self.body = data = bodyType(attrs = attrs) self._next = "" break elif len(self._stack) == 3 and self._next == None: if (ns, name) == (NS.ENV, "Fault"): data = faultType() self._next = None # allow followons break #print "\n" #print "data=", self._data #print "kind=", kind #print "cur.kind=", cur.kind #print "cur.rules=", cur.rules #print "\n" if cur.rules != None: rule = cur.rules if type(rule) in (StringType, UnicodeType): rule = (None, rule) # none flags special handling elif type(rule) == ListType: rule = tuple(rule) #print "kind=",kind #print "rule=",rule # XXX What if rule != kind? if callable(rule): data = rule(string.join(self._data, "")) elif type(rule) == DictType: data = structType(name = (ns, name), attrs = attrs) elif rule[1][:9] == 'arrayType': data = self.convertType(cur.contents, rule, attrs) else: data = self.convertType(string.join(self._data, ""), rule, attrs) break #print "No rules, using kind or cur.kind..." if (kind == None and cur.kind != None) or \ (kind == (NS.ENC, 'Array')): kind = cur.kind if kind == None: kind = 'ur-type[%d]' % len(cur) else: kind = kind[1] if len(cur.namecounts) == 1: elemsname = cur.names[0] else: elemsname = None data = self.startArray((ns, name), kind, attrs, elemsname) break if len(self._stack) == 3 and kind == None and \ len(cur) == 0 and \ (self._data == None or string.join(self._data, "").strip() == ''): data = structType(name = (ns, name), attrs = attrs) break if len(cur) == 0 and ns != NS.URN: # Nothing's been added to the current frame so it must be a # simple type. if kind == None: # If the current item's container is an array, it will # have a kind. If so, get the bit before the first [, # which is the type of the array, therefore the type of # the current item. kind = self._stack[-1].kind if kind != None: i = kind[1].find('[') if i >= 0: kind = (kind[0], kind[1][:i]) elif ns != None: kind = (ns, name) if kind != None: try: data = self.convertType(string.join(self._data, ""), kind, attrs) except UnknownTypeError: data = None else: data = None if data == None: if self._data == None: data = '' else: data = string.join(self._data, "") if len(attrs) == 0: try: data = str(data) except: pass break data = structType(name = (ns, name), attrs = attrs) break if isinstance(data, compoundType): for i in range(len(cur)): v = cur.contents[i] data._addItem(cur.names[i], v, cur.subattrs[i]) if isinstance(v, RefHolder): v.parent = data if root: self._stack[-1].append(name, data, attrs) if idval != None: self._ids[idval] = data if self._refs.has_key(idval): for i in self._refs[idval]: i.parent._placeItem(i.name, data, i.pos, i.subpos, attrs) del self._refs[idval] self.attrs[id(data)] = attrs if isinstance(data, anyType): data._setAttrs(attrs) self._data = None # Stop accumulating def endDocument(self): if len(self._refs) == 1: raise Error, \ "unresolved reference " + self._refs.keys()[0] elif len(self._refs) > 1: raise Error, \ "unresolved references " + ', '.join(self._refs.keys()) def startPrefixMapping(self, prefix, uri): self._prem[prefix] = uri self._prem_r[uri] = prefix def endPrefixMapping(self, prefix): try: del self._prem_r[self._prem[prefix]] del self._prem[prefix] except: pass def characters(self, c): if self._data != None: self._data.append(c) arrayre = '^(?:(?P[^:]*):)?' \ '(?P[^[]+)' \ '(?:\[(?P,*)\])?' \ '(?:\[(?P\d+(?:,\d+)*)?\])$' def startArray(self, name, kind, attrs, elemsname): if type(self.arrayre) == StringType: self.arrayre = re.compile (self.arrayre) offset = attrs.get((NS.ENC, "offset")) if offset != None: del attrs[(NS.ENC, "offset")] try: if offset[0] == '[' and offset[-1] == ']': offset = int(offset[1:-1]) if offset < 0: raise Exception else: raise Exception except: raise AttributeError, "invalid Array offset" else: offset = 0 try: m = self.arrayre.search(kind) if m == None: raise Exception t = m.group('type') if t == 'ur-type': return arrayType(None, name, attrs, offset, m.group('rank'), m.group('asize'), elemsname) elif m.group('ns') != None: return typedArrayType(None, name, (self._prem[m.group('ns')], t), attrs, offset, m.group('rank'), m.group('asize'), elemsname) else: return typedArrayType(None, name, (None, t), attrs, offset, m.group('rank'), m.group('asize'), elemsname) except: raise AttributeError, "invalid Array type `%s'" % kind # Conversion class DATETIMECONSTS: SIGNre = '(?P-?)' CENTURYre = '(?P\d{2,})' YEARre = '(?P\d{2})' MONTHre = '(?P\d{2})' DAYre = '(?P\d{2})' HOURre = '(?P\d{2})' MINUTEre = '(?P\d{2})' SECONDre = '(?P\d{2}(?:\.\d*)?)' TIMEZONEre = '(?PZ)|(?P[-+])(?P\d{2}):' \ '(?P\d{2})' BOSre = '^\s*' EOSre = '\s*$' __allres = {'sign': SIGNre, 'century': CENTURYre, 'year': YEARre, 'month': MONTHre, 'day': DAYre, 'hour': HOURre, 'minute': MINUTEre, 'second': SECONDre, 'timezone': TIMEZONEre, 'b': BOSre, 'e': EOSre} dateTime = '%(b)s%(sign)s%(century)s%(year)s-%(month)s-%(day)sT' \ '%(hour)s:%(minute)s:%(second)s(%(timezone)s)?%(e)s' % __allres timeInstant = dateTime timePeriod = dateTime time = '%(b)s%(hour)s:%(minute)s:%(second)s(%(timezone)s)?%(e)s' % \ __allres date = '%(b)s%(sign)s%(century)s%(year)s-%(month)s-%(day)s' \ '(%(timezone)s)?%(e)s' % __allres century = '%(b)s%(sign)s%(century)s(%(timezone)s)?%(e)s' % __allres gYearMonth = '%(b)s%(sign)s%(century)s%(year)s-%(month)s' \ '(%(timezone)s)?%(e)s' % __allres gYear = '%(b)s%(sign)s%(century)s%(year)s(%(timezone)s)?%(e)s' % \ __allres year = gYear gMonthDay = '%(b)s--%(month)s-%(day)s(%(timezone)s)?%(e)s' % __allres recurringDate = gMonthDay gDay = '%(b)s---%(day)s(%(timezone)s)?%(e)s' % __allres recurringDay = gDay gMonth = '%(b)s--%(month)s--(%(timezone)s)?%(e)s' % __allres month = gMonth recurringInstant = '%(b)s%(sign)s(%(century)s|-)(%(year)s|-)-' \ '(%(month)s|-)-(%(day)s|-)T' \ '(%(hour)s|-):(%(minute)s|-):(%(second)s|-)' \ '(%(timezone)s)?%(e)s' % __allres duration = '%(b)s%(sign)sP' \ '((?P\d+)Y)?' \ '((?P\d+)M)?' \ '((?P\d+)D)?' \ '((?PT)' \ '((?P\d+)H)?' \ '((?P\d+)M)?' \ '((?P\d*(?:\.\d*)?)S)?)?%(e)s' % \ __allres timeDuration = duration # The extra 31 on the front is: # - so the tuple is 1-based # - so months[month-1] is December's days if month is 1 months = (31, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31) def convertDateTime(self, value, kind): def getZoneOffset(d): zoffs = 0 try: if d['zulu'] == None: zoffs = 60 * int(d['tzhour']) + int(d['tzminute']) if d['tzsign'] != '-': zoffs = -zoffs except TypeError: pass return zoffs def applyZoneOffset(months, zoffs, date, minfield, posday = 1): if zoffs == 0 and (minfield > 4 or 0 <= date[5] < 60): return date if minfield > 5: date[5] = 0 if minfield > 4: date[4] = 0 if date[5] < 0: date[4] += int(date[5]) / 60 date[5] %= 60 date[4] += zoffs if minfield > 3 or 0 <= date[4] < 60: return date date[3] += date[4] / 60 date[4] %= 60 if minfield > 2 or 0 <= date[3] < 24: return date date[2] += date[3] / 24 date[3] %= 24 if minfield > 1: if posday and date[2] <= 0: date[2] += 31 # zoffs is at most 99:59, so the # day will never be less than -3 return date while 1: # The date[1] == 3 (instead of == 2) is because we're # going back a month, so we need to know if the previous # month is February, so we test if this month is March. leap = minfield == 0 and date[1] == 3 and \ date[0] % 4 == 0 and \ (date[0] % 100 != 0 or date[0] % 400 == 0) if 0 < date[2] <= months[date[1]] + leap: break date[2] += months[date[1] - 1] + leap date[1] -= 1 if date[1] > 0: break date[1] = 12 if minfield > 0: break date[0] -= 1 return date try: exp = getattr(self.DATETIMECONSTS, kind) except AttributeError: return None if type(exp) == StringType: exp = re.compile(exp) setattr (self.DATETIMECONSTS, kind, exp) m = exp.search(value) try: if m == None: raise Exception d = m.groupdict() f = ('century', 'year', 'month', 'day', 'hour', 'minute', 'second') fn = len(f) # Index of first non-None value r = [] if kind in ('duration', 'timeDuration'): if d['sep'] != None and d['hour'] == None and \ d['minute'] == None and d['second'] == None: raise Exception f = f[1:] for i in range(len(f)): s = d[f[i]] if s != None: if f[i] == 'second': s = float(s) else: try: s = int(s) except ValueError: s = long(s) if i < fn: fn = i r.append(s) if fn > len(r): # Any non-Nones? raise Exception if d['sign'] == '-': r[fn] = -r[fn] return tuple(r) if kind == 'recurringInstant': for i in range(len(f)): s = d[f[i]] if s == None or s == '-': if i > fn: raise Exception s = None else: if i < fn: fn = i if f[i] == 'second': s = float(s) else: try: s = int(s) except ValueError: s = long(s) r.append(s) s = r.pop(0) if fn == 0: r[0] += s * 100 else: fn -= 1 if fn < len(r) and d['sign'] == '-': r[fn] = -r[fn] cleanDate(r, fn) return tuple(applyZoneOffset(self.DATETIMECONSTS.months, getZoneOffset(d), r, fn, 0)) r = [0, 0, 1, 1, 0, 0, 0] for i in range(len(f)): field = f[i] s = d.get(field) if s != None: if field == 'second': s = float(s) else: try: s = int(s) except ValueError: s = long(s) if i < fn: fn = i r[i] = s if fn > len(r): # Any non-Nones? raise Exception s = r.pop(0) if fn == 0: r[0] += s * 100 else: fn -= 1 if d.get('sign') == '-': r[fn] = -r[fn] cleanDate(r, fn) zoffs = getZoneOffset(d) if zoffs: r = applyZoneOffset(self.DATETIMECONSTS.months, zoffs, r, fn) if kind == 'century': return r[0] / 100 s = [] for i in range(1, len(f)): if d.has_key(f[i]): s.append(r[i - 1]) if len(s) == 1: return s[0] return tuple(s) except Exception, e: raise Error, "invalid %s value `%s' - %s" % (kind, value, e) intlimits = \ { 'nonPositiveInteger': (0, None, 0), 'non-positive-integer': (0, None, 0), 'negativeInteger': (0, None, -1), 'negative-integer': (0, None, -1), 'long': (1, -9223372036854775808L, 9223372036854775807L), 'int': (0, -2147483648L, 2147483647), 'short': (0, -32768, 32767), 'byte': (0, -128, 127), 'nonNegativeInteger': (0, 0, None), 'non-negative-integer': (0, 0, None), 'positiveInteger': (0, 1, None), 'positive-integer': (0, 1, None), 'unsignedLong': (1, 0, 18446744073709551615L), 'unsignedInt': (0, 0, 4294967295L), 'unsignedShort': (0, 0, 65535), 'unsignedByte': (0, 0, 255), } floatlimits = \ { 'float': (7.0064923216240861E-46, -3.4028234663852886E+38, 3.4028234663852886E+38), 'double': (2.4703282292062327E-324, -1.7976931348623158E+308, 1.7976931348623157E+308), } zerofloatre = '[1-9]' def convertType(self, d, t, attrs, config=Config): if t[0] is None and t[1] is not None: type = t[1].strip() if type[:9] == 'arrayType': index_eq = type.find('=') index_obr = type.find('[') index_cbr = type.find(']') elemtype = type[index_eq+1:index_obr] elemnum = type[index_obr+1:index_cbr] if elemtype=="ur-type": return(d) else: newarr = map( lambda(di): self.convertToBasicTypes(d=di, t = ( NS.XSD, elemtype), attrs=attrs, config=config), d) return newarr else: t = (NS.XSD, t[1]) return self.convertToBasicTypes(d, t, attrs, config) def convertToSOAPpyTypes(self, d, t, attrs, config=Config): pass def convertToBasicTypes(self, d, t, attrs, config=Config): dnn = d or '' #if Config.debug: #print "convertToBasicTypes:" #print " requested_type=", t #print " data=", d if t[0] in NS.EXSD_L: if t[1] == "integer": try: d = int(d) if len(attrs): d = long(d) except: d = long(d) return d if self.intlimits.has_key (t[1]): # integer types l = self.intlimits[t[1]] try: d = int(d) except: d = long(d) if l[1] != None and d < l[1]: raise UnderflowError, "%s too small" % d if l[2] != None and d > l[2]: raise OverflowError, "%s too large" % d if l[0] or len(attrs): return long(d) return d if t[1] == "string": if len(attrs): return unicode(dnn) try: return str(dnn) except: return dnn if t[1] == "boolean": d = d.strip().lower() if d in ('0', 'false'): return 0 if d in ('1', 'true'): return 1 raise AttributeError, "invalid boolean value" if t[1] in ('double','float'): l = self.floatlimits[t[1]] s = d.strip().lower() d = float(s) if config.strict_range: if d < l[1]: raise UnderflowError if d > l[2]: raise OverflowError else: # some older SOAP impementations (notably SOAP4J, # Apache SOAP) return "infinity" instead of "INF" # so check the first 3 characters for a match. if s == "nan": return fpconst.NaN elif s[0:3] in ("inf", "+inf"): return fpconst.PosInf elif s[0:3] == "-inf": return fpconst.NegInf if fpconst.isNaN(d): if s != 'nan': raise ValueError, "invalid %s: %s" % (t[1], s) elif fpconst.isNegInf(d): if s != '-inf': raise UnderflowError, "%s too small: %s" % (t[1], s) elif fpconst.isPosInf(d): if s != 'inf': raise OverflowError, "%s too large: %s" % (t[1], s) elif d < 0 and d < l[1]: raise UnderflowError, "%s too small: %s" % (t[1], s) elif d > 0 and ( d < l[0] or d > l[2] ): raise OverflowError, "%s too large: %s" % (t[1], s) elif d == 0: if type(self.zerofloatre) == StringType: self.zerofloatre = re.compile(self.zerofloatre) if self.zerofloatre.search(s): raise UnderflowError, "invalid %s: %s" % (t[1], s) return d if t[1] in ("dateTime", "date", "timeInstant", "time"): return self.convertDateTime(d, t[1]) if t[1] == "decimal": return float(d) if t[1] in ("language", "QName", "NOTATION", "NMTOKEN", "Name", "NCName", "ID", "IDREF", "ENTITY"): return collapseWhiteSpace(d) if t[1] in ("IDREFS", "ENTITIES", "NMTOKENS"): d = collapseWhiteSpace(d) return d.split() if t[0] in NS.XSD_L: if t[1] in ("base64", "base64Binary"): if d: return base64.decodestring(d) else: return '' if t[1] == "hexBinary": if d: return decodeHexString(d) else: return if t[1] == "anyURI": return urllib.unquote(collapseWhiteSpace(d)) if t[1] in ("normalizedString", "token"): return collapseWhiteSpace(d) if t[0] == NS.ENC: if t[1] == "base64": if d: return base64.decodestring(d) else: return '' if t[0] == NS.XSD: if t[1] == "binary": try: e = attrs[(None, 'encoding')] if d: if e == 'hex': return decodeHexString(d) elif e == 'base64': return base64.decodestring(d) else: return '' except: pass raise Error, "unknown or missing binary encoding" if t[1] == "uri": return urllib.unquote(collapseWhiteSpace(d)) if t[1] == "recurringInstant": return self.convertDateTime(d, t[1]) if t[0] in (NS.XSD2, NS.ENC): if t[1] == "uriReference": return urllib.unquote(collapseWhiteSpace(d)) if t[1] == "timePeriod": return self.convertDateTime(d, t[1]) if t[1] in ("century", "year"): return self.convertDateTime(d, t[1]) if t[0] in (NS.XSD, NS.XSD2, NS.ENC): if t[1] == "timeDuration": return self.convertDateTime(d, t[1]) if t[0] == NS.XSD3: if t[1] == "anyURI": return urllib.unquote(collapseWhiteSpace(d)) if t[1] in ("gYearMonth", "gMonthDay"): return self.convertDateTime(d, t[1]) if t[1] == "gYear": return self.convertDateTime(d, t[1]) if t[1] == "gMonth": return self.convertDateTime(d, t[1]) if t[1] == "gDay": return self.convertDateTime(d, t[1]) if t[1] == "duration": return self.convertDateTime(d, t[1]) if t[0] in (NS.XSD2, NS.XSD3): if t[1] == "token": return collapseWhiteSpace(d) if t[1] == "recurringDate": return self.convertDateTime(d, t[1]) if t[1] == "month": return self.convertDateTime(d, t[1]) if t[1] == "recurringDay": return self.convertDateTime(d, t[1]) if t[0] == NS.XSD2: if t[1] == "CDATA": return collapseWhiteSpace(d) raise UnknownTypeError, "unknown type `%s'" % (str(t[0]) + ':' + t[1]) ################################################################################ # call to SOAPParser that keeps all of the info ################################################################################ def _parseSOAP(xml_str, rules = None): try: from cStringIO import StringIO except ImportError: from StringIO import StringIO parser = xml.sax.make_parser() t = SOAPParser(rules = rules) parser.setContentHandler(t) e = xml.sax.handler.ErrorHandler() parser.setErrorHandler(e) inpsrc = xml.sax.xmlreader.InputSource() inpsrc.setByteStream(StringIO(xml_str)) # turn on namespace mangeling parser.setFeature(xml.sax.handler.feature_namespaces,1) try: parser.parse(inpsrc) except xml.sax.SAXParseException, e: parser._parser = None raise e return t ################################################################################ # SOAPParser's more public interface ################################################################################ def parseSOAP(xml_str, attrs = 0): t = _parseSOAP(xml_str) if attrs: return t.body, t.attrs return t.body def parseSOAPRPC(xml_str, header = 0, body = 0, attrs = 0, rules = None): t = _parseSOAP(xml_str, rules = rules) p = t.body[0] # Empty string, for RPC this translates into a void if type(p) in (type(''), type(u'')) and p in ('', u''): name = "Response" for k in t.body.__dict__.keys(): if k[0] != "_": name = k p = structType(name) if header or body or attrs: ret = (p,) if header : ret += (t.header,) if body: ret += (t.body,) if attrs: ret += (t.attrs,) return ret else: return p SOAPpy-0.12.0/SOAPpy/SOAP.py0100644001604000501700000000151310202425140014744 0ustar warnegclinical"""This file is here for backward compatibility with versions <= 0.9.9 Delete when 1.0.0 is released! """ ident = '$Id: SOAP.py,v 1.38 2004/01/31 04:20:06 warnes Exp $' from version import __version__ from Client import * from Config import * from Errors import * from NS import * from Parser import * from SOAPBuilder import * from Server import * from Types import * from Utilities import * import wstools import WSDL from warnings import warn warn(""" The sub-module SOAPpy.SOAP is deprecated and is only provided for short-term backward compatibility. Objects are now available directly within the SOAPpy module. Thus, instead of from SOAPpy import SOAP ... SOAP.SOAPProxy(...) use from SOAPpy import SOAPProxy ... SOAPProxy(...) instead. """, DeprecationWarning) SOAPpy-0.12.0/SOAPpy/SOAPBuilder.py0100644001604000501700000005315710206441555016302 0ustar warnegclinical""" ################################################################################ # Copyright (c) 2003, Pfizer # Copyright (c) 2001, Cayce Ullman. # Copyright (c) 2001, Brian Matthews. # # All rights reserved. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions are met: # Redistributions of source code must retain the above copyright notice, this # list of conditions and the following disclaimer. # # Redistributions in binary form must reproduce the above copyright notice, # this list of conditions and the following disclaimer in the documentation # and/or other materials provided with the distribution. # # Neither the name of actzero, inc. nor the names of its contributors may # be used to endorse or promote products derived from this software without # specific prior written permission. # # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE # ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR # ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES # (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; # LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND # ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS # SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. # ################################################################################ """ ident = '$Id: SOAPBuilder.py,v 1.27 2005/02/21 20:24:13 warnes Exp $' from version import __version__ import cgi import copy from wstools.XMLname import toXMLname, fromXMLname import fpconst # SOAPpy modules from Config import Config from NS import NS from Types import * # Test whether this Python version has Types.BooleanType # If it doesn't have it, then False and True are serialized as integers try: BooleanType pythonHasBooleanType = 1 except NameError: pythonHasBooleanType = 0 ################################################################################ # SOAP Builder ################################################################################ class SOAPBuilder: _xml_top = '\n' _xml_enc_top = '\n' _env_top = ( '%(ENV_T)s:Envelope\n' + \ ' %(ENV_T)s:encodingStyle="%(ENC)s"\n' ) % \ NS.__dict__ _env_bot = '\n' % NS.__dict__ # Namespaces potentially defined in the Envelope tag. _env_ns = {NS.ENC: NS.ENC_T, NS.ENV: NS.ENV_T, NS.XSD: NS.XSD_T, NS.XSD2: NS.XSD2_T, NS.XSD3: NS.XSD3_T, NS.XSI: NS.XSI_T, NS.XSI2: NS.XSI2_T, NS.XSI3: NS.XSI3_T} def __init__(self, args = (), kw = {}, method = None, namespace = None, header = None, methodattrs = None, envelope = 1, encoding = 'UTF-8', use_refs = 0, config = Config, noroot = 0): # Test the encoding, raising an exception if it's not known if encoding != None: ''.encode(encoding) self.args = args self.kw = kw self.envelope = envelope self.encoding = encoding self.method = method self.namespace = namespace self.header = header self.methodattrs= methodattrs self.use_refs = use_refs self.config = config self.out = [] self.tcounter = 0 self.ncounter = 1 self.icounter = 1 self.envns = {} self.ids = {} self.depth = 0 self.multirefs = [] self.multis = 0 self.body = not isinstance(args, bodyType) self.noroot = noroot def build(self): if Config.debug: print "In build." ns_map = {} # Cache whether typing is on or not typed = self.config.typed if self.header: # Create a header. self.dump(self.header, "Header", typed = typed) #self.header = None # Wipe it out so no one is using it. if self.body: # Call genns to record that we've used SOAP-ENV. self.depth += 1 body_ns = self.genns(ns_map, NS.ENV)[0] self.out.append("<%sBody>\n" % body_ns) if self.method: # Save the NS map so that it can be restored when we # fall out of the scope of the method definition save_ns_map = ns_map.copy() self.depth += 1 a = '' if self.methodattrs: for (k, v) in self.methodattrs.items(): a += ' %s="%s"' % (k, v) if self.namespace: # Use the namespace info handed to us methodns, n = self.genns(ns_map, self.namespace) else: methodns, n = '', '' self.out.append('<%s%s%s%s%s>\n' % ( methodns, self.method, n, a, self.genroot(ns_map))) try: if type(self.args) != TupleType: args = (self.args,) else: args = self.args for i in args: self.dump(i, typed = typed, ns_map = ns_map) if hasattr(self.config, "argsOrdering") and self.config.argsOrdering.has_key(self.method): for k in self.config.argsOrdering.get(self.method): self.dump(self.kw.get(k), k, typed = typed, ns_map = ns_map) else: for (k, v) in self.kw.items(): self.dump(v, k, typed = typed, ns_map = ns_map) except RecursionError: if self.use_refs == 0: # restart b = SOAPBuilder(args = self.args, kw = self.kw, method = self.method, namespace = self.namespace, header = self.header, methodattrs = self.methodattrs, envelope = self.envelope, encoding = self.encoding, use_refs = 1, config = self.config) return b.build() raise if self.method: self.out.append("\n" % (methodns, self.method)) # End of the method definition; drop any local namespaces ns_map = save_ns_map self.depth -= 1 if self.body: # dump may add to self.multirefs, but the for loop will keep # going until it has used all of self.multirefs, even those # entries added while in the loop. self.multis = 1 for obj, tag in self.multirefs: self.dump(obj, tag, typed = typed, ns_map = ns_map) self.out.append("\n" % body_ns) self.depth -= 1 if self.envelope: e = map (lambda ns: ' xmlns:%s="%s"\n' % (ns[1], ns[0]), self.envns.items()) self.out = ['<', self._env_top] + e + ['>\n'] + \ self.out + \ [self._env_bot] if self.encoding != None: self.out.insert(0, self._xml_enc_top % self.encoding) return ''.join(self.out).encode(self.encoding) self.out.insert(0, self._xml_top) return ''.join(self.out) def gentag(self): if Config.debug: print "In gentag." self.tcounter += 1 return "v%d" % self.tcounter def genns(self, ns_map, nsURI): if nsURI == None: return ('', '') if type(nsURI) == TupleType: # already a tuple if len(nsURI) == 2: ns, nsURI = nsURI else: ns, nsURI = None, nsURI[0] else: ns = None if ns_map.has_key(nsURI): return (ns_map[nsURI] + ':', '') if self._env_ns.has_key(nsURI): ns = self.envns[nsURI] = ns_map[nsURI] = self._env_ns[nsURI] return (ns + ':', '') if not ns: ns = "ns%d" % self.ncounter self.ncounter += 1 ns_map[nsURI] = ns if self.config.buildWithNamespacePrefix: return (ns + ':', ' xmlns:%s="%s"' % (ns, nsURI)) else: return ('', ' xmlns="%s"' % (nsURI)) def genroot(self, ns_map): if self.noroot: return '' if self.depth != 2: return '' ns, n = self.genns(ns_map, NS.ENC) return ' %sroot="%d"%s' % (ns, not self.multis, n) # checkref checks an element to see if it needs to be encoded as a # multi-reference element or not. If it returns None, the element has # been handled and the caller can continue with subsequent elements. # If it returns a string, the string should be included in the opening # tag of the marshaled element. def checkref(self, obj, tag, ns_map): if self.depth < 2: return '' if not self.ids.has_key(id(obj)): n = self.ids[id(obj)] = self.icounter self.icounter = n + 1 if self.use_refs == 0: return '' if self.depth == 2: return ' id="i%d"' % n self.multirefs.append((obj, tag)) else: if self.use_refs == 0: raise RecursionError, "Cannot serialize recursive object" n = self.ids[id(obj)] if self.multis and self.depth == 2: return ' id="i%d"' % n self.out.append('<%s href="#i%d"%s/>\n' % (tag, n, self.genroot(ns_map))) return None # dumpers def dump(self, obj, tag = None, typed = 1, ns_map = {}): if Config.debug: print "In dump.", "obj=", obj ns_map = ns_map.copy() self.depth += 1 if type(tag) not in (NoneType, StringType, UnicodeType): raise KeyError, "tag must be a string or None" try: meth = getattr(self, "dump_" + type(obj).__name__) except AttributeError: if type(obj) == LongType: obj_type = "integer" elif pythonHasBooleanType and type(obj) == BooleanType: obj_type = "boolean" else: obj_type = type(obj).__name__ self.out.append(self.dumper(None, obj_type, obj, tag, typed, ns_map, self.genroot(ns_map))) else: meth(obj, tag, typed, ns_map) self.depth -= 1 # generic dumper def dumper(self, nsURI, obj_type, obj, tag, typed = 1, ns_map = {}, rootattr = '', id = '', xml = '<%(tag)s%(type)s%(id)s%(attrs)s%(root)s>%(data)s\n'): if Config.debug: print "In dumper." if nsURI == None: nsURI = self.config.typesNamespaceURI tag = tag or self.gentag() tag = toXMLname(tag) # convert from SOAP 1.2 XML name encoding a = n = t = '' if typed and obj_type: ns, n = self.genns(ns_map, nsURI) ins = self.genns(ns_map, self.config.schemaNamespaceURI)[0] t = ' %stype="%s%s"%s' % (ins, ns, obj_type, n) try: a = obj._marshalAttrs(ns_map, self) except: pass try: data = obj._marshalData() except: if (obj_type != "string"): # strings are already encoded data = cgi.escape(str(obj)) else: data = obj return xml % {"tag": tag, "type": t, "data": data, "root": rootattr, "id": id, "attrs": a} def dump_float(self, obj, tag, typed = 1, ns_map = {}): if Config.debug: print "In dump_float." tag = tag or self.gentag() tag = toXMLname(tag) # convert from SOAP 1.2 XML name encoding if Config.strict_range: doubleType(obj) if fpconst.isPosInf(obj): obj = "INF" elif fpconst.isNegInf(obj): obj = "-INF" elif fpconst.isNaN(obj): obj = "NaN" else: obj = repr(obj) # Note: python 'float' is actually a SOAP 'double'. self.out.append(self.dumper(None, "double", obj, tag, typed, ns_map, self.genroot(ns_map))) def dump_string(self, obj, tag, typed = 0, ns_map = {}): if Config.debug: print "In dump_string." tag = tag or self.gentag() tag = toXMLname(tag) # convert from SOAP 1.2 XML name encoding id = self.checkref(obj, tag, ns_map) if id == None: return try: data = obj._marshalData() except: data = obj self.out.append(self.dumper(None, "string", cgi.escape(data), tag, typed, ns_map, self.genroot(ns_map), id)) dump_str = dump_string # For Python 2.2+ dump_unicode = dump_string def dump_None(self, obj, tag, typed = 0, ns_map = {}): if Config.debug: print "In dump_None." tag = tag or self.gentag() tag = toXMLname(tag) # convert from SOAP 1.2 XML name encoding ns = self.genns(ns_map, self.config.schemaNamespaceURI)[0] self.out.append('<%s %snull="1"%s/>\n' % (tag, ns, self.genroot(ns_map))) dump_NoneType = dump_None # For Python 2.2+ def dump_list(self, obj, tag, typed = 1, ns_map = {}): if Config.debug: print "In dump_list.", "obj=", obj tag = tag or self.gentag() tag = toXMLname(tag) # convert from SOAP 1.2 XML name encoding if type(obj) == InstanceType: data = obj.data else: data = obj if typed: id = self.checkref(obj, tag, ns_map) if id == None: return try: sample = data[0] empty = 0 except: # preserve type if present if getattr(obj,"_typed",None) and getattr(obj,"_type",None): if getattr(obj, "_complexType", None): sample = typedArrayType(typed=obj._type, complexType = obj._complexType) sample._typename = obj._type if not getattr(obj,"_ns",None): obj._ns = NS.URN else: sample = typedArrayType(typed=obj._type) else: sample = structType() empty = 1 # First scan list to see if all are the same type same_type = 1 if not empty: for i in data[1:]: if type(sample) != type(i) or \ (type(sample) == InstanceType and \ sample.__class__ != i.__class__): same_type = 0 break ndecl = '' if same_type: if (isinstance(sample, structType)) or \ type(sample) == DictType or \ (isinstance(sample, anyType) and \ (getattr(sample, "_complexType", None) and \ sample._complexType)): # force to urn struct try: tns = obj._ns or NS.URN except: tns = NS.URN ns, ndecl = self.genns(ns_map, tns) try: typename = sample._typename except: typename = "SOAPStruct" t = ns + typename elif isinstance(sample, anyType): ns = sample._validNamespaceURI(self.config.typesNamespaceURI, self.config.strictNamespaces) if ns: ns, ndecl = self.genns(ns_map, ns) t = ns + str(sample._type) else: t = 'ur-type' else: typename = type(sample).__name__ # For Python 2.2+ if type(sample) == StringType: typename = 'string' # HACK: unicode is a SOAP string if type(sample) == UnicodeType: typename = 'string' # HACK: python 'float' is actually a SOAP 'double'. if typename=="float": typename="double" t = self.genns(ns_map, self.config.typesNamespaceURI)[0] + \ typename else: t = self.genns(ns_map, self.config.typesNamespaceURI)[0] + \ "ur-type" try: a = obj._marshalAttrs(ns_map, self) except: a = '' ens, edecl = self.genns(ns_map, NS.ENC) ins, idecl = self.genns(ns_map, self.config.schemaNamespaceURI) if typed: self.out.append( '<%s %sarrayType="%s[%d]" %stype="%sArray"%s%s%s%s%s%s>\n' % (tag, ens, t, len(data), ins, ens, ndecl, edecl, idecl, self.genroot(ns_map), id, a)) if typed: try: elemsname = obj._elemsname except: elemsname = "item" else: elemsname = tag for i in data: self.dump(i, elemsname, not same_type, ns_map) if typed: self.out.append('\n' % tag) dump_tuple = dump_list def dump_dictionary(self, obj, tag, typed = 1, ns_map = {}): if Config.debug: print "In dump_dictionary." tag = tag or self.gentag() tag = toXMLname(tag) # convert from SOAP 1.2 XML name encoding id = self.checkref(obj, tag, ns_map) if id == None: return try: a = obj._marshalAttrs(ns_map, self) except: a = '' self.out.append('<%s%s%s%s>\n' % (tag, id, a, self.genroot(ns_map))) for (k, v) in obj.items(): if k[0] != "_": self.dump(v, k, 1, ns_map) self.out.append('\n' % tag) dump_dict = dump_dictionary # For Python 2.2+ def dump_instance(self, obj, tag, typed = 1, ns_map = {}): if Config.debug: print "In dump_instance.", "obj=", obj, "tag=", tag if not tag: # If it has a name use it. if isinstance(obj, anyType) and obj._name: tag = obj._name else: tag = self.gentag() tag = toXMLname(tag) # convert from SOAP 1.2 XML name encoding if isinstance(obj, arrayType): # Array self.dump_list(obj, tag, typed, ns_map) return if isinstance(obj, faultType): # Fault cns, cdecl = self.genns(ns_map, NS.ENC) vns, vdecl = self.genns(ns_map, NS.ENV) self.out.append('''<%sFault %sroot="1"%s%s> %s %s ''' % (vns, cns, vdecl, cdecl, obj.faultcode, obj.faultstring)) if hasattr(obj, "detail"): self.dump(obj.detail, "detail", typed, ns_map) self.out.append("\n" % vns) return r = self.genroot(ns_map) try: a = obj._marshalAttrs(ns_map, self) except: a = '' if isinstance(obj, voidType): # void self.out.append("<%s%s%s>\n" % (tag, a, r, tag)) return id = self.checkref(obj, tag, ns_map) if id == None: return if isinstance(obj, structType): # Check for namespace ndecl = '' ns = obj._validNamespaceURI(self.config.typesNamespaceURI, self.config.strictNamespaces) if ns: ns, ndecl = self.genns(ns_map, ns) tag = ns + tag self.out.append("<%s%s%s%s%s>\n" % (tag, ndecl, id, a, r)) keylist = obj.__dict__.keys() # first write out items with order information if hasattr(obj, '_keyord'): for i in range(len(obj._keyord)): self.dump(obj._aslist(i), obj._keyord[i], 1, ns_map) keylist.remove(obj._keyord[i]) # now write out the rest for k in keylist: if (k[0] != "_"): self.dump(getattr(obj,k), k, 1, ns_map) if isinstance(obj, bodyType): self.multis = 1 for v, k in self.multirefs: self.dump(v, k, typed = typed, ns_map = ns_map) self.out.append('\n' % tag) elif isinstance(obj, anyType): t = '' if typed: ns = obj._validNamespaceURI(self.config.typesNamespaceURI, self.config.strictNamespaces) if ns: ons, ondecl = self.genns(ns_map, ns) ins, indecl = self.genns(ns_map, self.config.schemaNamespaceURI) t = ' %stype="%s%s"%s%s' % \ (ins, ons, obj._type, ondecl, indecl) self.out.append('<%s%s%s%s%s>%s\n' % (tag, t, id, a, r, obj._marshalData(), tag)) else: # Some Class self.out.append('<%s%s%s>\n' % (tag, id, r)) for (k, v) in obj.__dict__.items(): if k[0] != "_": self.dump(v, k, 1, ns_map) self.out.append('\n' % tag) ################################################################################ # SOAPBuilder's more public interface ################################################################################ def buildSOAP(args=(), kw={}, method=None, namespace=None, header=None, methodattrs=None, envelope=1, encoding='UTF-8', config=Config, noroot = 0): t = SOAPBuilder(args=args, kw=kw, method=method, namespace=namespace, header=header, methodattrs=methodattrs,envelope=envelope, encoding=encoding, config=config,noroot=noroot) return t.build() SOAPpy-0.12.0/SOAPpy/Server.py0100644001604000501700000006500010204422026015453 0ustar warnegclinical""" ################################################################################ # # SOAPpy - Cayce Ullman (cayce@actzero.com) # Brian Matthews (blm@actzero.com) # Gregory Warnes (Gregory.R.Warnes@Pfizer.com) # Christopher Blunck (blunck@gst.com) # ################################################################################ # Copyright (c) 2003, Pfizer # Copyright (c) 2001, Cayce Ullman. # Copyright (c) 2001, Brian Matthews. # # All rights reserved. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions are met: # Redistributions of source code must retain the above copyright notice, this # list of conditions and the following disclaimer. # # Redistributions in binary form must reproduce the above copyright notice, # this list of conditions and the following disclaimer in the documentation # and/or other materials provided with the distribution. # # Neither the name of actzero, inc. nor the names of its contributors may # be used to endorse or promote products derived from this software without # specific prior written permission. # # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE # ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR # ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES # (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; # LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND # ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS # SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. # ################################################################################ """ ident = '$Id: Server.py,v 1.21 2005/02/15 16:32:22 warnes Exp $' from version import __version__ from __future__ import nested_scopes #import xml.sax import re import socket import sys import SocketServer from types import * import BaseHTTPServer import thread # SOAPpy modules from Parser import parseSOAPRPC from Config import Config from Types import faultType, voidType, simplify from NS import NS from SOAPBuilder import buildSOAP from Utilities import debugHeader, debugFooter try: from M2Crypto import SSL except: pass ident = '$Id: Server.py,v 1.21 2005/02/15 16:32:22 warnes Exp $' from version import __version__ ################################################################################ # Call context dictionary ################################################################################ _contexts = dict() def GetSOAPContext(): global _contexts return _contexts[thread.get_ident()] ################################################################################ # Server ################################################################################ # Method Signature class for adding extra info to registered funcs, right now # used just to indicate it should be called with keywords, instead of ordered # params. class MethodSig: def __init__(self, func, keywords=0, context=0): self.func = func self.keywords = keywords self.context = context self.__name__ = func.__name__ def __call__(self, *args, **kw): return apply(self.func,args,kw) class SOAPContext: def __init__(self, header, body, attrs, xmldata, connection, httpheaders, soapaction): self.header = header self.body = body self.attrs = attrs self.xmldata = xmldata self.connection = connection self.httpheaders= httpheaders self.soapaction = soapaction # A class to describe how header messages are handled class HeaderHandler: # Initially fail out if there are any problems. def __init__(self, header, attrs): for i in header.__dict__.keys(): if i[0] == "_": continue d = getattr(header, i) try: fault = int(attrs[id(d)][(NS.ENV, 'mustUnderstand')]) except: fault = 0 if fault: raise faultType, ("%s:MustUnderstand" % NS.ENV_T, "Required Header Misunderstood", "%s" % i) ################################################################################ # SOAP Server ################################################################################ class SOAPServerBase: def get_request(self): sock, addr = SocketServer.TCPServer.get_request(self) if self.ssl_context: sock = SSL.Connection(self.ssl_context, sock) sock._setup_ssl(addr) if sock.accept_ssl() != 1: raise socket.error, "Couldn't accept SSL connection" return sock, addr def registerObject(self, object, namespace = '', path = ''): if namespace == '' and path == '': namespace = self.namespace if namespace == '' and path != '': namespace = path.replace("/", ":") if namespace[0] == ":": namespace = namespace[1:] self.objmap[namespace] = object def registerFunction(self, function, namespace = '', funcName = None, path = ''): if not funcName : funcName = function.__name__ if namespace == '' and path == '': namespace = self.namespace if namespace == '' and path != '': namespace = path.replace("/", ":") if namespace[0] == ":": namespace = namespace[1:] if self.funcmap.has_key(namespace): self.funcmap[namespace][funcName] = function else: self.funcmap[namespace] = {funcName : function} def registerKWObject(self, object, namespace = '', path = ''): if namespace == '' and path == '': namespace = self.namespace if namespace == '' and path != '': namespace = path.replace("/", ":") if namespace[0] == ":": namespace = namespace[1:] for i in dir(object.__class__): if i[0] != "_" and callable(getattr(object, i)): self.registerKWFunction(getattr(object,i), namespace) # convenience - wraps your func for you. def registerKWFunction(self, function, namespace = '', funcName = None, path = ''): if namespace == '' and path == '': namespace = self.namespace if namespace == '' and path != '': namespace = path.replace("/", ":") if namespace[0] == ":": namespace = namespace[1:] self.registerFunction(MethodSig(function,keywords=1), namespace, funcName) def unregisterObject(self, object, namespace = '', path = ''): if namespace == '' and path == '': namespace = self.namespace if namespace == '' and path != '': namespace = path.replace("/", ":") if namespace[0] == ":": namespace = namespace[1:] del self.objmap[namespace] class SOAPRequestHandler(BaseHTTPServer.BaseHTTPRequestHandler): def version_string(self): return '' + \ 'SOAPpy ' + __version__ + ' (Python ' + \ sys.version.split()[0] + ')' def date_time_string(self): self.__last_date_time_string = \ BaseHTTPServer.BaseHTTPRequestHandler.\ date_time_string(self) return self.__last_date_time_string def do_POST(self): global _contexts status = 500 try: if self.server.config.dumpHeadersIn: s = 'Incoming HTTP headers' debugHeader(s) print self.raw_requestline.strip() print "\n".join(map (lambda x: x.strip(), self.headers.headers)) debugFooter(s) data = self.rfile.read(int(self.headers["Content-length"])) if self.server.config.dumpSOAPIn: s = 'Incoming SOAP' debugHeader(s) print data, if data[-1] != '\n': print debugFooter(s) (r, header, body, attrs) = \ parseSOAPRPC(data, header = 1, body = 1, attrs = 1) method = r._name args = r._aslist() kw = r._asdict() if Config.simplify_objects: args = simplify(args) kw = simplify(kw) # Handle mixed named and unnamed arguments by assuming # that all arguments with names of the form "v[0-9]+" # are unnamed and should be passed in numeric order, # other arguments are named and should be passed using # this name. # This is a non-standard exension to the SOAP protocol, # but is supported by Apache AXIS. # It is enabled by default. To disable, set # Config.specialArgs to False. if Config.specialArgs: ordered_args = {} named_args = {} for (k,v) in kw.items(): if k[0]=="v": try: i = int(k[1:]) ordered_args[i] = v except ValueError: named_args[str(k)] = v else: named_args[str(k)] = v # We have to decide namespace precedence # I'm happy with the following scenario # if r._ns is specified use it, if not check for # a path, if it's specified convert it and use it as the # namespace. If both are specified, use r._ns. ns = r._ns if len(self.path) > 1 and not ns: ns = self.path.replace("/", ":") if ns[0] == ":": ns = ns[1:] # authorization method a = None keylist = ordered_args.keys() keylist.sort() # create list in proper order w/o names tmp = map( lambda x: ordered_args[x], keylist) ordered_args = tmp #print '<-> Argument Matching Yielded:' #print '<-> Ordered Arguments:' + str(ordered_args) #print '<-> Named Arguments :' + str(named_args) resp = "" # For fault messages if ns: nsmethod = "%s:%s" % (ns, method) else: nsmethod = method try: # First look for registered functions if self.server.funcmap.has_key(ns) and \ self.server.funcmap[ns].has_key(method): f = self.server.funcmap[ns][method] # look for the authorization method if self.server.config.authMethod != None: authmethod = self.server.config.authMethod if self.server.funcmap.has_key(ns) and \ self.server.funcmap[ns].has_key(authmethod): a = self.server.funcmap[ns][authmethod] else: # Now look at registered objects # Check for nested attributes. This works even if # there are none, because the split will return # [method] f = self.server.objmap[ns] # Look for the authorization method if self.server.config.authMethod != None: authmethod = self.server.config.authMethod if hasattr(f, authmethod): a = getattr(f, authmethod) # then continue looking for the method l = method.split(".") for i in l: f = getattr(f, i) except: info = sys.exc_info() try: resp = buildSOAP(faultType("%s:Client" % NS.ENV_T, "Method Not Found", "%s : %s %s %s" % (nsmethod, info[0], info[1], info[2])), encoding = self.server.encoding, config = self.server.config) finally: del info status = 500 else: try: if header: x = HeaderHandler(header, attrs) fr = 1 # call context book keeping # We're stuffing the method into the soapaction if there # isn't one, someday, we'll set that on the client # and it won't be necessary here # for now we're doing both if "SOAPAction".lower() not in self.headers.keys() or \ self.headers["SOAPAction"] == "\"\"": self.headers["SOAPAction"] = method thread_id = thread.get_ident() _contexts[thread_id] = SOAPContext(header, body, attrs, data, self.connection, self.headers, self.headers["SOAPAction"]) # Do an authorization check if a != None: if not apply(a, (), {"_SOAPContext" : _contexts[thread_id] }): raise faultType("%s:Server" % NS.ENV_T, "Authorization failed.", "%s" % nsmethod) # If it's wrapped, some special action may be needed if isinstance(f, MethodSig): c = None if f.context: # retrieve context object c = _contexts[thread_id] if Config.specialArgs: if c: named_args["_SOAPContext"] = c fr = apply(f, ordered_args, named_args) elif f.keywords: # This is lame, but have to de-unicode # keywords strkw = {} for (k, v) in kw.items(): strkw[str(k)] = v if c: strkw["_SOAPContext"] = c fr = apply(f, (), strkw) elif c: fr = apply(f, args, {'_SOAPContext':c}) else: fr = apply(f, args, {}) else: if Config.specialArgs: fr = apply(f, ordered_args, named_args) else: fr = apply(f, args, {}) if type(fr) == type(self) and \ isinstance(fr, voidType): resp = buildSOAP(kw = {'%sResponse' % method: fr}, encoding = self.server.encoding, config = self.server.config) else: resp = buildSOAP(kw = {'%sResponse' % method: {'Result': fr}}, encoding = self.server.encoding, config = self.server.config) # Clean up _contexts if _contexts.has_key(thread_id): del _contexts[thread_id] except Exception, e: import traceback info = sys.exc_info() try: if self.server.config.dumpFaultInfo: s = 'Method %s exception' % nsmethod debugHeader(s) traceback.print_exception(info[0], info[1], info[2]) debugFooter(s) if isinstance(e, faultType): f = e else: f = faultType("%s:Server" % NS.ENV_T, "Method Failed", "%s" % nsmethod) if self.server.config.returnFaultInfo: f._setDetail("".join(traceback.format_exception( info[0], info[1], info[2]))) elif not hasattr(f, 'detail'): f._setDetail("%s %s" % (info[0], info[1])) finally: del info resp = buildSOAP(f, encoding = self.server.encoding, config = self.server.config) status = 500 else: status = 200 except faultType, e: import traceback info = sys.exc_info() try: if self.server.config.dumpFaultInfo: s = 'Received fault exception' debugHeader(s) traceback.print_exception(info[0], info[1], info[2]) debugFooter(s) if self.server.config.returnFaultInfo: e._setDetail("".join(traceback.format_exception( info[0], info[1], info[2]))) elif not hasattr(e, 'detail'): e._setDetail("%s %s" % (info[0], info[1])) finally: del info resp = buildSOAP(e, encoding = self.server.encoding, config = self.server.config) status = 500 except Exception, e: # internal error, report as HTTP server error if self.server.config.dumpFaultInfo: s = 'Internal exception %s' % e import traceback debugHeader(s) info = sys.exc_info() try: traceback.print_exception(info[0], info[1], info[2]) finally: del info debugFooter(s) self.send_response(500) self.end_headers() if self.server.config.dumpHeadersOut and \ self.request_version != 'HTTP/0.9': s = 'Outgoing HTTP headers' debugHeader(s) if self.responses.has_key(status): s = ' ' + self.responses[status][0] else: s = '' print "%s %d%s" % (self.protocol_version, 500, s) print "Server:", self.version_string() print "Date:", self.__last_date_time_string debugFooter(s) else: # got a valid SOAP response self.send_response(status) t = 'text/xml'; if self.server.encoding != None: t += '; charset="%s"' % self.server.encoding self.send_header("Content-type", t) self.send_header("Content-length", str(len(resp))) self.end_headers() if self.server.config.dumpHeadersOut and \ self.request_version != 'HTTP/0.9': s = 'Outgoing HTTP headers' debugHeader(s) if self.responses.has_key(status): s = ' ' + self.responses[status][0] else: s = '' print "%s %d%s" % (self.protocol_version, status, s) print "Server:", self.version_string() print "Date:", self.__last_date_time_string print "Content-type:", t print "Content-length:", len(resp) debugFooter(s) if self.server.config.dumpSOAPOut: s = 'Outgoing SOAP' debugHeader(s) print resp, if resp[-1] != '\n': print debugFooter(s) self.wfile.write(resp) self.wfile.flush() # We should be able to shut down both a regular and an SSL # connection, but under Python 2.1, calling shutdown on an # SSL connections drops the output, so this work-around. # This should be investigated more someday. if self.server.config.SSLserver and \ isinstance(self.connection, SSL.Connection): self.connection.set_shutdown(SSL.SSL_SENT_SHUTDOWN | SSL.SSL_RECEIVED_SHUTDOWN) else: self.connection.shutdown(1) def do_GET(self): #print 'command ', self.command #print 'path ', self.path #print 'request_version', self.request_version #print 'headers' #print ' type ', self.headers.type #print ' maintype', self.headers.maintype #print ' subtype ', self.headers.subtype #print ' params ', self.headers.plist path = self.path.lower() if path.endswith('wsdl'): method = 'wsdl' function = namespace = None if self.server.funcmap.has_key(namespace) \ and self.server.funcmap[namespace].has_key(method): function = self.server.funcmap[namespace][method] else: if namespace in self.server.objmap.keys(): function = self.server.objmap[namespace] l = method.split(".") for i in l: function = getattr(function, i) if function: self.send_response(200) self.send_header("Content-type", 'text/plain') self.end_headers() response = apply(function, ()) self.wfile.write(str(response)) return # return error self.send_response(200) self.send_header("Content-type", 'text/html') self.end_headers() self.wfile.write('''\ <head>Error!</head>

Oops!

This server supports HTTP GET requests only for the the purpose of obtaining Web Services Description Language (WSDL) for a specific service. Either you requested an URL that does not end in "wsdl" or this server does not implement a wsdl method.

''') def log_message(self, format, *args): if self.server.log: BaseHTTPServer.BaseHTTPRequestHandler.\ log_message (self, format, *args) class SOAPServer(SOAPServerBase, SocketServer.TCPServer): def __init__(self, addr = ('localhost', 8000), RequestHandler = SOAPRequestHandler, log = 0, encoding = 'UTF-8', config = Config, namespace = None, ssl_context = None): # Test the encoding, raising an exception if it's not known if encoding != None: ''.encode(encoding) if ssl_context != None and not config.SSLserver: raise AttributeError, \ "SSL server not supported by this Python installation" self.namespace = namespace self.objmap = {} self.funcmap = {} self.ssl_context = ssl_context self.encoding = encoding self.config = config self.log = log self.allow_reuse_address= 1 SocketServer.TCPServer.__init__(self, addr, RequestHandler) class ThreadingSOAPServer(SOAPServerBase, SocketServer.ThreadingTCPServer): def __init__(self, addr = ('localhost', 8000), RequestHandler = SOAPRequestHandler, log = 0, encoding = 'UTF-8', config = Config, namespace = None, ssl_context = None): # Test the encoding, raising an exception if it's not known if encoding != None: ''.encode(encoding) if ssl_context != None and not config.SSLserver: raise AttributeError, \ "SSL server not supported by this Python installation" self.namespace = namespace self.objmap = {} self.funcmap = {} self.ssl_context = ssl_context self.encoding = encoding self.config = config self.log = log self.allow_reuse_address= 1 SocketServer.ThreadingTCPServer.__init__(self, addr, RequestHandler) # only define class if Unix domain sockets are available if hasattr(socket, "AF_UNIX"): class SOAPUnixSocketServer(SOAPServerBase, SocketServer.UnixStreamServer): def __init__(self, addr = 8000, RequestHandler = SOAPRequestHandler, log = 0, encoding = 'UTF-8', config = Config, namespace = None, ssl_context = None): # Test the encoding, raising an exception if it's not known if encoding != None: ''.encode(encoding) if ssl_context != None and not config.SSLserver: raise AttributeError, \ "SSL server not supported by this Python installation" self.namespace = namespace self.objmap = {} self.funcmap = {} self.ssl_context = ssl_context self.encoding = encoding self.config = config self.log = log self.allow_reuse_address= 1 SocketServer.UnixStreamServer.__init__(self, str(addr), RequestHandler) SOAPpy-0.12.0/SOAPpy/Types.py0100644001604000501700000014523710206532467015341 0ustar warnegclinical""" ################################################################################ # Copyright (c) 2003, Pfizer # Copyright (c) 2001, Cayce Ullman. # Copyright (c) 2001, Brian Matthews. # # All rights reserved. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions are met: # Redistributions of source code must retain the above copyright notice, this # list of conditions and the following disclaimer. # # Redistributions in binary form must reproduce the above copyright notice, # this list of conditions and the following disclaimer in the documentation # and/or other materials provided with the distribution. # # Neither the name of actzero, inc. nor the names of its contributors may # be used to endorse or promote products derived from this software without # specific prior written permission. # # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE # ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR # ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES # (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; # LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND # ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS # SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. # ################################################################################ """ ident = '$Id: Types.py,v 1.19 2005/02/22 04:29:43 warnes Exp $' from version import __version__ from __future__ import nested_scopes import UserList import base64 import cgi import urllib import copy import re import time from types import * # SOAPpy modules from Errors import * from NS import NS from Utilities import encodeHexString, cleanDate from Config import Config ############################################################################### # Utility functions ############################################################################### def isPrivate(name): return name[0]=='_' def isPublic(name): return name[0]!='_' ############################################################################### # Types and Wrappers ############################################################################### class anyType: _validURIs = (NS.XSD, NS.XSD2, NS.XSD3, NS.ENC) def __init__(self, data = None, name = None, typed = 1, attrs = None): if self.__class__ == anyType: raise Error, "anyType can't be instantiated directly" if type(name) in (ListType, TupleType): self._ns, self._name = name else: self._ns = self._validURIs[0] self._name = name self._typed = typed self._attrs = {} self._cache = None self._type = self._typeName() self._data = self._checkValueSpace(data) if attrs != None: self._setAttrs(attrs) def __str__(self): if hasattr(self,'_name') and self._name: return "<%s %s at %d>" % (self.__class__, self._name, id(self)) return "<%s at %d>" % (self.__class__, id(self)) __repr__ = __str__ def _checkValueSpace(self, data): return data def _marshalData(self): return str(self._data) def _marshalAttrs(self, ns_map, builder): a = '' for attr, value in self._attrs.items(): ns, n = builder.genns(ns_map, attr[0]) a += n + ' %s%s="%s"' % \ (ns, attr[1], cgi.escape(str(value), 1)) return a def _fixAttr(self, attr): if type(attr) in (StringType, UnicodeType): attr = (None, attr) elif type(attr) == ListType: attr = tuple(attr) elif type(attr) != TupleType: raise AttributeError, "invalid attribute type" if len(attr) != 2: raise AttributeError, "invalid attribute length" if type(attr[0]) not in (NoneType, StringType, UnicodeType): raise AttributeError, "invalid attribute namespace URI type" return attr def _getAttr(self, attr): attr = self._fixAttr(attr) try: return self._attrs[attr] except: return None def _setAttr(self, attr, value): attr = self._fixAttr(attr) if type(value) is StringType: value = unicode(value) self._attrs[attr] = value def _setAttrs(self, attrs): if type(attrs) in (ListType, TupleType): for i in range(0, len(attrs), 2): self._setAttr(attrs[i], attrs[i + 1]) return if type(attrs) == DictType: d = attrs elif isinstance(attrs, anyType): d = attrs._attrs else: raise AttributeError, "invalid attribute type" for attr, value in d.items(): self._setAttr(attr, value) def _setMustUnderstand(self, val): self._setAttr((NS.ENV, "mustUnderstand"), val) def _getMustUnderstand(self): return self._getAttr((NS.ENV, "mustUnderstand")) def _setActor(self, val): self._setAttr((NS.ENV, "actor"), val) def _getActor(self): return self._getAttr((NS.ENV, "actor")) def _typeName(self): return self.__class__.__name__[:-4] def _validNamespaceURI(self, URI, strict): if not hasattr(self, '_typed') or not self._typed: return None if URI in self._validURIs: return URI if not strict: return self._ns raise AttributeError, \ "not a valid namespace for type %s" % self._type class voidType(anyType): pass class stringType(anyType): def _checkValueSpace(self, data): if data == None: raise ValueError, "must supply initial %s value" % self._type if type(data) not in (StringType, UnicodeType): raise AttributeError, "invalid %s type:" % self._type return data class untypedType(stringType): def __init__(self, data = None, name = None, attrs = None): stringType.__init__(self, data, name, 0, attrs) class IDType(stringType): pass class NCNameType(stringType): pass class NameType(stringType): pass class ENTITYType(stringType): pass class IDREFType(stringType): pass class languageType(stringType): pass class NMTOKENType(stringType): pass class QNameType(stringType): pass class tokenType(anyType): _validURIs = (NS.XSD2, NS.XSD3) __invalidre = '[\n\t]|^ | $| ' def _checkValueSpace(self, data): if data == None: raise ValueError, "must supply initial %s value" % self._type if type(data) not in (StringType, UnicodeType): raise AttributeError, "invalid %s type" % self._type if type(self.__invalidre) == StringType: self.__invalidre = re.compile(self.__invalidre) if self.__invalidre.search(data): raise ValueError, "invalid %s value" % self._type return data class normalizedStringType(anyType): _validURIs = (NS.XSD3,) __invalidre = '[\n\r\t]' def _checkValueSpace(self, data): if data == None: raise ValueError, "must supply initial %s value" % self._type if type(data) not in (StringType, UnicodeType): raise AttributeError, "invalid %s type" % self._type if type(self.__invalidre) == StringType: self.__invalidre = re.compile(self.__invalidre) if self.__invalidre.search(data): raise ValueError, "invalid %s value" % self._type return data class CDATAType(normalizedStringType): _validURIs = (NS.XSD2,) class booleanType(anyType): def __int__(self): return self._data __nonzero__ = __int__ def _marshalData(self): return ['false', 'true'][self._data] def _checkValueSpace(self, data): if data == None: raise ValueError, "must supply initial %s value" % self._type if data in (0, '0', 'false', ''): return 0 if data in (1, '1', 'true'): return 1 raise ValueError, "invalid %s value" % self._type class decimalType(anyType): def _checkValueSpace(self, data): if data == None: raise ValueError, "must supply initial %s value" % self._type if type(data) not in (IntType, LongType, FloatType): raise Error, "invalid %s value" % self._type return data class floatType(anyType): def _checkValueSpace(self, data): if data == None: raise ValueError, "must supply initial %s value" % self._type if type(data) not in (IntType, LongType, FloatType) or \ data < -3.4028234663852886E+38 or \ data > 3.4028234663852886E+38: raise ValueError, "invalid %s value: %s" % (self._type, repr(data)) return data def _marshalData(self): return "%.18g" % self._data # More precision class doubleType(anyType): def _checkValueSpace(self, data): if data == None: raise ValueError, "must supply initial %s value" % self._type if type(data) not in (IntType, LongType, FloatType) or \ data < -1.7976931348623158E+308 or \ data > 1.7976931348623157E+308: raise ValueError, "invalid %s value: %s" % (self._type, repr(data)) return data def _marshalData(self): return "%.18g" % self._data # More precision class durationType(anyType): _validURIs = (NS.XSD3,) def _checkValueSpace(self, data): if data == None: raise ValueError, "must supply initial %s value" % self._type try: # A tuple or a scalar is OK, but make them into a list if type(data) == TupleType: data = list(data) elif type(data) != ListType: data = [data] if len(data) > 6: raise Exception, "too many values" # Now check the types of all the components, and find # the first nonzero element along the way. f = -1 for i in range(len(data)): if data[i] == None: data[i] = 0 continue if type(data[i]) not in \ (IntType, LongType, FloatType): raise Exception, "element %d a bad type" % i if data[i] and f == -1: f = i # If they're all 0, just use zero seconds. if f == -1: self._cache = 'PT0S' return (0,) * 6 # Make sure only the last nonzero element has a decimal fraction # and only the first element is negative. d = -1 for i in range(f, len(data)): if data[i]: if d != -1: raise Exception, \ "all except the last nonzero element must be " \ "integers" if data[i] < 0 and i > f: raise Exception, \ "only the first nonzero element can be negative" elif data[i] != long(data[i]): d = i # Pad the list on the left if necessary. if len(data) < 6: n = 6 - len(data) f += n d += n data = [0] * n + data # Save index of the first nonzero element and the decimal # element for _marshalData. self.__firstnonzero = f self.__decimal = d except Exception, e: raise ValueError, "invalid %s value - %s" % (self._type, e) return tuple(data) def _marshalData(self): if self._cache == None: d = self._data t = 0 if d[self.__firstnonzero] < 0: s = '-P' else: s = 'P' t = 0 for i in range(self.__firstnonzero, len(d)): if d[i]: if i > 2 and not t: s += 'T' t = 1 if self.__decimal == i: s += "%g" % abs(d[i]) else: s += "%d" % long(abs(d[i])) s += ['Y', 'M', 'D', 'H', 'M', 'S'][i] self._cache = s return self._cache class timeDurationType(durationType): _validURIs = (NS.XSD, NS.XSD2, NS.ENC) class dateTimeType(anyType): _validURIs = (NS.XSD3,) def _checkValueSpace(self, data): try: if data == None: data = time.time() if (type(data) in (IntType, LongType)): data = list(time.gmtime(data)[:6]) elif (type(data) == FloatType): f = data - int(data) data = list(time.gmtime(int(data))[:6]) data[5] += f elif type(data) in (ListType, TupleType): if len(data) < 6: raise Exception, "not enough values" if len(data) > 9: raise Exception, "too many values" data = list(data[:6]) cleanDate(data) else: raise Exception, "invalid type" except Exception, e: raise ValueError, "invalid %s value - %s" % (self._type, e) return tuple(data) def _marshalData(self): if self._cache == None: d = self._data s = "%04d-%02d-%02dT%02d:%02d:%02d" % ((abs(d[0]),) + d[1:]) if d[0] < 0: s = '-' + s f = d[5] - int(d[5]) if f != 0: s += ("%g" % f)[1:] s += 'Z' self._cache = s return self._cache class recurringInstantType(anyType): _validURIs = (NS.XSD,) def _checkValueSpace(self, data): try: if data == None: data = list(time.gmtime(time.time())[:6]) if (type(data) in (IntType, LongType)): data = list(time.gmtime(data)[:6]) elif (type(data) == FloatType): f = data - int(data) data = list(time.gmtime(int(data))[:6]) data[5] += f elif type(data) in (ListType, TupleType): if len(data) < 1: raise Exception, "not enough values" if len(data) > 9: raise Exception, "too many values" data = list(data[:6]) if len(data) < 6: data += [0] * (6 - len(data)) f = len(data) for i in range(f): if data[i] == None: if f < i: raise Exception, \ "only leftmost elements can be none" else: f = i break cleanDate(data, f) else: raise Exception, "invalid type" except Exception, e: raise ValueError, "invalid %s value - %s" % (self._type, e) return tuple(data) def _marshalData(self): if self._cache == None: d = self._data e = list(d) neg = '' if not e[0]: e[0] = '--' else: if e[0] < 0: neg = '-' e[0] = abs(e[0]) if e[0] < 100: e[0] = '-' + "%02d" % e[0] else: e[0] = "%04d" % e[0] for i in range(1, len(e)): if e[i] == None or (i < 3 and e[i] == 0): e[i] = '-' else: if e[i] < 0: neg = '-' e[i] = abs(e[i]) e[i] = "%02d" % e[i] if d[5]: f = abs(d[5] - int(d[5])) if f: e[5] += ("%g" % f)[1:] s = "%s%s-%s-%sT%s:%s:%sZ" % ((neg,) + tuple(e)) self._cache = s return self._cache class timeInstantType(dateTimeType): _validURIs = (NS.XSD, NS.XSD2, NS.ENC) class timePeriodType(dateTimeType): _validURIs = (NS.XSD2, NS.ENC) class timeType(anyType): def _checkValueSpace(self, data): try: if data == None: data = time.gmtime(time.time())[3:6] elif (type(data) == FloatType): f = data - int(data) data = list(time.gmtime(int(data))[3:6]) data[2] += f elif type(data) in (IntType, LongType): data = time.gmtime(data)[3:6] elif type(data) in (ListType, TupleType): if len(data) == 9: data = data[3:6] elif len(data) > 3: raise Exception, "too many values" data = [None, None, None] + list(data) if len(data) < 6: data += [0] * (6 - len(data)) cleanDate(data, 3) data = data[3:] else: raise Exception, "invalid type" except Exception, e: raise ValueError, "invalid %s value - %s" % (self._type, e) return tuple(data) def _marshalData(self): if self._cache == None: d = self._data s = '' s = time.strftime("%H:%M:%S", (0, 0, 0) + d + (0, 0, -1)) f = d[2] - int(d[2]) if f != 0: s += ("%g" % f)[1:] s += 'Z' self._cache = s return self._cache class dateType(anyType): def _checkValueSpace(self, data): try: if data == None: data = time.gmtime(time.time())[0:3] elif type(data) in (IntType, LongType, FloatType): data = time.gmtime(data)[0:3] elif type(data) in (ListType, TupleType): if len(data) == 9: data = data[0:3] elif len(data) > 3: raise Exception, "too many values" data = list(data) if len(data) < 3: data += [1, 1, 1][len(data):] data += [0, 0, 0] cleanDate(data) data = data[:3] else: raise Exception, "invalid type" except Exception, e: raise ValueError, "invalid %s value - %s" % (self._type, e) return tuple(data) def _marshalData(self): if self._cache == None: d = self._data s = "%04d-%02d-%02dZ" % ((abs(d[0]),) + d[1:]) if d[0] < 0: s = '-' + s self._cache = s return self._cache class gYearMonthType(anyType): _validURIs = (NS.XSD3,) def _checkValueSpace(self, data): try: if data == None: data = time.gmtime(time.time())[0:2] elif type(data) in (IntType, LongType, FloatType): data = time.gmtime(data)[0:2] elif type(data) in (ListType, TupleType): if len(data) == 9: data = data[0:2] elif len(data) > 2: raise Exception, "too many values" data = list(data) if len(data) < 2: data += [1, 1][len(data):] data += [1, 0, 0, 0] cleanDate(data) data = data[:2] else: raise Exception, "invalid type" except Exception, e: raise ValueError, "invalid %s value - %s" % (self._type, e) return tuple(data) def _marshalData(self): if self._cache == None: d = self._data s = "%04d-%02dZ" % ((abs(d[0]),) + d[1:]) if d[0] < 0: s = '-' + s self._cache = s return self._cache class gYearType(anyType): _validURIs = (NS.XSD3,) def _checkValueSpace(self, data): try: if data == None: data = time.gmtime(time.time())[0:1] elif type(data) in (IntType, LongType, FloatType): data = [data] if type(data) in (ListType, TupleType): if len(data) == 9: data = data[0:1] elif len(data) < 1: raise Exception, "too few values" elif len(data) > 1: raise Exception, "too many values" if type(data[0]) == FloatType: try: s = int(data[0]) except: s = long(data[0]) if s != data[0]: raise Exception, "not integral" data = [s] elif type(data[0]) not in (IntType, LongType): raise Exception, "bad type" else: raise Exception, "invalid type" except Exception, e: raise ValueError, "invalid %s value - %s" % (self._type, e) return data[0] def _marshalData(self): if self._cache == None: d = self._data s = "%04dZ" % abs(d) if d < 0: s = '-' + s self._cache = s return self._cache class centuryType(anyType): _validURIs = (NS.XSD2, NS.ENC) def _checkValueSpace(self, data): try: if data == None: data = time.gmtime(time.time())[0:1] / 100 elif type(data) in (IntType, LongType, FloatType): data = [data] if type(data) in (ListType, TupleType): if len(data) == 9: data = data[0:1] / 100 elif len(data) < 1: raise Exception, "too few values" elif len(data) > 1: raise Exception, "too many values" if type(data[0]) == FloatType: try: s = int(data[0]) except: s = long(data[0]) if s != data[0]: raise Exception, "not integral" data = [s] elif type(data[0]) not in (IntType, LongType): raise Exception, "bad type" else: raise Exception, "invalid type" except Exception, e: raise ValueError, "invalid %s value - %s" % (self._type, e) return data[0] def _marshalData(self): if self._cache == None: d = self._data s = "%02dZ" % abs(d) if d < 0: s = '-' + s self._cache = s return self._cache class yearType(gYearType): _validURIs = (NS.XSD2, NS.ENC) class gMonthDayType(anyType): _validURIs = (NS.XSD3,) def _checkValueSpace(self, data): try: if data == None: data = time.gmtime(time.time())[1:3] elif type(data) in (IntType, LongType, FloatType): data = time.gmtime(data)[1:3] elif type(data) in (ListType, TupleType): if len(data) == 9: data = data[0:2] elif len(data) > 2: raise Exception, "too many values" data = list(data) if len(data) < 2: data += [1, 1][len(data):] data = [0] + data + [0, 0, 0] cleanDate(data, 1) data = data[1:3] else: raise Exception, "invalid type" except Exception, e: raise ValueError, "invalid %s value - %s" % (self._type, e) return tuple(data) def _marshalData(self): if self._cache == None: self._cache = "--%02d-%02dZ" % self._data return self._cache class recurringDateType(gMonthDayType): _validURIs = (NS.XSD2, NS.ENC) class gMonthType(anyType): _validURIs = (NS.XSD3,) def _checkValueSpace(self, data): try: if data == None: data = time.gmtime(time.time())[1:2] elif type(data) in (IntType, LongType, FloatType): data = [data] if type(data) in (ListType, TupleType): if len(data) == 9: data = data[1:2] elif len(data) < 1: raise Exception, "too few values" elif len(data) > 1: raise Exception, "too many values" if type(data[0]) == FloatType: try: s = int(data[0]) except: s = long(data[0]) if s != data[0]: raise Exception, "not integral" data = [s] elif type(data[0]) not in (IntType, LongType): raise Exception, "bad type" if data[0] < 1 or data[0] > 12: raise Exception, "bad value" else: raise Exception, "invalid type" except Exception, e: raise ValueError, "invalid %s value - %s" % (self._type, e) return data[0] def _marshalData(self): if self._cache == None: self._cache = "--%02d--Z" % self._data return self._cache class monthType(gMonthType): _validURIs = (NS.XSD2, NS.ENC) class gDayType(anyType): _validURIs = (NS.XSD3,) def _checkValueSpace(self, data): try: if data == None: data = time.gmtime(time.time())[2:3] elif type(data) in (IntType, LongType, FloatType): data = [data] if type(data) in (ListType, TupleType): if len(data) == 9: data = data[2:3] elif len(data) < 1: raise Exception, "too few values" elif len(data) > 1: raise Exception, "too many values" if type(data[0]) == FloatType: try: s = int(data[0]) except: s = long(data[0]) if s != data[0]: raise Exception, "not integral" data = [s] elif type(data[0]) not in (IntType, LongType): raise Exception, "bad type" if data[0] < 1 or data[0] > 31: raise Exception, "bad value" else: raise Exception, "invalid type" except Exception, e: raise ValueError, "invalid %s value - %s" % (self._type, e) return data[0] def _marshalData(self): if self._cache == None: self._cache = "---%02dZ" % self._data return self._cache class recurringDayType(gDayType): _validURIs = (NS.XSD2, NS.ENC) class hexBinaryType(anyType): _validURIs = (NS.XSD3,) def _checkValueSpace(self, data): if data == None: raise ValueError, "must supply initial %s value" % self._type if type(data) not in (StringType, UnicodeType): raise AttributeError, "invalid %s type" % self._type return data def _marshalData(self): if self._cache == None: self._cache = encodeHexString(self._data) return self._cache class base64BinaryType(anyType): _validURIs = (NS.XSD3,) def _checkValueSpace(self, data): if data == None: raise ValueError, "must supply initial %s value" % self._type if type(data) not in (StringType, UnicodeType): raise AttributeError, "invalid %s type" % self._type return data def _marshalData(self): if self._cache == None: self._cache = base64.encodestring(self._data) return self._cache class base64Type(base64BinaryType): _validURIs = (NS.ENC,) class binaryType(anyType): _validURIs = (NS.XSD, NS.ENC) def __init__(self, data, name = None, typed = 1, encoding = 'base64', attrs = None): anyType.__init__(self, data, name, typed, attrs) self._setAttr('encoding', encoding) def _marshalData(self): if self._cache == None: if self._getAttr((None, 'encoding')) == 'base64': self._cache = base64.encodestring(self._data) else: self._cache = encodeHexString(self._data) return self._cache def _checkValueSpace(self, data): if data == None: raise ValueError, "must supply initial %s value" % self._type if type(data) not in (StringType, UnicodeType): raise AttributeError, "invalid %s type" % self._type return data def _setAttr(self, attr, value): attr = self._fixAttr(attr) if attr[1] == 'encoding': if attr[0] != None or value not in ('base64', 'hex'): raise AttributeError, "invalid encoding" self._cache = None anyType._setAttr(self, attr, value) class anyURIType(anyType): _validURIs = (NS.XSD3,) def _checkValueSpace(self, data): if data == None: raise ValueError, "must supply initial %s value" % self._type if type(data) not in (StringType, UnicodeType): raise AttributeError, "invalid %s type" % self._type return data def _marshalData(self): if self._cache == None: self._cache = urllib.quote(self._data) return self._cache class uriType(anyURIType): _validURIs = (NS.XSD,) class uriReferenceType(anyURIType): _validURIs = (NS.XSD2,) class NOTATIONType(anyType): def __init__(self, data, name = None, typed = 1, attrs = None): if self.__class__ == NOTATIONType: raise Error, "a NOTATION can't be instantiated directly" anyType.__init__(self, data, name, typed, attrs) class ENTITIESType(anyType): def _checkValueSpace(self, data): if data == None: raise ValueError, "must supply initial %s value" % self._type if type(data) in (StringType, UnicodeType): return (data,) if type(data) not in (ListType, TupleType) or \ filter (lambda x: type(x) not in (StringType, UnicodeType), data): raise AttributeError, "invalid %s type" % self._type return data def _marshalData(self): return ' '.join(self._data) class IDREFSType(ENTITIESType): pass class NMTOKENSType(ENTITIESType): pass class integerType(anyType): def _checkValueSpace(self, data): if data == None: raise ValueError, "must supply initial %s value" % self._type if type(data) not in (IntType, LongType): raise ValueError, "invalid %s value" % self._type return data class nonPositiveIntegerType(anyType): _validURIs = (NS.XSD2, NS.XSD3, NS.ENC) def _checkValueSpace(self, data): if data == None: raise ValueError, "must supply initial %s value" % self._type if type(data) not in (IntType, LongType) or data > 0: raise ValueError, "invalid %s value" % self._type return data class non_Positive_IntegerType(nonPositiveIntegerType): _validURIs = (NS.XSD,) def _typeName(self): return 'non-positive-integer' class negativeIntegerType(anyType): _validURIs = (NS.XSD2, NS.XSD3, NS.ENC) def _checkValueSpace(self, data): if data == None: raise ValueError, "must supply initial %s value" % self._type if type(data) not in (IntType, LongType) or data >= 0: raise ValueError, "invalid %s value" % self._type return data class negative_IntegerType(negativeIntegerType): _validURIs = (NS.XSD,) def _typeName(self): return 'negative-integer' class longType(anyType): _validURIs = (NS.XSD2, NS.XSD3, NS.ENC) def _checkValueSpace(self, data): if data == None: raise ValueError, "must supply initial %s value" % self._type if type(data) not in (IntType, LongType) or \ data < -9223372036854775808L or \ data > 9223372036854775807L: raise ValueError, "invalid %s value" % self._type return data class intType(anyType): _validURIs = (NS.XSD2, NS.XSD3, NS.ENC) def _checkValueSpace(self, data): if data == None: raise ValueError, "must supply initial %s value" % self._type if type(data) not in (IntType, LongType) or \ data < -2147483648L or \ data > 2147483647: raise ValueError, "invalid %s value" % self._type return data class shortType(anyType): _validURIs = (NS.XSD2, NS.XSD3, NS.ENC) def _checkValueSpace(self, data): if data == None: raise ValueError, "must supply initial %s value" % self._type if type(data) not in (IntType, LongType) or \ data < -32768 or \ data > 32767: raise ValueError, "invalid %s value" % self._type return data class byteType(anyType): _validURIs = (NS.XSD2, NS.XSD3, NS.ENC) def _checkValueSpace(self, data): if data == None: raise ValueError, "must supply initial %s value" % self._type if type(data) not in (IntType, LongType) or \ data < -128 or \ data > 127: raise ValueError, "invalid %s value" % self._type return data class nonNegativeIntegerType(anyType): _validURIs = (NS.XSD2, NS.XSD3, NS.ENC) def _checkValueSpace(self, data): if data == None: raise ValueError, "must supply initial %s value" % self._type if type(data) not in (IntType, LongType) or data < 0: raise ValueError, "invalid %s value" % self._type return data class non_Negative_IntegerType(nonNegativeIntegerType): _validURIs = (NS.XSD,) def _typeName(self): return 'non-negative-integer' class unsignedLongType(anyType): _validURIs = (NS.XSD2, NS.XSD3, NS.ENC) def _checkValueSpace(self, data): if data == None: raise ValueError, "must supply initial %s value" % self._type if type(data) not in (IntType, LongType) or \ data < 0 or \ data > 18446744073709551615L: raise ValueError, "invalid %s value" % self._type return data class unsignedIntType(anyType): _validURIs = (NS.XSD2, NS.XSD3, NS.ENC) def _checkValueSpace(self, data): if data == None: raise ValueError, "must supply initial %s value" % self._type if type(data) not in (IntType, LongType) or \ data < 0 or \ data > 4294967295L: raise ValueError, "invalid %s value" % self._type return data class unsignedShortType(anyType): _validURIs = (NS.XSD2, NS.XSD3, NS.ENC) def _checkValueSpace(self, data): if data == None: raise ValueError, "must supply initial %s value" % self._type if type(data) not in (IntType, LongType) or \ data < 0 or \ data > 65535: raise ValueError, "invalid %s value" % self._type return data class unsignedByteType(anyType): _validURIs = (NS.XSD2, NS.XSD3, NS.ENC) def _checkValueSpace(self, data): if data == None: raise ValueError, "must supply initial %s value" % self._type if type(data) not in (IntType, LongType) or \ data < 0 or \ data > 255: raise ValueError, "invalid %s value" % self._type return data class positiveIntegerType(anyType): _validURIs = (NS.XSD2, NS.XSD3, NS.ENC) def _checkValueSpace(self, data): if data == None: raise ValueError, "must supply initial %s value" % self._type if type(data) not in (IntType, LongType) or data <= 0: raise ValueError, "invalid %s value" % self._type return data class positive_IntegerType(positiveIntegerType): _validURIs = (NS.XSD,) def _typeName(self): return 'positive-integer' # Now compound types class compoundType(anyType): def __init__(self, data = None, name = None, typed = 1, attrs = None): if self.__class__ == compoundType: raise Error, "a compound can't be instantiated directly" anyType.__init__(self, data, name, typed, attrs) self._keyord = [] if type(data) == DictType: self.__dict__.update(data) def _aslist(self, item=None): if item is not None: return self.__dict__[self._keyord[item]] else: return map( lambda x: self.__dict__[x], self._keyord) def _asdict(self, item=None, encoding=Config.dict_encoding): if item is not None: if type(item) in (UnicodeType,StringType): item = item.encode(encoding) return self.__dict__[item] else: retval = {} def fun(x): retval[x.encode(encoding)] = self.__dict__[x] if hasattr(self, '_keyord'): map( fun, self._keyord) else: for name in dir(self): if isPublic(name): retval[name] = getattr(self,name) return retval def __getitem__(self, item): if type(item) == IntType: return self.__dict__[self._keyord[item]] else: return getattr(self, item) def __len__(self): return len(self._keyord) def __nonzero__(self): return 1 def _keys(self): return filter(lambda x: x[0] != '_', self.__dict__.keys()) def _addItem(self, name, value, attrs = None): if name in self._keyord: if type(self.__dict__[name]) != ListType: self.__dict__[name] = [self.__dict__[name]] self.__dict__[name].append(value) else: self.__dict__[name] = value self._keyord.append(name) def _placeItem(self, name, value, pos, subpos = 0, attrs = None): if subpos == 0 and type(self.__dict__[name]) != ListType: self.__dict__[name] = value else: self.__dict__[name][subpos] = value self._keyord[pos] = name def _getItemAsList(self, name, default = []): try: d = self.__dict__[name] except: return default if type(d) == ListType: return d return [d] def __str__(self): return anyType.__str__(self) + ": " + str(self._asdict()) def __repr__(self): return self.__str__() class structType(compoundType): pass class headerType(structType): _validURIs = (NS.ENV,) def __init__(self, data = None, typed = 1, attrs = None): structType.__init__(self, data, "Header", typed, attrs) class bodyType(structType): _validURIs = (NS.ENV,) def __init__(self, data = None, typed = 1, attrs = None): structType.__init__(self, data, "Body", typed, attrs) class arrayType(UserList.UserList, compoundType): def __init__(self, data = None, name = None, attrs = None, offset = 0, rank = None, asize = 0, elemsname = None): if data: if type(data) not in (ListType, TupleType): raise Error, "Data must be a sequence" UserList.UserList.__init__(self, data) compoundType.__init__(self, data, name, 0, attrs) self._elemsname = elemsname or "item" if data == None: self._rank = rank # According to 5.4.2.2 in the SOAP spec, each element in a # sparse array must have a position. _posstate keeps track of # whether we've seen a position or not. It's possible values # are: # -1 No elements have been added, so the state is indeterminate # 0 An element without a position has been added, so no # elements can have positions # 1 An element with a position has been added, so all elements # must have positions self._posstate = -1 self._full = 0 if asize in ('', None): asize = '0' self._dims = map (lambda x: int(x), str(asize).split(',')) self._dims.reverse() # It's easier to work with this way self._poss = [0] * len(self._dims) # This will end up # reversed too for i in range(len(self._dims)): if self._dims[i] < 0 or \ self._dims[i] == 0 and len(self._dims) > 1: raise TypeError, "invalid Array dimensions" if offset > 0: self._poss[i] = offset % self._dims[i] offset = int(offset / self._dims[i]) # Don't break out of the loop if offset is 0 so we test all the # dimensions for > 0. if offset: raise AttributeError, "invalid Array offset" a = [None] * self._dims[0] for i in range(1, len(self._dims)): b = [] for j in range(self._dims[i]): b.append(copy.deepcopy(a)) a = b self.data = a def _aslist(self, item=None): if item is not None: return self.data[int(item)] else: return self.data def _asdict(self, item=None, encoding=Config.dict_encoding): if item is not None: if type(item) in (UnicodeType,StringType): item = item.encode(encoding) return self.data[int(item)] else: retval = {} def fun(x): retval[str(x).encode(encoding)] = self.data[x] map( fun, range(len(self.data)) ) return retval def __getitem__(self, item): try: return self.data[int(item)] except ValueError: return getattr(self, item) def __len__(self): return len(self.data) def __nonzero__(self): return 1 def __str__(self): return anyType.__str__(self) + ": " + str(self._aslist()) def _keys(self): return filter(lambda x: x[0] != '_', self.__dict__.keys()) def _addItem(self, name, value, attrs): if self._full: raise ValueError, "Array is full" pos = attrs.get((NS.ENC, 'position')) if pos != None: if self._posstate == 0: raise AttributeError, \ "all elements in a sparse Array must have a " \ "position attribute" self._posstate = 1 try: if pos[0] == '[' and pos[-1] == ']': pos = map (lambda x: int(x), pos[1:-1].split(',')) pos.reverse() if len(pos) == 1: pos = pos[0] curpos = [0] * len(self._dims) for i in range(len(self._dims)): curpos[i] = pos % self._dims[i] pos = int(pos / self._dims[i]) if pos == 0: break if pos: raise Exception elif len(pos) != len(self._dims): raise Exception else: for i in range(len(self._dims)): if pos[i] >= self._dims[i]: raise Exception curpos = pos else: raise Exception except: raise AttributeError, \ "invalid Array element position %s" % str(pos) else: if self._posstate == 1: raise AttributeError, \ "only elements in a sparse Array may have a " \ "position attribute" self._posstate = 0 curpos = self._poss a = self.data for i in range(len(self._dims) - 1, 0, -1): a = a[curpos[i]] if curpos[0] >= len(a): a += [None] * (len(a) - curpos[0] + 1) a[curpos[0]] = value if pos == None: self._poss[0] += 1 for i in range(len(self._dims) - 1): if self._poss[i] < self._dims[i]: break self._poss[i] = 0 self._poss[i + 1] += 1 if self._dims[-1] and self._poss[-1] >= self._dims[-1]: #self._full = 1 #FIXME: why is this occuring? pass def _placeItem(self, name, value, pos, subpos, attrs = None): curpos = [0] * len(self._dims) for i in range(len(self._dims)): if self._dims[i] == 0: curpos[0] = pos break curpos[i] = pos % self._dims[i] pos = int(pos / self._dims[i]) if pos == 0: break if self._dims[i] != 0 and pos: raise Error, "array index out of range" a = self.data for i in range(len(self._dims) - 1, 0, -1): a = a[curpos[i]] if curpos[0] >= len(a): a += [None] * (len(a) - curpos[0] + 1) a[curpos[0]] = value class typedArrayType(arrayType): def __init__(self, data = None, name = None, typed = None, attrs = None, offset = 0, rank = None, asize = 0, elemsname = None, complexType = 0): arrayType.__init__(self, data, name, attrs, offset, rank, asize, elemsname) self._typed = 1 self._type = typed self._complexType = complexType class faultType(structType, Error): def __init__(self, faultcode = "", faultstring = "", detail = None): self.faultcode = faultcode self.faultstring = faultstring if detail != None: self.detail = detail structType.__init__(self, None, 0) def _setDetail(self, detail = None): if detail != None: self.detail = detail else: try: del self.detail except AttributeError: pass def __repr__(self): if getattr(self, 'detail', None) != None: return "" % (self.faultcode, self.faultstring, self.detail) else: return "" % (self.faultcode, self.faultstring) __str__ = __repr__ def __call__(self): return (self.faultcode, self.faultstring, self.detail) class SOAPException(Exception): def __init__(self, code="", string="", detail=None): self.value = ("SOAPpy SOAP Exception", code, string, detail) self.code = code self.string = string self.detail = detail def __str__(self): return repr(self.value) class RequiredHeaderMismatch(Exception): def __init__(self, value): self.value = value def __str__(self): return repr(self.value) class MethodNotFound(Exception): def __init__(self, value): (val, detail) = value.split(":") self.value = val self.detail = detail def __str__(self): return repr(self.value, self.detail) class AuthorizationFailed(Exception): def __init__(self, value): self.value = value def __str__(self): return repr(self.value) class MethodFailed(Exception): def __init__(self, value): self.value = value def __str__(self): return repr(self.value) ####### # Convert complex SOAPpy objects to native python equivalents ####### def simplify(object, level=0): """ Convert the SOAPpy objects and thier contents to simple python types. This function recursively converts the passed 'container' object, and all public subobjects. (Private subobjects have names that start with '_'.) Conversions: - faultType --> raise python exception - arrayType --> array - compoundType --> dictionary """ if level > 10: return object if isinstance( object, faultType ): if object.faultstring == "Required Header Misunderstood": raise RequiredHeaderMismatch(object.detail) elif object.faultstring == "Method Not Found": raise MethodNotFound(object.detail) elif object.faultstring == "Authorization Failed": raise AuthorizationFailed(object.detail) elif object.faultstring == "Method Failed": raise MethodFailed(object.detail) else: se = SOAPException(object.faultcode, object.faultstring, object.detail) raise se elif isinstance( object, arrayType ): data = object._aslist() for k in range(len(data)): data[k] = simplify(data[k], level=level+1) return data elif isinstance( object, compoundType ) or isinstance(object, structType): data = object._asdict() for k in data.keys(): if isPublic(k): data[k] = simplify(data[k], level=level+1) return data elif type(object)==DictType: for k in object.keys(): if isPublic(k): object[k] = simplify(object[k]) return object elif type(object)==list: for k in range(len(object)): object[k] = simplify(object[k]) return object else: return object def simplify_contents(object, level=0): """ Convert the contents of SOAPpy objects to simple python types. This function recursively converts the sub-objects contained in a 'container' object to simple python types. Conversions: - faultType --> raise python exception - arrayType --> array - compoundType --> dictionary """ if level>10: return object if isinstance( object, faultType ): for k in object._keys(): if isPublic(k): setattr(object, k, simplify(object[k], level=level+1)) raise object elif isinstance( object, arrayType ): data = object._aslist() for k in range(len(data)): object[k] = simplify(data[k], level=level+1) elif isinstance(object, structType): data = object._asdict() for k in data.keys(): if isPublic(k): setattr(object, k, simplify(data[k], level=level+1)) elif isinstance( object, compoundType ) : data = object._asdict() for k in data.keys(): if isPublic(k): object[k] = simplify(data[k], level=level+1) elif type(object)==DictType: for k in object.keys(): if isPublic(k): object[k] = simplify(object[k]) elif type(object)==list: for k in range(len(object)): object[k] = simplify(object[k]) return object SOAPpy-0.12.0/SOAPpy/URLopener.py0100644001604000501700000000111510202425140016053 0ustar warnegclinical"""Provide a class for loading data from URL's that handles basic authentication""" ident = '$Id: URLopener.py,v 1.2 2004/01/31 04:20:06 warnes Exp $' from version import __version__ from Config import Config from urllib import FancyURLopener class URLopener(FancyURLopener): username = None passwd = None def __init__(self, username=None, passwd=None, *args, **kw): FancyURLopener.__init__( self, *args, **kw) self.username = username self.passwd = passwd def prompt_user_passwd(self, host, realm): return self.username, self.passwd SOAPpy-0.12.0/SOAPpy/Utilities.py0100644001604000501700000001203110202425140016152 0ustar warnegclinical""" ################################################################################ # Copyright (c) 2003, Pfizer # Copyright (c) 2001, Cayce Ullman. # Copyright (c) 2001, Brian Matthews. # # All rights reserved. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions are met: # Redistributions of source code must retain the above copyright notice, this # list of conditions and the following disclaimer. # # Redistributions in binary form must reproduce the above copyright notice, # this list of conditions and the following disclaimer in the documentation # and/or other materials provided with the distribution. # # Neither the name of actzero, inc. nor the names of its contributors may # be used to endorse or promote products derived from this software without # specific prior written permission. # # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE # ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR # ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES # (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; # LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND # ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS # SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. # ################################################################################ """ ident = '$Id: Utilities.py,v 1.4 2004/01/31 04:20:06 warnes Exp $' from version import __version__ import exceptions import copy import re import string import sys from types import * # SOAPpy modules from Errors import * ################################################################################ # Utility infielders ################################################################################ def collapseWhiteSpace(s): return re.sub('\s+', ' ', s).strip() def decodeHexString(data): conv = { '0': 0x0, '1': 0x1, '2': 0x2, '3': 0x3, '4': 0x4, '5': 0x5, '6': 0x6, '7': 0x7, '8': 0x8, '9': 0x9, 'a': 0xa, 'b': 0xb, 'c': 0xc, 'd': 0xd, 'e': 0xe, 'f': 0xf, 'A': 0xa, 'B': 0xb, 'C': 0xc, 'D': 0xd, 'E': 0xe, 'F': 0xf, } ws = string.whitespace bin = '' i = 0 while i < len(data): if data[i] not in ws: break i += 1 low = 0 while i < len(data): c = data[i] if c in string.whitespace: break try: c = conv[c] except KeyError: raise ValueError, \ "invalid hex string character `%s'" % c if low: bin += chr(high * 16 + c) low = 0 else: high = c low = 1 i += 1 if low: raise ValueError, "invalid hex string length" while i < len(data): if data[i] not in string.whitespace: raise ValueError, \ "invalid hex string character `%s'" % c i += 1 return bin def encodeHexString(data): h = '' for i in data: h += "%02X" % ord(i) return h def leapMonth(year, month): return month == 2 and \ year % 4 == 0 and \ (year % 100 != 0 or year % 400 == 0) def cleanDate(d, first = 0): ranges = (None, (1, 12), (1, 31), (0, 23), (0, 59), (0, 61)) months = (0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31) names = ('year', 'month', 'day', 'hours', 'minutes', 'seconds') if len(d) != 6: raise ValueError, "date must have 6 elements" for i in range(first, 6): s = d[i] if type(s) == FloatType: if i < 5: try: s = int(s) except OverflowError: if i > 0: raise s = long(s) if s != d[i]: raise ValueError, "%s must be integral" % names[i] d[i] = s elif type(s) == LongType: try: s = int(s) except: pass elif type(s) != IntType: raise TypeError, "%s isn't a valid type" % names[i] if i == first and s < 0: continue if ranges[i] != None and \ (s < ranges[i][0] or ranges[i][1] < s): raise ValueError, "%s out of range" % names[i] if first < 6 and d[5] >= 61: raise ValueError, "seconds out of range" if first < 2: leap = first < 1 and leapMonth(d[0], d[1]) if d[2] > months[d[1]] + leap: raise ValueError, "day out of range" def debugHeader(title): s = '*** ' + title + ' ' print s + ('*' * (72 - len(s))) def debugFooter(title): print '*' * 72 sys.stdout.flush() SOAPpy-0.12.0/SOAPpy/WSDL.py0100644001604000501700000000771310206440617014775 0ustar warnegclinical"""Parse web services description language to get SOAP methods. Rudimentary support.""" ident = '$Id: WSDL.py,v 1.11 2005/02/21 20:16:15 warnes Exp $' from version import __version__ import wstools from Client import SOAPProxy, SOAPAddress from Config import Config import urllib class Proxy: """WSDL Proxy. SOAPProxy wrapper that parses method names, namespaces, soap actions from the web service description language (WSDL) file passed into the constructor. The WSDL reference can be passed in as a stream, an url, a file name, or a string. Loads info into self.methods, a dictionary with methodname keys and values of WSDLTools.SOAPCallinfo. For example, url = 'http://www.xmethods.org/sd/2001/TemperatureService.wsdl' wsdl = WSDL.Proxy(url) print len(wsdl.methods) # 1 print wsdl.methods.keys() # getTemp See WSDLTools.SOAPCallinfo for more info on each method's attributes. """ def __init__(self, wsdlsource, config=Config, **kw ): reader = wstools.WSDLTools.WSDLReader() self.wsdl = None # From Mark Pilgrim's "Dive Into Python" toolkit.py--open anything. if self.wsdl is None and hasattr(wsdlsource, "read"): #print 'stream' self.wsdl = reader.loadFromStream(wsdlsource) # NOT TESTED (as of April 17, 2003) #if self.wsdl is None and wsdlsource == '-': # import sys # self.wsdl = reader.loadFromStream(sys.stdin) # print 'stdin' if self.wsdl is None: try: file(wsdlsource) self.wsdl = reader.loadFromFile(wsdlsource) #print 'file' except (IOError, OSError): pass if self.wsdl is None: try: stream = urllib.urlopen(wsdlsource) self.wsdl = reader.loadFromStream(stream, wsdlsource) except (IOError, OSError): pass if self.wsdl is None: import StringIO self.wsdl = reader.loadFromString(str(wsdlsource)) #print 'string' # Package wsdl info as a dictionary of remote methods, with method name # as key (based on ServiceProxy.__init__ in ZSI library). self.methods = {} service = self.wsdl.services[0] port = service.ports[0] name = service.name binding = port.getBinding() portType = binding.getPortType() for operation in portType.operations: callinfo = wstools.WSDLTools.callInfoFromWSDL(port, operation.name) self.methods[callinfo.methodName] = callinfo self.soapproxy = SOAPProxy('http://localhost/dummy.webservice', config=config, **kw) def __str__(self): s = '' for method in self.methods.values(): s += str(method) return s def __getattr__(self, name): """Set up environment then let parent class handle call. Raises AttributeError is method name is not found.""" if not self.methods.has_key(name): raise AttributeError, name callinfo = self.methods[name] self.soapproxy.proxy = SOAPAddress(callinfo.location) self.soapproxy.namespace = callinfo.namespace self.soapproxy.soapaction = callinfo.soapAction return self.soapproxy.__getattr__(name) def show_methods(self): for key in self.methods.keys(): method = self.methods[key] print "Method Name:", key.ljust(15) print inps = method.inparams for parm in range(len(inps)): details = inps[parm] print " In #%d: %s (%s)" % (parm, details.name, details.type) print outps = method.outparams for parm in range(len(outps)): details = outps[parm] print " Out #%d: %s (%s)" % (parm, details.name, details.type) print SOAPpy-0.12.0/SOAPpy/__init__.py0100644001604000501700000000055310202425140015744 0ustar warnegclinical ident = '$Id: __init__.py,v 1.9 2004/01/31 04:20:06 warnes Exp $' from version import __version__ from Client import * from Config import * from Errors import * from NS import * from Parser import * from SOAPBuilder import * from Server import * from Types import * from Utilities import * import wstools import WSDL SOAPpy-0.12.0/SOAPpy/version.py0100644001604000501700000000002610206654523015702 0ustar warnegclinical__version__="0.12.0" SOAPpy-0.12.0/bid/0040755001604000501700000000000010206655324013273 5ustar warnegclinicalSOAPpy-0.12.0/bid/inventoryClient.py0100755001604001300100000002151310202425140017072 0ustar warnegcompstat#!/usr/bin/env python import getopt import sys import string import re import time sys.path.insert(1,"..") from SOAPpy import SOAP import traceback DEFAULT_SERVERS_FILE = './inventory.servers' DEFAULT_METHODS = ('SimpleBuy', 'RequestForQuote','Buy','Ping') def usage (error = None): sys.stdout = sys.stderr if error != None: print error print """usage: %s [options] [server ...] If a long option shows an argument is mandatory, it's mandatory for the equivalent short option also. -?, --help display this usage -d, --debug turn on debugging in the SOAP library -i, --invert test servers *not* in the list of servers given -m, --method=METHOD#[,METHOD#...] call only the given methods, specify a METHOD# of ? for the list of method numbers -o, --output=TYPE turn on output, TYPE is one or more of s(uccess), f(ailure), n(ot implemented), F(ailed (as expected)), a(ll) [f] -s, --servers=FILE use FILE as list of servers to test [%s] -t, --stacktrace print a stack trace on each unexpected failure -T, --always-stacktrace print a stack trace on any failure """ % (sys.argv[0], DEFAULT_SERVERS_FILE), sys.exit (0) def methodUsage (): sys.stdout = sys.stderr print "Methods are specified by number. Multiple methods can be " \ "specified using a\ncomma-separated list of numbers or ranges. " \ "For example 1,4-6,8 specifies\nmethods 1, 4, 5, 6, and 8.\n" print "The available methods are:\n" half = (len (DEFAULT_METHODS) + 1) / 2 for i in range (half): print "%4d. %-25s" % (i + 1, DEFAULT_METHODS[i]), if i + half < len (DEFAULT_METHODS): print "%4d. %-25s" % (i + 1 + half, DEFAULT_METHODS[i + half]), print sys.exit (0) def readServers (file): servers = [] f = open (file, 'r') while 1: line = f.readline () if line == '': break if line[0] in ('#', '\n') or line[0] in string.whitespace: continue cur = {'nonfunctional': {}} tag = None servers.append (cur) while 1: if line[0] in string.whitespace: if tag == 'nonfunctional': value = method + ' ' + cur[tag][method] else: value = cur[tag] value += ' ' + line.strip () else: tag, value = line.split (':', 1) tag = tag.strip ().lower () value = value.strip () if value[0] == '"' and value[-1] == '"': value = value[1:-1] if tag == 'nonfunctional': value = value.split (' ', 1) + [''] method = value[0] cur[tag][method] = value[1] else: cur[tag] = value line = f.readline () if line == '' or line[0] == '\n': break return servers def str2list (s): l = {} for i in s.split (','): if i.find ('-') != -1: i = i.split ('-') for i in range (int (i[0]),int (i[1]) + 1): l[i] = 1 else: l[int (i)] = 1 l = l.keys () l.sort () return l def SimpleBuy(serv, sa, epname): serv = serv._sa (sa % {'methodname':'SimpleBuy'}) return serv.SimpleBuy(ProductName="widget", Quantity = 50, Address = "this is my address") #JHawk, Phalanx require this order of params def RequestForQuote(serv, sa, epname): serv = serv._sa (sa % {'methodname':'RequestForQuote'}) return serv.RequestForQuote(Quantity=3, ProductName = "thing") # for Phalanx, JHawk def Buy(serv, sa, epname): import copy serv = serv._sa (sa % {'methodname':'Buy'}) billTo_d = {"name":"Buyer One", "address":"1 1st Street", "city":"New York", "state":"NY", "zipCode":"10000"} shipTo_d = {"name":"Buyer One ", "address":"1 1st Street ", "city":"New York ", "state":"NY ", "zipCode":"10000 "} for k,v in shipTo_d.items(): shipTo_d[k] = v[:-1] itemd1 = SOAP.structType( {"name":"widg1","quantity":200,"price":SOAP.decimalType(45.99), "_typename":"LineItem"}) itemd2 = SOAP.structType( {"name":"widg2","quantity":400,"price":SOAP.decimalType(33.45), "_typename":"LineItem"}) items_d = SOAP.arrayType( [itemd1, itemd2] ) items_d._ns = "http://www.soapinterop.org/Bid" po_d = SOAP.structType( data = {"poID":"myord","createDate":SOAP.dateTimeType(),"shipTo":shipTo_d, "billTo":billTo_d, "items":items_d}) try: # it's called PO by MST (MS SOAP Toolkit), JHawk (.NET Remoting), # Idoox WASP, Paul (SOAP::Lite), PranishK (ATL), GLUE, Aumsoft, # HP, EasySoap, and Jake (Frontier). [Actzero accepts either] return serv.Buy(PO=po_d) except: # called PurchaseOrder by KeithBa return serv.Buy(PurchaseOrder=po_d) def Ping(serv, sa, epname): serv = serv._sa (sa % {'methodname':'Ping'}) return serv.Ping() def main(): servers = DEFAULT_SERVERS_FILE methodnums = None output = 'f' invert = 0 succeed = 0 printtrace = 0 stats = 1 total = 0 fail = 0 failok = 0 notimp = 0 try: opts,args = getopt.getopt (sys.argv[1:], '?dm:io:s:t', ['help', 'method', 'debug', 'invert', 'output', 'servers=']) for opt, arg in opts: if opt in ('-?', '--help'): usage () elif opt in ('-d', '--debug'): SOAP.Config.debug = 1 elif opt in ('-i', '--invert'): invert = 1 elif opt in ('-m', '--method'): if arg == '?': methodUsage () methodnums = str2list (arg) elif opt in ('-o', '--output'): output = arg elif opt in ('-s', '--servers'): servers = arg else: raise AttributeError, \ "Recognized but unimplemented option `%s'" % opt except SystemExit: raise except: usage (sys.exc_info ()[1]) if 'a' in output: output = 'fFns' servers = readServers(servers) if methodnums == None: methodnums = range (1, len (DEFAULT_METHODS) + 1) limitre = re.compile ('|'.join (args), re.IGNORECASE) for s in servers: if (not not limitre.match (s['name'])) == invert: continue serv = SOAP.SOAPProxy(s['endpoint'], namespace = s['namespace']) for num in (methodnums): if num > len(DEFAULT_METHODS): break total += 1 name = DEFAULT_METHODS[num - 1] title = '%s: %s (#%d)' % (s['name'], name, num) try: fn = globals ()[name] except KeyboardInterrupt: raise except: if 'n' in output: print title, "test not yet implemented" notimp += 1 continue try: res = fn (serv, s['soapaction'], s['name']) if s['nonfunctional'].has_key (name): print title, "succeeded despite marked nonfunctional" elif 's' in output: print title, "succeeded " succeed += 1 except KeyboardInterrupt: print "fail" raise except: if s['nonfunctional'].has_key (name): if 'F' in output: t = 'as expected' if s['nonfunctional'][name] != '': t += ', ' + s['nonfunctional'][name] print title, "failed (%s) -" %t, sys.exc_info()[1] failok += 1 else: if 'f' in output: print title, "failed -", str (sys.exc_info()[1]) fail += 1 if stats: print " Tests ended at:", time.ctime (time.time()) if stats > 0: print " Total tests: %d" % total print " Successes: %d (%3.2f%%)" % \ (succeed, 100.0 * succeed / total) if stats > 0 or fail > 0: print "Failed unexpectedly: %d (%3.2f%%)" % \ (fail, 100.0 * fail / total) if stats > 0: print " Failed as expected: %d (%3.2f%%)" % \ (failok, 100.0 * failok / total) if stats > 0 or notimp > 0: print " Not implemented: %d (%3.2f%%)" % \ (notimp, 100.0 * notimp / total) return fail + notimp if __name__ == "__main__": main() SOAPpy-0.12.0/bid/inventoryServer.py0100755001604001300100000001056710202425140017131 0ustar warnegcompstat#!/usr/bin/env python # Copyright (c) 2001, actzero, inc. import sys sys.path.insert(1,"..") from SOAPpy import SOAP #SOAP.Config.debug = 1 serverstring = "SOAP.py (actzero.com) running "+sys.platform NUMBUYS = 0 NUMSIMPLEBUYS = 0 NUMREQUESTS = 0 NUMPINGS = 0 def SimpleBuy(Address, ProductName, Quantity): # currently, this type-checks the params, and makes sure # the strings are of len > 0 global NUMSIMPLEBUYS NUMSIMPLEBUYS += 1 if Quantity < 1: raise ValueError, "must order at least one" else: return "Receipt for %d %s(s) bought from %s" % (int(Quantity), ProductName, serverstring) def RequestForQuote(ProductName, Quantity): # type-checks and makes sure Quantity >= 1 global NUMREQUESTS NUMREQUESTS += 1 if Quantity < 1: raise ValueError, "must order at least 1" else: import whrandom mult = whrandom.random() times = 0 while mult > 0.25: mult = mult - 0.25 times += 1 mult += 0.5 mult = round(mult, 3) print mult, times return SOAP.doubleType(round(mult*int(Quantity),2)) def Buy(**kw): global NUMBUYS NUMBUYS += 1 try: PurchaseOrder = kw["PurchaseOrder"] except: PurchaseOrder = kw["PO"] try: POkeys = PurchaseOrder['_keyord'] POkeys.sort() POkeys_expected = ["shipTo","billTo","items","poID","createDate"] POkeys_expected.sort() if POkeys != POkeys_expected: raise ValueError, "struct 'PurchaseOrder' needs %s, %s, %s, %s, and %s" % tuple(POkeys_expected) except: raise TypeError, "'PurchaseOrder' missing one or more element(s)" try: btkeys = PurchaseOrder["billTo"]["_keyord"] btkeys.sort() btkeys_expected = ["address","zipCode","name","state","city"] btkeys_expected.sort() except: raise TypeError, "'billTo' missing one or more elements" try: stkeys = PurchaseOrder["shipTo"]["_keyord"] stkeys.sort() stkeys_expected = ["address","zipCode","name","state","city"] stkeys_expected.sort() except: raise TypeError, "'shipTo' missing one or more elements" try: items = PurchaseOrder["items"].__dict__ data = items["data"] retstring = "" for item in data: itemdict = item["_asdict"] q = itemdict["quantity"] p = itemdict["price"] name = itemdict["name"] if retstring != "": retstring += ", " else: retstring = "bought " retstring += "%d %s(s) for %.2f" % (q,name,p) retstring += " from "+serverstring return retstring except: raise TypeError, "items must be an array of 'item' structs" def Ping(): global NUMPINGS NUMPINGS += 1 return def Monitor(str): if str=="actzero": global NUMBUYS global NUMREQUESTS global NUMSIMPLEBUYS global NUMPINGS return "(Buys, RequestForQuote(s),SimpleBuy(s), Ping(s)) = " + \ repr( (NUMBUYS,NUMREQUESTS,NUMSIMPLEBUYS, NUMPINGS) ) else: raise ValueError, "not the right string" def Clear(str): if str=="actzero": global NUMBUYS global NUMREQUESTS global NUMSIMPLEBUYS global NUMPINGS NUMBUYS = 0 NUMREQUESTS = 0 NUMSIMPLEBUYS = 0 NUMPINGS = 0 return "(Buys, RequestForQuote(s),SimpleBuy(s), Ping(s)) = " + \ repr( (NUMBUYS,NUMREQUESTS,NUMSIMPLEBUYS, NUMPINGS) ) else: raise ValueError, "not the right string" if __name__ == "__main__": if len(sys.argv) > 1: try: port = int(sys.argv[1]) if port not in range(2000,15000): raise ValueError except: print "port must be a number between 2000 and 15000" sys.exit(1) else: port = 9000 namespace = "http://www.soapinterop.org/Bid" server = SOAP.SOAPServer( ('zoo',port) ) server.registerKWFunction(SimpleBuy, namespace ) server.registerKWFunction(RequestForQuote, namespace ) server.registerKWFunction(Buy, namespace ) server.registerKWFunction(Ping, namespace ) server.registerKWFunction(Monitor, namespace ) server.registerKWFunction(Clear, namespace ) try: server.serve_forever() except KeyboardInterrupt: pass SOAPpy-0.12.0/bid/monitorClient.py0100755001604001300100000000223010202425140016517 0ustar warnegcompstatfrom SOAPpy import SOAP import sys import getopt def usage(): print """usage: %s [options] -m, --method=METHOD#[,METHOD#...] specify METHOD# of ? for the list -p, --port=PORT# allows to specify PORT# of server """ sys.exit(1) def methodUsage(): print "The available methods are:" print "1. Monitor \t\t2. Clear" sys.exit(0) port = 12080 methodnum = 1 try: opts, args = getopt.getopt (sys.argv[1:], 'p:m:', ['method','port']) for opt, arg in opts: if opt in ('-m','--method'): if arg == '?': methodUsage() methodnum = int(arg) elif opt in ('-p', '--port'): port = int(arg) else: raise AttributeError, "Recognized but unimpl option '%s'" % opt except SystemExit: raise except: usage () ep = "http://208.177.157.221:%d/xmethodsInterop" % (port) sa = "urn:soapinterop" ns = "http://www.soapinterop.org/Bid" serv = SOAP.SOAPProxy(ep, namespace =ns, soapaction = sa) if methodnum == 1: print serv.Monitor(str="actzero") elif methodnum == 2: print serv.Clear(str="actzero") else: print "invalid methodnum" methodUsage() SOAPpy-0.12.0/contrib/0040755001604000501700000000000010206655324014175 5ustar warnegclinicalSOAPpy-0.12.0/contrib/soap_cli.py0100755001604001300100000000051410202425140016367 0ustar warnegcompstat#!/usr/bin/env python import time from SOAPpy import SOAP srv = SOAP.SOAPProxy('http://localhost:10080/') for p in ('good param', 'ok param'): ret = srv.badparam(p) if isinstance(ret, SOAP.faultType): print ret else: print 'ok' dt = SOAP.dateTimeType(time.localtime(time.time())) print srv.dt(dt) SOAPpy-0.12.0/contrib/soap_handler.py0100755001604001300100000001764310202425140017250 0ustar warnegcompstat import http_server from SOAPpy.SOAP import * Fault = faultType import string, sys Config = SOAPConfig(debug=1) class soap_handler: def __init__(self, encoding='UTF-8', config=Config, namespace=None): self.namespace = namespace self.objmap = {} self.funcmap = {} self.config = config self.encoding = encoding def match (self, request): return 1 def handle_request (self, request): [path, params, query, fragment] = request.split_uri() if request.command == 'post': request.collector = collector(self, request) else: request.error(400) def continue_request(self, data, request): # Everthing that follows is cripped from do_POST(). if self.config.debug: print "\n***RECEIVING***\n", data, "*" * 13 + "\n" sys.stdout.flush() try: r, header, body = parseSOAPRPC(data, header=1, body=1) method = r._name args = r._aslist kw = r._asdict ns = r._ns resp = "" # For faults messages if ns: nsmethod = "%s:%s" % (ns, method) else: nsmethod = method try: # First look for registered functions if self.funcmap.has_key(ns) and \ self.funcmap[ns].has_key(method): f = self.funcmap[ns][method] else: # Now look at registered objects # Check for nested attributes if method.find(".") != -1: t = self.objmap[ns] l = method.split(".") for i in l: t = getattr(t,i) f = t else: f = getattr(self.objmap[ns], method) except: if self.config.debug: import traceback traceback.print_exc () resp = buildSOAP(Fault("%s:Client" % NS.ENV_T, "No method %s found" % nsmethod, "%s %s" % tuple(sys.exc_info()[0:2])), encoding = self.encoding, config = self.config) status = 500 else: try: # If it's wrapped to indicate it takes keywords # send it keywords if header: x = HeaderHandler(header) if isinstance(f,MethodSig): c = None if f.context: # Build context object c = SOAPContext(header, body, d, self.connection, self.headers, self.headers["soapaction"]) if f.keywords: tkw = {} # This is lame, but have to de-unicode keywords for (k,v) in kw.items(): tkw[str(k)] = v if c: tkw["_SOAPContext"] = c fr = apply(f,(),tkw) else: if c: fr = apply(f,args,{'_SOAPContext':c}) else: fr = apply(f,args,{}) else: fr = apply(f,args,{}) if type(fr) == type(self) and isinstance(fr, voidType): resp = buildSOAP(kw = {'%sResponse' % method:fr}, encoding = self.encoding, config = self.config) else: resp = buildSOAP(kw = {'%sResponse' % method:{'Result':fr}}, encoding = self.encoding, config = self.config) except Fault, e: resp = buildSOAP(e, config = self.config) status = 500 except: if self.config.debug: import traceback traceback.print_exc () resp = buildSOAP(Fault("%s:Server" % NS.ENV_T, \ "Method %s failed." % nsmethod, "%s %s" % tuple(sys.exc_info()[0:2])), encoding = self.encoding, config = self.config) status = 500 else: status = 200 except Fault,e: resp = buildSOAP(e, encoding = self.encoding, config = self.config) status = 500 except: # internal error, report as HTTP server error if self.config.debug: import traceback traceback.print_exc () request.error(500) #self.send_response(500) #self.end_headers() else: request['Content-Type'] = 'text/xml; charset="%s"' % self.encoding request.push(resp) request.done() # got a valid SOAP response #self.send_response(status) #self.send_header("Content-type", # 'text/xml; charset="%s"' % self.encoding) #self.send_header("Content-length", str(len(resp))) #self.end_headers() if self.config.debug: print "\n***SENDING***\n", resp, "*" * 13 + "\n" sys.stdout.flush() """ # We should be able to shut down both a regular and an SSL # connection, but under Python 2.1, calling shutdown on an # SSL connections drops the output, so this work-around. # This should be investigated more someday. if self.config.SSLserver and \ isinstance(self.connection, SSL.Connection): self.connection.set_shutdown(SSL.SSL_SENT_SHUTDOWN | SSL.SSL_RECEIVED_SHUTDOWN) else: self.connection.shutdown(1) """ def registerObject(self, object, namespace = ''): if namespace == '': namespace = self.namespace self.objmap[namespace] = object def registerFunction(self, function, namespace = '', funcName = None): if not funcName : funcName = function.__name__ if namespace == '': namespace = self.namespace if self.funcmap.has_key(namespace): self.funcmap[namespace][funcName] = function else: self.funcmap[namespace] = {funcName : function} class collector: "gathers input for POST and PUT requests" def __init__ (self, handler, request): self.handler = handler self.request = request self.data = '' # make sure there's a content-length header cl = request.get_header ('content-length') if not cl: request.error (411) else: cl = string.atoi (cl) # using a 'numeric' terminator self.request.channel.set_terminator (cl) def collect_incoming_data (self, data): self.data = self.data + data def found_terminator (self): # set the terminator back to the default self.request.channel.set_terminator ('\r\n\r\n') self.handler.continue_request (self.data, self.request) if __name__ == '__main__': import asyncore import http_server class Thing: def badparam(self, param): if param == 'good param': return 1 else: return Fault(faultstring='bad param') def dt(self, aDateTime): return aDateTime thing = Thing() soaph = soap_handler() soaph.registerObject(thing) hs = http_server.http_server('', 10080) hs.install_handler(soaph) asyncore.loop() SOAPpy-0.12.0/docs/0040755001604000501700000000000010206655324013465 5ustar warnegclinicalSOAPpy-0.12.0/docs/GettingStarted.txt0100644001604000501700000001204010206437771017154 0ustar warnegclinical Getting Started =============== NEW: Mark Pilgrims' online book _Dive Into Python_ at http://diveintopython.org includes a nice tutorial for SOAPpy in Chapter 12. "SOAP Web Services" at http://diveintopython.org/soap_web_services. The easiest way to get up to speed is to run and read the scripts in the tests directory. Better documentation is coming. Here are some examples of how to use SOAPpy: CLIENT EXAMPLES: ## CODE from SOAPpy import SOAPProxy server = SOAPProxy("http://localhost:8080/") print server.echo("Hello world") ## /CODE This opens a connection to the server listening on localhost:8080, calls the method echo with the ordered parameter of "Hello World", and prints the results. ## CODE from SOAPpy import SOAPProxy server = SOAPProxy("https://localhost:8443/") print server.echo("Hello world") ## /CODE This opens a secure connection to the SSL server listening on localhost:8443, calls the method echo with the ordered parameter of "Hello World" and prints the results. Python must be built with OpenSSL. ## CODE from SOAPpy import SOAPProxy server = SOAPProxy("http://services.xmethods.com/soap", namespace = "urn:xmethods-delayed-quotes") print server.getQuote(symbol = "IBM") ## /CODE This calls method getQuote that is in the namespace URI of urn:xmethods-delayed-quotes on server services.xmethods.com. getQuote is passed a named parameter, symbol. ## CODE from SOAPpy import SOAPProxy server = SOAPProxy("http://services.xmethods.com/soap") print server._ns("urn:xmethods-delayed-quotes").getQuote(symbol = "IBM") ## /CODE This does the same thing as the previous example, however namespace is specified inline on a per call basis rather than at the server level. ## CODE from SOAPpy import SOAPProxy server = SOAPProxy("http://services.xmethods.com/soap", soapaction = "http://somesite.com/myaction") print server._ns("urn:xmethods-delayed-quotes").getQuote(symbol = "IBM") ## /CODE This is the same quote call with a soapaction specified. ## CODE from SOAPpy import SOAPProxy server = SOAPProxy("http://services.xmethods.com:80/soap") ns = "urn:xmethods-delayed-quotes") sa = "http://somesite.com/myaction" my_call = server._ns(ns)._sa(sa) my_call.getQuote(symbol = "IBM") my_call.getQuote(symbol = "IBM") my_call.getQuote(symbol = "IBM") ## /CODE The same example, this time with both the soapaction and the namespace specified inline and saved in a local variable for getQuote to be called against. ** What SOAPpy does with the results of a call could seem surprising. If there is only one element in the structType that has the return value and unwrap_results is turned on (the default) it will bubble up the single attribute, otherwise it will return you a structType object with all of the attributes. SERVER EXAMPLES: ## CODE from SOAPpy import SOAPServer def echo(s): return s + s # repeats a string twice server = SOAPServer(("localhost", 8080)) server.registerFunction(echo) server.serve_forever() ## /CODE This exposes the function echo (that takes an unnamed arguement) on a server running on localhost:8080. ## CODE from SOAPpy import SOAPServer def echo(s): return s + s # repeats a string twice server = SOAPServer() server.registerFunction(echo, "echo-space") server.serve_forever() ## /CODE The same as above, but this time the method is available in the namespace "echo-space". ## CODE from SOAPpy import SOAPServer class echoBuilder: def echo(self, val): return val + val server = SOAPServer() e = echoBuilder() server.registerObject(e) server.serve_forever() ## /CODE This registers the whole instance of the object echoBuilder, e. Every method of the instance is exposed on the server. ## CODE from SOAPpy import SOAPServer def echo(**kw): return kw['first'] + kw['second'] + kw['third'] server = SOAPServer() server.registerKWFunction(echo) server.serve_forever() ## /CODE This time the method echo is exposed and it expects named arguments. The main thing to notice here is the use of the method registerKWFunction over registerFunction. ## CODE from SOAPpy import SOAPServer from M2Crypto import SSL def echo(s): return s+s # repeats a string twice ssl_context = SSL.Context() ssl_context.load_cert('server.pem') server = SOAPServer(("localhost",8443), ssl_context = ssl_context) server.registerFunction(echo) server.serve_forever() ## /CODE This exposes the function echo (taking an unnamed arguement) on a server accepting SSL connections at localhost:8443. Ng Pheng Siong's M2Crypto package (available at ) must be installed. Also see tests/silabserver.py. $Id: GettingStarted.txt,v 1.4 2005/02/21 20:09:29 warnes Exp $ SOAPpy-0.12.0/docs/GlobusSupport.txt0100644001604000501700000000760010206437774017065 0ustar warnegclinical Globus Support ============== Extensions have been added to the SOAPpy module to allow the use of the Globus Toolkit v2 for secure transport of SOAP calls. These extensions are possible by using the Globus Toolkit (http://www.globus.org) and the pyGlobus software (http://www-itg.lbl.gov/gtg/projects/pyGlobus/), which exposes the Globus Toolkit via a set of Python interfaces. This enables bi-directional PKI authentication so that the server and client are both guaranteed of the identity of the other. Using PKI this way also allows a more robust authorization solution above the SOAP hosting layer, which provides better application level authorization control. These tools are used by the Access Grid Project (http://www.accessgrid.org) to build a Grid-based, Web Services based, real-time collaboration environment. In order to use the SOAPpy module with the Globus Toolkit, you must first obtain and install the Globus Toolkit and pyGlobus software. Information on how to do that is at the respective web sites listed below. In order to use the Globus Toolkit it is necessary to have an x509 identity certificate. Information on how to obtain one of those is available on the web as well. To use GSI with an authorization method, set the SOAPConfig.authMethod = "methodname". You must have this method defined on any objects you register with SOAPpy, and/or as a registered method. It should return 0 or 1 to indicate if authorization is allowed or not. Once the software is installed, you have obtained your certificate, and the SOAPpy module is installed, the following code shows how to run a GSI secured SOAP server (These snippets are directly from the echoServer.py and echoClient.py in the test directory). Server ------ def _authorize(self, *args, **kw): return 1 Config.authMethod = "_authorize" addr = ('localhost', 9900) from SOAPpy.GSIServer import GSISOAPServer server = GSISOAPServer(addr) server.registerFunction(_authorize) server.registerFunction(echo) Then you use the server like the SSL server or the standard server. Client ------ import pyGlobus # The httpg distinguishes this as a GSI TCP connection, so after # this you can use the SOAP proxy as you would any other SOAP Proxy. server = SOAPProxy("httpg://localhost:9900/") print server.echo("moo") Globus Toolkit http://www.globus.org ------------------------------------ The Globus Toolkit is an open source software toolkit used for building grids. It is being developed by the Globus Alliance and many others all over the world. A growing number of projects and companies are using the Globus Toolkit to unlock the potential of grids for their cause. PyGlobus http://www-itg.lbl.gov/gtg/projects/pyGlobus/ ------------------------------------------------------ The goal of this project is to allow the use of the entire Globus toolkit from Python, a high-level scripting language. SWIG is used to generate the necessary interface code. Currently a substantial subset of the 2.2.4 and 2.4 versions of the Globus toolkit has been wrapped. The Access Grid http://www.accessgrid.org/ ------------------------------------------ The Access GridT is an ensemble of resources including multimedia large-format displays, presentation and interactive environments, and interfaces to Grid middleware and to visualization environments. These resources are used to support group-to-group interactions across the Grid. For example, the Access Grid (AG) is used for large-scale distributed meetings, collaborative work sessions, seminars, lectures, tutorials, and training. The Access Grid thus differs from desktop-to-desktop tools that focus on individual communication. - Submitted 2004-01-08 by Ivan R. Judson $Id: GlobusSupport.txt,v 1.3 2005/02/21 20:09:32 warnes Exp $ SOAPpy-0.12.0/docs/MethodParameterNaming.txt0100755001604001300100000000676310202425140020504 0ustar warnegcompstat Experimental method for handing ordered vs named method parameters ------------------------------------------------------------------ There is an incompatibility with the way that Python and SOAP handle method arguments: SOAP requires that all arguments have names and that they are presented in the same order as the method signature. Python (like other scripting languages, notably the S language) has the concept of unnamed arguments. Further Python does not preserve the order of named arguments, since they are handled using the dictionary data type. It seems to me that this makes it impossible to fully meet the SOAP specification without significant modifications to the Python method of handling named arguments or to the Python dictionary class. Historically SOAPpy has attempted to work around this issue by handling all arguments as unnamed unless the method or function was explicitly flagged, in which case all arguments were considered named. This has resulted in a several problems, particularly for a SOAPpy client communicating with a SOAPpy server. First, when named arguments were used in call to a non-flagged function, the argument would silently be reordered by the sender (since they were stored using a Python dictionary), *and* the names would be ignored by the receiver, which assumed that the parameters were unnamed and only the order was significant. This results in incorrect argument matching. This problem also occurred with mixed named and unnamed arguments. For my primary SOAP application, it is not reasonable to flag all of the SOAPpy methods as requiring named arguments, for a variety of reasons. One reason is that the available methods are not known apriori by the client software, hence the names of the arguments are not known. Second, many of the methods provide a large number of optional arguments, making it impractical to specify them all. In an attempt to overcome this problem, I implemented an experimental and non-standard method of handling named and unnamed arguments. This mechanism is enabled in SOAPpy by setting SOAPpy.SOAP.Config.specialArgs=1, and disabled by setting SOAPpy.SOAP.Config.specialArgs=0. When enabled, parameters with names of the form v#### (i.e., matching the regexp "^v[0-9]+$") are assumed to be unnamed parameters and are passed to the method in numeric order. All other parameters are assumed to be named and are passed using the name. Outgoing SOAP method calls now always generate names in this way--whether or not specialArgs is enabled. I selected the form v#### because it is a valid XML name, but is unlikely to be used as a parameter name. [As it turns out, this choice was fortitous because Apache's SOAP tool uses the same system.] In my testing, this mechanism for handling method parameter names works fine between a SOAPpy client and a SOAPpy server, and resolves the parameter reordering problems I was experiencing. This system seems unlikely to have any negative side effects on other SOAP applications, except in the (hopefully) rare case when v#### might be used as an actual parameter name. **In version 0.9.9-pre1, this feature is enabled by default.** Please let me know if there are situations where this causes problems. Note that this mechanism is only a partial solution, since it is still impossible to return named parameters in a specified order using SOAPpy. SOAP applications or implementations which require this feature are simply not compatible with SOAPpy. -Greg Warnes 2003-03-07 (updated 2003-11-14) SOAPpy-0.12.0/docs/UsingHeaders.txt0100755001604000501700000000544510205405554016614 0ustar warnegclinicalUsing Headers ============= SOAPpy has a Header class to hold data for the header of a SOAP message. Each Header instance has methods to set/get the MustUnderstand attribute, and methods to set/get the Actor attribute. SOAPpy also has a SOAPContext class so that each server method can be implemented in such a way that it gets the context of the connecting client. This includes both common SOAP information and connection information (see below for an example). CLIENT EXAMPLES --------------- ## CODE import SOAPpy test = 42 server = SOAPpy.SOAPProxy("http://localhost:8888") server = server._sa ("urn:soapinterop") hd = SOAPpy.Header() hd.InteropTestHeader ='This should fault, as you don\'t understand the header.' hd._setMustUnderstand ('InteropTestHeader', 0) hd._setActor ('InteropTestHeader','http://schemas.xmlsoap.org/soap/actor/next') server = server._hd (hd) print server.echoInteger (test) ## /CODE This should succeed (provided the server has defined echoInteger), as it builds a valid header into this client with MustUnderstand set to 0 and then sends the SOAP with this header. ## CODE import SOAPpy test = 42 server = SOAPpy.SOAPProxy("http://localhost:8888") server = server._sa ("urn:soapinterop") #Header hd = SOAPpy.Header() hd.InteropTestHeader = 'This should fault,as you don\'t understand the header.' hd._setMustUnderstand ('InteropTestHeader', 1) hd._setActor ('InteropTestHeader','http://schemas.xmlsoap.org/soap/actor/next') server = server._hd (hd) print server.echoInteger (test) ## /CODE This should fail (even if the server has defined 'echoInteger'), as it builds a valid header into this client, but sets MustUnderstand to 1 for a message that the server presumably won't understand before sending. SERVER EXAMPLES --------------- ## CODE import SOAPpy def echoInteger (inputInteger): return inputInteger server = SOAPpy.SOAPServer ( ('localhost', 8080) ) server.registerFunction (echoInteger) server.serve_forever() ## /CODE This is a simple server designed to work with the first 2 clients above. ## CODE import SOAPpy def echoInteger (inputInteger, _SOAPContext): c = _SOAPContext print c.xmldata print c.header print c.body print c.connection.getpeername() print c.soapaction print c.httpheaders return inputInteger host = 'localhost' port = 8888 server = SOAPpy.SOAPServer ( (host, port) ) server.registerFunction (SOAPpy.MethodSig(echoInteger, keywords=0,context=1)) server.serve_forever() ## /CODE This is a server which shows off the SOAPContext feature. This server gets a context from the client that has connected to it, and prints some of the pertinent aspects of that client before returning. This server should also work with the code for the two clients written above. $Id: UsingHeaders.txt,v 1.1 2005/02/18 15:36:12 warnes Exp $ SOAPpy-0.12.0/docs/WSDL.txt0100644001604000501700000000136210206437776015007 0ustar warnegclinical WSDL NOTES: Release 0.9.9 and later include logic for dealing with web service description language (WSDL) files. - SOAPpy.WSDL provides a SOAP Proxy object that parses a WSDL file and provides access to the listed services: url = 'http://www.xmethods.org/sd/2001/TemperatureService.wsdl' zip = '01072' proxy = SOAPpy.WSDL.Proxy(url) temp = proxy.getTemp(zip) print 'Temperature at', zip, 'is', temp - On the server, you can allow the client to download the WSDL for a service by sending a request of the form by adding a do_GET method to the SOAPRequestHandler. [Not yet working when debug=FALSE. Add example here when working] $Id: WSDL.txt,v 1.2 2005/02/21 20:09:34 warnes Exp $ SOAPpy-0.12.0/docs/attrs.txt0100644001604000501700000000056010205406176015357 0ustar warnegclinical Using SOAPpy Attributes ======================= All SOAPpy data classes implement methods to access and mutate individual attributes. The _setAttr method has as parameters a 'tag', the attribute name, and the value to which the attribute should be set. The _getAttrs method simply has the 'tag' parameter. $Id: attrs.txt,v 1.2 2005/02/18 15:40:46 warnes Exp $ SOAPpy-0.12.0/docs/complexTypes.txt0100644001604000501700000000120310205414724016707 0ustar warnegclinicalCOMPLEX TYPES HOWTO =================== The easiest way (at the moment) to create complex SOAP typs is to use the SOAPpy.structType class, which allows you to create an object with named arguments of arbitraty types. For example: >>> in0 = SOAPpy.structType() >>> in0._addItem('outwardDate', dep) >>> in0._addItem('returnDate', ret) >>> in0._addItem('originAirport', 'den') >>> in0._addItem('destinationAirport', 'iad') SOAPpy has code for declaring structured object templates including the type for each component, but this broke sometime in the past and has not yet been corrected. (See tests/TCtypes.py to see how it should work.) SOAPpy-0.12.0/docs/simpleTypes.txt0100644001604000501700000002001510206440003016521 0ustar warnegclinicalSimple Types HOWTO ================== The easiest way to understand use of data types is look at and run the examples already written (in tests/, validate/ and bid/) , and to write your own clients, looking at the xml as it is sent (by setting SOAP.Config.debug=1). As far as the built-in types are concerned, SOAP.py will preserve type as expected. That is: python integer will be of type integer, and equivalently for string and float. To access more than just these types, there are classes in SOAP.py. These allow invoking a certain type by making an instance of the corresponding class. The SOAPBuilder in SOAP.py will automatically convert python lists to Arrays and python dictionaries to Structs- these are two of the most frequently used data types. CLIENT EXAMPLES --------------- ## CODE import SOAP server = SOAP.SOAPProxy("http://localhost:8080/") print server.echo("Hello world") ## /CODE This example (taken from quickstart.txt) sends an ordered parameter of type string. ## CODE import SOAP import time #SOAP.Config.debug = 1 test = time.gmtime (time.time ()) server = SOAP.SOAPProxy("http://localhost:8080/") print server.echoDate (inputDate = SOAP.DateTime(test)) ## /CODE This test calls echoDate with the named parameter inputDate, which is a TimeInstant. It prints the the result. **Note: The reason that it is a TimeInstant and not a DateTime is that SOAP.py uses the 1999 schema intead of the 2001 schema. To make it a DateTime, one would just use SOAP.dateTimeType() in place of SOAP.DateTime(). ** ## CODE import SOAP server = SOAP.SOAPProxy("http://localhost:8080/") test = [0, 1, -1, 3853] print server.echoIntegerArray (inputIntegerArray = test) ## /CODE This calls echoIntegerArray with the named parameter inputIntegerArray, which is a four-member array of type int. It prints the result. ## CODE import SOAP test = {'varFloat': 2.256, 'varInt': 474, 'varString': 'Utah'} server = SOAP.SOAPProxy("http://localhost:8080/") print server.echoStruct (inputStruct = test) ## /CODE This code calls the method echoStruct with the named parameter inputStruct, which is of type Struct. It then prints the result. ## CODE import SOAP item1 = SOAP.Struct( data = {"name":"widget","quantity":200,"price":SOAP.decimalType(45.99), "_typename":"LineItem"}) items = SOAP.Array ( data = [item1] ) items._ns = "http://www.soapinterop.org/Bid" server = SOAP.SOAPProxy("http://localhost:8080") server = server._sa ("http://www.soapinterop.org/Buy") server = server._ns ("http://www.soapinterop.org/Bid") po = SOAP.Struct( data = {"poID":"Order 1234", "createDate": SOAP.dateTimeType(), "items": items} ) print server.Buy(PurchaseOrder = po) ## /CODE A few new things here. -First, we are creating an Array, 'items', with components of (made up) type 'LineItem'. (Notice the use of "_typename" to specify type). -This code associates a namespace with the Array, rather than use the default. -SOAP.dateTimeType() is called directly to get a dateTime instead of SOAP.py's default, 'timeInstant'. -Note that when creating a Struct or Array, the data must be passed in as a named 'data' param (as the first param, by order, is 'name'). -The proxy is instantiated and then the values for its namespace (_ns) and soapaction (_sa) are assigned. -This call will work for a server expecting a parameter with the same components as those in the variable 'po' above. It will work whether the server has a named param 'PurchaseOrder' or has an unnamed param, but will not work if the server expects a named param with a name of anything but 'PurchaseOrder'. SERVER EXAMPLES --------------- ## CODE import SOAP def echo(s): return s + s # repeats a string twice server = SOAP.SOAPServer(("localhost", 8080)) server.registerFunction(echo) server.serve_forever() ## /CODE This server example, from quickstart.txt, echoes (as type string) the string that is passed in, s. ## CODE import SOAP def echoDate (inputDate): return SOAP.DateTime(inputDate) server = SOAP.SOAPServer(("localhost", 8080)) server.registerKWFunction(echoDate ) server.serve_forever() ## /CODE This code accepts an inputDate and returns the same date, ensuring that it is of type TimeInstant by returning an instance of DateTime instead of simply returning the value. ## CODE import SOAP def echoIntegerArray (inputIntegerArray): if type(inputIntegerArray) != type([]) or len(inputIntegerArray) != 4: for elem in inputIntegerArray: if type(elem) != type(1): raise TypeError, "expected 4-member Array of ints" return inputIntegerArray server = SOAP.SOAPServer(("localhost", 8080)) server.registerKWFunction(echoIntegerArray ) server.serve_forever() ## /CODE This server supports the method echoIntegerArray, requiring the named parameter inputIntegerArray, which must be a four-member array of type int. ## CODE import SOAP def echoStruct (inputStruct): myfloat = inputStruct["varFloat"] mystr = inputStruct["varString"] myint = inputStruct["varInt"] return inputStruct server = SOAP.SOAPServer(("localhost", 8080)) server.registerKWFunction(echoStruct ) server.serve_forever() ## /CODE This code creates a server with a method echoStruct, which requires that the incoming Struct have elements named varFloat, varString, and varInt. That is, the server will fault if the incoming Struct does not have any of those elements. **Note, this server code does NOT require that these be the only elements in the struct- just that they be present**. This method simply returns the Struct passed in. ## CODE import sys import SOAP serverstring = "SOAP.py (actzero.com) running "+sys.platform def Buy(**kw): try: PurchaseOrder = kw["PurchaseOrder"] except: PurchaseOrder = kw["PO"] POkeys = PurchaseOrder['_keyord'] POkeys.sort() POkeys_expected = ["items","poID","createDate"] POkeys_expected.sort() if POkeys != POkeys_expected: raise ValueError, "struct 'PurchaseOrder' needs %s, %s, and %s" % tuple(POkeys_expected) items = PurchaseOrder["items"].__dict__ data = items["data"] retstring = "" for item in data: itemdict = item["_asdict"] q = itemdict["quantity"] p = itemdict["price"] name = itemdict["name"] if retstring != "": retstring += ", " else: retstring = "bought " retstring += "%d %s(s) for %.2f" % (q,name,p) retstring += " from "+serverstring return retstring server = SOAP.SOAPServer(("localhost", 8080)) namespace = "http://www.soapinterop.org/Bid" server.registerKWFunction(Buy, namespace ) server.serve_forever() ## /CODE This example creates a server to implement 'Buy', which takes a parameter named either PurchaseOrder or PO. (Notice the use of **kw as the input parameter to the method for this functionality). The server gets the names of the Struct's members by using the '_keyord' key of the Struct-as-dictionary. It checks these names against what it expects from the client, and raises a fault if the two are not the same. By using the __dict__ attribute, the server gets the 'items' (an elemnent of the PurchaseOrder Struct) as a dictionary. Then it checks that 'items' is formatted as expected. Finally, it returns a confirmation of what was bought. $Id: simpleTypes.txt,v 1.2 2005/02/21 20:09:39 warnes Exp $ SOAPpy-0.12.0/tests/0040755001604000501700000000000010206655324013677 5ustar warnegclinicalSOAPpy-0.12.0/tests/BabelfishWSDLTest.py0100755001604000501700000000157110202425142017453 0ustar warnegclinical#!/usr/bin/env python ident = '$Id: BabelfishWSDLTest.py,v 1.1 2003/07/18 15:58:28 warnes Exp $' import os, re import sys sys.path.insert(1, "..") from SOAPpy import WSDL # Check for a web proxy definition in environment try: proxy_url=os.environ['http_proxy'] phost, pport = re.search('http://([^:]+):([0-9]+)', proxy_url).group(1,2) proxy = "%s:%s" % (phost, pport) except: proxy = None server = WSDL.Proxy('http://www.xmethods.net/sd/2001/BabelFishService.wsdl', http_proxy=proxy) english = "Hi Friend!" print "Babelfish Translations" print "------------------------" print "English: '%s'" % english print "French: '%s'" % server.BabelFish('en_fr',english) print "Spanish: '%s'" % server.BabelFish('en_es',english) print "Italian: '%s'" % server.BabelFish('en_it',english) print "German: '%s'" % server.BabelFish('en_de',english) print "Done." SOAPpy-0.12.0/tests/Bug1001646.py0100644001604000501700000000307510206522716015530 0ustar warnegclinical""" Check handing of unicode. """ import sys sys.path.insert(1, "..") from SOAPpy import * # Uncomment to see outgoing HTTP headers and SOAP and incoming #Config.debug = 1 #Config.dumpHeadersIn = 1 #Config.dumpSOAPIn = 1 #Config.dumpSOAPOut = 1 # ask for returned SOAP responses to be converted to basic python types Config.simplify_objects = 1 #Config.BuildWithNoType = 1 #Config.BuildWithNoNamespacePrefix = 1 def headers(): '''Return a soap header containing all the needed information.''' hd = Types.headerType() hd.useragent = Types.stringType("foo") return hd server = SOAPProxy("http://localhost:9900/",header=headers()) adgroupid = 197497504 keyword1 = { 'status': 'Moderate', 'adGroupId': 197497504, 'destinationURL': None, 'language': '', 'text': 'does not work', 'negative': bool(0), 'maxCpc': 50000, 'type': 'Keyword', 'id': 1 } keyword2 = { 'status': 'Moderate', 'adGroupId': 197497504, 'destinationURL': None, 'language': '', 'text': 'yes it does not', 'negative': bool(0), 'maxCpc': 50000, 'type': 'Keyword', 'id': 2 } keylist = [keyword1, keyword2] # Check that the data goes through properly retval = server.echo_simple(adgroupid, keylist) kw1 = retval[1][0] kw2 = retval[1][1] assert(retval[0] == adgroupid) for key in kw1.keys(): assert(kw1[key]==keyword1[key]) for key in kw2.keys(): assert(kw2[key]==keyword2[key]) # Check that the header is preserved retval = server.echo_header((adgroupid, keylist)) assert(retval[1].has_key('useragent')) assert(retval[1]['useragent'] == 'foo') server.quit() print "Success!" SOAPpy-0.12.0/tests/Bug916265.py0100644001604000501700000000150710206526711015460 0ustar warnegclinical""" Check handing of unicode. """ import sys sys.path.insert(1, "..") from SOAPpy import * # Uncomment to see outgoing HTTP headers and SOAP and incoming #Config.debug = 1 #Config.dumpHeadersIn = 1 #Config.dumpSOAPIn = 1 #Config.dumpSOAPOut = 1 # ask for returned SOAP responses to be converted to basic python types Config.simplify_objects = 0 #Config.BuildWithNoType = 1 #Config.BuildWithNoNamespacePrefix = 1 server = SOAPProxy("http://localhost:9900/") x = u'uMOO' # Single unicode string y = server.echo_simple((x,)) assert( x==y[0] ) x = [u'uMoo1',u'uMoo2'] # array of unicode strings y = server.echo_simple(x) assert( x[0] == y[0] ) assert( x[1] == y[1] ) x = { u'A':1, u'B':u'B', 'C':u'C', 'D':'D' } y = server.echo_simple(x) for key in x.keys(): assert( x[key] == y[0][key] ) print "Success" SOAPpy-0.12.0/tests/Bug918216.py0100644001604000501700000000261710204453006015453 0ustar warnegclinicalimport sys sys.path.insert(1, "..") from SOAPpy import * detailed_fault = \ """ soapenv:Server.generalException Exception thrown on Server ... Login failure (504):Unknown User ... ... ... ... """ z = parseSOAPRPC(detailed_fault.strip() ) assert(z.__class__==faultType) assert(z.faultstring=="Exception thrown on Server") assert(z.detail.loginFailureFault.description=='Login failure (504):Unknown User') print "Success" SOAPpy-0.12.0/tests/ComplexTypes.py0100644001604000501700000000121010205437123016666 0ustar warnegclinicalimport sys sys.path.insert(1, "..") import SOAPpy import time dep = SOAPpy.dateTimeType((2004, 3, 24, 12, 30, 59, 4, 86, 0)) ret = SOAPpy.dateTimeType((2004, 3, 26, 12, 30, 59, 4, 86, 0)) in0 = SOAPpy.structType() in0._addItem('outwardDate', dep) in0._addItem('returnDate', ret) in0._addItem('originAirport', 'den') in0._addItem('destinationAirport', 'iad') x = SOAPpy.buildSOAP( in0, method="getAirFareQuote", namespace="urn:SBGAirFareQuotes.sbg.travel.ws.dsdata.co.uk" ) wsdl = 'http://www.xmethods.net/sd/2001/TemperatureService.wsdl' proxy = SOAPpy.WSDL.Proxy(wsdl) SOAPpy-0.12.0/tests/GoogleTest.py0100644001604000501700000000062210205441570016315 0ustar warnegclinicalfrom SOAPpy import WSDL server = WSDL.Proxy('/home/warneg/src/google/googleapi/GoogleSearch.wsdl') key = "6k0oDPZQFHL0zpjy6ZO6ufUVFKBgvqTo" results = server.doGoogleSearch(key, 'warnes', 0, 10, False, "", False, "", "utf-8", "utf-8") for i in range(len(results.resultElements)): res = results.resultElements[i] print '%d: %s --> %s' % ( i, res.title, res.URL ) SOAPpy-0.12.0/tests/SOAPtest.py0100755001604000501700000042146710202425142015716 0ustar warnegclinical#!/usr/bin/env python ################################################################################ # # A bunch of regression type tests for the builder and parser. # ################################################################################ ident = '$Id: SOAPtest.py,v 1.19 2004/04/01 13:25:46 warnes Exp $' import urllib import sys import unittest import re sys.path.insert(1, "..") from SOAPpy import * config=Config config.strict_range=1 # run these tests with this variable set both to 1 and 0 config.simplify_objects=0 # as borrowed from jake.soapware.org for float compares. def nearlyeq(a, b, prec = 1e-7): return abs(a - b) <= abs(a) * prec # helper def negfloat(x): return float(x) * -1.0 class Book(structType): def __init__(self): self.title = "Title of a book" structType.__init__(self) class Person(structType): def __init__(self): self.age = "49" self.height = "5.5" structType.__init__(self) class Result(structType): def __init__(self): structType.__init__(self, name = 'Result') self.Book = Book() self.Person = Person() class one: def __init__(self): self.str = "one" class two: def __init__(self): self.str = "two" class three: def __init__(self): self.str = "three" ws = ' \t\r\n' N = None class SOAPTestCase(unittest.TestCase): # big message def notestBigMessage(self): x=[] for y in string.lowercase: x.append(y*999999) buildSOAP(x) # test arrayType def testArrayType(self): x = structType( {"name":"widg1","quantity":200, "price":decimalType(45.99), "_typename":"LineItem"}) y = buildSOAP([x, x]) # could be parsed using an XML parser? self.failUnless(string.find(y, "LineItem")>-1) # test arguments ordering def testOrdering(self): x = buildSOAP(method="newCustomer", namespace="urn:customer", \ kw={"name":"foo1", "address":"bar"}, \ config=SOAPConfig(argsOrdering={"newCustomer":("address", "name")})) # could be parsed using an XML parser? self.failUnless(string.find(x, "
string.find(x, " My Life and Work Henry Ford 49 5.5 ''' # parse rules pr = {'SomeMethod': {'Result': {'Book': {'title':(NS.XSD, "string")}, 'Person': {'age':(NS.XSD, "int"), 'height':negfloat} } } } y = parseSOAPRPC(x, rules=pr) if config.simplify_objects: self.assertEquals(y['Result']['Person']['age'], 49); self.assertEquals(y['Result']['Person']['height'], -5.5); else: self.assertEquals(y.Result.Person.age, 49); self.assertEquals(y.Result.Person.height, -5.5); # Try the reverse def testStructOut(self): x = buildSOAP(Result()) def testIntFloat(self): x=''' West Virginia -546 -5.398 New Mexico -641 -9.351 Missouri -819 1.375 ''' y = parseSOAPRPC(x) if(config.simplify_objects): self.assertEquals(y['return'][0]['varString'], "West Virginia") self.assertEquals(y['return'][1]['varInt'], -641) self.assertEquals(y['return'][2]['varFloat'], 1.375) else: self.assertEquals(getattr(y,"return")[0].varString, "West Virginia") self.assertEquals(getattr(y,"return")[1].varInt, -641) self.assertEquals(getattr(y,"return")[2].varFloat, 1.375) def testArray1(self): x=''' West Virginia -546 -5.398 New Mexico -641 -9.351 Missouri -819 1.375 ''' y = parseSOAPRPC(x) if(config.simplify_objects): self.assertEquals(y["return"][0]['string'], "West Virginia") self.assertEquals(y["return"][1]['int'], -641) self.assertEquals(y["return"][2]['float'], 1.375) else: self.assertEquals(getattr(y,"return")[0].string, "West Virginia") self.assertEquals(getattr(y,"return")[1].int, -641) self.assertEquals(getattr(y,"return")[2].float, 1.375) def testUTF8Encoding1(self): x = ''' Hello \'<&>" ''' y = parseSOAPRPC(x) if config.simplify_objects: self.assertEquals(y['return2'][1], "Hello") else: self.assertEquals(y.return2[1], "Hello") def testUTF8Encoding2(self): x = ''' Hello \'<&>" Goodbye ''' y = parseSOAPRPC(x) self.assertEquals(type(y.a), type([])) self.assertEquals(type(y.b), type('')) self.assertEquals(type(y._getItemAsList('a')), type([])) self.assertEquals(type(y._getItemAsList('b')), type([])) self.assertEquals(y.b, 'Goodbye') self.assertEquals(y.a, ['', 'Hello', '\'<&>"']) self.assertEquals(y._getItemAsList('b'), ['Goodbye']) self.assertEquals(y._getItemAsList('c'), []) self.assertEquals(y._getItemAsList('c', 'hello'), 'hello') def testUTF8Encoding2(self): x = ''' Hello \'<&>" Goodbye ''' y = parseSOAP(x) self.assertEquals(y.a1, 'Hello') self.assertEquals(y.a3, 'Goodbye') self.failIf(hasattr(y, 'a2')) def testUTF8Encoding3(self): x = ''' My Life and Work Henry Ford
mailto:henryford@hotmail.com http://www.henryford.com
''' y = parseSOAPRPC(x) if config.simplify_objects: self.assertEquals(y['Result']['Book']['author']['name'], "Henry Ford") self.assertEquals(y['Result']['Book']['author']['address']['web'], "http://www.henryford.com") self.assertEquals(y['Result']['Book']['author']['address']['pers']['name'], "Henry Ford") else: self.assertEquals(y.Result.Book.author.name, "Henry Ford") self.assertEquals(y.Result.Book.author.address.web, "http://www.henryford.com") self.assertEquals(y.Result.Book.author.address.pers.name, "Henry Ford") # ref example def testRef(self): x = ''' 0 1 -1 3853.33325 ''' y = parseSOAPRPC(x) if config.simplify_objects: self.assertEquals(y['Return'][0], 0) self.assertEquals(y['Return'][1], 1) self.assertEquals(y['Return'][2], -1) self.failUnless(nearlyeq(y['Return'][3], 3853.33325)) else: self.assertEquals(y.Return[0], 0) self.assertEquals(y.Return[1], 1) self.assertEquals(y.Return[2], -1) self.failUnless(nearlyeq(y.Return[3], 3853.33325)) # Make sure passing in our own bodyType works. def testBodyType(self): a = [23, 42] b = bodyType() b.a = b.b = a x = buildSOAP(b) y = parseSOAP(x) self.assertEquals(id(y.a), id(y.b)) self.assertEquals(y.a, a) self.assertEquals(y.b, a) # Test Envelope versioning (see section 4.1.2 of http://www.w3.org/TR/SOAP). def testEnvelopeVersioning(self): xml = ''' <_1 xsi:type="xsd:int" SOAP-ENC:root="1">1 ''' try: parseSOAP(xml) except Exception, e: self.failUnless(isinstance(e, faultType)) self.assertEquals(e.faultcode, '%s:VersionMismatch' % NS.ENV_T) self.failIf(hasattr(e, 'detail')) # Big terrible ordered data with attributes test. def testBigOrderedData(self): data = ''' first_main_item whatever etc. unoItem1 unoItem2 unoItem3 second_main_item whatever etc. dosItem1 dosItem2 dosItem3 single_main_item whatever etc. singleItem1 ''' x = parseSOAP(data) # print ".>",x.replyBlock.itemList._ns y = buildSOAP(x) def testEnvelope1(self): my_xml2 = ''' 5 34.5 10000 ''' (x,h) = parseSOAPRPC(my_xml2,header=1) def testEnvelope2(self): x =''' ''' x = parseSOAPRPC(x) def testEnvelope3(self): x = ''' hello ''' x, a = parseSOAPRPC(x, attrs = 1) if config.simplify_objects: self.assertEquals(a[id(x['Result'])][(None, 'name')], 'fred') else: self.assertEquals(a[id(x.Result)][(None, 'name')], 'fred') def testParseException(self): x=''' SOAP-ENV:Server Exception thrown on Server System.Runtime.Serialization.SerializationException, mscorlib, Version=1.0.2411.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 Soap Parser Error System.Runtime.Serialization.SerializationException: Parse Error, xsd type not valid: Array at System.Runtime.Serialization.Formatters.Soap.SoapHandler.ProcessGetType(String value, String xmlKey) at System.Runtime.Serialization.Formatters.Soap.SoapHandler.ProcessType(ParseRecord pr, ParseRecord objectPr) at System.Runtime.Serialization.Formatters.Soap.SoapHandler.ProcessAttributes(ParseRecord pr, ParseRecord objectPr) at System.Runtime.Serialization.Formatters.Soap.SoapHandler.StartElement(String prefix, String name, String urn) at System.XML.XmlParser.ParseElement() at System.XML.XmlParser.ParseTag() at System.XML.XmlParser.Parse() at System.XML.XmlParser.Parse0() at System.XML.XmlParser.Run() at System.Runtime.Serialization.Formatters.Soap.SoapHandler.Error(IXmlProcessor p, Exception ex) at System.XML.XmlParser.Run() at System.Runtime.Serialization.Formatters.Soap.SoapParser.Run() at System.Runtime.Serialization.Formatters.Soap.ObjectReader.Deserialize(HeaderHandler handler, ISerParser serParser) at System.Runtime.Serialization.Formatters.Soap.SoapFormatter.Deserialize(Stream serializationStream, HeaderHandler handler) at System.Runtime.Remoting.Channels.CoreChannel.DeserializeMessage(String mimeType, Stream xstm, Boolean methodRequest, IMessage msg, Header[] h) at System.Runtime.Remoting.Channels.SoapServerFormatterSink.ProcessMessage(IServerChannelSinkStack sinkStack, ITransportHeaders requestHeaders, Stream requestStream, IMessage& msg, ITransportHeaders& responseHeaders, Stream& responseStream) ''' z = parseSOAPRPC(x) self.assertEquals(z.__class__,faultType) self.assertEquals(z.faultstring, "Exception thrown on Server") def testFlatEnvelope(self): x = ''' ''' z = parseSOAPRPC(x) if config.simplify_objects: self.assertEquals(type(z['Result']), type('')) else: self.assertEquals(type(z.Result), type('')) def testNumericArray(self): x = [1,2,3,4,5] y = buildSOAP(x) z = parseSOAPRPC(y) self.assertEquals(x, z) def testStringArray(self): x = ["cayce", "asd", "buy"] y = buildSOAP(x) z = parseSOAPRPC(y) self.assertEquals(x, z) def testStringArray1(self): x = arrayType(['a', 'b', 'c']) y = buildSOAP(x) z = parseSOAP(y) if config.simplify_objects: self.assertEquals(z.v1._elemsname, 'item') self.assertEquals(z.v1, x) else: self.assertEquals(z['v1']['_elemsname'], 'item') self.assertEquals(z['v1'], x) def testStringArray2(self): x = arrayType(['d', 'e', 'f'], elemsname = 'elementals') y = buildSOAP(x) z = parseSOAP(y) if config.simplify_objects: self.assertEquals(z.v1._elemsname, 'elementals') self.assertEquals(z.v1, x) else: self.assertEquals(z['v1']['_elemsname'], 'elementals') self.assertEquals(z['v1'], x) def testInt1(self): my_xml = ''' 41 ''' s = parseSOAPRPC(my_xml) if config.simplify_objects: self.assertEquals(s['statenum'], 41) self.assertEquals(type(s['statenum']), type(0)) else: self.assertEquals(s.statenum, 41) self.assertEquals(type(s.statenum), type(0)) def testInt2(self): my_xml_ns = ''' 41 ''' s = parseSOAPRPC(my_xml_ns) if config.simplify_objects: self.assertEquals(s['statenum'], 41, "NS one failed") self.assertEquals(type(s['statenum']), type(0)) else: self.assertEquals(s.statenum, 41, "NS one failed") self.assertEquals(type(s.statenum), type(0)) def testPriceAndVolume(self): my_xml2 = ''' 5 34.5 10000 ''' s = parseSOAPRPC(my_xml2) if config.simplify_objects: self.assertEquals(s['PriceAndVolume']['LastTradePrice'].strip(), "34.5") self.assertEquals(s['PriceAndVolume']['DayVolume'].strip(), "10000") else: self.assertEquals(s.PriceAndVolume.LastTradePrice.strip(), "34.5") self.assertEquals(s.PriceAndVolume.DayVolume.strip(), "10000") def testInt3(self): my_xml3 = ''' 18 139 ''' s = parseSOAPRPC(my_xml3) if config.simplify_objects: self.assertEquals(s['param']['lowerBound'], 18) self.assertEquals(s['param']['upperBound'], 139) else: self.assertEquals(s.param.lowerBound, 18) self.assertEquals(s.param.upperBound, 139) def testBoolean(self): my_xml4 = ''' 12 Egypt 0 -31 7 ''' s = parseSOAPRPC(my_xml4) if config.simplify_objects: self.assertEquals(s['param'][0], 12) self.assertEquals(s['param'][1], "Egypt") self.assertEquals(s['param'][2], 0) self.assertEquals(s['param'][3], -31) self.assertEquals(s['param1'], None) self.assertEquals(s['param2'], None) self.assertEquals(s['param3'], 7) else: self.assertEquals(s.param[0], 12) self.assertEquals(s.param[1], "Egypt") self.assertEquals(s.param[2], 0) self.assertEquals(s.param[3], -31) self.assertEquals(s.param1, None) self.assertEquals(s.param2, None) self.assertEquals(s.param3, 7) def testFault(self): my_xml5 = ''' SOAP-ENV:Client Cant call getStateName because there are too many parameters. ''' s = parseSOAPRPC(my_xml5) self.assertEquals(s.__class__, faultType) self.assertEquals(s.faultcode, "SOAP-ENV:Client") def testArray2(self): my_xml6 = ''' 5 3 2 monkey cay hello 5 4 3 2 1 moose 5 ''' q = parseSOAPRPC(my_xml6) self.assertEquals(q[0], 5) self.assertEquals(q[1], 3) self.assertEquals(q[2], 2) self.assertEquals(q[3], 'monkey') self.assertEquals(q[4], 'cay') x = q[5] if config.simplify_objects: self.assertEquals(x['monkey'], 5) self.assertEquals(x['cat'], "hello") self.assertEquals(x['ferret'][0], 5) self.assertEquals(x['ferret'][3], 2) self.assertEquals(x['ferret'][5]['cow'], "moose") else: self.assertEquals(x.monkey, 5) self.assertEquals(x.cat, "hello") self.assertEquals(x.ferret[0], 5) self.assertEquals(x.ferret[3], 2) self.assertEquals(x.ferret[5].cow, "moose") def testArray3(self): x = arrayType([5,4,3,21], "spam") y = buildSOAP(x) z = parseSOAPRPC(y) self.assertEquals(x, z) # test struct def testStruct(self): x = structType(name = "eggs") x.test = 5 y = buildSOAP(x) z = parseSOAPRPC(y) if config.simplify_objects: self.assertEquals( x['test'], z['test'] ) else: self.assertEquals( x.test, z.test ) # test faults def testFault1(self): x = faultType("ServerError","Howdy",[5,4,3,2,1]) y = buildSOAP(x) z = parseSOAPRPC(y) self.assertEquals( x.faultcode , z.faultcode) self.assertEquals( x.faultstring , z.faultstring) self.assertEquals( x.detail , z.detail) # Test the recursion def testRecursion(self): o = one() t = two() o.t = t t.o = o tre = three() tre.o = o tre.t = t x = buildSOAP(tre) y = parseSOAPRPC(x) if config.simplify_objects: self.assertEquals( y['t']['o']['t']['o']['t']['o']['t']['str'] , "two") else: self.assertEquals( y.t.o.t.o.t.o.t.str , "two") # Test the recursion with structs def testRecursionWithStructs(self): o = structType("one") t = structType("two") o.t = t o.str = "one" t.o = o t.str = "two" tre = structType("three") tre.o = o tre.t = t tre.str = "three" x = buildSOAP(tre) y = parseSOAPRPC(x) if config.simplify_objects: self.assertEquals( y['t']['o']['t']['o']['t']['o']['t']['str'] , "two") else: self.assertEquals( y.t.o.t.o.t.o.t.str , "two") def testAmp(self): m = "Test Message & " x = structType("test") x.msg = m y = buildSOAP(x) z = parseSOAPRPC(y) if config.simplify_objects: self.assertEquals( m , z['msg']) else: self.assertEquals( m , z.msg) def testInt4(self): my_xml7 = ''' 18 139 ''' x = parseSOAPRPC(my_xml7) y = buildSOAP(x) # Does buildSOAP require a valid encoding? def testBuildSOAPEncoding(self): try: x = buildSOAP('hello', encoding = 'gleck') except LookupError, e: if str (e)[0:16] != 'unknown encoding': raise x = None except: print "Got unexpected exception: %s %s" % tuple (sys.exc_info ()[0:2]) x = '' self.assertEquals( x , None) # Does SOAPProxy require a valid encoding? def testSOAPProxyEncoding(self): try: x = SOAPProxy('', encoding = 'gleck') except LookupError, e: if str (e)[0:16] != 'unknown encoding': raise x = None except: print "Got unexpected exception: %s %s" % tuple (sys.exc_info ()[0:2]) x = '' self.assertEquals( x , None) # Does SOAPServer require a valid encoding? def testSOAPServerEncoding(self): try: x = SOAPServer(('localhost', 0), encoding = 'gleck') except LookupError, e: if str (e)[0:16] != 'unknown encoding': raise x = None except: print "Got unexpected exception: %s %s" % tuple (sys.exc_info ()[0:2]) x = '' self.assertEquals( x , None) def testEncodings(self): encodings = ('US-ASCII', 'ISO-8859-1', 'UTF-8', 'UTF-16') tests = ('A', u'\u0041') for t in tests: for i in range (len (encodings)): x = buildSOAP (t, encoding = encodings[i]) y = parseSOAPRPC (x) self.assertEquals( y , t) tests = (u'\u00a1',) for t in tests: for i in range (len (encodings)): try: x = buildSOAP (t, encoding = encodings[i]) except: if i > 0: raise continue y = parseSOAPRPC (x) self.assertEquals( y , t) tests = (u'\u01a1', u'\u2342') for t in tests: for i in range (len (encodings)): try: x = buildSOAP (t, encoding = encodings[i]) except: if i > 1: raise continue y = parseSOAPRPC (x) self.assertEquals( y , t) def build_xml(self, schema, type, value, attrs = ''): return ''' <_1 xsi:type="xsd:%(type)s"%(attrs)s>%(value)s ''' % {'schema': schema, 'type': type, 'value': value, 'attrs': attrs} # Make sure the various limits are checked when parsing def testIntegerLimits(self): for t, l in SOAPParser.intlimits.items(): try: parseSOAP(xml % (NS.XSD, t, 'hello')) raise AssertionError, "parsed %s of 'hello' without error" % t except AssertionError: raise except: pass if l[1] != None: try: parseSOAP(self.build_xml(NS.XSD, t, l[1] - 1)) raise AssertionError, "parsed %s of %s without error" % \ (t, l[1] - 1) except AssertionError: raise except UnderflowError: pass if l[2] != None: try: parseSOAP(self.build_xml(NS.XSD, t, l[2] + 1)) raise AssertionError, "parsed %s of %s without error" % \ (t, l[2] + 1) except AssertionError: raise except OverflowError: pass # Make sure the various limits are checked when parsing # Next, floats. Note that chances are good this won't work in any non-Unix Pythons. def testFloatLimits(self): for i in \ ( ('float', '-3.402823466391E+38'), ('float', '3.402823466391E+38'), ('float', '3.5e+38'), ('float', '6.9e-46'), ('double', '-1.7976931348623159E+308'), ('double', '1.7976931348623159E+308'), ('double', '1.8e308'), ('double', '2.4e-324'), ): try: parseSOAP(self.build_xml(NS.XSD, i[0], i[1])) # Hide this error for now, cause it is a bug in python 2.0 and 2.1 #if not (sys.version_info[0] == 2 and sys.version_info[1] <= 2) \ # and i[1]=='1.7976931348623159E+308': raise AssertionError, "parsed %s of %s without error" % i except AssertionError: raise except (UnderflowError, OverflowError): pass # Make sure we can't instantiate the base classes def testCannotInstantiateBaseClasses(self): for t in (anyType, NOTATIONType): try: x = t() raise AssertionError, "instantiated %s directly" % repr(t) except: pass # Try everything that requires initial data without any. def testMustBeInitialized(self): for t in (CDATAType, ENTITIESType, ENTITYType, IDType, IDREFType, IDREFSType, NCNameType, NMTOKENType, NMTOKENSType, NOTATIONType, NameType, QNameType, anyURIType, base64Type, base64BinaryType, binaryType, booleanType, byteType, decimalType, doubleType, durationType, floatType, hexBinaryType, intType, integerType, languageType, longType, negative_IntegerType, negativeIntegerType, non_Negative_IntegerType, non_Positive_IntegerType, nonNegativeIntegerType, nonPositiveIntegerType, normalizedStringType, positive_IntegerType, positiveIntegerType, shortType, stringType, timeDurationType, tokenType, unsignedByteType, unsignedIntType, unsignedLongType, unsignedShortType, untypedType, uriType, uriReferenceType): try: t() raise AssertionError, "instantiated a %s with no value" % t.__name__ except AssertionError: raise except: pass def testInstantiations(self): # string, ENTITY, ID, IDREF, language, Name, NCName, # NMTOKEN, QName, untypedType for t in (stringType, ENTITYType, IDType, IDREFType, languageType, NameType, NCNameType, NMTOKENType, QNameType, untypedType): # First some things that shouldn't be taken as the current type test = (10, (), [], {}) for i in test: try: t(i) raise AssertionError, \ "instantiated a %s with a bad type (%s)" % \ (repr(t), repr(type(i))) except AssertionError: raise except: pass # Now some things that should for i in ('hello', u'goodbye'): x = t(i) d = x._marshalData() if d != i: raise AssertionError, "expected %s, got %s" % (i, d) y = buildSOAP(x) z = parseSOAPRPC(y) if z != i: raise AssertionError, "expected %s, got %s" % (i, z) # ENTITIES, IDREFS, NMTOKENS for t in (ENTITIESType, IDREFSType, NMTOKENSType): # First some things that shouldn't be taken as the current type test = ({}, lambda x: x, ((),), ([],), [{}], [()]) for i in test: try: t(i) raise AssertionError, \ "instantiated a %s with a bad type (%s)" % \ repr(t), repr(type(i)) except AssertionError: raise except: pass # Now some things that should for i in ('hello', (), [], ('hello', 'goodbye'), ['aloha', 'guten_tag']): x = t(i) d = x._marshalData() if type(i) in (type(()), type([])): j = list(i) else: j = [i] k = ' '.join(j) if d != k: raise AssertionError, "expected %s, got %s" % (k, d) y = buildSOAP(x) z = parseSOAPRPC(y) if z != j: raise AssertionError, "expected %s, got %s" % (repr(j), repr(z)) # uri, uriReference, anyURI for t in (uriType, uriReferenceType, anyURIType): # First some things that shouldn't be taken as the current type test = (10, (), [], {}) for i in test: try: t(i) raise AssertionError, \ "instantiated a %s with a bad type (%s)" % \ t.__name__, repr(type(i)) except AssertionError: raise except: pass # Now some things that should for i in ('hello', u'goodbye', '!@#$%^&*()-_=+[{]}\|;:\'",<.>/?`~'): x = t(i) d = x._marshalData() j = urllib.quote(i) if d != j: raise AssertionError, "expected %s, got %s" % (j, d) y = buildSOAP(x) z = parseSOAPRPC(y) if z != i: raise AssertionError, "expected %s, got %s" % (repr(i), repr(z)) # token First some things that shouldn't be valid because of type test = (42, 3.14, (), [], {}) t = tokenType for i in test: try: t(i) raise AssertionError, \ "instantiated a %s with a bad type (%s)" % (t.__name__, repr(i)) except AssertionError: raise except AttributeError: pass # Now some things that shouldn't be valid because of content test = (' hello', 'hello ', 'hel\nlo', 'hel\tlo', 'hel lo', ' \n \t ') for i in test: try: t(i) raise AssertionError, \ "instantiated a %s with a bad value (%s)" % (t.__name__, repr(i)) except AssertionError: raise except ValueError: pass # Now some things that should be valid for i in ('', 'hello', u'hello'): x = t(i) d = x._marshalData() if d != i: raise AssertionError, "expected %s, got %s" % (i, d) y = buildSOAP(x) z = parseSOAPRPC(y) if z != i and i != '': raise AssertionError, "expected %s, got %s" % (repr(i), repr(z)) #### CDATA, normalizedString for t in (CDATAType, normalizedStringType): # First some things that shouldn't be valid because of type test = (42, 3.14, (), [], {}) for i in test: try: t(i) raise AssertionError, \ "instantiated a %s with a bad type (%s)" % \ (t.__name__, repr(i)) except AssertionError: raise except AttributeError: pass # Now some things that shouldn't be valid because of content test = ('hel\nlo', 'hel\rlo', 'hel\tlo', '\n\r\t') for i in test: try: t(i) raise AssertionError, \ "instantiated a %s with a bad value (%s)" % \ (t.__name__, repr(i)) except AssertionError: raise except ValueError: pass # Now some things that should be valid for i in ('', 'hello', u'hello', 'hel lo'): x = t(i) d = x._marshalData() if d != i: raise AssertionError, "expected %s, got %s" % (i, d) y = buildSOAP(x) z = parseSOAPRPC(y) if z != i and i != '': raise AssertionError, "expected %s, got %s" % (repr(i), repr(z)) #### boolean # First some things that shouldn't be valid test = (10, 'hello', (), [], {}) t = booleanType for i in test: try: t(i) raise AssertionError, \ "instantiated a %s with a bad value (%s)" % (t.__name__, repr(i)) except AssertionError: raise except: pass # Now some things that should for i in ((0, 'false'), ('false', 'false'), (1, 'true'), ('true', 'true'), (0.0, 'false'), (1.0, 'true')): x = t(i[0]) d = x._marshalData() if d != i[1]: raise AssertionError, "%s: expected %s, got %s" % (i[0], i[1], d) y = buildSOAP(x) z = parseSOAPRPC(y) j = ('false', 'true')[z] if j != i[1]: raise AssertionError, "%s: expected %s, got %s" % \ (i[0], repr(i[1]), repr(j)) # Now test parsing, both valid and invalid test = (('10', None), ('hello', None), ('false', 0), ('FALSE', 0), (ws + 'false' + ws, 0), (ws + '0' + ws, 0), ('0', 0), ('true', 1), ('TRUE', 1), ('1', 1), (ws + 'true' + ws, 1), (ws + '1' + ws, 1)) for i in test: try: z = parseSOAPRPC(self.build_xml(t._validURIs[0], t.__name__[:-4], i[0])) if z != i[1]: raise AssertionError, "%s: expected %s, got %s" % \ (i[0], i[1], repr(z)) except AssertionError: raise except: if i[1] != None: raise AssertionError, \ "parsing %s as %s threw exception %s:%s" % \ (i[0], t.__name__, sys.exc_info()[0], sys.exc_info()[1]) # Can we give it a name and no type? #print x = t(1, name = 'George', typed = 0) #print "x=",x y = buildSOAP(x) #print "y=",y z = parseSOAP(y) #print "z=",z test = 'true' if z.George != test: raise AssertionError, "expected %s, got %s" % (repr(test), repr(z)) # How about some attributes, set in various and sundry manners? x = t(1, attrs = {'nonamespaceURI': 1}) x._setAttrs({(None, 'NonenamespaceURI'): 2, ('http://some/namespace', 'namespaceURIattr1'): 3}) x._setAttr(('http://some/other/namespace', 'namespaceURIattr2'), 4) self.assertEquals( x._getAttr('nonamespaceURI') , 1) self.assertEquals( x._getAttr('NonenamespaceURI') , 2) self.assertEquals( x._getAttr(('http://some/namespace', 'namespaceURIattr1')) , 3) self.assertEquals( x._getAttr(('http://some/other/namespace', 'namespaceURIattr2')) , 4) self.assertEquals( x._getAttr('non-extant attr') , None) y = buildSOAP(x) z = parseSOAPRPC(y) self.assertEquals( z , 1) #### decimal # First some things that shouldn't be valid test = ('hello', (), [], {}) t = decimalType for i in test: try: t(i) raise AssertionError, \ "instantiated a %s with a bad type (%s)" % \ (t.__name__, repr(type(i))) except AssertionError: raise except: pass # Now some things that should for i in (10, 3.14, 23L): x = t(i) d = x._marshalData() if d != str(i): raise AssertionError, "expected %f, got %s" % (i, d) y = buildSOAP(x) z = parseSOAPRPC(y) if z != i: raise AssertionError, "expected %s, got %s" % (repr(i), repr(z)) # Now test parsing, both valid and invalid test = (('hello', None), ('1.2.3', None), ('10', 10), ('10.', 10), ('.1', .1), ('.1000000', .1), (ws + '10.4' + ws, 10.4)) for i in test: try: z = parseSOAPRPC(self.build_xml(t._validURIs[0], t.__name__[:-4], i[0])) if z != i[1]: raise AssertionError, "%s: expected %s, got %s" % \ (i[0], i[1], repr(z)) except AssertionError: raise except: if i[1] != None: raise AssertionError, \ "parsing %s as %s threw exception %s:%s" % \ (i[0], t.__name__, sys.exc_info()[0], sys.exc_info()[1]) #### float # First some things that shouldn't be valid test = ('hello', (), [], {}, -3.402823466391E+38, 3.402823466391E+38) t = floatType for i in test: try: t(i) raise AssertionError, \ "instantiated a %s with a bad value (%s)" % \ (t.__name__, repr(i)) except AssertionError: raise except ValueError: pass # Now some things that should for i in (10, 3.14, 23L, -3.4028234663852886E+38, 3.4028234663852886E+38): x = t(i) d = x._marshalData() if not nearlyeq(float(d), i): raise AssertionError, "expected %f, got %s" % (i, d) y = buildSOAP(x) z = parseSOAPRPC(y) if not nearlyeq(z, i): raise AssertionError, "expected %s, got %s" % (repr(i), repr(z)) # Now test parsing, both valid and invalid test = (('hello', None), ('1.2.3', None), ('10', 10), ('10.', 10), ('.1', .1), ('.1000000', .1), (ws + '10.4' + ws, 10.4), ('-3.402823466391E+38', None), ('3.402823466391E+38', None), ('-3.4028234663852886E+38', -3.4028234663852886E+38), ('3.4028234663852886E+38', 3.4028234663852886E+38)) for i in test: try: z = parseSOAPRPC(self.build_xml(t._validURIs[0], t.__name__[:-4], i[0])) if abs(z - i[1]) > 1e-6: raise AssertionError, "%s: expected %s, got %s" % \ (i[0], i[1], repr(z)) except AssertionError: raise except: if i[1] != None: raise AssertionError, \ "parsing %s as %s threw exception %s:%s" % \ (i[0], t.__name__, sys.exc_info()[0], sys.exc_info()[1]) #### double # First some things that shouldn't be valid test = ('hello', (), [], {}, -1.7976931348623159E+308, 1.7976931348623159E+308) t = doubleType for i in test: try: t(i) # Hide this error for now, cause it is a bug in python 2.0 and 2.1 if not (sys.version_info[0] == 2 and sys.version_info[1] <= 2 and i==1.7976931348623159E+308): raise AssertionError, \ "instantiated a double with a bad value (%s)" % repr(i) except AssertionError: raise except ValueError: pass # Now some things that should for i in (10, 3.14, 23L, -1.79769313486E+308, 1.79769313486E+308): x = t(i) d = x._marshalData() if not nearlyeq(float(d), i): raise AssertionError, "expected %s, got %s" % (i, str(x)) y = buildSOAP(x) z = parseSOAPRPC(y) if not nearlyeq(z, i): raise AssertionError, "expected %s, got %s" % (repr(i), repr(z)) # Now test parsing, both valid and invalid test = (('hello', None), ('1.2.3', None), ('10', 10), ('10.', 10), ('.1', .1), ('.1000000', .1), (ws + '10.4' + ws, 10.4), ('-1.7976931348623159E+308', None), ('1.7976931348623158E+308', None), ('-1.79769313486E+308', -1.79769313486E+308), ('1.79769313486E+308', 1.79769313486E+308)) for i in test: try: z = parseSOAPRPC(self.build_xml(t._validURIs[0], t.__name__[:-4], i[0])) if abs(z - i[1]) > 1e-6: raise AssertionError, "%s: expected %s, got %s" % \ (i[0], i[1], repr(z)) except AssertionError: raise except: if i[1] != None: raise AssertionError, \ "parsing %s as %s threw exception %s:%s" % \ (i[0], t.__name__, sys.exc_info()[0], sys.exc_info()[1]) #### hexBinary x = '' for i in range(256): x += chr(i) test = ('', x, 'hello') t = hexBinaryType l = [] for i in test: l.append(hexBinaryType(i)) x = buildSOAP(l) y = parseSOAPRPC(x) for i in range(len(test)): if test[i] != y[i]: raise AssertionError, "@ %d expected '%s', got '%s'" % \ (i, test[i], y[i]) # Now test parsing, both valid and invalid test = (('hello', None), ('6163 747A65726F', None), ('6163747A65726', None), ('6163747A65726F', 'actzero'), (ws + '6163747A65726F' + ws, 'actzero')) for i in test: try: z = parseSOAPRPC(self.build_xml(t._validURIs[0], t.__name__[:-4], i[0])) if z != i[1]: raise AssertionError, "%s: expected %s, got %s" % \ (i[0], i[1], repr(z)) except AssertionError: raise except: if i[1] != None: raise AssertionError, \ "parsing %s as %s threw exception %s:%s" % \ (i[0], t.__name__, sys.exc_info()[0], sys.exc_info()[1]) #### base64Binary and base64 s = '' for i in range(256): s += chr(i) for t in (base64BinaryType, base64Type): # First some things that shouldn't be valid test = ((), [], {}, lambda x: x) for i in test: try: t(i) raise AssertionError, \ "instantiated a %s with a bad value (%s)" % \ (t.__name__, repr(i)) except AssertionError: raise except AttributeError: pass # Now some things that should test = ('', s, u'hello') l = [] for i in test: l.append(t(i)) x = buildSOAP(l) y = parseSOAPRPC(x) for i in range(len(test)): if test[i] != y[i]: raise AssertionError, "@ %d expected '%s', got '%s'" % \ (i, test[i], y[i]) # Now test parsing, both valid and invalid test = (('hello', None), ('YWN0emVybw=', None), ('YWN 0emVybw==', 'actzero'), ('YWN0emVybw==', 'actzero'), (ws + 'YWN0emVybw==' + ws, 'actzero')) for i in test: try: z = parseSOAPRPC(self.build_xml(t._validURIs[0], t.__name__[:-4], i[0])) if z != i[1]: raise AssertionError, "%s: expected %s, got %s" % \ (i[0], i[1], repr(z)) except AssertionError: raise except: if i[1] != None: raise AssertionError, \ "parsing %s as %s threw exception %s:%s" % \ (i[0], t.__name__, sys.exc_info()[0], sys.exc_info()[1]) #### binary (uses s from above) # First some check invalid encodings try: x = binaryType('hello', encoding = 'yellow') raise AssertionError, "created binary with invalid encoding" except AssertionError: raise except: pass for t in ('hex', 'base64'): # First some things that shouldn't be valid test = ((), [], {}, lambda x: x) for i in test: try: binaryType(i, encoding = t) raise AssertionError, \ "instantiated a %s binary with a bad value (%s)" % \ (e, repr(i)) except AssertionError: raise except AttributeError: pass # Now some things that should test = ('', s, u'hello') l = [] for i in test: l.append(binaryType(i, encoding = t)) x = buildSOAP(l) y = parseSOAPRPC(x) for i in range(len(test)): if test[i] != y[i]: raise AssertionError, "@ %d expected '%s', got '%s'" % \ (i, test[i], y[i]) # Now test parsing, both valid and invalid if t == 'hex': test = (('hello', None), ('6163 747A65726F', None), ('6163747A65726', None), ('6163747A65726F', 'actzero'), (ws + '6163747A65726F' + ws, 'actzero')) else: test = (('hello', None), ('YWN0emVybw=', None), ('YWN 0emVybw==', 'actzero'), ('YWN0emVybw==', 'actzero'), (ws + 'YWN0emVybw==' + ws, 'actzero')) for i in test: try: z = parseSOAPRPC(self.build_xml(NS.XSD, 'binary', i[0], ' encoding="%s"' % t)) if z != i[1]: raise AssertionError, "%s: expected %s, got %s" % \ (i[0], i[1], repr(z)) except AssertionError: raise except: if i[1] != None: raise AssertionError, \ "parsing %s as %s threw exception %s:%s" % \ (i[0], t, sys.exc_info()[0], sys.exc_info()[1]) # Finally try an Array of binaries (with references!) test = ('', s, u'hello') l = [] for i in test: l.append(binaryType(i, encoding = t)) l.append(l[1]) x = buildSOAP(l) y = parseSOAPRPC(x) for i in range(len(test)): if test[i] != y[i]: raise AssertionError, "@ %d expected '%s', got '%s'" % \ (i, test[i], y[i]) # Make sure the references worked self.assertEquals( id(y[1]) , id(y[3])) def badTest(self, t, data): for i in data: try: t(i) raise AssertionError, \ "instantiated a %s with a bad value (%s)" % \ (t.__name__, repr(i)) except AssertionError: raise except: pass def goodTest(self, t, data): for i in data: x = t(i[0]) d = x._marshalData() if d != i[1]: raise AssertionError, "%s(%s): expected %s, got %s" % \ (t.__name__, repr(i[0]), i[1], d) y = buildSOAP(x) z = parseSOAPRPC(y) if z != i[2]: raise AssertionError, "%s(%s): expected %s, got %s" % \ (t.__name__, repr(i[0]), repr(i[2]), repr(z)) def parseTest(self, t, data): for i in data: try: z = parseSOAPRPC(self.build_xml(t._validURIs[0], t.__name__[:-4], i[0])) if z != i[1]: raise AssertionError, "%s(%s): expected %s, got %s" % \ (t.__name__, repr(i[0]), i[1], repr(z)) except AssertionError: raise except: if i[1] != N: raise AssertionError, \ "parsing %s as %s threw exception %s:%s" % \ (i[0], t.__name__, sys.exc_info()[0], sys.exc_info()[1]) def allTests(self, t, baddata, gooddata, parsedata): self.badTest(t, baddata) self.goodTest(t, gooddata) self.parseTest(t, parsedata) # duration and timeDuration def testTimeDuration(self): baddata = \ ( 'hello', ('hello',), (-10, -10), (-10, 0, -10), (10.5, 10.5), (0, 10.5, 0, 10.5, 0), (1, 2, 3, 4, 5, 6, 7), (1, 2, 'hello', 4, 5, 6), (1, 2, 3.5, 4, 5, 6), ) gooddata = \ ( (0, 'PT0S', (N, N, N, N, N, 0.0,)), ((), 'PT0S', (N, N, N, N, N, 0.0,)), ([], 'PT0S', (N, N, N, N, N, 0.0,)), ((0.5,), 'PT0.5S', (N, N, N, N, N, 0.5,)), (10L, 'PT10S', (N, N, N, N, N, 10.0,)), (-10, '-PT10S', (N, N, N, N, N, -10.0,)), (10.5, 'PT10.5S', (N, N, N, N, N, 10.5,)), ((10L, 20), 'PT10M20S', (N, N, N, N, 10, 20.0)), ((-10, 20), '-PT10M20S', (N, N, N, N, -10, 20.0)), ((10, 0), 'PT10M', (N, N, N, N, 10, N)), ((10, 0, 0), 'PT10H', (N, N, N, 10, N, N)), ((10, 0L, 0, 0), 'P10D', (N, N, 10, N, N, N)), ((10, 0, 0, 0, 0), 'P10M', (N, 10, N, N, N, N)), ((10, 0, 0, 0L, 0, 0), 'P10Y', (10, N, N, N, N, N)), ((-10, 0, 0, 0, 0, 0), '-P10Y', (-10, N, N, N, N, N)), ((10, 0, 0, 0, 0, 20L), 'P10YT20S', (10, N, N, N, N, 20.0,)), ((1, 2, 3, 4, 5, 6.75), 'P1Y2M3DT4H5M6.75S', (1, 2, 3, 4, 5, 6.75)), ((-1, 2, 3, 4, 5, 6.75), '-P1Y2M3DT4H5M6.75S', (-1, 2, 3, 4, 5, 6.75)), ((1, 2, 3, 10, 30, 0), 'P1Y2M3DT10H30M', (1, 2, 3, 10, 30, N)), ((1e6, 2e6, 3e6, 4e6, 5e6, 6.7e6), 'P1000000Y2000000M3000000DT4000000H5000000M6700000S', (1e6, 2e6, 3e6, 4e6, 5e6, 6.7e6)), ((1347, 0, N, 0, 0), 'P1347M', (N, 1347, N, N, N, N)), ((-1347, 0, 0, 0, N), '-P1347M', (N, -1347, N, N, N, N)), ((1e15, 0, 0, 0, 0), 'P1000000000000000M', (N, 1000000000000000L, N, N, N, N)), ((-1e15, 0, 0, 0, 0), '-P1000000000000000M', (N, -1000000000000000L, N, N, N, N)), ((1000000000000000L, 0, 0, 0, 0), 'P1000000000000000M', (N, 1000000000000000L, N, N, N, N)), ((-1000000000000000L, 0, 0, 0, 0), '-P1000000000000000M', (N, -1000000000000000L, N, N, N, N)), ) parsedata = ( ('hello', N), ('P T0S', N), ('P10.5Y10.5M', N), ('P1Y2MT', N), ('PT0S', (N, N, N, N, N, 0,)), ('P10Y', (10, N, N, N, N, N)), (ws + 'P10M' + ws, (N, 10, N, N, N, N)), ('P0Y1347M', (0, 1347, N, N, N, N)), ('P0Y1347M0D', (0, 1347, 0, N, N, N)), ('P0MT0M', (N, 0, N, N, 0, N)), ) for t in (durationType, timeDurationType): self.allTests(t, baddata, gooddata, parsedata) # dateTime, timeInstant, and timePeriod def testTimePeriod(self): baddata = \ ( 'hello', ('hello',), (1, 2, 3, 4, 5), (1, 2, 3, 4, 5, 6, 7, 8, 9, 10), (1, 2, 3, 4, 5, 'hello'), (1, 2.5, 3, 4, 5, 6), (1, 0, 3, 4, 5, 6), (1, 13, 3, 4, 5, 6), (1, 1, 0, 4, 5, 6), (1, 1, 32, 4, 5, 6), (1, 2, 29, 4, 5, 6), (0, 2, 30, 4, 5, 6), (100, 2, 29, 4, 5, 6), (1, 2, 3, -1, 5, 6), (1, 2, 3, 24, 5, 6), (1, 2, 3, 4, -1, 6), (1, 2, 3, 4, 60, 6), (1, 2, 3, 4, 5, -1), (1, 2, 3, 4, 5, 61), (1, 3, 32, 4, 5, 6), (1, 4, 31, 4, 5, 6), (1, 5, 32, 4, 5, 6), (1, 6, 31, 4, 5, 6), (1, 7, 32, 4, 5, 6), (1, 8, 32, 4, 5, 6), (1, 9, 31, 4, 5, 6), (1, 10, 32, 4, 5, 6), (1, 11, 31, 4, 5, 6), (1, 12, 32, 4, 5, 6), ) gooddata = \ ( (1L, '1970-01-01T00:00:01Z', (1970, 1, 1, 0, 0, 1.0)), (1.5, '1970-01-01T00:00:01.5Z', (1970, 1, 1, 0, 0, 1.5)), ((-1, 2, 3, 4, 5, 6), '-0001-02-03T04:05:06Z', (-1, 2, 3, 4, 5, 6.0)), ((1, 2, 3, 4, 5, 6), '0001-02-03T04:05:06Z', (1, 2, 3, 4, 5, 6.0)), ((10, 2, 3, 4, 5, 6), '0010-02-03T04:05:06Z', (10, 2, 3, 4, 5, 6.0)), ((100, 2, 3, 4, 5, 6), '0100-02-03T04:05:06Z', (100, 2, 3, 4, 5, 6.0)), ((1970, 2, 3, 4, 5, 6), '1970-02-03T04:05:06Z', (1970, 2, 3, 4, 5, 6.0)), ((-1970, 2, 3, 4, 5, 6), '-1970-02-03T04:05:06Z', (-1970, 2, 3, 4, 5, 6.0)), ((1970L, 2.0, 3.0, 4L, 5L, 6.875), '1970-02-03T04:05:06.875Z', (1970, 2, 3, 4, 5, 6.875)), ((11990, 1, 2, 3, 4L, 5.25, 0, 0, 0), '11990-01-02T03:04:05.25Z', (11990, 1, 2, 3, 4, 5.25)), ((1e15, 1, 2, 3, 4L, 5.25, 0, 0, 0), '1000000000000000-01-02T03:04:05.25Z', (1e15, 1, 2, 3, 4, 5.25)), ((-1e15, 1, 2, 3, 4L, 5.25, 0, 0, 0), '-1000000000000000-01-02T03:04:05.25Z', (-1e15, 1, 2, 3, 4, 5.25)), ((1000000000000000L, 1, 2, 3, 4L, 5.25, 0, 0, 0), '1000000000000000-01-02T03:04:05.25Z', (1e15, 1, 2, 3, 4, 5.25)), ((-1000000000000000L, 1, 2, 3, 4L, 5.25, 0, 0, 0), '-1000000000000000-01-02T03:04:05.25Z', (-1e15, 1, 2, 3, 4, 5.25)), ) parsedata = \ ( # Some strings that won't match the r.e. ('hello', N), ('1970 -01 -01T00:00:01Z', N), ('0001-02-03t07:08:23Z', N), # Invalid ranges ('2001-00-03T07:08:23Z', N), ('2001-13-03T07:08:23Z', N), ('2001-02-00T07:08:23Z', N), ('2001-02-29T07:08:23Z', N), ('2000-02-30T07:08:23Z', N), ('1900-02-29T07:08:23Z', N), ('2001-02-03T24:08:23Z', N), ('2001-02-03T04:60:23Z', N), ('2001-02-03T04:05:61Z', N), ('2001-01-32T04:05:06Z', N), ('2001-03-32T04:05:06Z', N), ('2001-04-31T04:05:06Z', N), ('2001-05-32T04:05:06Z', N), ('2001-06-31T04:05:06Z', N), ('2001-07-32T04:05:06Z', N), ('2001-08-32T04:05:06Z', N), ('2001-09-31T04:05:06Z', N), ('2001-10-32T04:05:06Z', N), ('2001-11-31T04:05:06Z', N), ('2001-12-32T04:05:06Z', N), # Whitespace (ws + '1970-01-01T00:00:00Z' + ws, (1970, 1, 1, 0, 0, 0)), # No timezones ('11971-02-03T04:05:06.125', (11971, 2, 3, 4, 5, 6.125)), ('1971-02-03T04:05:06.125', (1971, 2, 3, 4, 5, 6.125)), ('-1971-02-03T04:05:06.125', (-1971, 2, 3, 4, 5, 6.125)), # Non-zulu ('11971-02-03T04:05:06.125-07:08', (11971, 2, 3, 11, 13, 6.125)), ('11971-02-03T04:05:06.125+07:08', (11971, 2, 2, 20, 57, 6.125)), ('-11971-02-03T04:05:06.125-07:08', (-11971, 2, 3, 11, 13, 6.125)), ('-11971-02-03T04:05:06.125+07:08', (-11971, 2, 2, 20, 57, 6.125)), ('1971-02-03T04:05:06.125-07:08', (1971, 2, 3, 11, 13, 6.125)), ('1971-02-03T04:05:06.125+07:08', (1971, 2, 2, 20, 57, 6.125)), ('-1971-02-03T04:05:06.125-07:08', (-1971, 2, 3, 11, 13, 6.125)), ('-1971-02-03T04:05:06.125+07:08', (-1971, 2, 2, 20, 57, 6.125)), # Edgepoints (ranges) ('2001-01-03T07:08:09Z', (2001, 1, 3, 7, 8, 9)), ('2001-12-03T07:08:09Z', (2001, 12, 3, 7, 8, 9)), ('2001-02-01T07:08:09Z', (2001, 2, 1, 7, 8, 9)), ('2001-02-28T07:08:09Z', (2001, 2, 28, 7, 8, 9)), ('2000-02-29T07:08:09Z', (2000, 2, 29, 7, 8, 9)), ('1900-02-28T07:08:09Z', (1900, 2, 28, 7, 8, 9)), ('2001-02-03T00:08:09Z', (2001, 2, 3, 0, 8, 9)), ('2001-02-03T23:08:09Z', (2001, 2, 3, 23, 8, 9)), ('2001-02-03T04:00:09Z', (2001, 2, 3, 4, 0, 9)), ('2001-02-03T04:59:09Z', (2001, 2, 3, 4, 59, 9)), ('2001-02-03T04:05:00Z', (2001, 2, 3, 4, 5, 0)), ('2001-02-03T04:05:60.9Z', (2001, 2, 3, 4, 5, 60.9)), ('2001-01-31T04:05:06Z', (2001, 1, 31, 4, 5, 6)), ('2001-03-31T04:05:06Z', (2001, 3, 31, 4, 5, 6)), ('2001-04-30T04:05:06Z', (2001, 4, 30, 4, 5, 6)), ('2001-05-31T04:05:06Z', (2001, 5, 31, 4, 5, 6)), ('2001-06-30T04:05:06Z', (2001, 6, 30, 4, 5, 6)), ('2001-07-31T04:05:06Z', (2001, 7, 31, 4, 5, 6)), ('2001-08-31T04:05:06Z', (2001, 8, 31, 4, 5, 6)), ('2001-09-30T04:05:06Z', (2001, 9, 30, 4, 5, 6)), ('2001-10-31T04:05:06Z', (2001, 10, 31, 4, 5, 6)), ('2001-11-30T04:05:06Z', (2001, 11, 30, 4, 5, 6)), ('2001-12-31T04:05:06Z', (2001, 12, 31, 4, 5, 6)), # Edgepoints (crossing boundaries) ('0001-01-01T07:08:23+07:08', (1, 1, 1, 0, 0, 23)), ('0001-01-01T07:07:42+07:08', (0, 12, 31, 23, 59, 42)), ('-0004-01-01T07:07:42+07:08', (-5, 12, 31, 23, 59, 42)), ('2001-03-01T07:07:42+07:08', (2001, 2, 28, 23, 59, 42)), ('2000-03-01T07:07:42+07:08', (2000, 2, 29, 23, 59, 42)), ('1900-03-01T07:07:42+07:08', (1900, 2, 28, 23, 59, 42)), ) for t in (dateTimeType, timeInstantType, timePeriodType): self.allTests(t, baddata, gooddata, parsedata) # recurringInstant def testRecurringInstant(self): baddata = \ ( 'hello', ('hello',), (1, 2, N, 3, 4, 5), (1, 2, 3, 4, 5, 6, 7, 8, 9, 10), (1, 2, 3, 4, 5, 'hello'), (1, 2, 3.5, 4, 5, 6), ) gooddata = \ ( (1L, '1970-01-01T00:00:01Z', (1970, 1, 1, 0, 0, 1.0)), (1.5, '1970-01-01T00:00:01.5Z', (1970, 1, 1, 0, 0, 1.5)), (1e9, '2001-09-09T01:46:40Z', (2001, 9, 9, 1, 46, 40.0)), ((1, 1, 2, 3, 4, 5), '-01-01-02T03:04:05Z', (1, 1, 2, 3, 4, 5)), ((-1, 1, 2, 3, 4, 5), '--01-01-02T03:04:05Z', (-1, 1, 2, 3, 4, 5)), ((10, 1, 2, 3, 4, 5), '-10-01-02T03:04:05Z', (10, 1, 2, 3, 4, 5)), ((-10, 1, 2, 3, 4, 5), '--10-01-02T03:04:05Z', (-10, 1, 2, 3, 4, 5)), ((100, 1, 2, 3, 4, 5), '0100-01-02T03:04:05Z', (100, 1, 2, 3, 4, 5)), ((-100, 1, 2, 3, 4, 5), '-0100-01-02T03:04:05Z', (-100, 1, 2, 3, 4, 5)), ((1970L, 1, 2, 3, 4, 5), '1970-01-02T03:04:05Z', (1970, 1, 2, 3, 4, 5)), ((1970L, 1, 2L, 3, 4.0, 5.25), '1970-01-02T03:04:05.25Z', (1970, 1, 2, 3, 4, 5.25)), ((11990, 1, 2, 3L, 4, 5.25), '11990-01-02T03:04:05.25Z', (11990, 1, 2, 3, 4, 5.25)), ((1e15, 1, 2, 3L, 4, 5.25), '1000000000000000-01-02T03:04:05.25Z', (1e15, 1, 2, 3, 4, 5.25)), ((-1e15, 1, 2, 3L, 4, 5.25), '-1000000000000000-01-02T03:04:05.25Z', (-1e15, 1, 2, 3, 4, 5.25)), ((N, 1, 2, 3, 4L, 5.25), '---01-02T03:04:05.25Z', (N, 1, 2, 3, 4, 5.25)), ((N, N, 2, 3, 4, 5.25, 0, 0, 0), '-----02T03:04:05.25Z', (N, N, 2, 3, 4, 5.25)), ((N, N, -2, 3, 4, 5.25, 0, 0, 0), '------02T03:04:05.25Z', (N, N, -2, 3, 4, 5.25)), ((N, N, N, 3, 4, 5.25), '------T03:04:05.25Z', (N, N, N, 3, 4, 5.25)), ((N, N, N, N, 4, 5.25, 0, 0, 0), '------T-:04:05.25Z', (N, N, N, N, 4, 5.25)), ((N, N, N, N, N, 5.25), '------T-:-:05.25Z', (N, N, N, N, N, 5.25)), ((N, N, N, N, N, -5.25), '-------T-:-:05.25Z', (N, N, N, N, N, -5.25)), ((N, N, N, N, N, N, 0, 0, 0), '------T-:-:-Z', (N, N, N, N, N, N)), ((N, N, N, N, N, N, N), '------T-:-:-Z', (N, N, N, N, N, N)), ((N, N, N, N, N, N, N, N), '------T-:-:-Z', (N, N, N, N, N, N)), ((N, N, N, N, N, N, N, N, N), '------T-:-:-Z', (N, N, N, N, N, N)), ) parsedata = \ ( # Some strings that won't match the r.e. ('hello', N), ('1970 -01 -01T00:00:01Z', N), ('0001-01-01t07:08:23+07:08', N), # Invalid ranges ('2001-00-03T07:08:23Z', N), ('2001-13-03T07:08:23Z', N), ('2001-02-00T07:08:23Z', N), ('2001-02-29T07:08:23Z', N), ('2000-02-30T07:08:23Z', N), ('1900-02-29T07:08:23Z', N), ('2001-02-03T24:08:23Z', N), ('2001-02-03T04:60:23Z', N), ('2001-02-03T04:05:61Z', N), ('2001-01-32T04:05:06Z', N), ('2001-03-32T04:05:06Z', N), ('2001-04-31T04:05:06Z', N), ('2001-05-32T04:05:06Z', N), ('2001-06-31T04:05:06Z', N), ('2001-07-32T04:05:06Z', N), ('2001-08-32T04:05:06Z', N), ('2001-09-31T04:05:06Z', N), ('2001-10-32T04:05:06Z', N), ('2001-11-31T04:05:06Z', N), ('2001-12-32T04:05:06Z', N), # Whitespace (ws + '1970-01-01T00:00:01Z' + ws, (1970, 1, 1, 0, 0, 1)), # No timezones ('11971-02-03T04:05:06.125', (11971, 2, 3, 4, 5, 6.125)), ('-11971-02-03T04:05:06.125', (-11971, 2, 3, 4, 5, 6.125)), ('1971-02-03T04:05:06.125', (1971, 2, 3, 4, 5, 6.125)), ('-1971-02-03T04:05:06.125', (-1971, 2, 3, 4, 5, 6.125)), ('-71-02-03T04:05:06.125', (71, 2, 3, 4, 5, 6.125)), ('--71-02-03T04:05:06.125', (-71, 2, 3, 4, 5, 6.125)), ('---02-03T04:05:06.125', (N, 2, 3, 4, 5, 6.125)), ('----02-03T04:05:06.125', (N, -2, 3, 4, 5, 6.125)), ('-----03T04:05:06.125', (N, N, 3, 4, 5, 6.125)), ('------03T04:05:06.125', (N, N, -3, 4, 5, 6.125)), ('------T04:05:06.125', (N, N, N, 4, 5, 6.125)), ('-------T04:05:06.125', (N, N, N, -4, 5, 6.125)), ('------T-:05:06.125', (N, N, N, N, 5, 6.125)), ('-------T-:05:06.125', (N, N, N, N, -5, 6.125)), ('------T-:-:06.125', (N, N, N, N, N, 6.125)), ('-------T-:-:06.125', (N, N, N, N, N, -6.125)), ('------T-:-:-', (N, N, N, N, N, N)), ('-------T-:-:-', (N, N, N, N, N, N)), # Non-zulu ('11971-02-03T04:05:06.125-07:08', (11971, 2, 3, 11, 13, 6.125)), ('11971-02-03T04:05:06.125+07:08', (11971, 2, 2, 20, 57, 6.125)), ('-11971-02-03T04:05:06.125-07:08', (-11971, 2, 3, 11, 13, 6.125)), ('-11971-02-03T04:05:06.125+07:08', (-11971, 2, 2, 20, 57, 6.125)), ('1971-02-03T04:05:06.125-07:08', (1971, 2, 3, 11, 13, 6.125)), ('1971-02-03T04:05:06.125+07:08', (1971, 2, 2, 20, 57, 6.125)), ('-1971-02-03T04:05:06.125-07:08', (-1971, 2, 3, 11, 13, 6.125)), ('-1971-02-03T04:05:06.125+07:08', (-1971, 2, 2, 20, 57, 6.125)), ('-71-02-03T04:05:06.125-07:08', (71, 2, 3, 11, 13, 6.125)), ('-71-02-03T04:05:06.125+07:08', (71, 2, 2, 20, 57, 6.125)), ('--71-02-03T04:05:06.125-07:08', (-71, 2, 3, 11, 13, 6.125)), ('--71-02-03T04:05:06.125+07:08', (-71, 2, 2, 20, 57, 6.125)), ('---02-03T04:05:06.125-07:08', (N, 2, 3, 11, 13, 6.125)), ('---02-03T04:05:06.125+07:08', (N, 2, 2, 20, 57, 6.125)), ('----02-03T04:05:06.125-07:08', (N, -2, 3, 11, 13, 6.125)), ('----02-03T04:05:06.125+07:08', (N, -2, 2, 20, 57, 6.125)), ('-----03T04:05:06.125-07:08', (N, N, 3, 11, 13, 6.125)), ('-----03T04:05:06.125+07:08', (N, N, 2, 20, 57, 6.125)), ('------03T04:05:06.125-07:08', (N, N, -3, 11, 13, 6.125)), ('------03T04:05:06.125+07:08', (N, N, -4, 20, 57, 6.125)), ('------T04:05:06.125-07:08', (N, N, N, 11, 13, 6.125)), ('------T04:05:06.125+07:08', (N, N, N, -4, 57, 6.125)), ('-------T04:05:06.125-07:08', (N, N, N, 3, 13, 6.125)), ('-------T04:05:06.125+07:08', (N, N, N, -12, 57, 6.125)), ('------T-:05:06.125-07:08', (N, N, N, N, 433, 6.125)), ('------T-:05:06.125+07:08', (N, N, N, N, -423, 6.125)), ('-------T-:05:06.125-07:08', (N, N, N, N, 423, 6.125)), ('-------T-:05:06.125+07:08', (N, N, N, N, -433, 6.125)), ('------T-:-:06.125-07:08', (N, N, N, N, 428, 6.125)), ('------T-:-:06.125+07:08', (N, N, N, N, -428, 6.125)), ('-------T-:-:06.125-07:08', (N, N, N, N, 427, 53.875)), ('-------T-:-:06.125+07:08', (N, N, N, N, -429, 53.875)), ('------T-:-:--07:08', (N, N, N, N, 428, 0)), ('------T-:-:-+07:08', (N, N, N, N, -428, 0)), ('-------T-:-:--07:08', (N, N, N, N, 428, 0)), ('-------T-:-:-+07:08', (N, N, N, N, -428, 0)), # Edgepoints (ranges) ('2001-01-03T07:08:09Z', (2001, 1, 3, 7, 8, 9)), ('2001-12-03T07:08:09Z', (2001, 12, 3, 7, 8, 9)), ('2001-02-01T07:08:09Z', (2001, 2, 1, 7, 8, 9)), ('2001-02-28T07:08:09Z', (2001, 2, 28, 7, 8, 9)), ('2000-02-29T07:08:09Z', (2000, 2, 29, 7, 8, 9)), ('1900-02-28T07:08:09Z', (1900, 2, 28, 7, 8, 9)), ('2001-02-03T00:08:09Z', (2001, 2, 3, 0, 8, 9)), ('2001-02-03T23:08:09Z', (2001, 2, 3, 23, 8, 9)), ('2001-02-03T04:00:09Z', (2001, 2, 3, 4, 0, 9)), ('2001-02-03T04:59:09Z', (2001, 2, 3, 4, 59, 9)), ('2001-02-03T04:05:00Z', (2001, 2, 3, 4, 5, 0)), ('2001-02-03T04:05:60.9Z', (2001, 2, 3, 4, 5, 60.9)), ('2001-01-31T04:05:06Z', (2001, 1, 31, 4, 5, 6)), ('2001-03-31T04:05:06Z', (2001, 3, 31, 4, 5, 6)), ('2001-04-30T04:05:06Z', (2001, 4, 30, 4, 5, 6)), ('2001-05-31T04:05:06Z', (2001, 5, 31, 4, 5, 6)), ('2001-06-30T04:05:06Z', (2001, 6, 30, 4, 5, 6)), ('2001-07-31T04:05:06Z', (2001, 7, 31, 4, 5, 6)), ('2001-08-31T04:05:06Z', (2001, 8, 31, 4, 5, 6)), ('2001-09-30T04:05:06Z', (2001, 9, 30, 4, 5, 6)), ('2001-10-31T04:05:06Z', (2001, 10, 31, 4, 5, 6)), ('2001-11-30T04:05:06Z', (2001, 11, 30, 4, 5, 6)), ('2001-12-31T04:05:06Z', (2001, 12, 31, 4, 5, 6)), # Edgepoints (crossing boundaries) ('0001-01-01T07:08:23+07:08', (1, 1, 1, 0, 0, 23)), ('0001-01-01T07:07:42+07:08', (0, 12, 31, 23, 59, 42)), ('-0004-01-01T07:07:42+07:08', (-5, 12, 31, 23, 59, 42)), ('2001-03-01T07:07:42+07:08', (2001, 2, 28, 23, 59, 42)), ('2000-03-01T07:07:42+07:08', (2000, 2, 29, 23, 59, 42)), ('1900-03-01T07:07:42+07:08', (1900, 2, 28, 23, 59, 42)), ('---03-01T07:07:42+07:08', (N, 2, 28, 23, 59, 42)), ) for t in (recurringInstantType,): self.allTests(t, baddata, gooddata, parsedata) def testTime(self): baddata = \ ( 'hello', ('hello',), (1, 2, 3, 4, 5), (1, 2, 3, 4, 5, 6, 7, 8), (1, 2, 3, 4, 5, 6, 7, 8, 9, 10), (1, 2, 'hello'), (1, 2.5, 3), (25, 0, 0), (1, 60, 0), (1, 0, 61), ) gooddata = \ ( (1L, '00:00:01Z', (0, 0, 1.0)), (1.5, '00:00:01.5Z', (0, 0, 1.5)), (3661.5, '01:01:01.5Z', (1, 1, 1.5)), (86399.75, '23:59:59.75Z', (23, 59, 59.75)), ((1,), '01:00:00Z', (1, 0, 0)), ((1, 2), '01:02:00Z', (1, 2, 0)), ((10L, 20.0, 30), '10:20:30Z', (10, 20, 30.0)), ) parsedata = \ ( # Some strings that won't match the r.e. ('hello', N), ('00 00:01Z', N), ('07:O8:23Z', N), # Invalid ranges ('24:08:23Z', N), ('04:60:23Z', N), ('04:05:61Z', N), # Whitespace (ws + '00:00:01Z' + ws, (0, 0, 1)), # No timezones ('04:05:06.125', (4, 5, 6.125)), # Non-zulu ('04:05:06.125-07:08', (11, 13, 6.125)), ('04:05:06.125+07:08', (-4, 57, 6.125)), # Edgepoints (ranges) ('00:08:09Z', (0, 8, 9)), ('23:08:09Z', (23, 8, 9)), ('04:00:09Z', (4, 0, 9)), ('04:59:09Z', (4, 59, 9)), ('04:05:00Z', (4, 5, 0)), ('04:05:60.9Z', (4, 5, 60.9)), # Edgepoints (crossing boundaries) ('07:08:23+07:08', (0, 0, 23)), ('07:07:42+07:08', (-1, 59, 42)), ) for t in (timeType,): self.allTests(t, baddata, gooddata, parsedata) def testDate(self): baddata = \ ( 'hello', ('hello',), (1, 2, 3, 4, 5), (1, 2, 3, 4, 5, 6, 7, 8, 9, 10), (1, 2, 3, 4, 5, 'hello'), (1, 2.5, 3, 4, 5, 6), (1, 2, 3.5), (1, 0, 3), (1, 13, 3), (1, 1, 0), (1, 1, 32), (1, 2, 29), (0, 2, 30), (100, 2, 29), (1, 3, 32), (1, 4, 31), (1, 5, 32), (1, 6, 31), (1, 7, 32), (1, 8, 32), (1, 9, 31), (1, 10, 32), (1, 11, 31), (1, 12, 32), ) gooddata = \ ( (1L, '1970-01-01Z', (1970, 1, 1)), (1.5, '1970-01-01Z', (1970, 1, 1)), ((2,), '0002-01-01Z', (2, 1, 1)), ((2, 3), '0002-03-01Z', (2, 3, 1)), ((-2, 3, 4), '-0002-03-04Z', (-2, 3, 4)), ((2, 3, 4), '0002-03-04Z', (2, 3, 4)), ((10, 2, 3), '0010-02-03Z', (10, 2, 3)), ((100, 2, 3), '0100-02-03Z', (100, 2, 3)), ((1970, 2, 3), '1970-02-03Z', (1970, 2, 3)), ((-1970, 2, 3), '-1970-02-03Z', (-1970, 2, 3)), ((1970L, 2.0, 3.0), '1970-02-03Z', (1970, 2, 3)), ((11990, 1L, 2), '11990-01-02Z', (11990, 1, 2)), ((1e15, 1, 2), '1000000000000000-01-02Z', (1e15, 1, 2)), ((-1e15, 1, 2), '-1000000000000000-01-02Z', (-1e15, 1, 2)), ((1000000000000000L, 1, 2), '1000000000000000-01-02Z', (1e15, 1, 2)), ((-1000000000000000L, 1, 2), '-1000000000000000-01-02Z', (-1e15, 1, 2)), ) parsedata = \ ( # Some strings that won't match the r.e. ('hello', N), ('1970 -01 -01Z', N), ('0001-02-03z', N), # Invalid ranges ('2001-00-03Z', N), ('2001-13-03Z', N), ('2001-02-00Z', N), ('2001-02-29Z', N), ('2000-02-30Z', N), ('1900-02-29Z', N), ('2001-01-32Z', N), ('2001-03-32Z', N), ('2001-04-31Z', N), ('2001-05-32Z', N), ('2001-06-31Z', N), ('2001-07-32Z', N), ('2001-08-32Z', N), ('2001-09-31Z', N), ('2001-10-32Z', N), ('2001-11-31Z', N), ('2001-12-32Z', N), # Whitespace (ws + '1970-01-01Z' + ws, (1970, 1, 1)), # No timezones ('11971-02-03', (11971, 2, 3)), ('1971-02-03', (1971, 2, 3)), ('-1971-02-03', (-1971, 2, 3)), # Non-zulu ('11971-02-03-07:08', (11971, 2, 3)), ('11971-02-03+07:08', (11971, 2, 2)), ('-11971-02-03-07:08', (-11971, 2, 3)), ('-11971-02-03+07:08', (-11971, 2, 2)), ('1971-02-03-07:08', (1971, 2, 3)), ('1971-02-03+07:08', (1971, 2, 2)), ('-1971-02-03-07:08', (-1971, 2, 3)), ('-1971-02-03+07:08', (-1971, 2, 2)), # Edgepoints (ranges) ('2001-01-03Z', (2001, 1, 3)), ('2001-12-03Z', (2001, 12, 3)), ('2001-02-01Z', (2001, 2, 1)), ('2001-02-28Z', (2001, 2, 28)), ('2000-02-29Z', (2000, 2, 29)), ('1900-02-28Z', (1900, 2, 28)), ('2001-01-31Z', (2001, 1, 31)), ('2001-03-31Z', (2001, 3, 31)), ('2001-04-30Z', (2001, 4, 30)), ('2001-05-31Z', (2001, 5, 31)), ('2001-06-30Z', (2001, 6, 30)), ('2001-07-31Z', (2001, 7, 31)), ('2001-08-31Z', (2001, 8, 31)), ('2001-09-30Z', (2001, 9, 30)), ('2001-10-31Z', (2001, 10, 31)), ('2001-11-30Z', (2001, 11, 30)), ('2001-12-31Z', (2001, 12, 31)), # Edgepoints (crossing boundaries) ('0001-01-01+07:08', (0, 12, 31)), ('-0004-01-01+07:08', (-5, 12, 31)), ('2001-03-01+07:08', (2001, 2, 28)), ('2000-03-01+07:08', (2000, 2, 29)), ('1900-03-01+07:08', (1900, 2, 28)), ) for t in (dateType,): self.allTests(t, baddata, gooddata, parsedata) def testGYearMonth(self): baddata = \ ( 'hello', ('hello',), (1, 2, 3), (1, 2, 3, 4, 5, 6, 7, 8, 9, 10), (1, 2, 3.5), (1, 'hello'), (1, 2.5), (1, 0), (1, 13), ) gooddata = \ ( (1L, '1970-01Z', (1970, 1)), (1.5, '1970-01Z', (1970, 1)), ((2,), '0002-01Z', (2, 1)), ((2, 3), '0002-03Z', (2, 3)), ((-2, 3), '-0002-03Z', (-2, 3)), ((10, 2), '0010-02Z', (10, 2)), ((100, 2), '0100-02Z', (100, 2)), ((1970, 2), '1970-02Z', (1970, 2)), ((-1970, 2), '-1970-02Z', (-1970, 2)), ((1970L, 2.0), '1970-02Z', (1970, 2)), ((11990, 1L), '11990-01Z', (11990, 1)), ((1e15, 1), '1000000000000000-01Z', (1e15, 1)), ((-1e15, 1), '-1000000000000000-01Z', (-1e15, 1)), ((1000000000000000L, 1), '1000000000000000-01Z', (1e15, 1)), ((-1000000000000000L, 1), '-1000000000000000-01Z', (-1e15, 1)), ) parsedata = \ ( # Some strings that won't match the r.e. ('hello', N), ('1970 -01Z', N), ('0001-02z', N), # Invalid ranges ('2001-00Z', N), ('2001-13Z', N), # Whitespace (ws + '1970-01Z' + ws, (1970, 1)), # No timezones ('11971-02', (11971, 2)), ('1971-02', (1971, 2)), ('-1971-02', (-1971, 2)), # Non-zulu ('11971-02-07:08', (11971, 2)), ('11971-02+07:08', (11971, 1)), ('-11971-02-07:08', (-11971, 2)), ('-11971-02+07:08', (-11971, 1)), ('1971-02-07:08', (1971, 2)), ('1971-02+07:08', (1971, 1)), ('-1971-02-07:08', (-1971, 2)), ('-1971-02+07:08', (-1971, 1)), # Edgepoints (ranges) ('2001-01Z', (2001, 1)), ('2001-12Z', (2001, 12)), # Edgepoints (crossing boundaries) ('0001-01+07:08', (0, 12)), ('-0004-01+07:08', (-5, 12)), ('2001-03+07:08', (2001, 2)), ('2000-03+07:08', (2000, 2)), ('1900-03+07:08', (1900, 2)), ) for t in (gYearMonthType,): self.allTests(t, baddata, gooddata, parsedata) def testGYearAndYear(self): baddata = \ ( 'hello', ('hello',), (1, 2), (1, 2, 3, 4, 5, 6, 7, 8, 9, 10), (2.5,), ) gooddata = \ ( (1L, '0001Z', 1), (10, '0010Z', 10), (100, '0100Z', 100), (1970, '1970Z', 1970), (-1970, '-1970Z', -1970), (1970L, '1970Z', 1970), (11990.0, '11990Z', 11990), (1e15, '1000000000000000Z', 1e15), (-1e15, '-1000000000000000Z', -1e15), (1000000000000000L, '1000000000000000Z', 1e15), (-1000000000000000L, '-1000000000000000Z', -1e15), ) parsedata = \ ( # Some strings that won't match the r.e. ('hello', N), ('197OZ', N), ('0001z', N), # Whitespace (ws + '1970Z' + ws, 1970), # No timezones ('11971', 11971), ('1971', 1971), ('-1971', -1971), # Non-zulu ('11971-07:08', 11971), ('11971+07:08', 11970), ('-11971-07:08', -11971), ('-11971+07:08', -11972), ('1971-07:08', 1971), ('1971+07:08', 1970), ('-1971-07:08', -1971), ('-1971+07:08', -1972), # Edgepoints (crossing boundaries) ('0001+07:08', 0), ('-0004+07:08', -5), ) for t in (gYearType, yearType): self.allTests(t, baddata, gooddata, parsedata) def testCentury(self): baddata = \ ( 'hello', ('hello',), (1, 2), (1, 2, 3, 4, 5, 6, 7, 8, 9, 10), (2.5,), ) gooddata = \ ( (1L, '01Z', 1), (10, '10Z', 10), (100, '100Z', 100), (19, '19Z', 19), (-19, '-19Z', -19), (19L, '19Z', 19), (119.0, '119Z', 119), (1e15, '1000000000000000Z', 1e15), (-1e15, '-1000000000000000Z', -1e15), (1000000000000000L, '1000000000000000Z', 1e15), (-1000000000000000L, '-1000000000000000Z', -1e15), ) parsedata = \ ( # Some strings that won't match the r.e. ('hello', N), ('197OZ', N), ('0001z', N), # Whitespace (ws + '1970Z' + ws, 1970), # No timezones ('11971', 11971), ('1971', 1971), ('-1971', -1971), # Non-zulu ('11971-07:08', 11971), ('11971+07:08', 11970), ('-11971-07:08', -11971), ('-11971+07:08', -11972), ('1971-07:08', 1971), ('1971+07:08', 1970), ('-1971-07:08', -1971), ('-1971+07:08', -1972), # Edgepoints (crossing boundaries) ('0001+07:08', 0), ('-0004+07:08', -5), ) for t in (centuryType,): self.allTests(t, baddata, gooddata, parsedata) def testGMonthDayAndRecurringDate(self): baddata = \ ( 'hello', ('hello',), (3, 4, 5), (1, 2, 3, 4, 5, 6, 7, 8, 9, 10), (4, 5, 'hello'), (2.5, 3), (0, 3), (13, 3), (1, 0), (1, 32), (2, 29), (3, 32), (4, 31), (5, 32), (6, 31), (7, 32), (8, 32), (9, 31), (10, 32), (11, 31), (12, 32), ) gooddata = \ ( (1L, '--01-01Z', (1, 1)), (1.5, '--01-01Z', (1, 1)), ((2,), '--02-01Z', (2, 1)), ((2, 3), '--02-03Z', (2, 3)), ((10, 2), '--10-02Z', (10, 2)), ) parsedata = \ ( # Some strings that won't match the r.e. ('hello', N), ('--01 -01Z', N), ('--02-03z', N), # Invalid ranges ('--00-03Z', N), ('--13-03Z', N), ('--01-32Z', N), ('--02-00Z', N), ('--02-29Z', N), ('--03-32Z', N), ('--04-31Z', N), ('--05-32Z', N), ('--06-31Z', N), ('--07-32Z', N), ('--08-32Z', N), ('--09-31Z', N), ('--10-32Z', N), ('--11-31Z', N), ('--12-32Z', N), # Whitespace (ws + '--01-01Z' + ws, (1, 1)), # No timezones ('--02-03', (2, 3)), # Non-zulu ('--02-03-07:08', (2, 3)), ('--02-03+07:08', (2, 2)), # Edgepoints (ranges) ('--01-03Z', (1, 3)), ('--12-03Z', (12, 3)), ('--01-31Z', (1, 31)), ('--02-01Z', (2, 1)), ('--02-28Z', (2, 28)), ('--03-31Z', (3, 31)), ('--04-30Z', (4, 30)), ('--05-31Z', (5, 31)), ('--06-30Z', (6, 30)), ('--07-31Z', (7, 31)), ('--08-31Z', (8, 31)), ('--09-30Z', (9, 30)), ('--10-31Z', (10, 31)), ('--11-30Z', (11, 30)), ('--12-31Z', (12, 31)), # Edgepoints (crossing boundaries) ('--01-01+07:08', (12, 31)), ('--03-01+07:08', (2, 28)), ) for t in (gMonthDayType, recurringDateType): self.allTests(t, baddata, gooddata, parsedata) def testGMonthAndMonth(self): baddata = \ ( 'hello', ('hello',), (3, 4,), (1, 2, 3, 4, 5, 6, 7, 8, 9, 10), (2.5,), (0,), (13,), ) gooddata = \ ( (1L, '--01--Z', 1), ((2,), '--02--Z', 2), ((10,), '--10--Z', 10), ) parsedata = \ ( # Some strings that won't match the r.e. ('hello', N), ('--01 --Z', N), ('--03--z', N), # Invalid ranges ('--00--Z', N), ('--13--Z', N), # Whitespace (ws + '--01--Z' + ws, 1), # No timezones ('--03--', 3), # Non-zulu ('--03---07:08', 3), ('--03--+07:08', 2), # Edgepoints (ranges) ('--01--Z', 1), ('--12--Z', 12), # Edgepoints (crossing boundaries) ('--01--+07:08', 12), ('--12---07:08', 12), ) for t in (gMonthType, monthType): self.allTests(t, baddata, gooddata, parsedata) def testGDayAndRecurringDay(self): baddata = \ ( 'hello', ('hello',), (3, 4,), (1, 2, 3, 4, 5, 6, 7, 8, 9, 10), (2.5,), (0,), (32,), ) gooddata = \ ( (1L, '---01Z', 1), ((2,), '---02Z', 2), ((10,), '---10Z', 10), ) parsedata = \ ( # Some strings that won't match the r.e. ('hello', N), ('---01 Z', N), ('---03z', N), # Invalid ranges ('---00Z', N), ('---32Z', N), # Whitespace (ws + '---01Z' + ws, 1), # No timezones ('---03', 3), # Non-zulu ('---03-07:08', 3), ('---03+07:08', 2), # Edgepoints (ranges) ('---01Z', 1), ('---31Z', 31), # Edgepoints (crossing boundaries) ('---01+07:08', 31), ('---31-07:08', 31), ) for t in (gDayType, recurringDayType): self.allTests(t, baddata, gooddata, parsedata) def testInteger(self): # First some things that shouldn't be valid test = ('hello', 3.14, (), [], {}) t = integerType for i in test: try: t(i) raise AssertionError, \ "instantiated a %s with a bad value (%s)" % \ (t.__name__, repr(i)) except AssertionError: raise except ValueError: pass # Now some things that should for i in (10, 23L, 1111111111111111111111111111111111111111111111111111L): x = integerType(i) d = x._marshalData() if d != str(i): raise AssertionError, "expected %d, got %s" % (i, d) y = buildSOAP(x) z = parseSOAPRPC(y) if z != i: raise AssertionError, "expected %s, got %s" % (repr(i), repr(z)) # Now test parsing, both valid and invalid test = (('hello', N), ('3.14', N), ('10 000', N), ('1', 1), ('123456789012345678901234567890', 123456789012345678901234567890L), (ws + '12' + ws, 12)) for i in test: try: z = parseSOAPRPC(self.build_xml(t._validURIs[0], t.__name__[:-4], i[0])) if z != i[1]: raise AssertionError, "%s: expected %s, got %s" % \ (i[0], i[1], repr(z)) except AssertionError: raise except: if i[1] != N: raise AssertionError, \ "parsing %s as %s threw exception %s:%s" % \ (i[0], t.__name__, sys.exc_info()[0], sys.exc_info()[1]) def testNonPositiveInteger(self): # First some things that shouldn't be valid test = ('hello', 3.14, (), [], {}, 1, 23) for t in (nonPositiveIntegerType, non_Positive_IntegerType): for i in test: try: t(i) raise AssertionError, \ "instantiated a t with a bad value (%s)" % \ (t.__name__, repr(i)) except AssertionError: raise except ValueError: pass # Now some things that should for i in (0, -23L, -1111111111111111111111111111111111111111111111111L): x = t(i) d = x._marshalData() if d != str(i): raise AssertionError, "expected %d, got %s" % (i, d) y = buildSOAP(x) z = parseSOAPRPC(y) if z != i: raise AssertionError, "%s: expected %s, got %s" % \ (i[0], i[1], repr(z)) # Now test parsing, both valid and invalid test = (('hello', N), ('3.14', N), ('-10 000', N), ('1', N), ('0', 0), ('-1', -1), ('-123456789012345678901234567890', -123456789012345678901234567890L), (ws + '-12' + ws, -12)) for i in test: try: if t == nonPositiveIntegerType: n = t.__name__[:-4] else: n = 'non-positive-integer' z = parseSOAPRPC(self.build_xml(t._validURIs[0], n, i[0])) if z != i[1]: raise AssertionError, "%s: expected %s, got %s" % \ (i[0], i[1], repr(z)) except AssertionError: raise except: if i[1] != N: raise AssertionError, \ "parsing %s as %s threw exception %s:%s" % \ (i[0], t.__name__, sys.exc_info()[0], sys.exc_info()[1]) def testNegativeInteger(self): # First some things that shouldn't be valid test = ('hello', 3.14, (), [], {}, 0, 23) for t in (negativeIntegerType, negative_IntegerType): for i in test: try: t(i) raise AssertionError, \ "instantiated a %s with a bad value (%s)" % \ (t.__name__, repr(i)) except AssertionError: raise except ValueError: pass # Now some things that should for i in (-1, -23L, -111111111111111111111111111111111111111111111111L): x = t(i) d = x._marshalData() if d != str(i): raise AssertionError, "expected %d, got %s" % (i, d) y = buildSOAP(x) z = parseSOAPRPC(y) if z != i: raise AssertionError, "%s: expected %s, got %s" % \ (i[0], i[1], repr(z)) # Now test parsing, both valid and invalid test = (('hello', N), ('3.14', N), ('-10 000', N), ('1', N), ('0', N), ('-1', -1), ('-123456789012345678901234567890', -123456789012345678901234567890L), (ws + '-12' + ws, -12)) for i in test: try: if t == negativeIntegerType: n = t.__name__[:-4] else: n = 'negative-integer' z = parseSOAPRPC(self.build_xml(t._validURIs[0], n, i[0])) if z != i[1]: raise AssertionError, "expected %s, got %s" % (i[1], repr(z)) except AssertionError: raise except: if i[1] != N: raise AssertionError, \ "parsing %s as %s threw exception %s:%s" % \ (i[0], t.__name__, sys.exc_info()[0], sys.exc_info()[1]) def testLong(self): # First some things that shouldn't be valid test = ('hello', 3.14, (), [], {}, -9223372036854775809L, 9223372036854775808L) t = longType for i in test: try: t(i) raise AssertionError, \ "instantiated a %s with a bad value (%s)" % \ (t.__name__, repr(i)) except AssertionError: raise except ValueError: pass # Now some things that should for i in (-1, -23L, -9223372036854775808L, 9223372036854775807L): x = t(i) d = x._marshalData() if d != str(i): raise AssertionError, "expected %d, got %s" % (i, d) y = buildSOAP(x) z = parseSOAPRPC(y) if z != i: raise AssertionError, "expected %s, got %s" % (repr(i), repr(z)) # Now test parsing, both valid and invalid test = (('hello', N), ('3.14', N), ('-10 000', N), ('-9223372036854775809', N), ('9223372036854775808', N), ('-1', -1), ('0', 0), ('1', 1), ('-9223372036854775808', -9223372036854775808L), ('9223372036854775807', 9223372036854775807L), (ws + '-12' + ws, -12)) for i in test: try: z = parseSOAPRPC(self.build_xml(t._validURIs[0], t.__name__[:-4], i[0])) if z != i[1]: raise AssertionError, "%s: expected %s, got %s" % \ (i[0], i[1], repr(z)) except AssertionError: raise except: if i[1] != N: raise AssertionError, \ "parsing %s as %s threw exception %s:%s" % \ (i[0], t.__name__, sys.exc_info()[0], sys.exc_info()[1]) def testInt(self): # First some things that shouldn't be valid test = ('hello', 3.14, (), [], {}, -2147483649L, 2147483648L) t = intType for i in test: try: t(i) raise AssertionError, \ "instantiated a %s with a bad value (%s)" % \ (t.__name__, repr(i)) except AssertionError: raise except ValueError: pass # Now some things that should for i in (-1, -23L, -2147483648L, 2147483647): x = intType(i) d = x._marshalData() if d != str(i): raise AssertionError, "expected %d, got %s" % (i, d) y = buildSOAP(x) z = parseSOAPRPC(y) if z != i: raise AssertionError, "expected %s, got %s" % (repr(i), repr(z)) # Now test parsing, both valid and invalid test = (('hello', N), ('3.14', N), ('-10 000', N), ('-2147483649', N), ('2147483648', N), ('-1', -1), ('0', 0), ('1', 1), ('-2147483648', -2147483648L), ('2147483647', 2147483647), (ws + '-12' + ws, -12)) for i in test: try: z = parseSOAPRPC(self.build_xml(t._validURIs[0], t.__name__[:-4], i[0])) if z != i[1]: raise AssertionError, "%s: expected %s, got %s" % \ (i[0], i[1], repr(z)) except AssertionError: raise except: if i[1] != N: raise AssertionError, \ "parsing %s as %s threw exception %s:%s" % \ (i[0], t.__name__, sys.exc_info()[0], sys.exc_info()[1]) def testShort(self): # First some things that shouldn't be valid test = ('hello', 3.14, (), [], {}, -32769, 32768) t = shortType for i in test: try: t(i) raise AssertionError, \ "instantiated a %s with a bad value (%s)" % \ (t.__name__, repr(i)) except AssertionError: raise except ValueError: pass # Now some things that should for i in (-1, -23L, -32768, 32767): x = t(i) d = x._marshalData() if d != str(i): raise AssertionError, "expected %d, got %s" % (i, d) y = buildSOAP(x) z = parseSOAPRPC(y) if z != i: raise AssertionError, "expected %s, got %s" % (repr(i), repr(z)) # Now test parsing, both valid and invalid test = (('hello', N), ('3.14', N), ('-10 000', N), ('-32769', N), ('32768', N), ('-1', -1), ('0', 0), ('1', 1), ('-32768', -32768), ('32767', 32767), (ws + '-12' + ws, -12)) for i in test: try: z = parseSOAPRPC(self.build_xml(t._validURIs[0], t.__name__[:-4], i[0])) if z != i[1]: raise AssertionError, "%s: expected %s, got %s" % \ (i[0], i[1], repr(z)) except AssertionError: raise except: if i[1] != N: raise AssertionError, \ "parsing %s as %s threw exception %s:%s" % \ (i[0], t.__name__, sys.exc_info()[0], sys.exc_info()[1]) def testByte(self): # First some things that shouldn't be valid test = ('hello', 3.14, (), [], {}, -129, 128) t = byteType for i in test: try: t(i) raise AssertionError, \ "instantiated a %s with a bad value (%s)" % \ (t.__name__, repr(i)) except AssertionError: raise except ValueError: pass # Now some things that should for i in (-1, -23L, -128, 127): x = t(i) d = x._marshalData() if d != str(i): raise AssertionError, "expected %d, got %s" % (i, d) y = buildSOAP(x) z = parseSOAPRPC(y) if z != i: raise AssertionError, "expected %s, got %s" % (repr(i), repr(z)) # Now test parsing, both valid and invalid test = (('hello', N), ('3.14', N), ('-10 000', N), ('-129', N), ('128', N), ('-1', -1), ('0', 0), ('1', 1), ('-128', -128), ('127', 127), (ws + '-12' + ws, -12)) for i in test: try: z = parseSOAPRPC(self.build_xml(t._validURIs[0], t.__name__[:-4], i[0])) if z != i[1]: raise AssertionError, "%s: expected %s, got %s" % \ (i[0], i[1], repr(z)) except AssertionError: raise except: if i[1] != N: raise AssertionError, \ "parsing %s as %s threw exception %s:%s" % \ (i[0], t.__name__, sys.exc_info()[0], sys.exc_info()[1]) def testNonNegativeInteger(self): # First some things that shouldn't be valid test = ('hello', 3.14, (), [], {}, -42, -1) for t in (nonNegativeIntegerType, non_Negative_IntegerType): for i in test: try: t(i) raise AssertionError, \ "instantiated a %s with a bad value (%s)" % \ (t.__name__, repr(i)) except AssertionError: raise except ValueError: pass # Now some things that should for i in (0, 1, 23L, 111111111111111111111111111111111111111111111111L): x = t(i) d = x._marshalData() if d != str(i): raise AssertionError, "expected %d, got %s" % (i, d) y = buildSOAP(x) z = parseSOAPRPC(y) if z != i: raise AssertionError, "expected %s, got %s" % (repr(i), repr(z)) # Now test parsing, both valid and invalid test = (('hello', N), ('3.14', N), ('-10 000', N), ('-1', N), ('0', 0), ('1', 1), ('123456789012345678901234567890', 123456789012345678901234567890L), (ws + '12' + ws, 12)) for i in test: try: if t == nonNegativeIntegerType: n = t.__name__[:-4] else: n = 'non-negative-integer' z = parseSOAPRPC(self.build_xml(t._validURIs[0], n, i[0])) if z != i[1]: raise AssertionError, "%s: expected %s, got %s" % \ (i[0], i[1], repr(z)) except AssertionError: raise except: if i[1] != N: raise AssertionError, \ "parsing %s as %s threw exception %s:%s" % \ (i[0], t.__name__, sys.exc_info()[0], sys.exc_info()[1]) def testUnsignedLong(self): # First some things that shouldn't be valid test = ('hello', 3.14, (), [], {}, -42, -1, 18446744073709551616L) t = unsignedLongType for i in test: try: t(i) raise AssertionError, \ "instantiated a %s with a bad value (%s)" % \ (t.__name__, repr(i)) except AssertionError: raise except ValueError: pass # Now some things that should for i in (0, 23L, 18446744073709551615L): x = t(i) d = x._marshalData() if d != str(i): raise AssertionError, "expected %d, got %s" % (i, d) y = buildSOAP(x) z = parseSOAPRPC(y) if z != i: raise AssertionError, "expected %s, got %s" % (repr(i), repr(z)) # Now test parsing, both valid and invalid test = (('hello', N), ('3.14', N), ('-10 000', N), ('-1', N), ('18446744073709551616', N), ('0', 0), ('1', 1), ('18446744073709551615', 18446744073709551615L), (ws + '12' + ws, 12)) for i in test: try: z = parseSOAPRPC(self.build_xml(t._validURIs[0], t.__name__[:-4], i[0])) if z != i[1]: raise AssertionError, "%s: expected %s, got %s" % \ (i[0], i[1], repr(z)) except AssertionError: raise except: if i[1] != N: raise AssertionError, \ "parsing %s as %s threw exception %s:%s" % \ (i[0], t.__name__, sys.exc_info()[0], sys.exc_info()[1]) def testUnsignedInt(self): # First some things that shouldn't be valid test = ('hello', 3.14, (), [], {}, -42, -1, 4294967296L) t = unsignedIntType for i in test: try: t(i) raise AssertionError, \ "instantiated a %s with a bad value (%s)" % \ (t.__name__, repr(i)) except AssertionError: raise except ValueError: pass # Now some things that should for i in (0, 23L, 4294967295L): x = t(i) d = x._marshalData() if d != str(i): raise AssertionError, "expected %d, got %s" % (i, d) y = buildSOAP(x) z = parseSOAPRPC(y) if z != i: raise AssertionError, "expected %s, got %s" % (repr(i), repr(z)) # Now test parsing, both valid and invalid test = (('hello', N), ('3.14', N), ('-10 000', N), ('-1', N), ('4294967296', N), ('0', 0), ('1', 1), ('4294967295', 4294967295L), (ws + '12' + ws, 12)) for i in test: try: z = parseSOAPRPC(self.build_xml(t._validURIs[0], t.__name__[:-4], i[0])) if z != i[1]: raise AssertionError, "%s: expected %s, got %s" % \ (i[0], i[1], repr(z)) except AssertionError: raise except: if i[1] != N: raise AssertionError, \ "parsing %s as %s threw exception %s:%s" % \ (i[0], t.__name__, sys.exc_info()[0], sys.exc_info()[1]) def testUnsignedShort(self): # First some things that shouldn't be valid test = ('hello', 3.14, (), [], {}, -42, -1, 65536) t = unsignedShortType for i in test: try: t(i) raise AssertionError, \ "instantiated a %s with a bad value (%s)" % \ (t.__name__, repr(i)) except AssertionError: raise except ValueError: pass # Now some things that should for i in (0, 23L, 65535): x = t(i) d = x._marshalData() if d != str(i): raise AssertionError, "expected %d, got %s" % (i, d) y = buildSOAP(x) z = parseSOAPRPC(y) if z != i: raise AssertionError, "expected %s, got %s" % (repr(i), repr(z)) # Now test parsing, both valid and invalid test = (('hello', N), ('3.14', N), ('-10 000', N), ('-1', N), ('65536', N), ('0', 0), ('1', 1), ('65535', 65535), (ws + '12' + ws, 12)) for i in test: try: z = parseSOAPRPC(self.build_xml(t._validURIs[0], t.__name__[:-4], i[0])) if z != i[1]: raise AssertionError, "%s: expected %s, got %s" % \ (i[0], i[1], repr(z)) except AssertionError: raise except: if i[1] != N: raise AssertionError, \ "parsing %s as %s threw exception %s:%s" % \ (i[0], t.__name__, sys.exc_info()[0], sys.exc_info()[1]) def testUnsignedByte(self): # First some things that shouldn't be valid test = ('hello', 3.14, (), [], {}, -42, -1, 256) t = unsignedByteType for i in test: try: t(i) raise AssertionError, \ "instantiated a %s with a bad value (%s)" % \ (t.__name__, repr(i)) except AssertionError: raise except ValueError: pass # Now some things that should for i in (0, 23L, 255): x = t(i) d = x._marshalData() if d != str(i): raise AssertionError, "expected %d, got %s" % (i, d) y = buildSOAP(x) z = parseSOAPRPC(y) if z != i: raise AssertionError, "expected %s, got %s" % (repr(i), repr(z)) # Now test parsing, both valid and invalid test = (('hello', N), ('3.14', N), ('-10 000', N), ('-1', N), ('256', N), ('0', 0), ('1', 1), ('255', 255), (ws + '12' + ws, 12)) for i in test: try: z = parseSOAPRPC(self.build_xml(t._validURIs[0], t.__name__[:-4], i[0])) if z != i[1]: raise AssertionError, "%s: expected %s, got %s" % \ (i[0], i[1], repr(z)) except AssertionError: raise except: if i[1] != N: raise AssertionError, \ "parsing %s as %s threw exception %s:%s" % \ (i[0], t.__name__, sys.exc_info()[0], sys.exc_info()[1]) def testPositiveInteger(self): # First some things that shouldn't be valid test = ('hello', 3.14, (), [], {}, -42, -1, 0) for t in (positiveIntegerType, positive_IntegerType): for i in test: try: t(i) raise AssertionError, \ "instantiated a t with a bad value (%s)" % \ (t.__name__, repr(i)) except AssertionError: raise except ValueError: pass # Now some things that should for i in (1, 23L, 1111111111111111111111111111111111111111111111111111L): x = t(i) d = x._marshalData() if d != str(i): raise AssertionError, "expected %d, got %s" % (i, d) y = buildSOAP(x) z = parseSOAPRPC(y) if z != i: raise AssertionError, "expected %s, got %s" % (repr(i), repr(z)) # Now test parsing, both valid and invalid test = (('hello', N), ('3.14', N), ('-10 000', N), ('-1', N), ('0', N), ('1', 1), ('123456789012345678901234567890', 123456789012345678901234567890L), (ws + '12' + ws, 12)) for i in test: try: if t == positiveIntegerType: n = t.__name__[:-4] else: n = 'positive-integer' z = parseSOAPRPC(self.build_xml(t._validURIs[0], n, i[0])) if z != i[1]: raise AssertionError, "%s: expected %s, got %s" % \ (i[0], i[1], repr(z)) except AssertionError: raise except: if i[1] != N: raise AssertionError, \ "parsing %s as %s threw exception %s:%s" % \ (i[0], t.__name__, sys.exc_info()[0], sys.exc_info()[1]) def testUntyped(self): # Make sure untypedType really isn't typed a = stringType('hello', name = 'a') b = untypedType('earth', name = 'b') x = buildSOAP((a, b)) #print "x=",x self.failUnless(x.find('hello') != -1) self.failUnless(x.find('earth') != -1) # Now some Array tests def testArray(self): env = ''' %s ''' xml = env % ''' <_1 SOAP-ENC:arrayType="xsd:int[4]" SOAP-ENC:offset="[2]" xsi:type="SOAP-ENC:Array"> <_2 SOAP-ENC:arrayType="xsd:int[2]" xsi:type="SOAP-ENC:Array"> 1 2 <_3 SOAP-ENC:arrayType="xsd:int[2]" xsi:type="SOAP-ENC:Array"> 3 4 ''' x = parseSOAPRPC(xml) self.assertEquals( x , [None, None, [1, 2], [3, 4]]) xml = env % ''' <_1 SOAP-ENC:arrayType="xsd:int[3,4,2]" SOAP-ENC:offset="[17]" xsi:type="SOAP-ENC:Array"> 1 2 3 4 5 6 7 ''' x = parseSOAPRPC(xml) self.assertEquals( x , [ [[None, None], [None, None], [None, None], [None, None]], [[None, None], [None, None], [None, None], [None, None]], [[None, 1], [2, 3], [4, 5], [6, 7]] ]) xml = env % ''' <_1 SOAP-ENC:arrayType="xsd:int[3,4,2]" xsi:type="SOAP-ENC:Array"> -17 13 -22 1 17 23 6 ''' x = parseSOAPRPC(xml) self.assertEquals( x , [ [[None, 1L], [None, None], [None, None], [6L, None]], [[None, None], [None, None], [None, 13L], [None, None]], [[None, 17L], [None, None], [None, None], [-22L, 23L]] ]) xml = env % ''' <_1 SOAP-ENC:arrayType="xsd:int[4]" SOAP-ENC:offset="[3]" xsi:type="SOAP-ENC:Array"> 2 0 1 3 ''' x = parseSOAPRPC(xml) self.assertEquals( x , [0, 1, 2, 3]) xml = env % ''' <_1 SOAP-ENC:arrayType="xsd:int[2,3,4]" SOAP-ENC:offset="[23]" xsi:type="SOAP-ENC:Array"> ''' x = parseSOAPRPC(xml) self.assertEquals( x , [ [ [None, None, None, None], [None, None, None, None], [None, None, None, None], ], [ [None, None, None, None], [None, None, None, None], [None, None, None, None], ] ]) xml = env % ''' <_1 SOAP-ENC:arrayType="xsd:int[4]" SOAP-ENC:offset="[3]" xsi:type="SOAP-ENC:Array"> 2 3 ''' try: x = parseSOAPRPC(xml) raise AssertionError, "full array parsed" except AssertionError: raise except: pass xml = env % ''' <_1 SOAP-ENC:arrayType="xsd:int[2,0,4]" xsi:type="SOAP-ENC:Array"> ''' try: x = parseSOAPRPC(xml) raise AssertionError, "array with bad dimension (0) parsed" except AssertionError: raise except: pass xml = env % ''' <_1 SOAP-ENC:arrayType="xsd:int[2,3,-4]" xsi:type="SOAP-ENC:Array"> ''' try: x = parseSOAPRPC(xml) raise AssertionError, "array with bad dimension (negative) parsed" except AssertionError: raise except: pass xml = env % ''' <_1 SOAP-ENC:arrayType="xsd:int[2,3,4.4]" xsi:type="SOAP-ENC:Array"> ''' try: x = parseSOAPRPC(xml) raise AssertionError, "array with bad dimension (non-integral) parsed" except AssertionError: raise except: pass xml = env % ''' <_1 SOAP-ENC:arrayType="xsd:int[2,hello,4]" xsi:type="SOAP-ENC:Array"> ''' try: x = parseSOAPRPC(xml) raise AssertionError, "array with bad dimension (non-numeric) parsed" except AssertionError: raise except: pass xml = env % ''' <_1 SOAP-ENC:arrayType="xsd:int[2,3,4]" SOAP-ENC:offset="[-4]" xsi:type="SOAP-ENC:Array"> ''' try: x = parseSOAPRPC(xml) raise AssertionError, "array with too large offset parsed" except AssertionError: raise except: pass xml = env % ''' <_1 SOAP-ENC:arrayType="xsd:int[2,3,4]" SOAP-ENC:offset="[24]" xsi:type="SOAP-ENC:Array"> ''' try: x = parseSOAPRPC(xml) raise AssertionError, "array with too large offset parsed" except AssertionError: raise except: pass xml = env % ''' <_1 SOAP-ENC:arrayType="xsd:int[2,3,4]" xsi:type="SOAP-ENC:Array"> 2 3 ''' try: x = parseSOAPRPC(xml) raise AssertionError, "full array parsed" except AssertionError: raise except: pass xml = env % ''' 3 4 ''' x = parseSOAPRPC(xml) self.assertEquals( x , [3, 4]) xml = env % ''' 12345 6.789 Of Mans First Disobedience, and the Fruit Of that Forbidden Tree, whose mortal tast Brought Death into the World, and all our woe, http://www.dartmouth.edu/~milton/reading_room/ ''' x = parseSOAPRPC(xml) self.assertEquals( x , [12345, 6.789, '''Of Mans First Disobedience, and the Fruit Of that Forbidden Tree, whose mortal tast Brought Death into the World, and all our woe,''', 'http://www.dartmouth.edu/~milton/reading_room/']) xml = env % ''' Apple 1.56 Peach 1.48 ''' #x = parseSOAPRPC(xml) #print "x=",x xml = env % ''' r1c1 r1c2 r1c3 r2c1 r2c2 ''' x = parseSOAPRPC(xml) self.assertEquals( x , [['r1c1', 'r1c2', 'r1c3'], ['r2c1', 'r2c2'], ['r2c1', 'r2c2']]) xml = env % ''' r1c1 r1c2 r1c3 r2c1 r2c2 r2c3 ''' x = parseSOAPRPC(xml) self.assertEquals( x , [['r1c1', 'r1c2', 'r1c3'], ['r2c1', 'r2c2', 'r2c3']]) xml = env % ''' The third element The fourth element ''' x = parseSOAPRPC(xml) self.assertEquals( x , [None, None, 'The third element', 'The fourth element', None]) xml = env % ''' Third row, third col Eighth row, third col ''' x = parseSOAPRPC(xml) # Example using key data def testKeyData(self): xml = ''' Success Valid mailto:actzerotestkeyname MIIDPjCCAqegAwIBAgIEOroMvDANBgkqhkiG9w0BAQUFADAxMQswCQYDVQQGEwJVI3nlMkH84ZdPKIyz60sNcVEwJ8kF+B6ZVNimCF+r7BWgLi/Dolce5CpbfMMyexZ+UQEMADrc7331eYS891KXSDQx mailto:actzerotestkeyname wgmV2FY6MBKvtaMmCvCoNi/0hycZkiPKC2PXjRLJKFJ5wjNfF+vWsQQUXxOKUQnu HjJqRkx90jJvnEzW3j9FlZFQcZTfJbE0v6BXhhSre2kZvkgcOERmDMeMs//oEA4u epnedUwrkPzedWU9AL7c/oN7rk65UuPWf7V8c/4E9bc= AQAB 9GKuRC3ISwE9aEatzDKW0WIp+P/ufOvCxy9d5jVglLaRiTTIelHoGKCE6cDG62HYOu/3ebce6M7Z6LX6l1J9pB5PUx+f2DaMYYEGuOtNA7/ei5Ga/mibRBCehQIcN6FF6ESFOwAJBRLajj+orgYSy0u1sTCla0V4nSBrYA2H6lx8mD3qfDJ4hie7nU0YqZxy50F9f9UxXKIVSeutyIIBjWDDKv0kVpKy7OUerOaZXOW6HBohXuV74kXMUZu+MpLIkMHOrhJeo+edfhmeFuw4kCo5it6GkrOKrGs6zo1hSxWp7uuvKAPbvUrumC6sTsTxAUg4KTGq85IUnBTYI40Q9TZtzMcONtrWfIIF23/7NJyOmygBaFa4wFqHxe7j2gSWCQRv2fPwXo/AAJTeKwsUIY8OgmANHHbFVqJEeg27jbCuSaQFxWD7ms240YurTb55HBLk6JSufDl0CUbxoUgjrDB++gUb8oalroWDIb5NcZ94QER+HiTQfB11HcPDHvONnzk/n+iF+Mcri53ZbAButnfp2x87sh6RedeiUUWruYA4eonRq5+aj2I9cIrGLQaLemna1AQ+PyD2SMelBLukfR7GUc7zaSPjPJh2W/aYAJSyjM98g6ABNntdfhuf+6jRYnYFqSXZL1W1JPf92OMOfwfuXTE2K68sNwCRhcbHDLM= ''' x = parseSOAPRPC(xml) def testZeroLengthTypedArray(self): """ Test that zero length typed arrays maintain thier type information when converted to a SOAP message. """ empty_int = typedArrayType(typed="int") empty_int_message = buildSOAP( empty_int ) self.assertNotEquals( re.search("xsd:int\[0\]", empty_int_message), None ) if __name__ == '__main__': print """ NOTE: The 'testArray' test will fail because 'referenced' elements are included in the return object. This is a known shortcoming of the current version of SOAPpy. All other tests should succeed. """ unittest.main() SOAPpy-0.12.0/tests/TCtest.py0100755001604000501700000001026710206471437015466 0ustar warnegclinical#!/usr/bin/env python import sys, unittest sys.path.insert(1, "..") from SOAPpy import * Config.debug=1 class ClientTestCase(unittest.TestCase): def testParseRules(self): x = """ My Life and Work Henry Ford 49 5.5 """ def negfloat(x): return float(x) * -1.0 # parse rules pr = {'SomeMethod': {'Result': { 'Book': {'title':'string'}, 'Person': {'age':'int', 'height':negfloat} } } } y = parseSOAPRPC(x, rules=pr) assert y.Result.Person.age == 49 assert y.Result.Person.height == -5.5 x = ''' 12 23 0 -31 ''' # parse rules pr = {'Bounds': {'param': 'arrayType=string[]', } } pr2 = {'Bounds': {'param': 'arrayType=int[4]', } } y = parseSOAPRPC(x, rules=pr) assert y.param[1]=='23' y = parseSOAPRPC(x, rules=pr2) assert y.param[1]==23 x = ''' 12 23 0 -31 ''' pr = {'Bounds': {'param': 'arrayType=ur-type[]' } } y = parseSOAPRPC(x, rules=pr) assert y.param[0]==12 assert y.param[1]=='23' assert y.param[2]==float(0) assert y.param[3]==-31 # Try the reverse, not implemented yet. def testBuildObject(self): class Book(structType): def __init__(self): self.title = "Title of a book" class Person(structType): def __init__(self): self.age = "49" self.height = "5.5" class Library(structType): def __init__(self): self._name = "Result" self.Book = Book() self.Person = Person() obj = Library() x = buildSOAP( kw={'Library':obj} ) print(x) if __name__ == '__main__': unittest.main() SOAPpy-0.12.0/tests/TemperatureService.wsdl0100755001604001300100000000300210202425141020433 0ustar warnegcompstat Returns current temperature in a given U.S. zipcode SOAPpy-0.12.0/tests/ZeroLengthArray.py0100644001604000501700000000030210202425142017306 0ustar warnegclinicalimport sys sys.path.insert(1, "..") from SOAPpy import * one = typedArrayType(data=[1],typed=type(1)) tmp = typedArrayType(data=[], typed=type(1)) print buildSOAP( one ) print buildSOAP( tmp ) SOAPpy-0.12.0/tests/alanbushTest.py0100755001604001300100000000167710202425141016751 0ustar warnegcompstat#!/usr/bin/env python # Copyright (c) 2001 actzero, inc. All rights reserved. ident = '$Id: alanbushTest.py,v 1.5 2003/05/21 14:52:37 warnes Exp $' import os, re,sys # add local SOAPpy code to search path sys.path.insert(1, "..") from SOAPpy import * Config.debug=0 # Check for a web proxy definition in environment try: proxy_url=os.environ['http_proxy'] phost, pport = re.search('http://([^:]+):([0-9]+)', proxy_url).group(1,2) proxy = "%s:%s" % (phost, pport) except: proxy = None SoapEndpointURL = 'http://www.alanbushtrust.org.uk/soap/compositions.asp' MethodNamespaceURI = 'urn:alanbushtrust-org-uk:soap.methods' SoapAction = MethodNamespaceURI + ".GetCategories" server = SOAPProxy(SoapEndpointURL, namespace=MethodNamespaceURI, soapaction=SoapAction, http_proxy=proxy ) for category in server.GetCategories(): print category SOAPpy-0.12.0/tests/cardClient.py0100755001604000501700000000143710202425142016313 0ustar warnegclinical#!/usr/bin/env python # Copyright (c) 2001 actzero, inc. All rights reserved. import sys sys.path.insert (1, '..') from SOAPpy import * ident = '$Id: cardClient.py,v 1.4 2004/02/18 21:22:13 warnes Exp $' endpoint = "http://localhost:12027/xmethodsInterop" sa = "urn:soapinterop" ns = "http://soapinterop.org/" serv = SOAPProxy(endpoint, namespace=ns, soapaction=sa) try: hand = serv.dealHand(NumberOfCards = 13, StringSeparator = '\n') except: print "no dealHand"; hand = 0 try: sortedhand = serv.dealArrangedHand(NumberOfCards=13,StringSeparator='\n') except: print "no sorted"; sortedhand = 0 try: card = serv.dealCard() except: print "no card"; card = 0 print "*****hand****\n",hand,"\n*********" print "******sortedhand*****\n",sortedhand,"\n*********" print "card:",card serv.quit() SOAPpy-0.12.0/tests/cardServer.py0100755001604000501700000000566710202425142016354 0ustar warnegclinical#!/usr/bin/env python # Copyright (c) 2001 actzero, inc. All rights reserved. import string import sys sys.path.insert (1, '..') from SOAPpy import * ident = '$Id: cardServer.py,v 1.4 2004/02/18 21:22:13 warnes Exp $' # create the list of all cards, and keep strings for each suit __cs = "Clubs" __ds = "Diamonds" __hs = "Hearts" __ss = "Spades" __cards = [] for suit in [__cs, __ds, __hs, __ss]: for num in range(9): num += 1 __cards.append(str(num+1)+" of "+suit) for face in ["ace","King","Queen","Jack"]: __cards.append(face+" of "+suit) def deal(num): if num not in range(1,53): return -1 else: alreadydealt = [] ignore = 0 handdealt = [] import whrandom while num > 0: idx = int(str(whrandom.random())[2:4]) if idx in range(52) and idx not in alreadydealt: handdealt.append(__cards[idx]) alreadydealt.append(idx) num -= 1 else: ignore += 1 continue return handdealt def arrangeHand(hand): c = [] d = [] h = [] s = [] import string for card in hand: if string.find(card, __cs) != -1: c.append(card) elif string.find(card, __ds) != -1: d.append(card) elif string.find(card, __hs) != -1: h.append(card) elif string.find(card, __ss) != -1: s.append(card) for cards, str in ((c, __cs),(d, __ds),(h,__hs), (s,__ss)): cards.sort() idx = 0 if "10 of "+str in cards: cards.remove("10 of "+str) if "Jack of "+str in cards: idx += 1 if "Queen of "+str in cards: idx += 1 if "King of "+str in cards: idx += 1 if "ace of "+str in cards: idx +=1 cards.insert(len(cards)-idx,"10 of "+str) if "King of "+str in cards: cards.remove("King of "+str) if "ace of "+str in cards: cards.insert(len(cards)-1,"King of "+str) else: cards.append("King of "+str) return c+d+h+s def dealHand (NumberOfCards, StringSeparator): hand = deal(NumberOfCards) return string.join(hand,StringSeparator) def dealArrangedHand (NumberOfCards, StringSeparator): if NumberOfCards < 1 or NumberOfCards > 52: raise ValueError, "NumberOfCards must be between 1 and 52" unarranged = deal(NumberOfCards) hand = arrangeHand(unarranged) return string.join(hand, StringSeparator) def dealCard (): return deal(1)[0] run = 1 def quit(): global run run=0; namespace = 'http://soapinterop.org/' server = SOAPServer (("localhost", 12027)) server.registerKWFunction (dealHand, namespace) server.registerKWFunction (dealArrangedHand, namespace) server.registerKWFunction (dealCard, namespace) server.registerKWFunction (quit, namespace) try: while run: server.handle_request() except KeyboardInterrupt: pass SOAPpy-0.12.0/tests/echoClient.py0100755001604000501700000000466010206524540016327 0ustar warnegclinical#!/usr/bin/env python # Copyright (c) 2001 actzero, inc. All rights reserved. import sys sys.path.insert(1, "..") from SOAPpy import * # Uncomment to see outgoing HTTP headers and SOAP and incoming #Config.debug = 1 #Config.dumpHeadersIn = 1 #Config.dumpSOAPIn = 1 #Config.dumpSOAPOut = 1 # ask for returned SOAP responses to be converted to basic python types Config.simplify_objects = 1 #Config.BuildWithNoType = 1 #Config.BuildWithNoNamespacePrefix = 1 if len(sys.argv) > 1 and sys.argv[1] == '-s': # Use secure http pathserver = SOAPProxy("https://localhost:9900/pathtest") server = SOAPProxy("https://localhost:9900") elif len(sys.argv) > 1 and sys.argv[1] == '-g': # use Globus for communication import pyGlobus pathserver = SOAPProxy("httpg://localhost:9900/pathtest") server = SOAPProxy("httpg://localhost:9900") else: # Default: use standard http pathserver = SOAPProxy("http://localhost:9900/pathtest") server = SOAPProxy("http://localhost:9900") # Echo... try: print server.echo("MOO") except Exception, e: print "Caught exception: ", e try: print pathserver.echo("MOO") except Exception, e: print "Caught exception: ", e # ...in an object try: print server.echo_ino("moo") except Exception, e: print "Caught exception: ", e try: print pathserver.echo_ino("cow") except Exception, e: print "Caught exception: ", e # ...in an object in an object try: print server.prop.echo2("moo") except Exception, e: print "Caught exception: ", e try: print pathserver.prop.echo2("cow") except Exception, e: print "Caught exception: ", e # ...with keyword arguments try: print server.echo_wkw(third = "three", first = "one", second = "two") except Exception, e: print "Caught exception: ", e try: print pathserver.echo_wkw(third = "three", first = "one", second = "two") except Exception, e: print "Caught exception: ", e # ...with a context object try: print server.echo_wc("moo") except Exception, e: print "Caught exception: ", e try: print pathserver.echo_wc("cow") except Exception, e: print "Caught exception: ", e # ...with a header hd = headerType(data = {"mystring": "Hello World"}) try: print server._hd(hd).echo_wc("moo") except Exception, e: print "Caught exception: ", e try: print pathserver._hd(hd).echo_wc("cow") except Exception, e: print "Caught exception: ", e # close down server server.quit() SOAPpy-0.12.0/tests/echoHeader.py0100755001604001300100000000070010206520053016327 0ustar warnegcompstat#!/usr/bin/env python # Copyright (c) 2001 actzero, inc. All rights reserved. import sys sys.path.insert(1, "..") from SOAPpy import * # Uncomment to see outgoing HTTP headers and SOAP and incoming #Config.debug = 1 Config.BuildWithNoType = 1 Config.BuildWithNoNamespacePrefix = 1 hd = headerType(data = {"mystring": "Hello World"}) server = SOAPProxy("http://localhost:9900/", header=hd) print server.echo("Hello world") server.quit() SOAPpy-0.12.0/tests/echoServer.py0100755001604000501700000001144410206517673016366 0ustar warnegclinical#!/usr/bin/env python # # Copyright (c) 2001 actzero, inc. All rights reserved. import sys sys.path.insert(1, "..") from SOAPpy import * # Uncomment to see outgoing HTTP headers and SOAP and incoming Config.dumpSOAPIn = 1 Config.dumpSOAPOut = 1 Config.debug = 1 # specify name of authorization function Config.authMethod = "_authorize" # Set this to 0 to test authorization allowAll = 1 # ask for returned SOAP responses to be converted to basic python types Config.simplify_objects = 1 # provide a mechanism to stop the server run = 1 def quit(): global run run=0; if Config.SSLserver: from M2Crypto import SSL def _authorize(*args, **kw): global allowAll, Config if Config.debug: print "Authorize (function) called! (result = %d)" % allowAll print "Arguments: %s" % kw if allowAll: return 1 else: return 0 # Simple echo def echo(s): global Config # Test of context retrieval ctx = Server.GetSOAPContext() if Config.debug: print "SOAP Context: ", ctx return s + s # An echo class class echoBuilder2: def echo2(self, val): return val * 3 # A class that has an instance variable which is an echo class class echoBuilder: def __init__(self): self.prop = echoBuilder2() def echo_ino(self, val): return val + val def _authorize(self, *args, **kw): global allowAll, Config if Config.debug: print "Authorize (method) called with arguments:" print "*args=%s" % str(args) print "**kw =%s" % str(kw) print "Approved -> %d" % allowAll if allowAll: return 1 else: return 0 # Echo with context def echo_wc(s, _SOAPContext): global Config c = _SOAPContext sep = '-' * 72 # The Context object has extra info about the call if Config.debug: print "-- XML", sep[7:] # The original XML request print c.xmldata print "-- Header", sep[10:] # The SOAP Header or None if not present print c.header if c.header: print "-- Header.mystring", sep[19:] # An element of the SOAP Header print c.header.mystring print "-- Body", sep[8:] # The whole Body object print c.body print "-- Peer", sep[8:] if not GSI: # The socket object, useful for print c.connection.getpeername() else: # The socket object, useful for print c.connection.get_remote_address() ctx = c.connection.get_security_context() print ctx.inquire()[0].display() print "-- SOAPAction", sep[14:] # The SOAPaction HTTP header print c.soapaction print "-- HTTP headers", sep[16:] # All the HTTP headers print c.httpheaders return s + s # Echo with keyword arguments def echo_wkw(**kw): return kw['first'] + kw['second'] + kw['third'] # Simple echo def echo_simple(*arg): return arg def echo_header(s, _SOAPContext): global Config c = _SOAPContext return s, c.header addr = ('localhost', 9900) GSI = 0 SSL = 0 if len(sys.argv) > 1 and sys.argv[1] == '-s': SSL = 1 if not Config.SSLserver: raise RuntimeError, \ "this Python installation doesn't have OpenSSL and M2Crypto" ssl_context = SSL.Context() ssl_context.load_cert('validate/server.pem') server = SOAPServer(addr, ssl_context = ssl_context) prefix = 'https' elif len(sys.argv) > 1 and sys.argv[1] == '-g': GSI = 1 from SOAPpy.GSIServer import GSISOAPServer server = GSISOAPServer(addr) prefix = 'httpg' else: server = SOAPServer(addr) prefix = 'http' print "Server listening at: %s://%s:%d/" % (prefix, addr[0], addr[1]) # register the method server.registerFunction(echo) server.registerFunction(echo, path = "/pathtest") server.registerFunction(_authorize) server.registerFunction(_authorize, path = "/pathtest") # Register a whole object o = echoBuilder() server.registerObject(o, path = "/pathtest") server.registerObject(o) # Register a function which gets called with the Context object server.registerFunction(MethodSig(echo_wc, keywords = 0, context = 1), path = "/pathtest") server.registerFunction(MethodSig(echo_wc, keywords = 0, context = 1)) # Register a function that takes keywords server.registerKWFunction(echo_wkw, path = "/pathtest") server.registerKWFunction(echo_wkw) server.registerFunction(echo_simple) server.registerFunction(MethodSig(echo_header, keywords=0, context=1)) server.registerFunction(quit) # Start the server try: while run: server.handle_request() except KeyboardInterrupt: pass SOAPpy-0.12.0/tests/esj_test_client.py0100644001604000501700000000403710202425142017415 0ustar warnegclinical#!/usr/bin/python2 #standard imports import syslog, sys #domain specific imports sys.path.insert (1, '..') import SOAPpy SOAPpy.Config.simplify_objects=1 ## def test_integer(self,pass_integer): ## def test_string(self,pass_string): ## def test_float(self,pass_float): ## def test_tuple(self,pass_tuple): ## def test_list(self,pass_list): ## def test_dictionary(self,pass_dictionary): if __name__ == "__main__": server = SOAPpy.SOAPProxy("http://localhost:9999") original_integer = 5 result_integer = server.test_integer(original_integer) print "original_integer %s" % original_integer print "result_integer %s" % result_integer assert(result_integer==original_integer) print original_string = "five" result_string = server.test_string(original_string) print "original_string %s" % original_string print "result_string %s" % result_string assert(result_string==original_string) print original_float = 5.0 result_float = server.test_float(original_float) print "original_float %s" % original_float print "result_float %s" % result_float assert(result_float==original_float) print original_tuple = (1,2,"three","four",5) result_tuple = server.test_tuple(original_tuple) print "original_tuple %s" % str(original_tuple) print "result_tuple %s" % str(result_tuple) assert(tuple(result_tuple)==original_tuple) print original_list = [5,4,"three",2,1] result_list = server.test_list(original_list) print "original_list %s" % original_list print "result_list %s" % result_list assert(result_list==original_list) print original_dictionary = { 'one': 1, "two": 2, "three": 3, "four": 4, "five": 5, } result_dictionary = server.test_dictionary(original_dictionary) print "original_dictionary %s" % original_dictionary print "result_dictionary %s" % result_dictionary assert(result_dictionary==original_dictionary) print server.quit() SOAPpy-0.12.0/tests/esj_test_server.py0100644001604000501700000000202510202425142017440 0ustar warnegclinical#!/usr/bin/python2 #standard imports import syslog, sys #domain specific imports sys.path.insert (1, '..') import SOAPpy class test_service: run = 1 def test_integer(self,pass_integer): print type(pass_integer) return pass_integer def test_string(self,pass_string): print type(pass_string) return pass_string def test_float(self,pass_float): print type(pass_float) return pass_float def test_tuple(self,pass_tuple): print type(pass_tuple), pass_tuple return pass_tuple def test_list(self,pass_list): print type(pass_list), pass_list return pass_list def test_dictionary(self,pass_dictionary): print type(pass_dictionary), pass_dictionary return pass_dictionary def quit(self): self.run = 0 server = SOAPpy.SOAPServer(("localhost",9999)) SOAPpy.Config.simplify_objects=1 access_object = test_service() server.registerObject(access_object) while access_object.run: server.handle_request() SOAPpy-0.12.0/tests/excelTest.py0100755001604001300100000000045010202425141016240 0ustar warnegcompstat#!/usr/bin/env python import sys sys.path.insert(1, "..") from SOAPpy import * server = SOAPProxy("http://206.135.217.234:8000/") server.COM_SetProperty("Visible", 1) server.Workbooks.Open("c:\\test.xls") server.COM_NestedCall('ActiveSheet.Range("A2").EntireRow.Delete()') server.quit() SOAPpy-0.12.0/tests/largeDataTest.py0100755001604001300100000000210310206520077017031 0ustar warnegcompstat#!/usr/bin/env python # Copyright (c) 2001 actzero, inc. All rights reserved. import sys sys.path.insert(1, "..") from SOAPpy import * from SOAPpy import Parser # Uncomment to see outgoing HTTP headers and SOAP and incoming #Config.debug = 1 if len(sys.argv) > 1 and sys.argv[1] == '-s': server = SOAPProxy("https://localhost:9900") else: server = SOAPProxy("http://localhost:9900") # BIG data: big = repr('.' * (1<<18) ) # ...in an object print "server.echo_ino(big):..", tmp = server.echo_ino(big) print "done" # ...in an object in an object print "server.prop.echo2(big)..", tmp = server.prop.echo2(big) print "done" # ...with keyword arguments print 'server.echo_wkw(third = big, first = "one", second = "two")..', tmp = server.echo_wkw(third = big, first = "one", second = "two") print "done" # ...with a context object print "server.echo_wc(big)..", tmp = server.echo_wc(big) print "done" # ...with a header hd = headerType(data = {"mystring": "Hello World"}) print "server._hd(hd).echo_wc(big)..", tmp = server._hd(hd).echo_wc(big) print "done" server.quit() SOAPpy-0.12.0/tests/newsTest.py0100755001604001300100000000266010202425141016121 0ustar warnegcompstat#!/usr/bin/env python ident = '$Id: newsTest.py,v 1.4 2003/05/21 14:52:37 warnes Exp $' import os, re import sys sys.path.insert(1, "..") from SOAPpy import SOAPProxy # Check for a web proxy definition in environment try: proxy_url=os.environ['http_proxy'] phost, pport = re.search('http://([^:]+):([0-9]+)', proxy_url).group(1,2) proxy = "%s:%s" % (phost, pport) except: proxy = None SoapEndpointURL = 'http://www22.brinkster.com/prasads/BreakingNewsService.asmx?WSDL' MethodNamespaceURI = 'http://tempuri.org/' # Three ways to do namespaces, force it at the server level server = SOAPProxy(SoapEndpointURL, namespace = MethodNamespaceURI, soapaction='http://tempuri.org/GetCNNNews', encoding = None, http_proxy=proxy) print "[server level CNN News call]" print server.GetCNNNews() # Do it inline ala SOAP::LITE, also specify the actually ns (namespace) and # sa (soapaction) server = SOAPProxy(SoapEndpointURL, encoding = None) print "[inline CNNNews call]" print server._ns('ns1', MethodNamespaceURI)._sa('http://tempuri.org/GetCNNNews').GetCNNNews() # Create an instance of your server with specific namespace and then use # inline soapactions for each call dq = server._ns(MethodNamespaceURI) print "[namespaced CNNNews call]" print dq._sa('http://tempuri.org/GetCNNNews').GetCNNNews() print "[namespaced CBSNews call]" print dq._sa('http://tempuri.org/GetCBSNews').GetCBSNews() SOAPpy-0.12.0/tests/quoteTest.py0100755001604000501700000000230110202425142016227 0ustar warnegclinical#!/usr/bin/env python # Copyright (c) 2001 actzero, inc. All rights reserved. ident = '$Id: quoteTest.py,v 1.5 2003/12/18 06:31:50 warnes Exp $' import os, re import sys sys.path.insert(1, "..") from SOAPpy import SOAPProxy # Check for a web proxy definition in environment try: proxy_url=os.environ['http_proxy'] phost, pport = re.search('http://([^:]+):([0-9]+)', proxy_url).group(1,2) proxy = "%s:%s" % (phost, pport) except: proxy = None # Three ways to do namespaces, force it at the server level server = SOAPProxy("http://services.xmethods.com:9090/soap", namespace = 'urn:xmethods-delayed-quotes', http_proxy=proxy) print "IBM>>", server.getQuote(symbol = 'IBM') # Do it inline ala SOAP::LITE, also specify the actually ns server = SOAPProxy("http://services.xmethods.com:9090/soap", http_proxy=proxy) print "IBM>>", server._ns('ns1', 'urn:xmethods-delayed-quotes').getQuote(symbol = 'IBM') # Create a namespaced version of your server dq = server._ns('urn:xmethods-delayed-quotes') print "IBM>>", dq.getQuote(symbol='IBM') print "ORCL>>", dq.getQuote(symbol='ORCL') print "INTC>>", dq.getQuote(symbol='INTC') SOAPpy-0.12.0/tests/simpleWSDL.py0100644001604000501700000000034310202425142016216 0ustar warnegclinicalimport sys sys.path.insert(1, "..") import SOAPpy url = 'http://www.xmethods.org/sd/2001/TemperatureService.wsdl' zip = '06340' proxy = SOAPpy.WSDL.Proxy(url) temp = proxy.getTemp(zip) print 'Temperature at', zip, 'is', temp SOAPpy-0.12.0/tests/speedTest.py0100755001604001300100000000564010202425141016246 0ustar warnegcompstat#!/usr/bin/env python ident = '$Id: speedTest.py,v 1.4 2003/05/21 14:52:37 warnes Exp $' import time import sys sys.path.insert(1, "..") x=''' USA japan ''' x2=''' West Virginia -546 -5.398 New Mexico -641 -9.351 Missouri -819 1.495 ''' # Import in function, because for some reason they slow each other # down in same namespace ??? def SOAPParse(inxml): from SOAPpy import parseSOAPRPC t= time.time() parseSOAPRPC(inxml) return time.time()-t def SAXParse(inxml): import xml.sax y = xml.sax.handler.ContentHandler() t= time.time() xml.sax.parseString(inxml,y) return time.time()-t def DOMParse(inxml): import xml.dom.minidom t= time.time() xml.dom.minidom.parseString(inxml) return time.time()-t # Wierd but the SAX parser runs really slow the first time. # Probably got to load a c module or something SAXParse(x) print print "Simple XML" print "SAX Parse, no marshalling ", SAXParse(x) print "SOAP Parse, and marshalling ", SOAPParse(x) print "DOM Parse, no marshalling ", DOMParse(x) print print "Complex XML (references)" print "SAX Parse, no marshalling ", SAXParse(x2) print "SOAP Parse, and marshalling ", SOAPParse(x2) print "DOM Parse, no marshalling ", DOMParse(x2) SOAPpy-0.12.0/tests/storageTest.py0100755001604000501700000001000410204545426016547 0ustar warnegclinical#!/usr/bin/env python ident = '$Id: storageTest.py,v 1.6 2005/02/16 04:24:54 warnes Exp $' import sys, os, time, signal, re sys.path.insert(1, "..") from SOAPpy import SOAPProxy, SOAPConfig, SOAPUserAgent # Check for a web proxy definition in environment try: proxy_url=os.environ['http_proxy'] phost, pport = re.search('http://([^:]+):([0-9]+)', proxy_url).group(1,2) http_proxy = "%s:%s" % (phost, pport) except: http_proxy = None PROXY="http://www.soapware.org/xmlStorageSystem" EMAIL="SOAPpy@actzero.com" NAME="test_user" PASSWORD="mypasswd" SERIAL=1123214 MY_PORT=15600 def resourceChanged (url): print "\n##### NOTIFICATION MESSAGE: Resource %s has changed #####\n" % url return booleanType(1) def printstatus (cmd, stat): print if stat.flError: print "### %s failed: %s ###" % (cmd, stat.message) else: print "### %s successful: %s ###" % (cmd, stat.message) return not stat.flError server = SOAPProxy(encoding="US-ASCII", proxy=PROXY, soapaction="/xmlStorageSystem", http_proxy=http_proxy, # config=SOAPConfig(debug=1) ) # Register as a new user or update user information reg = server.registerUser(email=EMAIL, name=NAME, password=PASSWORD, clientPort=MY_PORT, userAgent=SOAPUserAgent(), serialnumber=SERIAL) printstatus("registerUser", reg) # See what this server can do reg = server.getServerCapabilities (email=EMAIL, password=PASSWORD) if printstatus("getServerCapabilities", reg): print "Legal file extensions: " + str(reg.legalFileExtensions) print "Maximum file size: " + str(reg.maxFileSize) print "Maximum bytes per user: " + str(reg.maxBytesPerUser) print "Number of bytes in use by the indicated user: " + str(reg.ctBytesInUse) print "URL of the folder containing your files: " + str(reg.yourUpstreamFolderUrl) # Store some files reg = server.saveMultipleFiles (email=EMAIL, password=PASSWORD, relativepathList=['index.html','again.html'], fileTextList=['bennett@actzero.com home page' + 'Hello Earth', 'bennett@actzero.com home page' + 'Hello Earth Again']) if printstatus("saveMultipleFiles", reg): print "Files stored:" for file in reg.urlList: print " %s" % file # Save this for call to test pleaseNotify mylist = reg.urlList else: mylist = [] # Check to see what files are stored reg = server.getMyDirectory (email=EMAIL, password=PASSWORD) if printstatus("getMyDirectory", reg): i = 1 while hasattr(reg.directory, "file%05d" % i): d = getattr(reg.directory, "file%05d" % i) print "Relative Path: %s" % d.relativePath print "Size: %d" % d.size print "Created: %s" % d.whenCreated print "Last Uploaded: %s" % d.whenLastUploaded print "URL: %s" % d.url print i += 1 # Set up notification reg = server.pleaseNotify(notifyProcedure="resourceChanged", port=MY_PORT, path="/", protocol="soap", urlList=mylist) printstatus("notifyProcedure", reg) pid = os.fork() if pid == 0: # I am a child process. Set up SOAP server to receive notification print print "## Starting notification server ##" s = SOAPServer(('localhost', MY_PORT)) s.registerFunction(resourceChanged) s.serve_forever() else: def handler(signum, frame): # Kill child process print "Killing child process %d" % pid os.kill(pid, signal.SIGINT) signal.signal(signal.SIGINT, handler) # I am a parent process # Change some files time.sleep(3) reg = server.saveMultipleFiles (email=EMAIL, password=PASSWORD, relativepathList=['index.html'], fileTextList=['bennett@actzero.com home page' + 'Hello Bennett']) if printstatus("saveMultipleFiles", reg): print "Files stored:" for file in reg.urlList: print " %s" % file os.waitpid(pid, 0) SOAPpy-0.12.0/tests/testClient1.py0100755001604000501700000000564010202425142016442 0ustar warnegclinicalimport gc import socket import threading import time import unittest import sys sys.path.insert(1, "..") import SOAPpy #SOAPpy.Config.debug=1 # global to shut down server quit = 0 def echoDateTime(dt): return dt def echo(s): """repeats a string twice""" return s + s def kill(): """tell the server to quit""" global quit quit = 1 def server1(): """start a SOAP server on localhost:8000""" print "Starting SOAP Server...", server = SOAPpy.Server.SOAPServer(addr=('127.0.0.1', 8000)) server.registerFunction(echoDateTime) server.registerFunction(echo) server.registerFunction(kill) print "Done." global quit while not quit: server.handle_request() quit = 0 print "Server shut down." class ClientTestCase(unittest.TestCase): server = None startup_timeout = 5 # seconds def setUp(self): '''This is run once before each unit test.''' serverthread = threading.Thread(target=server1, name="SOAPServer") serverthread.start() start = time.time() connected = False server = None while not connected and time.time() - start < self.startup_timeout: print "Trying to connect to the SOAP server...", try: server = SOAPpy.Client.SOAPProxy('127.0.0.1:8000') server.echo('Hello World') except socket.error, e: print "Failure:", e time.sleep(0.5) else: connected = True self.server = server print "Success." if not connected: raise 'Server failed to start.' def tearDown(self): '''This is run once after each unit test.''' print "Trying to shut down SOAP server..." if self.server is not None: self.server.kill() time.sleep(5) return 1 def testEcho(self): '''Test echo function.''' server = SOAPpy.Client.SOAPProxy('127.0.0.1:8000') s = 'Hello World' self.assertEquals(server.echo(s), s+s) def testNamedEcho(self): '''Test echo function.''' server = SOAPpy.Client.SOAPProxy('127.0.0.1:8000') s = 'Hello World' self.assertEquals(server.echo(s=s), s+s) def testEchoDateTime(self): '''Test passing DateTime objects.''' server = SOAPpy.Client.SOAPProxy('127.0.0.1:8000') dt = SOAPpy.Types.dateTimeType(data=time.time()) dt_return = server.echoDateTime(dt) self.assertEquals(dt_return, dt) # def testNoLeak(self): # '''Test for memory leak.''' # gc.set_debug(gc.DEBUG_SAVEALL) # for i in range(400): # server = SOAPpy.Client.SOAPProxy('127.0.0.1:8000') # s = 'Hello World' # server.echo(s) # gc.collect() # self.assertEquals(len(gc.garbage), 0) if __name__ == '__main__': unittest.main() SOAPpy-0.12.0/tests/testWSDL.py0100755001604001300100000001145010202425142015754 0ustar warnegcompstat#!/usr/bin/env python import unittest import os, re import sys sys.path.insert (1, '..') import SOAPpy ident = '$Id: testWSDL.py,v 1.2 2003/05/09 12:46:11 warnes Exp $' # Check for a web proxy definition in environment try: proxy_url=os.environ['http_proxy'] phost, pport = re.search('http://([^:]+):([0-9]+)', proxy_url).group(1,2) http_proxy = "%s:%s" % (phost, pport) except: http_proxy = None class IntegerArithmenticTestCase(unittest.TestCase): def setUp(self): self.wsdlstr1 = ''' Returns current temperature in a given U.S. zipcode ''' def testParseWsdlString(self): '''Parse XMethods TemperatureService wsdl from a string.''' wsdl = SOAPpy.WSDL.Proxy(self.wsdlstr1, http_proxy=http_proxy) self.assertEquals(len(wsdl.methods), 1) method = wsdl.methods.values()[0] self.assertEquals(method.methodName, 'getTemp') self.assertEquals(method.namespace, 'urn:xmethods-Temperature') self.assertEquals(method.location, 'http://services.xmethods.net:80/soap/servlet/rpcrouter') def testParseWsdlFile(self): '''Parse XMethods TemperatureService wsdl from a file.''' # figure out path to the test directory dir = os.path.abspath('.') fname = './TemperatureService.wsdl' try: f = file(fname) except (IOError, OSError): self.assert_(0, 'Cound not find wsdl file "%s"' % file) wsdl = SOAPpy.WSDL.Proxy(fname, http_proxy=http_proxy) self.assertEquals(len(wsdl.methods), 1) method = wsdl.methods.values()[0] self.assertEquals(method.methodName, 'getTemp') self.assertEquals(method.namespace, 'urn:xmethods-Temperature') self.assertEquals(method.location, 'http://services.xmethods.net:80/soap/servlet/rpcrouter') def testParseWsdlUrl(self): '''Parse XMethods TemperatureService wsdl from a url.''' wsdl = SOAPpy.WSDL.Proxy('http://www.xmethods.net/sd/2001/TemperatureService.wsdl', http_proxy=http_proxy) self.assertEquals(len(wsdl.methods), 1) method = wsdl.methods.values()[0] self.assertEquals(method.methodName, 'getTemp') self.assertEquals(method.namespace, 'urn:xmethods-Temperature') self.assertEquals(method.location, 'http://services.xmethods.net:80/soap/servlet/rpcrouter') def testGetTemp(self): '''Parse TemperatureService and call getTemp.''' zip = '01072' proxy = SOAPpy.WSDL.Proxy(self.wsdlstr1, http_proxy=http_proxy) temp = proxy.getTemp(zip) print 'Temperature at', zip, 'is', temp if __name__ == '__main__': unittest.main() SOAPpy-0.12.0/tests/testleak.py0100755001604001300100000000051410206521523016122 0ustar warnegcompstat#!/usr/bin/python import sys sys.path.insert(1, "..") import SOAPpy import time import gc import types gc.set_debug(gc.DEBUG_SAVEALL) for i in range(400): try: t = SOAPpy.SOAP.parseSOAPRPC('bad soap payload') except: pass gc.collect() if len(gc.garbage): print 'still leaking' else: print 'no leak' SOAPpy-0.12.0/tests/translateTest.py0100755001604001300100000000134310202425141017137 0ustar warnegcompstat#!/usr/bin/env python # Copyright (c) 2001 actzero, inc. All rights reserved. ident = '$Id: translateTest.py,v 1.5 2003/05/21 14:52:37 warnes Exp $' import os, re import sys sys.path.insert(1, "..") from SOAPpy import SOAPProxy # Check for a web proxy definition in environment try: proxy_url=os.environ['http_proxy'] phost, pport = re.search('http://([^:]+):([0-9]+)', proxy_url).group(1,2) proxy = "%s:%s" % (phost, pport) except: proxy = None server = SOAPProxy("http://services.xmethods.com:80/perl/soaplite.cgi", http_proxy=proxy) babel = server._ns('urn:xmethodsBabelFish#BabelFish') print babel.BabelFish(translationmode = "en_fr", sourcedata = "The quick brown fox did something or other") SOAPpy-0.12.0/tests/weatherTest.py0100755001604001300100000000132310202425141016577 0ustar warnegcompstat#!/usr/bin/env python ident = '$Id: weatherTest.py,v 1.4 2003/05/21 14:52:37 warnes Exp $' import os, re import sys sys.path.insert(1, "..") from SOAPpy import SOAPProxy # Check for a web proxy definition in environment try: proxy_url=os.environ['http_proxy'] phost, pport = re.search('http://([^:]+):([0-9]+)', proxy_url).group(1,2) proxy = "%s:%s" % (phost, pport) except: proxy = None SoapEndpointURL = 'http://services.xmethods.net:80/soap/servlet/rpcrouter' MethodNamespaceURI = 'urn:xmethods-Temperature' # Do it inline ala SOAP::LITE, also specify the actually ns server = SOAPProxy(SoapEndpointURL, http_proxy=proxy) print "inline", server._ns('ns1', MethodNamespaceURI).getTemp(zipcode='94063') SOAPpy-0.12.0/tests/whoisTest.py0100755001604001300100000000125110202425141016271 0ustar warnegcompstat#!/usr/bin/env python ident = '$Id: whoisTest.py,v 1.4 2003/05/21 14:52:37 warnes Exp $' import os, re import sys sys.path.insert(1, "..") from SOAPpy import SOAPProxy # Check for a web proxy definition in environment try: proxy_url=os.environ['http_proxy'] phost, pport = re.search('http://([^:]+):([0-9]+)', proxy_url).group(1,2) proxy = "%s:%s" % (phost, pport) except: proxy = None server = SOAPProxy("http://www.SoapClient.com/xml/SQLDataSoap.WSDL", http_proxy=proxy) print "whois>>", server.ProcessSRL(SRLFile="WHOIS.SRI", RequestName="whois", key = "microsoft.com") SOAPpy-0.12.0/tests/xmethods.py0100644001604000501700000000162510202425142016072 0ustar warnegclinical#!/usr/bin/env python # Copyright (c) 2001 actzero, inc. All rights reserved. ident = '$Id: xmethods.py,v 1.4 2003/12/18 06:31:50 warnes Exp $' import os, re import sys sys.path.insert(1, "..") from SOAPpy import SOAPProxy # Check for a web proxy definition in environment try: proxy_url=os.environ['http_proxy'] phost, pport = re.search('http://([^:]+):([0-9]+)', proxy_url).group(1,2) proxy = "%s:%s" % (phost, pport) except: proxy = None print "##########################################" print " SOAP services registered at xmethods.net" print "##########################################" server = SOAPProxy("http://www.xmethods.net/interfaces/query", namespace = 'urn:xmethods-delayed-quotes', http_proxy=proxy) names = server.getAllServiceNames() for item in names: print 'name:', item['name'] print 'id :', item['id'] print SOAPpy-0.12.0/tools/0040755001604000501700000000000010206655324013675 5ustar warnegclinicalSOAPpy-0.12.0/tools/interop2html.py0100755001604001300100000000617710202425153016744 0ustar warnegcompstat#!/usr/bin/env python import string import cgi ident = '$Id: interop2html.py,v 1.1.1.1 2001/06/27 21:36:14 cullman Exp $' lines = open('output.txt').readlines() #preserve the tally tally = lines[-6:] #whack the tally from lines lines = lines[:-6] table={} for line in lines: if line[:3] == ' ' or line == '>\n' : continue line = line[:-1] #delete end of line char row = [line[:line.find(': ')], line[line.find(': ')+2:]] #split server name from rest of line restofrow = row[1].split(' ',3) #break out method name, number, status code, status comment if len(restofrow) > 3: if restofrow[3].find('as expected') != -1: restofrow[2] = restofrow[2] + ' (as expected)' elif restofrow[3][:2] == '- ' : restofrow[3] = restofrow[3][2:] try: table[row[0]].append([restofrow[0],restofrow[2:]]) except KeyError: table[row[0]] = [[restofrow[0],restofrow[2:]]] print "" print "" print "
" for x in tally: z = x[:-1].split(":",1) print "" print "
Summary
",z[0],"",z[1],"

" c = 0 totalmethods = len(table[table.keys()[0]]) while c < totalmethods: print "
" print "" cols = [c, c + 1, c + 2] if c != 16: cols += [c + 3] for i in cols: try: header = table[table.keys()[0]][i][0] except: break print "" print "" l = table.keys() l.sort() for key in l: print "" for i in cols: try: status = table[key][i][1][0] except: break if status.find("succeed") != -1: bgcolor = "#339900" status = "Pass" elif status.find("expected") != -1: bgcolor = "#FF9900" hreftitle = table[key][i][1][1].replace("'","") # remove apostrophes from title properties popuphtml = '"' + cgi.escape(cgi.escape(table[key][i][1][1]).replace("'","'").replace('"',""")) + '"' status = "Failed (expected)" else: bgcolor = "#CC0000" hreftitle = table[key][i][1][1].replace("'","") # remove apostrophes from title properties popuphtml = '"' + cgi.escape(cgi.escape(table[key][i][1][1]).replace("'","'").replace('"',""")) + '"' status = "Failed" print "" print "" print "
",header,"
", key , "" , status , "
" c = c + len(cols) print "" SOAPpy-0.12.0/validate/0040755001604000501700000000000010206655324014326 5ustar warnegclinicalSOAPpy-0.12.0/validate/server.pem0100755001604001300100000000657110202425154016404 0ustar warnegcompstat$Id: server.pem,v 1.1.1.1 2001/06/27 21:36:14 cullman Exp $ # Test certificate generated using CA.pl written by Steve Hensen # bundled with OpenSSL. # # Steps used to generate server.pem : # a)CA.pl -newca (creates a new CA heirarchy) # b)CA.pl -newreq (creates a new certificate request) # c)CA.pl -sign (sign the certificate request) # d)openssl rsa newkey.pem (unencrypt the private key) # e)Copy the certificate from newcert.pem, the unencrypted RSA # private key from newkey.pem and the certificate request from # newreq.pem and create server.pem to contain all three of them. -----BEGIN CERTIFICATE----- MIIDhjCCAu+gAwIBAgIBATANBgkqhkiG9w0BAQQFADCBgDELMAkGA1UEBhMCVVMx CzAJBgNVBAgTAkNBMQswCQYDVQQHEwJSQzEQMA4GA1UEChMHYWN0emVybzETMBEG A1UECxMKdGVjaG5vbG9neTEPMA0GA1UEAxMGc3lzYWRtMR8wHQYJKoZIhvcNAQkB FhBpbmZvQGFjdHplcm8uY29tMB4XDTAxMDUxNjIyMzkwM1oXDTAyMDUxNjIyMzkw M1owgYAxCzAJBgNVBAYTAlVTMQswCQYDVQQIEwJDQTELMAkGA1UEBxMCUkMxEDAO BgNVBAoTB2FjdHplcm8xEzARBgNVBAsTCnRlY2hub2xvZ3kxDzANBgNVBAMTBnN5 c2FkbTEfMB0GCSqGSIb3DQEJARYQaW5mb0BhY3R6ZXJvLmNvbTCBnzANBgkqhkiG 9w0BAQEFAAOBjQAwgYkCgYEAyRBB6l+DI3aMNeYf7IuodvZ9nNxnfQHVnGyRtwhb 1g2tugTwFsE67oHA5qvwaDBILtsqkr9agXYDbZwJmV58xtBY675tibf7/1R8mcDO d4Dremdn0CMyk4+n6Z8GpLJ59TZ3y98DXUOqbLvzzltDz0si2XVa8G7f4K5k/xxB GZcCAwEAAaOCAQwwggEIMAkGA1UdEwQCMAAwLAYJYIZIAYb4QgENBB8WHU9wZW5T U0wgR2VuZXJhdGVkIENlcnRpZmljYXRlMB0GA1UdDgQWBBT/DGQzyXlwLXMWMaT4 lp9O928tvzCBrQYDVR0jBIGlMIGigBSdjwZua1AI3XoUtwLyW0Optc/4O6GBhqSB gzCBgDELMAkGA1UEBhMCVVMxCzAJBgNVBAgTAkNBMQswCQYDVQQHEwJSQzEQMA4G A1UEChMHYWN0emVybzETMBEGA1UECxMKdGVjaG5vbG9neTEPMA0GA1UEAxMGc3lz YWRtMR8wHQYJKoZIhvcNAQkBFhBpbmZvQGFjdHplcm8uY29tggEAMA0GCSqGSIb3 DQEBBAUAA4GBABQodV+rrwMsvTEEza08EeS1Rf2ISuzh6e9VbfiJLVB5Xv1SeEt1 sOv8ETZyN/4OXvZWQG/5md/5NNkf5K6CeKiwctztkyKTXdPIFS6FJVZdduWhiWPF 6gutQgOogtpCHTLwdSDk75n5MXFlnehORqOREMqqCJtFlHMEV1211Ssi -----END CERTIFICATE----- -----BEGIN RSA PRIVATE KEY----- MIICWwIBAAKBgQDJEEHqX4Mjdow15h/si6h29n2c3Gd9AdWcbJG3CFvWDa26BPAW wTrugcDmq/BoMEgu2yqSv1qBdgNtnAmZXnzG0Fjrvm2Jt/v/VHyZwM53gOt6Z2fQ IzKTj6fpnwaksnn1NnfL3wNdQ6psu/POW0PPSyLZdVrwbt/grmT/HEEZlwIDAQAB AoGALcho6gBjsRCObrt+63MFokkQY0aAviNLy7mhGIdrufsVYvU64kOPsr2S+jOO o3rTBPBc6ltuNWp072GHggfU61y4Bvfqxq2IRRDVH+yjmsdKSPYoBSIs3ZKjwJGx pFAT1nfNP05MfqUwZm8HbTnqqakrWm0p53Zvv6NP3vNjmzECQQD6EK5a7bD7VSVz MawUgUkZGZUtForbZL5nwIo1j94/TbnxUuuwej0MiCJ0MQsPCY/LML/gYaxTdQOg qYkGyIAPAkEAzdXbgTc81FflECxc5CXw9Yi1g0+nMkH5drlk+sct5dCzokPJZBQ3 oxIaQcJP/rUMgG0A2mSpOnbAHNHX+z/F+QJAEQGbafGqTJ1wy5HAOzDDsOJNg+B5 lwwV6uZsP9JF8hYuJBxYjQrzJewIM9C2CNLEpbPuCKt71b0qfv2opP5zvwJAMyjh WveAvgJuo5tzJx2rC0wEWXPVya8OMw0XZSFWbhV2YHFav+4qefSI5ClIurUDO3Rc TuvQCAD19PPPK9qI+QJADpbLUWw8NsMaHpJgeigXVIsRtJcroDw2r87bJxsgcgQz CsIH32VLvFOmpJdwnji6GX+vD2i0UH4ythnMCq4NUg== -----END RSA PRIVATE KEY----- -----BEGIN CERTIFICATE REQUEST----- MIIBwTCCASoCAQAwgYAxCzAJBgNVBAYTAlVTMQswCQYDVQQIEwJDQTELMAkGA1UE BxMCUkMxEDAOBgNVBAoTB2FjdHplcm8xEzARBgNVBAsTCnRlY2hub2xvZ3kxDzAN BgNVBAMTBnN5c2FkbTEfMB0GCSqGSIb3DQEJARYQaW5mb0BhY3R6ZXJvLmNvbTCB nzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAyRBB6l+DI3aMNeYf7IuodvZ9nNxn fQHVnGyRtwhb1g2tugTwFsE67oHA5qvwaDBILtsqkr9agXYDbZwJmV58xtBY675t ibf7/1R8mcDOd4Dremdn0CMyk4+n6Z8GpLJ59TZ3y98DXUOqbLvzzltDz0si2XVa 8G7f4K5k/xxBGZcCAwEAAaAAMA0GCSqGSIb3DQEBBAUAA4GBAIoUVScm4lAkfo1o n4b2Mpq3oV+dZnnTgYog4vmn/2UF0OSSTWlWPvINVkRtfg0iskZsbcWGn+RDY5e/ aTqN7Xz+BV5XlbQLZzuQdKPsfBcZ766El1chmUuO5tELpFtQkmlAgAXRMuh0Xeb+ A9wmVNyCMU6/+ajqwO642nSPOLM0 -----END CERTIFICATE REQUEST----- SOAPpy-0.12.0/validate/silab.servers0100755001604001300100000002461110202425154017073 0ustar warnegcompstat# This list of servers was taken from the SOAPBuilders Interoperability Lab # (http://www.xmethods.net/ilab/ilab.html) 4/23/01. # # $Id: silab.servers,v 1.1.1.1 2001/06/27 21:36:14 cullman Exp $ Name: SOAP.py 0.9.6 (1999) Endpoint: http://208.177.157.221:9595/xmethodsInterop SOAPAction: "urn:soapinterop" Namespace: http://soapinterop.org/ Name: SOAP.py 0.9.6 (2001) Like: SOAP.py 0.9.6 (1999) Style: 2001 Name: Apache 2.1 WSDL: http://www.xmethods.net/sd/interop/ApacheInterop11.wsdl Endpoint: http://nagoya.apache.org:5089/soap/servlet/rpcrouter SOAPAction: "urn:soapinterop" Namespace: http://soapinterop.org/ Nonfunctional: echoFloatINF server returns 'Infinity' instead of 'INF' Nonfunctional: echoFloatNegINF server returns '-Infinity' instead of '-INF' Nonfunctional: echoStruct WSDL specifies 'inputStruct' parameter, method takes 'echoStruct' parameter Nonfunctional: echoDate not implemented by server Nonfunctional: echoBase64 not implemented by server Name: EasySoap++ WSDL: http://easysoap.sourceforge.net/interop.wsdl Endpoint: http://www.xmethods.net/c/easysoap.cgi SOAPAction: "urn:soapinterop" Namespace: http://soapinterop.org/ Nonfunctional: actorShouldFail server doesn't fail when mustUnderstand=1 Nonfunctional: mustUnderstandEqualsOne server doesn't fail when mustUnderstand=1 Name: eSoapServer Endpoint: http://www.connecttel.com/cgi-bin/esoapserver.cgi SOAPAction: "urn:soapinterop" Namespace: http://soapinterop.org/ Name: Frontier 7.0b43 Endpoint: http://www.soapware.org:80/xmethodsInterop SOAPAction: "/xmethodsInterop" Namespace: http://soapinterop.org/ Style: 2001 Name: 4S4C 1.3.3 WSDL: http://soap.4s4c.com/ilab/soap.asp?WSDL Endpoint: http://soap.4s4c.com/ilab/soap.asp SOAPAction: "urn:soapinterop" Namespace: http://soapinterop.org/ Nonfunctional: echoFloatINF server doesn't understand 'INF' Nonfunctional: echoFloatNaN server doesn't understand 'NaN' Nonfunctional: echoFloatNegINF server doesn't understand '-INF' Name: GLUE WSDL: http://209.61.190.164:8004/glue/http://soapinterop.org/.wsdl Endpoint: http://209.61.190.164:8004/glue/http://soapinterop.org/ SOAPAction: "urn:soapinterop" Namespace: http://soapinterop.org/ Nonfunctional: actorShouldFail server doesn't fail when mustUnderstand=1 Nonfunctional: mustUnderstandEqualsOne server doesn't fail when mustUnderstand=1 Name: HP SOAP Page: http://soap.bluestone.com/interop/ WSDL: http://soap.bluestone.com:80/interop/EchoService/EchoService.wsdl Endpoint: http://soap.bluestone.com:80/scripts/SaISAPI.dll/SaServletEngine.class/hp-soap/soap/rpc/interop/EchoService SOAPAction: "urn:soapinterop" Namespace: http://soapinterop.org/ Name: IDOOX WASP 1.0 Page: http://soap.idoox.net:7080/IopResults/jsp/index.jsp WSDL: http://soap.idoox.net:7080/soap/services/ilab.wsdl Endpoint: http://soap.idoox.net:7080/soap/servlet/soap/ilab SOAPAction: "urn:soapinterop" Namespace: http://soapinterop.org/ Name: Kafka XSLT Interop Service Page: http://www.vbxml.com/soapworkshop/services/kafka10/services/interop.htm WSDL: http://www.vbxml.com/soapworkshop/services/kafka10/services/endpoint.asp?service=ilab&type=wsdl Endpoint: http://www.vbxml.com/soapworkshop/services/kafka10/services/endpoint.asp?service=ilab SOAPAction: "urn:soapinterop" Namespace: http://soapinterop.org/ Nonfunctional: actorShouldFail server doesn't fail when mustUnderstand=1 Nonfunctional: echoDate not implemented by server Nonfunctional: echoBase64 not implemented by server Nonfunctional: mustUnderstandEqualsOne server doesn't fail when mustUnderstand=1 Name: MS ATL Server WSDL: http://4.34.185.52/ilab/ilab.wsdl Endpoint: http://4.34.185.52/ilab/ilab.dll?Handler=Default SOAPAction: "urn:soapinterop" Namespace: http://soapinterop.org/ Style: 2001 Typed: no Name: MS SOAP Toolkit 2.0 (typed) Page: http://www.mssoapinterop.org/stk/ilab.htm WSDL: http://www.mssoapinterop.org/stk/InteropTyped.wsdl Endpoint: http://www.mssoapinterop.org/stk/InteropTyped.wsdl SOAPAction: "urn:soapinterop" Namespace: http://soapinterop.org/ Nonfunctional: echoBase64 return value doesn't have a type Nonfunctional: echoFloatINF server doesn't understand 'INF' Nonfunctional: echoFloatNaN server doesn't understand 'NaN' Nonfunctional: echoFloatNegINF server doesn't understand '-INF' Name: MS SOAP Toolkit 2.0 (untyped) Like: MS SOAP Toolkit 2.0 (typed) WSDL: http://www.mssoapinterop.org/stk/Interop.wsdl Endpoint: http://www.mssoapinterop.org/stk/Interop.wsdl Typed: no Functional: echoBase64 Name: MS .NET Beta 2 (typed) WSDL: http://www.mssoapinterop.org/test/typed.asmx?WSDL Endpoint: http://www.mssoapinterop.org/test/typed.asmx SOAPAction: "http://soapinterop.org/%(methodname)s" Namespace: http://soapinterop.org/ Nonfunctional: actorShouldFail server doesn't fail when mustUnderstand=1 Nonfunctional: mustUnderstandEqualsOne server doesn't fail when mustUnderstand=1 Nonfunctional: echoDate server doesn't recognize time zone of Z Nonfunctional: echoBase64 not implemented by server Name: MS .NET Beta 2 (untyped) Like: MS .NET Beta 2 (typed) WSDL: http://www.mssoapinterop.org/test/simple.asmx?WSDL Endpoint: http://www.mssoapinterop.org/test/simple.asmx Typed: no Name: MS .NET Remoting (1999 typed) WSDL: http://www.mssoapinterop.org/DotNetRemoting1999Typed/InteropService.WSDL Endpoint: http://www.mssoapinterop.org/DotNetRemoting1999Typed/InteropService.soap SOAPAction: "urn:soapinterop" Namespace: http://soapinterop.org/ Name: MS .NET Remoting (1999 untyped) WSDL: http://www.mssoapinterop.org/DotNetRemoting1999/InteropService.WSDL Endpoint: http://www.mssoapinterop.org/DotNetRemoting1999/InteropService.soap SOAPAction: "urn:soapinterop" Namespace: http://soapinterop.org/ Typed: no Name: MS .NET Remoting (2001 typed) WSDL: http://www.mssoapinterop.org/DotNetRemoting2001Typed/InteropService.WSDL Endpoint: http://www.mssoapinterop.org/DotNetRemoting2001Typed/InteropService.soap SOAPAction: "urn:soapinterop" Namespace: http://soapinterop.org/ Style: 2001 Name: MS .NET Remoting (2001 untyped) WSDL: http://www.mssoapinterop.org/DotNetRemoting2001/InteropService.WSDL Endpoint: http://www.mssoapinterop.org/DotNetRemoting2001/InteropService.soap SOAPAction: "urn:soapinterop" Namespace: http://soapinterop.org/ Typed: no Style: 2001 Name: Phalanx WSDL: http://www.phalanxsys.com/interop/interop.wsdl Endpoint: http://www.phalanxsys.com/interop/listener.asp SOAPAction: "urn:soapinterop" Namespace: http://soapinterop.org/ Style: 2001 Name: SOAP::Lite WSDL: http://services.soaplite.com/interop.wsdl Endpoint: http://services.soaplite.com/interop.cgi SOAPAction: "urn:soapinterop" Namespace: http://soapinterop.org/ Name: SOAPR4 (1999) Endpoint: http://www.jin.gr.jp/~nahi/Ruby/SOAP4R/SOAPBuildersInterop/1999/ SOAPAction: "urn:soapinterop" Namespace: http://soapinterop.org/ Nonfunctional: actorShouldFail server doesn't fail when mustUnderstand=1 Nonfunctional: mustUnderstandEqualsOne server doesn't fail when mustUnderstand=1 Nonfunctional: echoVoid server return nil element instead of no elements Name: SOAPR4 (2001) Like: SOAPR4 (1999) Endpoint: http://www.jin.gr.jp/~nahi/Ruby/SOAP4R/SOAPBuildersInterop/ Style: 2001 Name: SOAPx4 for PHP Endpoint: http://dietrich.ganx4.com/soapx4/soap.php SOAPAction: "urn:soapinterop" Namespace: http://soapinterop.org/ Nonfunctional: actorShouldPass server returns type with no namespace Nonfunctional: actorShouldFail server doesn't fail when mustUnderstand=1 Nonfunctional: echoDate not implemented by server Nonfunctional: echoBase64 not implemented by server Nonfunctional: echoFloat server returns type with no namespace Nonfunctional: echoFloatArray server returns array elements as strings Nonfunctional: echoFloatINF server returns type with no namespace Nonfunctional: echoFloatNaN server returns type with no namespace Nonfunctional: echoFloatNegINF returns float 0 instead of -INF and type has no namespace Nonfunctional: echoFloatNegZero returns 0 instead of -0 and type has no namespace Nonfunctional: echoInteger server returns type with no namespace Nonfunctional: echoIntegerArray server returns array elements as strings Nonfunctional: echoString server responds with fault when sent '<&>" Nonfunctional: echoStringArray server responds with fault when an array element is '<&>" Nonfunctional: echoVeryLargeFloat server returns type with no namespace Nonfunctional: echoVerySmallFloat server returns type with no namespace Nonfunctional: echoVoid server doesn't return anything Nonfunctional: mustUnderstandEqualsOne server doesn't fail when mustUnderstand=1 Nonfunctional: mustUnderstandEqualsZero server returns type with no namespace Name: SoapRMI Endpoint: http://rainier.extreme.indiana.edu:1568 SOAPAction: "urn:soapinterop" Namespace: http://soapinterop.org/ Nonfunctional: echoDate not implemented by server Nonfunctional: echoBase64 not implemented by server Name: SQLData SOAP Server WSDL: http://www.SoapClient.com/interop/SQLDataInterop.wsdl Endpoint: http://www.soapclient.com/interop/sqldatainterop.wsdl SOAPAction: "urn:soapinterop" Namespace: http://soapinterop.org/ Name: White Mesa SOAP RPC 2.2 (1999) WSDL: http://www.whitemesa.net/wsdl/interop.wsdl Endpoint: http://www.whitemesa.net/interop SOAPAction: "urn:soapinterop" Namespace: http://soapinterop.org/ Nonfunctional: echoFloatINF server doesn't understand 'INF' Nonfunctional: echoFloatNaN server doesn't understand 'NaN' Nonfunctional: echoFloatNegINF server doesn't understand '-INF' Nonfunctional: echoDate not implemented by server Nonfunctional: echoBase64 server returns data containing control character Style: 1999 Typed: no Name: White Mesa SOAP RPC 2.2 (2001) WSDL: http://www.whitemesa.net/wsdl/std/interop.wsdl Endpoint: http://www.whitemesa.net/interop/std SOAPAction: http://soapinterop.org/ Namespace: http://soapinterop.org/ Nonfunctional: echoFloatINF server doesn't understand 'INF' Nonfunctional: echoFloatNaN server doesn't understand 'NaN' Nonfunctional: echoFloatNegINF server doesn't understand '-INF' Nonfunctional: echoDate not implemented by server Nonfunctional: echoBase64 server returns data containing control character Style: 2001 Typed: no Name: Zolera SOAP Infrastructure Endpoint: http://63.142.188.184:7000/ SOAPAction: urn:soapinterop Namespace: http://soapinterop.org/ Style: 2001 Nonfunctional: actorShouldPass server claims message is unparsable Nonfunctional: echoBase64 server returns data with invalid type Nonfunctional: echoVoid server doesn't return an empty return value Nonfunctional: mustUnderstandEqualsZero server claims message is unparsable SOAPpy-0.12.0/validate/silabclient.py0100755001604001300100000005462210202425154017236 0ustar warnegcompstat#!/usr/bin/env python # Copyright (c) 2001 actzero, inc. All rights reserved. # This set of clients validates when run against the servers in # silab.servers. import copy import fileinput import getopt import re import string import sys import time import traceback sys.path.insert (1, '..') from SOAPpy import SOAP SOAP.Config.typesNamespace = SOAP.NS.XSD3 SOAP.Config.typesNamespace = SOAP.NS.XSD3 ident = '$Id: silabclient.py,v 1.2 2003/03/08 05:10:01 warnes Exp $' DEFAULT_SERVERS_FILE = 'silab.servers' DEFAULT_METHODS = \ ( 'actorShouldPass', 'actorShouldFail', 'echoDate', 'echoBase64', 'echoFloat', 'echoFloatArray', 'echoFloatINF', 'echoFloatNaN', 'echoFloatNegINF', 'echoFloatNegZero', 'echoInteger', 'echoIntegerArray', 'echoString', 'echoStringArray', 'echoStruct', 'echoStructArray', 'echoVeryLargeFloat', 'echoVerySmallFloat', 'echoVoid', 'mustUnderstandEqualsOne', 'mustUnderstandEqualsZero', ) def usage (error = None): sys.stdout = sys.stderr if error != None: print error print """usage: %s [options] [server ...] If a long option shows an argument is mandatory, it's mandatory for the equivalent short option also. -?, --help display this usage -d, --debug turn on debugging in the SOAP library -e, --exit-on-failure exit on the first (unexpected) failure -h, --harsh turn on harsh testing: - look for the documented error code from mustUnderstand failures - use non-ASCII strings in the string tests -i, --invert test servers *not* in the list of servers given -m, --method=METHOD#[,METHOD#...] call only the given methods, specify a METHOD# of ? for the list of method numbers -n, --no-stats, --no-statistics don't display success and failure statistics -N, --no-boring-stats, --no-boring-statistics only display unexpected failures and unimplemented tests, and only if non-zero -o, --output=TYPE turn on output, TYPE is one or more of s(uccess), f(ailure), n(ot implemented), F(ailed (as expected)), a(ll) [f] -s, --servers=FILE use FILE as list of servers to test [%s] -t, --stacktrace print a stack trace on each unexpected failure -T, --always-stacktrace print a stack trace on any failure """ % (sys.argv[0], DEFAULT_SERVERS_FILE), sys.exit (0) def methodUsage (): sys.stdout = sys.stderr print "Methods are specified by number. Multiple methods can be " \ "specified using a\ncomma-separated list of numbers or ranges. " \ "For example 1,4-6,8 specifies\nmethods 1, 4, 5, 6, and 8.\n" print "The available methods are:\n" half = (len (DEFAULT_METHODS) + 1) / 2 for i in range (half): print "%4d. %-25s" % (i + 1, DEFAULT_METHODS[i]), if i + half < len (DEFAULT_METHODS): print "%4d. %-25s" % (i + 1 + half, DEFAULT_METHODS[i + half]), print sys.exit (0) # as borrowed from jake.soapware.org for float compares. def nearlyeq (a, b, prec = 1e-7): return abs (a - b) <= abs (a) * prec def readServers (file): servers = [] names = {} cur = None f = fileinput.input(file) for line in f: if line[0] == '#': continue if line == '' or line[0] == '\n': cur = None continue if cur == None: cur = {'nonfunctional': {}, '_line': f.filelineno(), '_file': f.filename()} tag = None servers.append (cur) if line[0] in string.whitespace: if tag == 'nonfunctional': value = method + ' ' + cur[tag][method] else: value = cur[tag] value += ' ' + line.strip () elif line[0] == '_': raise ValueError, \ "%s, line %d: can't have a tag starting with `_'" % \ (f.filename(), f.filelineno()) else: tag, value = line.split (':', 1) tag = tag.strip ().lower () value = value.strip () if value[0] == '"' and value[-1] == '"': value = value[1:-1] if tag == 'typed': if value.lower() in ('0', 'no', 'false'): value = 0 elif value.lower() in ('1', 'yes', 'false'): value = 1 else: raise ValueError, \ "%s, line %d: unknown typed value `%s'" % \ (f.filename(), f.filelineno(), value) elif tag == 'name': if names.has_key(value): old = names[value] raise ValueError, \ "%s, line %d: already saw a server named `%s' " \ "(on line %d of %s)" % \ (f.filename(), f.filelineno(), value, old['_line'], old['_file']) names[value] = cur if tag == 'nonfunctional': value = value.split (' ', 1) + [''] method = value[0] cur[tag][method] = value[1] elif tag == 'functional': try: del cur['nonfunctional'][value] except: raise ValueError, \ "%s, line %d: `%s' not marked nonfunctional" % \ (f.filename(), f.filelineno(), value) elif tag == 'like': try: new = copy.deepcopy(names[value]) except: raise ValueError, \ "%s, line %d: don't know about a server named `%s'" % \ (f.filename(), f.filelineno(), value) # This is so we don't lose the nonfunctional methods in new or # in cur new['nonfunctional'].update(cur['nonfunctional']) del cur['nonfunctional'] new.update(cur) # This is because servers and possibly names has a reference to # cur, so we have to keep working with cur so changes are # reflected in servers and names. cur.update(new) else: cur[tag] = value return servers def str2list (s): l = {} for i in s.split (','): if i.find ('-') != -1: i = i.split ('-') for i in range (int (i[0]),int (i[1]) + 1): l[i] = 1 else: l[int (i)] = 1 l = l.keys () l.sort () return l def testActorShouldPass (server, action, harsh): test = 42 server = server._sa (action % {'methodname': 'echoInteger'}) hd = SOAP.headerType () hd.InteropTestHeader = SOAP.stringType ("This shouldn't fault because " "the mustUnderstand attribute is 0") hd.InteropTestHeader._setMustUnderstand (0) hd.InteropTestHeader._setActor ( 'http://schemas.xmlsoap.org/soap/actor/next') server = server._hd (hd) result = server.echoInteger (inputInteger = test) if not SOAP.Config.typed: result = int (result) if result != test: raise Exception, "expected %s, got %s" % (test, result) def testActorShouldFail (server, action, harsh): test = 42 server = server._sa (action % {'methodname': 'echoInteger'}) hd = SOAP.headerType () hd.InteropTestHeader = SOAP.stringType ("This should fault because " "the mustUnderstand attribute is 1") hd.InteropTestHeader._setMustUnderstand (1) hd.InteropTestHeader._setActor ( 'http://schemas.xmlsoap.org/soap/actor/next') server = server._hd (hd) try: result = server.echoInteger (inputInteger = test) except SOAP.faultType, e: if harsh and e.faultcode != 'SOAP-ENV:MustUnderstand': raise AttributeError, "unexpected faultcode %s" % e.faultcode return raise Exception, "should fail, succeeded with %s" % result def testEchoFloat (server, action, harsh): server = server._sa (action % {'methodname': 'echoFloat'}) for test in (0.0, 1.0, -1.0, 3853.33333333): result = server.echoFloat (inputFloat = test) if not SOAP.Config.typed: result = float (result) if not nearlyeq (result, test): raise Exception, "expected %.8f, got %.8f" % (test, result) def testEchoFloatArray (server, action, harsh): test = [0.0, 1.0, -1.0, 3853.33333333] server = server._sa (action % {'methodname': 'echoFloatArray'}) result = server.echoFloatArray (inputFloatArray = test) for i in range (len (test)): if not SOAP.Config.typed: result[i] = float (result[i]) if not nearlyeq (result[i], test[i]): raise Exception, "@ %d expected %s, got %s" % \ (i, repr (test), repr (result)) def testEchoFloatINF (server, action, harsh): try: test = float ('INF') except: test = float (1e300**2) server = server._sa (action % {'methodname': 'echoFloat'}) result = server.echoFloat (inputFloat = test) if not SOAP.Config.typed: result = float (result) if result != test: raise Exception, "expected %.8f, got %.8f" % (test, result) def testEchoFloatNaN (server, action, harsh): try: test = float ('NaN') except: test = float (0.0) server = server._sa (action % {'methodname': 'echoFloat'}) result = server.echoFloat (inputFloat = test) if not SOAP.Config.typed: result = float (result) if result != test: raise Exception, "expected %.8f, got %.8f" % (test, result) def testEchoFloatNegINF (server, action, harsh): try: test = float ('-INF') except: test = float (-1e300**2) server = server._sa (action % {'methodname': 'echoFloat'}) result = server.echoFloat (inputFloat = test) if not SOAP.Config.typed: result = float (result) if result != test: raise Exception, "expected %.8f, got %.8f" % (test, result) def testEchoFloatNegZero (server, action, harsh): test = float ('-0.0') server = server._sa (action % {'methodname': 'echoFloat'}) result = server.echoFloat (inputFloat = test) if not SOAP.Config.typed: result = float (result) if result != test: raise Exception, "expected %.8f, got %.8f" % (test, result) def testEchoInteger (server, action, harsh): server = server._sa (action % {'methodname': 'echoInteger'}) for test in (0, 1, -1, 3853): result = server.echoInteger (inputInteger = test) if not SOAP.Config.typed: result = int (result) if result != test: raise Exception, "expected %.8f, got %.8f" % (test, result) def testEchoIntegerArray (server, action, harsh): test = [0, 1, -1, 3853] server = server._sa (action % {'methodname': 'echoIntegerArray'}) result = server.echoIntegerArray (inputIntegerArray = test) for i in range (len (test)): if not SOAP.Config.typed: result[i] = int (result[i]) if result[i] != test[i]: raise Exception, "@ %d expected %s, got %s" % \ (i, repr (test), repr (result)) relaxedStringTests = ['', 'Hello', '\'<&>"',] relaxedStringTests = ['Hello', '\'<&>"',] harshStringTests = ['', 'Hello', '\'<&>"', u'\u0041', u'\u00a2', u'\u0141', u'\u2342', u'\'<\u0041&>"', u'\'<\u00a2&>"', u'\'<\u0141&>"', u'\'<\u2342&>"',] def testEchoString (server, action, harsh): if harsh: test = harshStringTests else: test = relaxedStringTests server = server._sa (action % {'methodname': 'echoString'}) for test in test: result = server.echoString (inputString = test) if result != test: raise Exception, "expected %s, got %s" % \ (repr (test), repr (result)) def testEchoStringArray (server, action, harsh): if harsh: test = harshStringTests else: test = relaxedStringTests server = server._sa (action % {'methodname': 'echoStringArray'}) result = server.echoStringArray (inputStringArray = test) if result != test: raise Exception, "expected %s, got %s" % (repr (test), repr (result)) def testEchoStruct (server, action, harsh): test = {'varFloat': 2.256, 'varInt': 474, 'varString': 'Utah'} server = server._sa (action % {'methodname': 'echoStruct'}) result = server.echoStruct (inputStruct = test) if not SOAP.Config.typed: result.varFloat = float (result.varFloat) result.varInt = int (result.varInt) if not nearlyeq (test['varFloat'], result.varFloat): raise Exception, ".varFloat expected %s, got %s" % \ (i, repr (test['varFloat']), repr (result.varFloat)) for i in test.keys (): if i == 'varFloat': continue if test[i] != getattr (result, i): raise Exception, ".%s expected %s, got %s" % \ (i, repr (test[i]), repr (getattr (result, i))) def testEchoStructArray (server, action, harsh): test = [{'varFloat': -5.398, 'varInt': -546, 'varString': 'West Virginia'}, {'varFloat': -9.351, 'varInt': -641, 'varString': 'New Mexico'}, {'varFloat': 1.495, 'varInt': -819, 'varString': 'Missouri'}] server = server._sa (action % {'methodname': 'echoStructArray'}) result = server.echoStructArray (inputStructArray = test) for s in range (len (test)): if not SOAP.Config.typed: result[s].varFloat = float (result[s].varFloat) result[s].varInt = int (result[s].varInt) if not nearlyeq (test[s]['varFloat'], result[s].varFloat): raise Exception, \ "@ %d.varFloat expected %s, got %s" % \ (s, repr (test[s]['varFloat']), repr (result[s].varFloat)) for i in test[s].keys (): if i == 'varFloat': continue if test[s][i] != getattr (result[s], i): raise Exception, "@ %d.%s expected %s, got %s" % \ (s, i, repr (test[s][i]), repr (getattr (result[s], i))) def testEchoVeryLargeFloat (server, action, harsh): test = 2.2535e29 server = server._sa (action % {'methodname': 'echoFloat'}) result = server.echoFloat (inputFloat = test) if not SOAP.Config.typed: result = float (result) if not nearlyeq (result, test): raise Exception, "expected %s, got %s" % (repr (test), repr (result)) def testEchoVerySmallFloat (server, action, harsh): test = 2.2535e29 server = server._sa (action % {'methodname': 'echoFloat'}) result = server.echoFloat (inputFloat = test) if not SOAP.Config.typed: result = float (result) if not nearlyeq (result, test): raise Exception, "expected %s, got %s" % (repr (test), repr (result)) def testEchoVoid (server, action, harsh): server = server._sa (action % {'methodname': 'echoVoid'}) result = server.echoVoid () for k in result.__dict__.keys (): if k[0] != '_': raise Exception, "expected an empty structType, got %s" % \ repr (result.__dict__) def testMustUnderstandEqualsOne (server, action, harsh): test = 42 server = server._sa (action % {'methodname': 'echoInteger'}) hd = SOAP.headerType () hd.MustUnderstandThis = SOAP.stringType ("This should fault because " "the mustUnderstand attribute is 1") hd.MustUnderstandThis._setMustUnderstand (1) server = server._hd (hd) try: result = server.echoInteger (inputInteger = test) except SOAP.faultType, e: if harsh and e.faultcode != 'SOAP-ENV:MustUnderstand': raise AttributeError, "unexpected faultcode %s" % e.faultcode return raise Exception, "should fail, succeeded with %s" % result def testMustUnderstandEqualsZero (server, action, harsh): test = 42 server = server._sa (action % {'methodname': 'echoInteger'}) hd = SOAP.headerType () hd.MustUnderstandThis = SOAP.stringType ("This shouldn't fault because " "the mustUnderstand attribute is 0") hd.MustUnderstandThis._setMustUnderstand (0) server = server._hd (hd) result = server.echoInteger (inputInteger = test) if not SOAP.Config.typed: result = int (result) if result != test: raise Exception, "expected %s, got %s" % (test, result) def testEchoDate (server, action, harsh): test = time.gmtime (time.time ()) server = server._sa (action % {'methodname': 'echoDate'}) if SOAP.Config.namespaceStyle == '1999': result = server.echoDate (inputDate = SOAP.timeInstantType (test)) else: result = server.echoDate (inputDate = SOAP.dateTimeType (test)) if not SOAP.Config.typed and type (result) in (type (''), type (u'')): p = SOAP.SOAPParser() result = p.convertDateTime(result, 'timeInstant') if result != test[:6]: raise Exception, "expected %s, got %s" % (repr (test), repr (result)) def testEchoBase64 (server, action, harsh): test = '\x00\x10\x20\x30\x40\x50\x60\x70\x80\x90\xa0\xb0\xc0\xd0\xe0\xf0' server = server._sa (action % {'methodname': 'echoBase64'}) result = server.echoBase64 (inputBase64 = SOAP.base64Type (test)) if not SOAP.Config.typed: import base64 result = base64.decodestring(result) if result != test: raise Exception, "expected %s, got %s" % (repr (test), repr (result)) def main (): stats = 1 total = 0 fail = 0 failok = 0 succeed = 0 exitonfailure = 0 harsh = 0 invert = 0 printtrace = 0 methodnums = None notimp = 0 output = 'f' servers = DEFAULT_SERVERS_FILE started = time.time () try: opts, args = getopt.getopt (sys.argv[1:], '?dehim:nNo:s:tT', ['help', 'debug', 'exit-on-failure', 'harsh', 'invert', 'method', 'no-stats', 'no-statistics', 'no-boring-statistics', 'no-boring-stats', 'output', 'servers=', 'stacktrace', 'always-stacktrace']) for opt, arg in opts: if opt in ('-?', '--help'): usage () elif opt in ('-d', '--debug'): SOAP.Config.debug = 1 elif opt in ('-h', '--harsh'): harsh = 1 elif opt in ('-i', '--invert'): invert = 1 elif opt in ('-e', '--exit-on-failure'): exitonfailure = 1 elif opt in ('-m', '--method'): if arg == '?': methodUsage () methodnums = str2list (arg) elif opt in ('-n', '--no-stats', '--no-statistics'): stats = 0 elif opt in ('-N', '--no-boring-stats', '--no-boring-statistics'): stats = -1 elif opt in ('-o', '--output'): output = arg elif opt in ('-s', '--servers'): servers = arg elif opt in ('-t', '--stacktrace'): printtrace = 1 elif opt in ('-T', '--always-stacktrace'): printtrace = 2 else: raise AttributeError, \ "Recognized but unimplemented option `%s'" % opt except SystemExit: raise except: usage (sys.exc_info ()[1]) if 'a' in output: output = 'fFns' servers = readServers (servers) if methodnums == None: methodnums = range (1, len (DEFAULT_METHODS) + 1) limitre = re.compile ('|'.join (args), re.IGNORECASE) for s in servers: if (not not limitre.match (s['name'])) == invert: continue try: typed = s['typed'] except: typed = 1 try: style = s['style'] except: style = 1999 SOAP.Config.typed = typed SOAP.Config.namespaceStyle = style server = SOAP.SOAPProxy (s['endpoint'], ("m", s['namespace'])) for num in (methodnums): if num > len (DEFAULT_METHODS): break total += 1 name = DEFAULT_METHODS[num - 1] title = '%s: %s (#%d)' % (s['name'], name, num) if SOAP.Config.debug: print "%s:" % title try: fn = globals ()['test' + name[0].upper () + name[1:]] except KeyboardInterrupt: raise except: if 'n' in output: print title, "test not yet implemented" notimp += 1 continue try: fn (server, s['soapaction'], harsh) if s['nonfunctional'].has_key (name): print title, \ "succeeded despite being marked nonfunctional" if 's' in output: print title, "succeeded" succeed += 1 except KeyboardInterrupt: raise except: fault = str (sys.exc_info ()[1]) if fault[-1] == '\n': fault = fault[:-1] if s['nonfunctional'].has_key (name): if 'F' in output: t = 'as expected' if s['nonfunctional'][name] != '': t += ', ' + s['nonfunctional'][name] print title, "failed (%s) -" % t, fault if printtrace > 1: traceback.print_exc () failok += 1 else: if 'f' in output: print title, "failed -", fault if printtrace: traceback.print_exc () fail += 1 if exitonfailure: return -1 if stats: print " Tests started at:", time.ctime (started) if stats > 0: print " Total tests: %d" % total print " Successes: %d (%3.2f%%)" % \ (succeed, 100.0 * succeed / total) if stats > 0 or fail > 0: print "Failed unexpectedly: %d (%3.2f%%)" % \ (fail, 100.0 * fail / total) if stats > 0: print " Failed as expected: %d (%3.2f%%)" % \ (failok, 100.0 * failok / total) if stats > 0 or notimp > 0: print " Not implemented: %d (%3.2f%%)" % \ (notimp, 100.0 * notimp / total) return fail + notimp if __name__ == '__main__': try: sys.exit (main ()) except KeyboardInterrupt: sys.exit (0) SOAPpy-0.12.0/validate/silabserver.py0100755001604001300100000000670310202425154017263 0ustar warnegcompstat#!/usr/bin/env python # Copyright (c) 2001 actzero, inc. All rights reserved. # This is a server for the XMethods matrix # (http://jake.soapware.org/currentXmethodsResults). import getopt import sys sys.path.insert (1, '..') from SOAPpy import SOAP if SOAP.Config.SSLserver: from M2Crypto import SSL ident = '$Id: silabserver.py,v 1.2 2003/03/08 05:10:01 warnes Exp $' def echoFloat (inputFloat): return inputFloat def echoFloatArray (inputFloatArray): return inputFloatArray def echoInteger (inputInteger): return inputInteger def echoIntegerArray (inputIntegerArray): return inputIntegerArray def echoString (inputString): return inputString def echoStringArray (inputStringArray): return inputStringArray def echoStruct (inputStruct): return inputStruct def echoStructArray (inputStructArray): return inputStructArray def echoVoid (): return SOAP.voidType() def echoDate (inputDate): return SOAP.dateTimeType (inputDate) def echoBase64 (inputBase64): return SOAP.binaryType (inputBase64) namespace = 'http://soapinterop.org/' DEFAULT_HOST = 'localhost' DEFAULT_HTTP_PORT = 8080 DEFAULT_HTTPS_PORT = 8443 def usage (error = None): sys.stdout = sys.stderr if error != None: print error print """usage: %s [options] If a long option shows an argument is mandatory, it's mandatory for the equivalent short option also. The default (if any) is shown in brackets. -?, --help display this usage -h, --host=HOST use HOST in the address to listen on [%s] -p, --port=PORT listen on PORT [%d] """ % (sys.argv[0], DEFAULT_HOST, DEFAULT_HTTP_PORT), if SOAP.Config.SSLserver: print " -s, --ssl serve using SSL" sys.exit (0) def main (): host = DEFAULT_HOST port = None ssl = 0 try: opts = '?h:p:' args = ['help', 'host', 'port'] if SOAP.Config.SSLserver: opts += 's' args += ['ssl'] opts, args = getopt.getopt (sys.argv[1:], opts, args) for opt, arg in opts: if opt in ('-?', '--help'): usage () elif opt in ('-h', '--host'): host = arg elif opt in ('-p', '--port'): port = int (arg) elif opt in ('-s', '--ssl'): ssl = 1 else: raise AttributeError, \ "Recognized but unimplemented option `%s'" % opt except SystemExit: raise except: usage (sys.exc_info ()[1]) if port == None: port = [DEFAULT_HTTP_PORT, DEFAULT_HTTPS_PORT][ssl] if ssl: ssl_context = SSL.Context() ssl_context.load_cert('server.pem') else: ssl_context = None server = SOAP.SOAPServer ((host, port), namespace = namespace, ssl_context = ssl_context) server.registerFunction (echoFloat) server.registerFunction (echoFloatArray) server.registerFunction (echoInteger) server.registerFunction (echoIntegerArray) server.registerFunction (echoString) server.registerFunction (echoStringArray) server.registerFunction (echoStruct) server.registerFunction (echoStructArray) server.registerFunction (echoVoid) server.registerFunction (echoDate) server.registerFunction (echoBase64) server.serve_forever() if __name__ == '__main__': try: sys.exit (main ()) except KeyboardInterrupt: sys.exit (0) SOAPpy-0.12.0/validate/soapware.py0100755001604001300100000000627010202425154016562 0ustar warnegcompstat#!/usr/bin/env python # This server validates as of 4/23/01 when run with UserLand's SOAP validator # (http://validator.soapware.org/). import getopt import sys sys.path.insert (1, '..') from SOAPpy import SOAP ident = '$Id: soapware.py,v 1.2 2003/03/08 05:10:01 warnes Exp $' def whichToolkit (): return SOAP.SOAPUserAgent () def countTheEntities (s): counts = {'ctLeftAngleBrackets': 0, 'ctRightAngleBrackets': 0, 'ctAmpersands': 0, 'ctApostrophes': 0, 'ctQuotes': 0} for i in s: if i == '<': counts['ctLeftAngleBrackets'] += 1 elif i == '>': counts['ctRightAngleBrackets'] += 1 elif i == '&': counts['ctAmpersands'] += 1 elif i == "'": counts['ctApostrophes'] += 1 elif i == '"': counts['ctQuotes'] += 1 return counts def easyStructTest (stooges): return stooges['larry'] + stooges['moe'] + stooges['curly'] def echoStructTest (myStruct): return myStruct def manyTypesTest (num, bool, state, doub, dat, bin): return [num, SOAP.booleanType (bool), state, doub, SOAP.dateTimeType (dat), bin] def moderateSizeArrayCheck (myArray): return myArray[0] + myArray[-1] def nestedStructTest (myStruct): return easyStructTest (myStruct.year2000.month04.day01) def simpleStructReturnTest (myNumber): return {'times10': myNumber * 10, 'times100': myNumber * 100, 'times1000': myNumber * 1000} namespace = 'http://www.soapware.org/' DEFAULT_HOST = 'localhost' DEFAULT_PORT = 8080 def usage (error = None): sys.stdout = sys.stderr if error != None: print error print """usage: %s [options] If a long option shows an argument is mandatory, it's mandatory for the equivalent short option also. The default (if any) is shown in brackets. -?, --help display this usage -h, --host=HOST use HOST in the address to listen on [%s] -p, --port=PORT listen on PORT [%d] """ % (sys.argv[0], DEFAULT_HOST, DEFAULT_PORT), sys.exit (0) def main (): host = DEFAULT_HOST port = DEFAULT_PORT try: opts, args = getopt.getopt (sys.argv[1:], '?h:p:', ['help', 'host', 'port']) for opt, arg in opts: if opt in ('-?', '--help'): usage () elif opt in ('-h', '--host'): host = arg elif opt in ('-p', '--port'): port = int (arg) else: raise AttributeError, \ "Recognized but unimplemented option `%s'" % opt except SystemExit: raise except: usage (sys.exc_info ()[1]) server = SOAP.SOAPServer ((host, port)) server.registerFunction (whichToolkit, namespace) server.registerFunction (countTheEntities) server.registerFunction (easyStructTest) server.registerFunction (echoStructTest) server.registerFunction (manyTypesTest) server.registerFunction (moderateSizeArrayCheck) server.registerFunction (nestedStructTest) server.registerFunction (simpleStructReturnTest) server.serve_forever() if __name__ == '__main__': try: sys.exit (main ()) except KeyboardInterrupt: sys.exit (0) SOAPpy-0.12.0/ChangeLog0100644001604000501700000026415010206653277014321 0ustar warnegclinical2005-02-22 10:58 warnes * ChangeLog, README, RELEASE_INFO: Update for 0.12.0 release. 2005-02-21 23:30 tag SOAPpy_0_12_0 2005-02-21 23:30 warnes * tests/README: update README since TCtests.py now passes! 2005-02-21 23:29 warnes * SOAPpy/: Parser.py, Types.py: Fix handling of parse rules! TCtest.py now passes! 2005-02-21 23:25 warnes * tests/: Bug1001646.py, Bug916265.py, ComplexTypes.py, GoogleTest.py, Makefile, README, TCtest.py, echoClient.py, echoHeader.py, echoServer.py, largeDataTest.py, testleak.py: Enhance echoServer with a quit method. Provide a makefile for running all working tests. 2005-02-21 15:27 warnes * SOAPpy/Client.py: Fix loss of quotes at start of file description. 2005-02-21 15:24 warnes * SOAPpy/SOAPBuilder.py: Add spaces and newlines to soap environment declarations when writing SOAP enclosure so that the results are more human readable. 2005-02-21 15:21 warnes * SOAPpy/Client.py: Add code to handle the case when headers are empty or not present. 2005-02-21 15:16 warnes * SOAPpy/WSDL.py: Add 'show_methods' which will print the methods and associated parameters. 2005-02-21 15:09 warnes * docs/: GettingStarted.txt, GlobusSupport.txt, WSDL.txt, complexTypes.txt, simpleTypes.txt: Update documentation. 2005-02-18 14:29 warnes * SOAPpy/Client.py: If content_length is missing or empty, we need not check for a the OC4J bug... 2005-02-18 11:28 warnes * README: Add bug reporting and mailing list information. 2005-02-18 10:42 warnes * docs/GettingStarted.txt: Change 'SOAP.py' to 'SOAPpy' 2005-02-18 10:40 warnes * docs/attrs.txt: Remove the long copyright and usage notices. Clarify the (too brief) text. 2005-02-18 10:36 warnes * docs/: complexTypes.txt, UsingHeaders.txt: Most of the information in the 'complexTypes.txt' file was actually about the use of headers. Moved that text to a new file 'UsingHeaders.txt'. 2005-02-18 08:50 warnes * SOAPpy/wstools/XMLSchema.py: Apply patch submitted by Peter McA'Nulty of WebReply.com: "class SimpleContent, class Extension.fromDom() at line ~2313 doesn't handle extensions without contents -- unusual, but not illegal" 2005-02-17 01:44 boverhof * SOAPpy/wstools/XMLSchema.py: ---------------------------------------------------------------------- Modified Files: XMLSchema.py -- added the item trace to an exception thrown when an unexpected child is encountered in complexType.fromDom method so one can see where the problem is occuring. ---------------------------------------------------------------------- 2005-02-16 13:39 warnes * tests/echoServer.py: Added echo_jheader which returns its argument and the header, in order to support Bug1001646.py 2005-02-16 13:34 warnes * tests/Bug1001646.py: Test now properly checks to see that the header is preserved. 2005-02-16 09:45 tag v1_7 2005-02-16 09:45 warnes * SOAPpy/wstools/XMLname.py: Remember to paste prefix back onto the XMLname before returning. 2005-02-15 23:27 warnes * SOAPpy/SOAPBuilder.py: Bug fix for [ 1078051 ] "Arrays of complex types (doc/lit)" per the patch submited with the bug report by Nelson Minar. 2005-02-15 23:25 warnes * tests/echoClient.py: Print what we're trying to do so that errors are easier to track down. 2005-02-15 23:24 warnes * tests/storageTest.py: Updated 'registerUser' to match current documentation, but still get an error from the server. 2005-02-15 23:23 warnes * tests/echoServer.py: Add 'echo_simple' command that just returns its arguments as-is. 2005-02-15 23:22 warnes * tests/Bug1001646.py: Turn of some debugging information. 2005-02-15 23:21 warnes * tests/Bug916265.py: Regression test for [ 916265 ] "Arrays of unicode do not serialize correctly (patch included)" 2005-02-15 23:09 warnes * tests/Bug1001646.py: Regression test for bug [ 1001646 ] SOAPpy stomps headers when sending multirefs. 2005-02-15 16:51 warnes * SOAPpy/Client.py: Create workaround for a bug in OC4J reported in [ 1122991 ] "error from SOAPpy/Client.py for content_length evaluation?" by Merten Schumann. 2005-02-15 16:09 warnes * SOAPpy/SOAPBuilder.py: Fix [ 1106450 ] "Floats are truncated to 10 digits, causing precision loss" submitted by Kerry 'krdavis'. 2005-02-15 16:07 warnes * SOAPpy/Client.py: Fixed [ 1096971 ] "Parse error: missing HTTP header 'Content-length'" submitted by 'pure water'. 2005-02-15 15:59 warnes * SOAPpy/Types.py: Fix [ 1064248 ] "Bugs in _asdict() and _asarray() in Types.py" submitted by Peter Lamb. 2005-02-15 15:56 warnes * SOAPpy/SOAPBuilder.py: Fix handling of 0-length arrays. 2005-02-15 15:52 warnes * SOAPpy/SOAPBuilder.py: Apply [ 1064233 ] "Bug fixes for complex types" from Peter Lamb. 2005-02-15 15:41 warnes * SOAPpy/SOAPBuilder.py: Fix bug [ 1001646 ] SOAPpy stomps headers when sending multirefs using included patch provide by Nelson Minar 2005-02-15 15:15 warnes * SOAPpy/Client.py: Fix [ 925077 ] SOAPpy prints out SOAP fault /even when Config.debug is off/. 2005-02-15 15:12 warnes * SOAPpy/Parser.py, tests/Bug918216.py: Fix parsing bug & add regression test. SOAPpy was not allowing anything after the close of a faulttype block, but multirefs should be permitted there. Closes bug [ 918216 ] "Parsing faults in SOAPpy 0.11.3" 2005-02-15 14:30 warnes * tests/ZeroLengthArray.py: Test handling of zero-length typed lists. Currently fails. 2005-02-15 14:22 warnes * SOAPpy/SOAPBuilder.py: Revert broken header generation from last patch. 2005-02-15 11:41 warnes * SOAPpy/SOAPBuilder.py: Fix bug [ 916265 ] Arrays of unicode do not serialize correctly, submitted by Nelson Minar. 2005-02-15 11:37 warnes * README: Fix typo in README. 2005-02-15 11:32 warnes * LICENSE, README, setup.py, SOAPpy/Client.py, SOAPpy/Errors.py, SOAPpy/GSIServer.py, SOAPpy/NS.py, SOAPpy/Server.py, SOAPpy/wstools/XMLname.py, docs/MethodParameterNaming.txt: Update email address 2005-02-09 13:33 tag bogus-12_9_123RC93 2005-02-09 13:33 boverhof * SOAPpy/wstools/Utility.py: ---------------------------------------------------------------------- Modified Files: Utility.py -- need to do isfile check before calling mod func "urlopen" for cross-platform compat. ---------------------------------------------------------------------- 2005-02-07 12:07 irjudson * SOAPpy/wstools/WSDLTools.py: Mod to flatten wsdl imports, schemas not dealt with yet. 2005-02-04 14:18 boverhof * SOAPpy/wstools/Namespaces.py: ---------------------------------------------------------------------- Committing in . Modified Files: Namespaces.py -- OASIS.PROPERTIES wasn't quite correct (suffix .wsdl --> .xsd) ---------------------------------------------------------------------- 2005-02-01 13:10 boverhof * SOAPpy/wstools/Namespaces.py: ---------------------------------------------------------------------- Modified Files: Namespaces.py -- added OASIS BaseFaults. ---------------------------------------------------------------------- 2005-01-31 09:45 warnes * README: Update URL for fpconst. 2005-01-27 18:01 boverhof * SOAPpy/wstools/XMLSchema.py: ---------------------------------------------------------------------- Modified Files: XMLSchema.py -- added a couple convenience methods for grabbing various Schema Items. ---------------------------------------------------------------------- 2005-01-25 19:31 boverhof * SOAPpy/wstools/Utility.py: ---------------------------------------------------------------------- Modified Files: Utility.py -- change to accomodate writing out XML instances w/o SOAP Envelopes, "known" prefixes aren't "known" when the Envelope isn't writen out. ---------------------------------------------------------------------- 2005-01-18 12:18 boverhof * SOAPpy/wstools/: Namespaces.py, XMLSchema.py: ---------------------------------------------------------------------- Modified Files: Namespaces.py -- added Oasis base notification ns. XMLSchema.py -- modified an exception message. ---------------------------------------------------------------------- 2004-12-20 15:36 boverhof * SOAPpy/wstools/: WSDLTools.py, XMLSchema.py: ---------------------------------------------------------------------- Modified Files: WSDLTools.py -- removed a line that was screwing up imports/includes of when WSDL file was specified to "wsdl2py" via a relative path. XMLSchema.py -- stop requiring suffix "xsd" for schema files. ---------------------------------------------------------------------- 2004-12-17 16:41 boverhof * SOAPpy/wstools/c14n.py: ---------------------------------------------------------------------- Modified Files: c14n.py -- fixed a bug affecting those who don't have pyXML installed. ---------------------------------------------------------------------- 2004-12-08 15:04 boverhof * SOAPpy/wstools/c14n.py: ---------------------------------------------------------------------- Modified Files: c14n.py -- just removed import of ZSI so SOAPy can use w/o ZSI. ---------------------------------------------------------------------- 2004-12-07 10:54 blunck2 * SOAPpy/wstools/__init__.py: uncommented import of WSDLTools. josh commented this out during another commit and i think it was unintentional 2004-11-30 01:27 boverhof * SOAPpy/wstools/: Namespaces.py, WSDLTools.py: ---------------------------------------------------------------------- Modified Files: Namespaces.py WSDLTools.py -- added WSA 2004/08 namespaces, and enabled "PortType" to discover it. ---------------------------------------------------------------------- 2004-11-16 15:59 boverhof * SOAPpy/wstools/XMLSchema.py: ---------------------------------------------------------------------- Modified Files: XMLSchema.py -- added a couple helper methods for discovering whether or not an element should be qualified. ---------------------------------------------------------------------- 2004-11-12 18:14 boverhof * SOAPpy/wstools/: Namespaces.py, WSDLTools.py, XMLSchema.py, logging.py: ---------------------------------------------------------------------- Modified Files: Namespaces.py -- Added a SOAP-1.2 binding WSDLTools.py -- Added some methods from grabbing ElementDeclaration and TypeDefintion from Message instances. XMLSchema.py -- fixed a bug in SchemaReader. logging.py -- added a couple more functions, and a level to basic logger. ---------------------------------------------------------------------- 2004-11-08 14:46 boverhof * SOAPpy/wstools/Utility.py: ---------------------------------------------------------------------- Committing in . Modified Files: Utility.py -- removed "sw" property in ElementProxy. ---------------------------------------------------------------------- 2004-11-05 02:32 boverhof * SOAPpy/wstools/c14n.py: ---------------------------------------------------------------------- Modified Files: c14n.py -- opps, want to call the implementation constructor when passed any NodeType, not just Element nodes. ---------------------------------------------------------------------- 2004-11-05 01:35 boverhof * SOAPpy/wstools/: Namespaces.py, Utility.py, WSDLTools.py, __init__.py, c14n.py: ---------------------------------------------------------------------- Modified Files: ** removed all "imports" of ZSI or ZSI.wstools, so wstools can be used independently by SOAPpy. Namespaces.py -- added a namespace Utility.py -- moved ZSI.utility here, and the "Base" class for logging. WSDLTools.py -- added a "toDom" and "GetWSDL" methods to several classes, so now you can construct a WSDL instance and then call WSDL.toDom() --> DOM --> and create a WSDL file. __init__.py -- removed "Base" class for logging. Added Files: c14n.py -- moved the c14n stuff from ZSI.compat here. ---------------------------------------------------------------------- 2004-11-04 18:06 mateo41 * SOAPpy/wstools/Namespaces.py: overloaded the DSIG.C14N (from PyXML Namespace with a newer canonicalization algorithm. Added GLOBUS.SIG, which is the namespace for SecureConversation 2004-10-26 20:09 boverhof * SOAPpy/wstools/Namespaces.py: ---------------------------------------------------------------------- Modified Files: Namespaces.py -- added OASIS.LIFETIME ---------------------------------------------------------------------- 2004-10-22 16:11 boverhof * SOAPpy/wstools/: Utility.py, XMLSchema.py: ---------------------------------------------------------------------- Modified Files: Utility.py -- catch any exceptions thrown when a DOM is loaded up, throw a ParseError with old ex.args and inform which file caused the problem. XMLSchema.py -- For attributeGroup incorrectly adding global attribute declarations, but these are declared locally. ---------------------------------------------------------------------- 2004-10-21 02:40 mateo41 * SOAPpy/wstools/Namespaces.py: added another namespace to WSSE, and created a GLOBUS namespace class with 2 namespaces 2004-10-20 18:35 boverhof * SOAPpy/wstools/WSDLTools.py: ---------------------------------------------------------------------- Modified Files: WSDLTools.py -- uncommented some "import" code that I didn't think was of any use. Now I need it. ---------------------------------------------------------------------- 2004-10-19 21:33 mateo41 * SOAPpy/wstools/Namespaces.py: added the BEA class, which is an organization which has created schema for the SecureConversation protocol 2004-10-19 18:52 boverhof * SOAPpy/wstools/: WSDLTools.py, XMLSchema.py: ---------------------------------------------------------------------- Modified Files: WSDLTools.py XMLSchema.py --removed some print statements I left behind. ---------------------------------------------------------------------- 2004-10-18 22:51 boverhof * SOAPpy/wstools/Namespaces.py: ---------------------------------------------------------------------- Modified Files: Namespaces.py -- added some URLs for Oasis specifications. ---------------------------------------------------------------------- 2004-10-15 21:15 boverhof * SOAPpy/wstools/WSDLTools.py: ---------------------------------------------------------------------- Modified Files: WSDLTools.py -- forgot to look for 2004 WS-Actions. ---------------------------------------------------------------------- 2004-10-14 04:24 boverhof * SOAPpy/wstools/: WSDLTools.py, XMLSchema.py: ---------------------------------------------------------------------- Modified Files: WSDLTools.py -- resolution of default WS-Action was incorrect when using imported portTypes. XMLSchema.py -- added a couple helper functions, and a few more Markers for introspecting modelGroups and simpleType derivations. ---------------------------------------------------------------------- 2004-10-01 00:27 boverhof * SOAPpy/wstools/XMLSchema.py: ---------------------------------------------------------------------- Modified Files: XMLSchema.py -- SchemaReader wasn't resolving relative paths correctly. ---------------------------------------------------------------------- 2004-09-27 16:40 boverhof * SOAPpy/wstools/XMLSchema.py: ---------------------------------------------------------------------- Modified Files: XMLSchema.py -- Shouldn't check attributes for WSDL definition since it's legal to specify attribute in ---------------------------------------------------------------------- 2004-09-27 15:55 boverhof * SOAPpy/wstools/XMLSchema.py: ---------------------------------------------------------------------- Modified Files: XMLSchema.py -- required another condition in getItemTrace, need to check if at or , also added some info to SchemaError throw in checkAttributes. Now provides namespace/attribute and the Schema Item containing the offending attribute. ---------------------------------------------------------------------- ~ 2004-09-22 18:40 boverhof * SOAPpy/wstools/: XMLSchema.py, __init__.py, logging.py: ---------------------------------------------------------------------- Modified Files: XMLSchema.py -- added a few convience methods, and 'disabled' a few methods to force a sane usage. __init__.py -- removed use of python logging module, and replaced it with the below. Added Files: logging.py -- simple interface to log message to, can write your own logger class. By default do no logging. ---------------------------------------------------------------------- 2004-09-21 18:19 boverhof * SOAPpy/wstools/XMLSchema.py: ---------------------------------------------------------------------- Modified Files: XMLSchema.py -- added a "getItemTrace" method to XMLSchemaComponent Base class to produce a node trace. Added a bunch of "tag" class variables for identifying what an instance represents, and removed a bunch of unused code. ---------------------------------------------------------------------- 2004-09-10 23:14 warnes * RELEASE_INFO: Update for release 0.11.6 2004-09-10 23:07 tag SOAPpy_0_11_6 2004-09-10 23:07 warnes * ChangeLog, SOAPpy/version.py: Update version number 2004-09-10 23:03 warnes * LICENSE, README, RELEASE_INFO, SOAPpy/Types.py: - Update URLs and email address. - Use 'dictType' instead of 'dict' in type check. 2004-09-09 19:32 boverhof * SOAPpy/wstools/__init__.py: ---------------------------------------------------------------------- Modified Files: __init__.py -- changed "Base", which contains a logger, to no-op logging if the logging configuration file is not found and avoid the overhead of using the logging module. ---------------------------------------------------------------------- 2004-09-09 00:37 boverhof * SOAPpy/wstools/WSDLTools.py: ---------------------------------------------------------------------- Modified Files: WSDLTools.py -- Commented out the "imports" collection, which isn't of much use. Now URLs are resolved relative to the importing document. Support for this scenario: --- /Users/boverhof/Desktop/Wsdl/Service/whatever.wsdl ... --- /Users/boverhof/Desktop/Wsdl/hello/hello.wsdl ... --- /Users/boverhof/Desktop/Wsdl/hello/goodbye.wsdl ... ---------------------------------------------------------------------- 2004-09-01 22:18 tag SOAPpy_0_11_5 2004-09-01 22:18 warnes * ChangeLog, RELEASE_INFO, SOAPpy/version.py: Update for release 0.11.5 2004-08-18 19:12 boverhof * SOAPpy/wstools/__init__.py: ---------------------------------------------------------------------- Modified Files: __init__.py -- cleaned up the module, removed some old code. ---------------------------------------------------------------------- 2004-06-23 16:10 boverhof * SOAPpy/wstools/XMLSchema.py: ---------------------------------------------------------------------- Modified Files: XMLSchema.py -- added getAttributeContent method wherever appropriate. ---------------------------------------------------------------------- 2004-06-23 14:05 boverhof * SOAPpy/wstools/WSDLTools.py: ---------------------------------------------------------------------- Modified Files: WSDLTools.py -- SoapBinding item soap:header message attribute needs to be stored as a (namespace,name) tuple to enable lookup. ---------------------------------------------------------------------- 2004-06-21 17:40 boverhof * SOAPpy/wstools/Namespaces.py: ---------------------------------------------------------------------- Modified Files: Namespaces.py -- added 2004 ws-addressing namespaces. ---------------------------------------------------------------------- 2004-06-05 14:30 boverhof * SOAPpy/wstools/WSDLTools.py: ---------------------------------------------------------------------- Modified Files: WSDLTools.py -- couple bug fixes for determining default wsa:Action values ---------------------------------------------------------------------- 2004-06-04 12:53 boverhof * SOAPpy/wstools/WSDLTools.py: ---------------------------------------------------------------------- Modified Files: WSDLTools.py -- added a "getResourceProperties" method to class PortType. ---------------------------------------------------------------------- 2004-06-04 12:44 boverhof * SOAPpy/wstools/__init__.py: ---------------------------------------------------------------------- Enter Log. Lines beginning with `CVS:' are removed automatically Committing in . Modified Files: __init__.py -- added some code for doing logging ---------------------------------------------------------------------- 2004-06-03 09:03 warnes * MANIFEST.in: Add text files like LICENSE to the list included in distributed packages. 2004-05-14 00:37 boverhof * SOAPpy/wstools/WSDLTools.py: ---------------------------------------------------------------------- Modified Files: WSDLTools.py -- Had to change how the default wsa:Action values are set up. Must wait until entire WSDL is loaded, otherwise can get into situations where the objects we need to access haven't been initialized yet because of the order of WSDL information items in the WSDL definition. ---------------------------------------------------------------------- 2004-05-13 13:15 tyger23 * SOAPpy/wstools/Namespaces.py: added XSD_LIST to SCHEMA because it's absence broke wsdl2python. 2004-05-11 04:07 boverhof * SOAPpy/wstools/: Namespaces.py, WSDLTools.py: ---------------------------------------------------------------------- Modified Files: Namespaces.py -- added a bunch of namespaces (encryption, ws-address, ws-resourcepolicy, etc) WSDLTools.py -- added functionality for getting WS-ResourceProperties and ws-Address information out of WSDL. Ran all unittests and passed. ---------------------------------------------------------------------- 2004-05-10 21:09 boverhof * SOAPpy/wstools/XMLSchema.py: ---------------------------------------------------------------------- Modified Files: XMLSchema.py -- added some code to generate user interpretable exceptions. BEFORE: File "/System/Library/Frameworks/Python.framework/Versions/2.3/lib/python2.3/site-packages/ZSI/wstools/Utility.py", line 600, in __getitem__ return self.data[key] KeyError: u'xtvd' AFTER: File "/System/Library/Frameworks/Python.framework/Versions/2.3/lib/python2.3/site-packages/ZSI/wstools/XMLSchema.py", line 465, in getQNameAttribute raise KeyError, "targetNamespace(%s) collection(%s) has no item(%s)"\ KeyError: u'targetNamespace(urn:TMSWebServices) collection(types) has no item(xtvd)' ---------------------------------------------------------------------- 2004-04-28 21:40 boverhof * SOAPpy/wstools/: Namespaces.py, Utility.py, XMLSchema.py: ---------------------------------------------------------------------- Modified Files: Utility.py XMLSchema.py -- just moved SplitQName out of here and into Utility Added Files: Namespaces.py -- WSDL, SOAP, SCHEMA, XMLNS namespaces here. Doesn't require PyXml ---------------------------------------------------------------------- 2004-04-28 17:47 warnes * SOAPpy/Server.py: Fix string format error in fault handling 2004-04-27 11:47 warnes * CHANGELOG: Renamed to ChangeLog 2004-04-27 11:39 warnes * ChangeLog, SOAPpy/version.py: Update for 0.11.4. 2004-04-27 11:38 warnes * RELEASE_INFO: Updated for 0.11.4 release. 2004-04-27 11:23 warnes * SOAPpy/Server.py: Check if header information contains SOAPAction key before checking its value. 2004-04-27 11:22 warnes * tests/TCtest.py: Convert TCtest.py to unit test framework. 2004-04-13 23:42 irjudson * SOAPpy/Types.py: Added traceback info to exception for methodnotfound. 2004-04-13 23:41 irjudson * SOAPpy/Server.py: Added traceback back in, without optional config arg, seems resonable to do it this way. 2004-04-11 18:01 boverhof * SOAPpy/wstools/Utility.py: ---------------------------------------------------------------------- Modified Files: Utility.py -- Fix to DOM singleton hasAttr method. _attr and _attrNS are instance variables of the minidom Element, and are implementation specific. Now hasAttr method will work when using FtNode.Element, which is what ZSI ParsedSoap defaults to (Ft.Doc). ---------------------------------------------------------------------- 2004-04-10 00:29 irjudson * SOAPpy/Types.py: Applied patch from antonio.beamud@linkend.com, for tagging complexType arrays. Looks entirely self-contained, and therefore safe to apply. Also includes new classes for the standard soap faults that can occur, so clients can catch them directly. 2004-04-10 00:28 irjudson * SOAPpy/SOAPBuilder.py: Applied patch from antonio.beamud@linkend.com, for tagging complexType arrays. Looks entirely self-contained, and therefore safe to apply. 2004-04-10 00:26 irjudson * SOAPpy/Server.py: Changed faultType construction to be more client side parsable, make faultstring a non-variable string (ie no nsmethod in it) so that it can be programmatically checked more easily. Modified faultdetail to be the nsmethod. Now the traceback doesn't get passed to the client side. 2004-04-10 00:22 irjudson * SOAPpy/Client.py: Put quotes back in around SOAP Action, for spec conformance. 2004-04-02 08:45 irjudson * SOAPpy/Client.py: Removed quotes from SOAPAction header, seems to be more correct. 2004-04-01 08:25 warnes * SOAPpy/SOAPBuilder.py, SOAPpy/Types.py, SOAPpy/version.py, tests/SOAPtest.py: - Fixed bug that caused typedArrayTypes to lose their type information when rendered to SOAP. - Added corresponding test case to SOAPtest.py - Updated version number. 2004-03-30 19:42 boverhof * SOAPpy/wstools/Utility.py: ---------------------------------------------------------------------- Modified Files: Utility.py -- 'attrsNS' replaced with '_attrNS', the actual name ---------------------------------------------------------------------- 2004-03-30 18:19 boverhof * SOAPpy/wstools/Utility.py: ---------------------------------------------------------------------- Modified Files: Utility.py -- isElement should return False if NOT an Element. ---------------------------------------------------------------------- 2004-03-25 15:46 irjudson * SOAPpy/Server.py: Modified unregsiterObject function to take optional namespace/path args to be consistent with registerObject. 2004-03-22 14:32 irjudson * SOAPpy/Client.py: Fixed indent block bug and removed extraneous print. 2004-03-18 19:21 boverhof * SOAPpy/wstools/WSDLTools.py: ---------------------------------------------------------------------- Modified Files: WSDLTools.py -- qualified Names are now stored as tuples (namespace, localName). These tuples are used as keys into CollectionNS instances. ---------------------------------------------------------------------- 2004-03-18 09:19 irjudson * SOAPpy/Client.py: Introduced the notion of a fault handler, if a call fails a user specified fault handler can be invoked (if it's specified). This can be used in many situations, we're using is specifically to handle credential problems. 2004-03-11 18:07 boverhof * SOAPpy/wstools/XMLSchema.py: ---------------------------------------------------------------------- Modified Files: XMLSchema.py -- fixed a few problem with the XML namespace, mainly affecting the use of 'xml:lang'. Fixed a bug identifying attributeGroup references vs. definitions. Also changed the inheritance of MarkerInterface, and moved the classes involved before all Schema classes. Now will parse "XML Schema Part 1: Structures", and "XML Schema Part 2: Datatypes" XML Schema definitions. ---------------------------------------------------------------------- 2004-03-11 14:14 boverhof * SOAPpy/wstools/: Utility.py, WSDLTools.py: ---------------------------------------------------------------------- Modified Files: Utility.py -- added a CollectionNS class that keys items via (targetNamespace, name). WSDLTools.py -- Made WSDL Collections into CollectionNS instances, this fixes problem with collisions, caused by wsdl:imports, between items with same name but defined in different targetNamespaces. So now all items can be accessed via (namespace,name), but ONLY those items defined in WSDL.targetNamepsace (not an import.targetNamespace) can be accessed using just 'name'. Also changed how portType is "loaded". Now instead of dropping all the operation nodes in "load", I drop the portType node into "load". This makes sense because portType really should know about itself, and the XML Schema definition of "portType" includes an "anyAttribute" and I need to make this stuff available. I may change the other WSDL information items to do this to be consistent. ---------------------------------------------------------------------- 2004-03-09 17:53 boverhof * SOAPpy/wstools/WSDLTools.py: ---------------------------------------------------------------------- Modified Files: WSDLTools.py - small fix for the creation of the output parameters, to enable return messages to be properly typecoded. ---------------------------------------------------------------------- 2004-03-04 14:50 irjudson * SOAPpy/SOAPBuilder.py: Added calls in dumpers to ensure tags are built using toXMLname. 2004-03-01 20:34 boverhof * SOAPpy/wstools/Utility.py: ---------------------------------------------------------------------- Modified Files: Utility.py -- fixed bug in _clone_node patch. This method was being called with qualifiedName for namespaced attributes, and bombing. It is supposed to be called like so: getAttributeNodeNS(self, namespaceURI, localName) Really could remove the if/else clause here but I decided to leave it there just to keep the 3 distinctions in the code. ---------------------------------------------------------------------- 2004-03-01 18:27 boverhof * SOAPpy/wstools/XMLSchema.py: ---------------------------------------------------------------------- Modified Files: XMLSchema.py -- fixed bugs concerning Model Group References (missing minOccurs/maxOccurs), and simpleType annotations. ---------------------------------------------------------------------- 2004-02-19 10:37 irjudson * SOAPpy/Server.py: Added an unregisterObject function, which unfortunately looks through the entire self.objmap dictionary to find the object to remove, but it does remove it. 2004-02-18 16:48 warnes * SOAPpy/: SOAPBuilder.py, Types.py: Changes to allow SOAPBuilder to allow it to be passed a 'raw' Python object. 2004-02-18 16:27 warnes * tests/: esj_test_client.py, esj_test_server.py: Add quit() method to server and appropriate call to client. 2004-02-18 16:22 warnes * tests/: cardClient.py, cardServer.py: Add quit() method to cardServer, and have cardClient call it when done. 2004-02-17 23:53 warnes * CHANGELOG, RELEASE_INFO: Update CHANGELOG and RELEASE_INFO for 0.11.3 release. 2004-02-17 23:36 warnes * tests/SOAPtest.py: Fix a change to how SOAPpy returns namespace URI's that are non-string. They used to be converted to strings and now are not. I'm not entirely sure what the correct behavior is... 2004-02-17 23:28 warnes * SOAPpy/Types.py: Accept provosed revision by Ivan Judson to the handling of faultType objects in simplify(). 2004-02-17 23:25 warnes * SOAPpy/version.py: Update version number for 0.11.1 release. 2004-02-17 23:17 warnes * docs/GettingStarted.txt: Add \n to end of file. 2004-02-17 23:16 warnes * tests/testClient1.py: Add test of echo with named parameter in call to catch bugs related to providing names. 2004-02-17 23:15 warnes * SOAPpy/SOAPBuilder.py: Fix bug #875977: no escaping of bad tagnames for NoneTypes. Both bug and fix suggested by Robert Zimmermann. 2004-02-17 23:10 warnes * SOAPpy/SOAPBuilder.py: Apply patch to fix bug #888345: Python 2.3 boolean type serialized as int, both provided by Nelson Minar. 2004-02-17 23:05 warnes * SOAPpy/Client.py: Nelson Minar reported bug 888352 and provided a patch: If the server does not send a content-length header for the response, SOAPpy's Client fails to read the response. The Google Web APIs at api.google.com are one such service, as of around 2004-01-20. A patch is included below to just read the whole socket's contents if there is no content-length. This should work fine for HTTP/1.0, but will cause troubles with HTTP/1.1 and chunked encoding. SOAPpy's Client.py uses an old HTTP compatibility class from httplib which sends 1.0 requests, so this seems safe. 2004-02-13 14:04 irjudson * SOAPpy/Types.py: I've added a SOAPException(Exception) class. The simplify_objects option now raises a SOAPException instead of a faultType. This seems to make more sense to me, but I could be wrong. 2004-02-13 14:02 irjudson * tests/echoClient.py: Added another missing call. 2004-02-03 22:21 irjudson * SOAPpy/GSIServer.py: Modified GSIServer to have a GSIConfig that handles the pyGlobus specific configuartion details. Hides this from users. 2004-02-03 01:39 irjudson * docs/GlobusSupport.txt: Updated for simpler client usage. 2004-02-03 01:38 irjudson * SOAPpy/Server.py: Added a fix for exception handling that cleans up exception data structures. This plugs a memory leak when exceptions are raised. 2004-02-03 01:21 irjudson * tests/echoServer.py: Added Context Test, cleaned up output to honor Config.debug flag more. 2004-02-03 01:20 irjudson * tests/echoClient.py: Cleaned up client usage of globus, added in simplest test. 2004-02-03 01:11 irjudson * SOAPpy/Client.py: Changed the use of SOAPAction, it used to default to setting it to "", now it defaults to setting it to the method (not the nsmethod). There is a clause in Server.py that catches 'old style' SOAPActions (aka "") and sets them to the method. When this is confirmed to be what everyone wants and we decide it's alright to (possibly) break client/server interop, we can take the clause out of Server.py and just handle SOAPActions of "" as a possible error/warning. 2004-02-03 01:08 irjudson * SOAPpy/GSIServer.py: Turned off default logging. 2004-02-03 01:08 irjudson * SOAPpy/Server.py: Added context handling. Each call builds a SOAP context and puts it in the global dict _contexts (indexed by thread id). There is also a new function: GetSOAPContext() that returns the context for the current thread. Removed previously added method keyword args,. Turned off default log = 1 in RequestHandler Classes. 2004-01-30 23:20 warnes * SOAPpy/: Client.py, Config.py, Errors.py, GSIServer.py, NS.py, Parser.py, SOAP.py, SOAPBuilder.py, Server.py, Types.py, URLopener.py, Utilities.py, WSDL.py, __init__.py, version.py: Add ident and __version string to all files. 2004-01-30 23:19 warnes * SOAPpy/Server.py: Fix bug reported by Dan Nathan that occurs using named arguments. 2004-01-26 01:39 dwrobertson * SOAPpy/wstools/test/test_WSDLReader.py: Removed duplicate test. 2004-01-26 01:38 dwrobertson * SOAPpy/wstools/test/: README, __init__.py, test_wsdl.py, test_wstools.py, test_wstools_net.py: Brought README up to date, made changes having to do with moving of ZSI-specific material to zsi/test/wsdlpy, removed dependencies on utils.py. 2004-01-26 01:35 dwrobertson * SOAPpy/wstools/test/: config.py, config.txt: config.py renamed to config.txt 2004-01-26 01:34 dwrobertson * SOAPpy/wstools/test/: test_wsdl2python.py, utils.py: Code moved to zsi/test/wsdl2py 2004-01-21 16:54 boverhof * SOAPpy/wstools/XMLSchema.py: ---------------------------------------------------------------------- Modified Files: XMLSchema.py -- added substutionGroup to the list of attributes that can be specified in an ElementDeclaration. ---------------------------------------------------------------------- 2004-01-15 01:09 warnes * docs/GlobusSupport.txt: Added GlobusSupport.txt documentation submitted by Ivan R. Judson . 2004-01-15 00:39 warnes * tests/testClient1.py: Add test for dataTimeType objects. 2004-01-15 00:34 warnes * SOAPpy/Server.py, tests/echoServer.py: Integrate patch from Ivan R. Judson [mailto:judson@mcs.anl.gov]: "There's a namespace collision in the Server.py module for deciding what namespace should be used, ie, r._ns or the path. I've resolved it with a big comment that basically says, r._ns is the preferred specification, but that if it is missing and self.path exists, use that. "This patch also includes the previous patch to include "method" : nsmethod in the keywords for invocations so that authorization gets the methodname." 2004-01-05 13:03 warnes * SOAPpy/Types.py: - Code assumes nested scopes, so I added the proper import so this will work under python 2.2.x - _setAttr was assuming that all attributes are strings. Fixed. 2004-01-01 23:17 rsalz * SOAPpy/.cvsignore: added 2003-12-23 05:19 tag SOAPpy_0_11_1 2003-12-23 05:19 warnes * CHANGELOG, RELEASE_INFO, TODO: - Updated documentation for 0.11.1 release. 2003-12-23 05:05 warnes * SOAPpy/version.py: - Update version number for new release. 2003-12-23 05:04 warnes * SOAPpy/Server.py: - Changes suggested by Richard Au (richardau) to fix ssl support. See bug report [ 752882 ] "SSL SOAP Server no longer working." 2003-12-23 04:33 warnes * SOAPpy/SOAPBuilder.py: - Fixed bug [ 792258 ] "SOAPBuilder.SOAPBuilder.dump can catch wrong exceptions" in SOAPBuilder.dump() submitted by Greg Chapman (glchapman). - Fixed a bug in SOAPBuilder.dump_instance() that had been masked by bug #792258. 2003-12-23 04:24 warnes * tests/SOAPtest.py: - Add call to structType.__init__ for user classes that inherit from structType. This fixes a bug in the tests that was masked by incorrectly catching & ignoring exceptions in SOAPBuilder.dump(). 2003-12-23 04:10 warnes * tests/testClient1.py: - testClient1.py now works. The problem was failing to set 'quit' back to zero after the SOAP server exited. 2003-12-23 03:22 warnes * SOAPpy/SOAPBuilder.py: - Remove call to gentag from 'dump' and add to 'dump_float', per bug report [ 792600 ] "SOAPBuilder.SOAPBuilder.dump possibly should not call gentag" by Greg Chapman (glchapman). 2003-12-23 03:21 warnes * tests/SOAPtest.py: - Add a tests for handling of nil="true" and nil="false". 2003-12-23 03:17 warnes * SOAPpy/Parser.py: - Correctly handle testing for nil="true" and for nil=1. 2003-12-23 02:56 warnes * SOAPpy/wstools/WSDLTools.py: - Fix syntax error from last change. 2003-12-23 02:42 warnes * SOAPpy/wstools/WSDLTools.py: - Added 'strict' option to the WSDL class. If strict is true, a RuntimeException will be raised if an unrecogned message is recieved. If strict is false, a warning will be printed to the console, the message type will be added to the WSDL schema, and processing will continue. This is in response to the second half of bug report [ 817331 ] "Some WSDL.py changes", submitted by Rudolf Ruland. 2003-12-23 02:21 warnes * SOAPpy/wstools/WSDLTools.py: - rename loadFromStream's 'file' argument to 'stream' to make it clear that the stream need not be a file. 2003-12-23 02:11 warnes * SOAPpy/Parser.py: - Fix bug [ 858168 ] 'xsi:nil="true" causes exception', reported by Robert Zimmermann (robertzett@user.sf.net). 2003-12-19 22:21 warnes * RELEASE_INFO: - Mistyped 'unwrap_results' instead of 'simplify_objects' 2003-12-19 22:03 tag SOAPpy_0_11_0 2003-12-19 22:03 warnes * SOAPpy/version.py: - Update version number for release. 2003-12-19 17:23 warnes * TODO: - Clarify what documentation needs to be done. 2003-12-19 17:20 warnes * docs/quickstart.txt: Renamed quickstart.txt to GettingStarted.txt. 2003-12-19 17:19 warnes * CHANGELOG, LICENSE, README, RELEASE_INFO, docs/GettingStarted.txt, docs/WSDL.txt: Updated README to be shorter and clearer: - Moved most example to docs/GettingStarted.txt - Moved WSDL example to docs/WSDL.txt - Moved license text to LICENSE Updated RELEASE_INFO Updated CHANGELOG 2003-12-19 15:19 warnes * SOAPpy/Client.py, SOAPpy/Parser.py, SOAPpy/SOAPBuilder.py, tests/SOAPtest.py, tests/simpleWSDL.py: - Updated calls to fpconst - SOAPpy now checks for nonstandard infinity encoding produced by some older SOAP tools like SOAP4J and Apache SOAP (both now superceeded by Axis SOAP). - Added the offending XML string to the exception thrown when a float/double underflow or overflow occurs. - Minor twiddles in the examples. 2003-12-19 13:22 warnes * SOAPpy/: Client.py, Config.py, Types.py: - Modified SOAPProxy code to correctly pull value of unwrap_results and simplify_objects from Config unless specifically provided in the instantiation call. - Modified Config to better handle configuration variables that are only valid when pyGlobus is available. - Added more documentation to Config variables. - Better documentation for simplify() and simplify_contents() functions. 2003-12-19 13:16 warnes * tests/: README, SOAPtest.py, echoClient.py, echoHeader.py, echoServer.py, esj_test_client.py, simpleWSDL.py: - Add more documentation - Modify echoClient to work properly when pyGlobus is not available. - Misc cleanup. 2003-12-19 12:04 warnes * SOAPpy/Client.py, SOAPpy/Config.py, SOAPpy/Parser.py, SOAPpy/Server.py, tests/SOAPtest.py, tests/echoClient.py, tests/echoServer.py, tests/esj_test_client.py, tests/esj_test_server.py: - Restored Config.unwrap_results to its previous meaning. - Added Config.simplify_objects to control whether SOAPpy objects are simplified into basic python types. - Moved simplification code out of ParseSOAPRPC into SOAPRequestHandler.do_POST and SOAPProxy.__call. - Modified test code appropriately. 2003-12-19 10:58 warnes * tests/simpleWSDL.py: - Add WSDL example from the README as simpleWSDL.py 2003-12-18 17:46 warnes * tests/README: - More information 2003-12-18 17:42 warnes * tests/: README, esj_test_client.py, esj_test_server.py, largeDataTest.py, testClient1.py: - Update test/README with more information - Remove/comment out verbose debugging from tests. 2003-12-18 17:40 warnes * SOAPpy/: Client.py, Config.py, GSIServer.py, Parser.py, SOAPBuilder.py, Server.py, Types.py, WSDL.py, version.py: - More changes to enable proper return of simple python objects when Config.unwrap_results=1. - Addition of support for Globus, contributed by Ivan R. Judson - Resolution of merge conflicts due to unsynchronized copies at home and work. 2003-12-18 13:28 warnes * tests/: echoHeader.py, esj_test_client.py, esj_test_server.py, largeDataTest.py, testClient1.py, testleak.py: - Added more test scripts. 2003-12-18 13:26 warnes * tests/: echoClient.py, echoServer.py: - Add testing of Globus Support code - Turn off verbose debugging messages 2003-12-18 13:25 warnes * tests/SOAPtest.py: - Missed a call to parseSOAPRPC when config.uwrap_results=0. 2003-12-18 02:08 warnes * RELEASE_INFO, TODO: - Update documentation. 2003-12-18 01:55 warnes * SOAPpy/version.py: - Update version string. 2003-12-18 01:54 warnes * SOAPpy/: Config.py, Parser.py, SOAPBuilder.py, Server.py, Types.py: - Config.unwrap_results now works properly. - New Config.dict_encoding option to control the encoding of dictionary keys. By default this is 'ascii' so that dictionaries have ordinary string keys even if they were encoded into UTF for transport (the default is UTF-8). Any other encoding known to string.encode is valid. - New Config.strict_range option to force Parsing to enforce range checking on double and float variables. This is off by default. 2003-12-18 01:31 warnes * tests/: SOAPtest.py, TCtest.py, echoClient.py, echoServer.py, quoteTest.py, storageTest.py, xmethods.py: - Modified SOAPtest.py to work when Config.unwrap_results=1. - Modified SOAPtest.py to set Config.strict_range to enforce checking of the range of float and double objects. [This is a new Config variable and is off by default.] - Fixed wrongly named arguments in TCtest.py - Turned off excess debugging information in echoClient.py, echoServer.py, storageTest.py - Removed unneeded import from quoteTest.py that was generating a warning. - Removed unnecessary explict mapping to dictionary in xmethods.py 2003-12-18 01:23 warnes * tests/README: - A little documentation can go a long way, ;^) 2003-12-17 17:18 warnes * SOAPpy/wstools/WSDLTools.py: - Fix problem when WSDL.Proxy was passed WSDL in a string or other object that does not have a 'name' attribute. 2003-12-08 03:04 boverhof * SOAPpy/wstools/WSDLTools.py: ---------------------------------------------------------------------- Modified Files: WSDLTools.py -- partial bug fix for [ 850905 ] wsdl2py crash on a more sophisticated WSDL. We do expect a list, but nmtokens is a list separated by a single space. So if "parts" is a string, the just split it to create a list. ---------------------------------------------------------------------- 2003-12-05 20:49 boverhof * SOAPpy/wstools/XMLSchema.py: ---------------------------------------------------------------------- Modified Files: XMLSchema.py -- If a schema needs to 'create' a schema instance itself it adds this schema to its import dictionary. ---------------------------------------------------------------------- 2003-12-05 19:17 boverhof * SOAPpy/wstools/XMLSchema.py: ---------------------------------------------------------------------- Modified Files: XMLSchema.py -- error in Import class for accessing a schemaLocation. This bug would only show up if a schema had to 'construct' a schema instance of a different namespace itself. Basically the last option. ---------------------------------------------------------------------- 2003-12-05 10:34 warnes * SOAPpy/: WSDL.py, wstools/WSDLTools.py: - Fixes submitted by Kirk Strauser for WSDL use in SOAPpy 2003-12-04 14:05 warnes * zope/: README, zope-2.5.0-soappy.diff, zope-2.6.2-soappy.diff, zope-soap-client.py: - Added contributed patches from Antonio Beamud Montero that extend Zope with SOAP support. 2003-12-04 13:57 warnes * README, README.MethodParameterNaming, SOAPpy/Config.py, SOAPpy/Parser.py, SOAPpy/SOAPBuilder.py, SOAPpy/Types.py, SOAPpy/version.py: - Mostly changes to allow returned SOAP objects to be 'unwrapped' into plain python objects when Config.unwrap_results=1. 2003-11-21 18:12 warnes * tests/SOAPtest.py: - Fix some errors - Updated to mactch change back to "v#" unnamed variable naming strategy. - Added config.unwrap=0 to prevent unwrapping since this test code expects the old behavior. - Only 1 failure now! 2003-11-14 14:09 warnes * docs/MethodParameterNaming.txt: Moved /README.MethodParameterNaming to /docs/MethodParameterNaming.txt 2003-11-14 13:48 warnes * SOAPpy/Types.py: - Modify compoundType to remove internal _asdict and _aslist objects which were different views of (some of) the object attributes. It was possible for these views to get out of sync causing (at least) confusion. Instead, I provide _aslist() and _asdict() functions to render the existing data in the desired format. - Modify simplify() function to work recursively on compound types. 2003-11-14 13:44 warnes * SOAPpy/Server.py: - if Config.unwrap_results is True, convert SOAPpy arrayType and structType to python list and dictionary. - Modify special argument handling to use "v[0-9]" for unnamed ordered arguments. 2003-11-14 13:36 warnes * SOAPpy/SOAPBuilder.py: - Modifid to use "v[0-9]+" as pattern for ordered but unnamed parameters instead of "_[0-9]". - Modified dump_instance to simplify writing out object components. 2003-11-14 13:32 warnes * SOAPpy/Parser.py: - Parser.py now converts arrayType and structType SOAPpy objects to standard python lists and dictionaries when Config.unwrap_results is True. 2003-11-14 13:29 warnes * SOAPpy/Config.py: - Changed config.specialArgs back to a simple flag. 2003-10-31 21:49 boverhof * SOAPpy/wstools/XMLSchema.py: ---------------------------------------------------------------------- Modified Files: XMLSchema.py -- fixed an unknown bug caused by overlooking the potential namespace contents of a "types" node. ---------------------------------------------------------------------- 2003-10-27 17:42 boverhof * SOAPpy/wstools/: Utility.py, WSDLTools.py, XMLSchema.py: ---------------------------------------------------------------------- Modified Files: Utility.py WSDLTools.py XMLSchema.py -- Fixed [ 810251 ] default method broken in wstools.Utility.Collection -- Also fixed problem with includes Collection key, and changed Types(Collection) class to declare a different default key instead of redefining several methods. ---------------------------------------------------------------------- 2003-10-27 16:26 boverhof * SOAPpy/wstools/: WSDLTools.py, XMLSchema.py: ---------------------------------------------------------------------- Modified Files: WSDLTools.py XMLSchema.py -- Fixed [ 808505 ] ZSI fails with Now schema include statements should be handled correctly. -- Also fixed a problem with relative uri handling for XMLSchema and SchemaReader. ---------------------------------------------------------------------- 2003-10-25 22:54 dwrobertson * SOAPpy/wstools/test/utils.py: Fixed bug, where if multiple tests using one diff file, and one test failed, subsequent tests failed on assertion errors. 2003-10-23 15:09 uid27080 * README: Updated for 0.10.4 2003-10-23 15:00 uid27080 * RELEASE_INFO: Updated for 0.10.4 2003-10-23 14:58 uid27080 * CHANGELOG: - Updated for 0.10.4. 2003-10-22 12:46 tag SOAPpy_0_10_4 2003-10-22 12:46 warnes * SOAPpy/version.py: Release with improved performace thanks to a patch by Erik Westra. 2003-10-22 12:45 warnes * SOAPpy/Parser.py: Patch improving parser performance submitted by Erik Westra: On Tuesday, October 21, 2003, at 09:44 PM, Erik Westra wrote: > Hi Greg, > > I've been using your SOAPpy library (version 0.10.3) in an application > I've been developing, and have had complaints about the amount of time > it takes to receive large packets of data. In this application, the > server was sending through PDF documents as base64-encoded strings, > which were transmitted using a perl SOAP library, and processed on my > end using SOAPpy. As soon as the PDF files got reasonably large, > SOAPpy was taking a long time to decode the data -- up to five minutes > in some cases. > > I started digging into the SOAPpy source code, and quickly found the > cause of the problem: the Parser.py module was using a Python string > to store the character data, and as new character data was being > received, it was "appending" the new data like this [from Parser.py, > line 404]: > > self._data += c > > The problem with this is that Python strings are immutable, so the > above statement is actually recreating the entire string buffer from > scratch every time a new line of character data is received -- which > is extremely inefficient. A much better way to do this is to use a > (mutable) Python list object, and to append the new character data to > the end of this list, like this: > > self._data = [] > > ... > > self._data.append(c) > > and then use: > > string.join(self._data, "") > > to obtain the complete copy of the list once all the lines of data > have been processed. I've attached a unified diff file listing the > changes I've made to Parser.py to implement this -- they're pretty > minimal, and won't affect anything other than the performance of > character data processing. > > The results of this patch are quite impressive: I tried processing a > SOAP response with a single string containing around 675K of data. > Using the unpatched Parser.py file, it took 111 seconds to process -- > with this patch, it took just 2.4 seconds. > > I hope you find this useful... > > Cheers, > > - Erik. > > PS: Thanks for the work you (and the others) are doing on SOAPpy. > It's a great library! 2003-10-21 17:19 dwrobertson * SOAPpy/wstools/test/config.py: Latest xmethods. 2003-10-14 12:08 mbucc * SOAPpy/wstools/Utility.py: Use m2crypto for SSL if it's installed 2003-10-08 13:07 boverhof * SOAPpy/wstools/XMLSchema.py: ---------------------------------------------------------------------- Modified Files: XMLSchema.py -- now we get reasonable error message back when import or include is incorrectly defined. File "/usr/local/lib/python2.3/site-packages/ZSI/wstools/XMLSchema.py", line 478, in __checkAttributes raise SchemaError, '%s, unknown attribute' %a ZSI.wstools.XMLSchema.SchemaError: location, unknown attribute ---------------------------------------------------------------------- 2003-10-03 13:49 rsalz * SOAPpy/wstools/Utility.py: Let lower layers (http lib) raise exception if trying to use SSL on a non-SSL-enabled system. 2003-10-03 10:01 mbucc * SOAPpy/wstools/XMLSchema.py: Removed pyXml dependency. 2003-10-01 18:08 dwrobertson * SOAPpy/wstools/test/__init__.py: For importing utils 2003-10-01 17:47 dwrobertson * SOAPpy/wstools/test/test_wsdl2python.py: High level client code generator tests moved elsewhere. 2003-09-30 04:25 dwrobertson * SOAPpy/wstools/test/utils.py: Fixed premature close of string buffer. 2003-09-25 14:12 tag SOAPpy_0_10_3 2003-09-25 14:12 warnes * SOAPpy/version.py: - Updated to 0.10.3 (we missed a cvs tag point) 2003-09-25 14:09 tag SOAPpy_0_10_2 2003-09-25 14:09 warnes * SOAPpy/SOAPBuilder.py: Updated version number for release 0.10.2. 2003-09-16 20:08 dwrobertson * SOAPpy/wstools/test/config.py: Updated with latest xmethods, removed URL's no longer in xmethods. 2003-09-16 15:25 rsalz * SOAPpy/WSDL.py: Bug 792247: Unnecessarily slow code in WSDL.Proxy.__getattr__ Use has_key instead of creating temporary names() list 2003-09-13 20:38 dwrobertson * SOAPpy/wstools/test/utils.py: Added ability to read values from multiple config file sections, added setUpWsdl utility function, cleaned up loadTestsFromNames, updated comments. 2003-09-13 20:36 dwrobertson * SOAPpy/wstools/test/test_WSDLReader.py: Now using separate MatchTestLoader in makeSuite. Improved way config file sections are selected. 2003-09-13 20:35 dwrobertson * SOAPpy/wstools/test/test_wsdl2python.py: Combined two tests generating services and services_types files into one method. Moved setUpWsdl to utils. Added easier choosing of config file sections. Used separate MatchTestLoader in makeTestSuite. 2003-09-13 20:32 dwrobertson * SOAPpy/wstools/test/: test_t1.py, test_wsdl.py, test_wstools.py, test_wstools_net.py: Converted to more automated way of generating test cases from configuration file. 2003-09-12 02:11 dwrobertson * SOAPpy/wstools/test/config.py: Cleaned up names. 2003-09-11 21:22 dwrobertson * SOAPpy/wstools/test/config.py: services_by_http section divided into services where there is no schema, those with only simple types, those with complex types, those with WSDLReader errors, and those with wsdl2python errors. The last contain mostly those that are raised by that module. 2003-09-11 18:53 boverhof * SOAPpy/wstools/XMLSchema.py: ---------------------------------------------------------------------- Modified Files: XMLSchema.py -- fixed two places where 'readFromURL' was supposed to be loadFromURL. ---------------------------------------------------------------------- 2003-09-10 02:01 dwrobertson * SOAPpy/wstools/test/test_wsdl2python.py: Got rid of pyGridWare import. 2003-09-10 02:01 dwrobertson * SOAPpy/wstools/test/test_WSDLReader.py: Got rid of pyGridWare import 2003-09-10 00:17 dwrobertson * SOAPpy/wstools/test/utils.py: Utilities to aid unit tests. 2003-09-10 00:16 dwrobertson * SOAPpy/wstools/test/test_wsdl2python.py: Unit tests for code generation in wsdl2python 2003-09-10 00:15 dwrobertson * SOAPpy/wstools/test/test_WSDLReader.py: Unit tests for WSDLReader from WSTools 2003-09-10 00:14 dwrobertson * SOAPpy/wstools/test/config.py: Added many URL's from xmethods to services_by_http section. 2003-09-05 15:59 warnes * README: Changed dependency list. SOAPpy does depend on fpconst, but no longer depends on pyXML. 2003-09-05 15:53 warnes * README: - Added dependencies list 2003-09-05 14:57 boverhof * SOAPpy/wstools/XMLSchema.py: ---------------------------------------------------------------------- Modified Files: XMLSchema.py -- added a try clause to catch xml.dom.ext ImportError, and added a SplitQName function that matches xml.dom.ext.SplitQName output. ---------------------------------------------------------------------- 2003-08-28 15:03 boverhof * SOAPpy/wstools/test/: README, config.py, test_t1.py, test_wsdl.py, xmethods.tar.gz: ---------------------------------------------------------------------- Modified Files: README config.py test_t1.py test_wsdl.py xmethods.tar.gz Added a couple tests and an explanation of how to add new tests. ---------------------------------------------------------------------- 2003-08-28 13:26 warnes * SOAPpy/Client.py: - Fixed missing import needed for basic authentication. 2003-08-27 18:27 boverhof * SOAPpy/wstools/test/: README, config.py, schema.tar.gz, test_t1.py, test_wsdl.py, test_wstools.py, test_wstools_net.py, xmethods.tar.gz: ---------------------------------------------------------------------- Added Files: README config.py schema.tar.gz test_t1.py test_wsdl.py test_wstools.py test_wstools_net.py xmethods.tar.gz -- basic unittesting framework for WSDLTools/XMLSchema, test_t1 just checks that everything goes where it's supposed to. ---------------------------------------------------------------------- 2003-08-27 18:25 boverhof * SOAPpy/wstools/XMLSchema.py: ---------------------------------------------------------------------- Modified Files: XMLSchema.py -- attribute declarations were going into wrong collection. ---------------------------------------------------------------------- 2003-08-26 18:43 boverhof * SOAPpy/wstools/: WSDLTools.py, XMLSchema.py: ---------------------------------------------------------------------- Modified Files: WSDLTools.py -- added a line in Reader to to set WSDL.location for files so that imports with relative paths will work for file paths as well as urls. XMLSchema.py -- a couple Attribute fixes, and the WSDLAdapter wasn't passing it's parent into the XMLSchemaComponent constructor which was messing up import lookups. ---------------------------------------------------------------------- 2003-08-25 18:35 boverhof * SOAPpy/wstools/XMLSchema.py: ---------------------------------------------------------------------- Modified Files: XMLSchema.py -- fixed XMLSchemaComponent.setAttributes, added the needed getNamespace method to all DOMAdapters. All changes are related to XML attribute handling. ---------------------------------------------------------------------- 2003-08-25 08:16 warnes * README: - Applied patch submitted by Humberto Diógenes (virtualspirit): Corrected examples inside "readme Just eliminated some warnings ("import SOAPProxy" instead of "import SOAP") 2003-08-07 00:49 boverhof * SOAPpy/wstools/XMLSchema.py: ---------------------------------------------------------------------- Modified Files: XMLSchema.py -- Modified/Extended some of the element classes. For LocalElementDeclaration inheritance was duplicitous, and for ElementReference it was wrong. ---------------------------------------------------------------------- 2003-08-05 19:42 boverhof * SOAPpy/wstools/XMLSchema.py: ---------------------------------------------------------------------- Modified Files: XMLSchema.py -- Fixed a few bugs, a few classes mistakenly thought they contained global attribute declarations and I fixed this to local attribute declarations. Couple spots where AttributeGroup declarations and references were incorreclty used in place of eachother. Completed a few classes but a few remain incomplete. ---------------------------------------------------------------------- 2003-07-31 02:37 boverhof * SOAPpy/wstools/XMLSchema.py: ---------------------------------------------------------------------- Modified Files: XMLSchema.py -- Namespaced a couple attributes in attribute dictionary that I missed. ---------------------------------------------------------------------- 2003-07-30 15:45 boverhof * SOAPpy/wstools/XMLSchema.py: ---------------------------------------------------------------------- Modified Files: XMLSchema.py -- there was a indexing logic error in Restriction/Extention classes fromDom method. Also changed the attribute dictionary of all classes that inherit XMLSchemaComponent, now all attributes are organized by namespace. ---------------------------------------------------------------------- 2003-07-25 17:46 boverhof * SOAPpy/wstools/XMLSchema.py: ---------------------------------------------------------------------- Modified Files: XMLSchema.py -- Wasn't resolving schema imports in every scenario. Now look in parent schema imported_schemas first, second look in the parent wsdl, lastly try to resolve schemaLocation. Removed 'what' parameter from marker interface methods, I don't know what it was doing there. Check self. ---------------------------------------------------------------------- 2003-07-23 20:34 boverhof * SOAPpy/wstools/XMLSchema.py: ---------------------------------------------------------------------- Modified Files: XMLSchema.py -- changed getQNameAttribute to return None if it can't find QName obj in it's own tns or in any of its imported namespaces. Used to throw an exception. ---------------------------------------------------------------------- 2003-07-23 18:16 boverhof * SOAPpy/wstools/XMLSchema.py: ---------------------------------------------------------------------- Modified Files: XMLSchema.py -- fixed some default attribute handling, added a few get methods in XMLSchema for elementFormDefault, attributeFormDefault, blockDefault, finalDefault. Also added a global method GetSchema. Now default attributes are set correctly in all schema components. ---------------------------------------------------------------------- 2003-07-23 16:33 boverhof * SOAPpy/wstools/XMLSchema.py: ---------------------------------------------------------------------- Modified Files: XMLSchema.py -- checking for wrong class in two methods. ---------------------------------------------------------------------- 2003-07-23 14:25 boverhof * SOAPpy/wstools/XMLSchema.py: ---------------------------------------------------------------------- Modified Files: XMLSchema.py -- removed bogus method setType in SimpleType class. ---------------------------------------------------------------------- 2003-07-22 13:39 boverhof * SOAPpy/wstools/Utility.py: ---------------------------------------------------------------------- Modified Files: Utility.py -- commited a mistake. fixed. ---------------------------------------------------------------------- 2003-07-22 13:34 boverhof * SOAPpy/wstools/: Utility.py, XMLSchema.py: ---------------------------------------------------------------------- Modified Files: Utility.py -- Added a parameter to Collection class constructor, 'name' is the default attribute used for keys but one can specify whatever key they want. XMLSchema.py -- Used the above parameter to make Collection instances use the appropriate 'attribute' as key. ---------------------------------------------------------------------- 2003-07-22 10:57 warnes * SOAPpy/: Parser.py, SOAPBuilder.py: - More fixes to use fpconst instead of ieee754. 2003-07-22 10:54 warnes * SOAPpy/: Parser.py, SOAPBuilder.py, wstools/__init__.py, wstools/ieee754.py: - Remove obsolete ieee754.py. PEP 754 provides a (proposed) fpconst module which is a newer version of this code. fpconst, will of course, need to be installed separately. 2003-07-21 18:13 boverhof * SOAPpy/wstools/XMLSchema.py: ---------------------------------------------------------------------- Modified Files: XMLSchema.py -- still a couple mistakes in constructors, changed XSDNS to SCHEMA.XSD_LIST which was a mistake. 2003-07-21 17:56 boverhof * SOAPpy/wstools/XMLSchema.py: ---------------------------------------------------------------------- Modified Files: XMLSchema.py -- missing parent parameter to a few constructors that expect to see it. fixed. 2003-07-21 15:14 boverhof * SOAPpy/wstools/: XMLSchema.py, license.txt: ---------------------------------------------------------------------- Modified Files: XMLSchema.py -- added LBNL copyright header. Added Files: license.txt -- LBNL copyright. 2003-07-21 10:18 warnes * SOAPpy/: version.py, wstools/UserTuple.py, wstools/XMLSchema.py: - Modified XMLSchema to extend UserTuple instead of tuple for python < 2.2. - Added UserTuple class, taken from from Stefan Schwarzer's ftputil library, which is available at . 2003-07-21 09:15 warnes * SOAPpy/Utilities.py: - Unecesssary import was creating a circular import loop. 2003-07-18 13:36 tyger23 * SOAPpy/wstools/XMLSchema.py: fixed a naming issue 2003-07-18 11:58 warnes * SOAPpy/URLopener.py, SOAPpy/WSDL.py, tests/BabelfishWSDLTest.py: - Modifed WSDL.Proxy to pass along all arguments to SOAPProxy. This should ensure that all features of SOAPProxy are accessible to users of WSDL.Proxy - Created URLopener.py, which contains a class extending urllib.FancyURLopener. This class allows reading from URLs that are protected by basic authenticatoin, have been relocated, etc. - Modified WSDL.Proxy to use URLopener. It should now permit access to WSDL files protected by basic authentication. 2003-07-18 10:13 warnes * SOAPpy/Client.py: - Trivial formatting change 2003-07-17 18:23 boverhof * SOAPpy/wstools/XMLSchema.py: ---------------------------------------------------------------------- Modified Files: XMLSchema.py -- fixed a couple bad variable references. 2003-07-17 17:48 boverhof * SOAPpy/wstools/: WSDLTools.py, XMLSchema.py: Modified Files: WSDLTools.py -- just a few minor changes so the new schema class will be used instead of the schema tns placeholder. Might want to add an argument to WSDL.load method so that programmer can specify the placeholder or actual implementation. XMLSchema.py -- mostly new, unused original code is commented out at the bottom. 2003-07-02 14:58 warnes * SOAPpy/: Client.py, version.py: - Client.py failed to import faultType from Types.py, and was getting the python default instead. This caused problems in properly detecting errors on the server reported via SOAP. 2003-05-29 17:01 warnes * SOAPpy/WSDL.py: - Add additional arguments to __init__ which will be passed to Proxy.__init__. This allows specification of proxy server and other options. 2003-05-22 22:31 feanor420 * SOAPpy/wstools/Utility.py: Running pychecker over ZSI, and I noticed some problems in wstools. I fixed that fact that Notation and Entity were not be found. I changed them to use the qualified name like the rest of the symbols from xml.dom.minidom. I also discovered that a RecursionError was being thrown, but RecursionError didn't exist. I created simple sub-class of Exception to rectify this. 2003-05-21 13:39 warnes * SOAPpy/Client.py: - Modified getNS pattern to prevent grabbing to much text. 2003-05-21 12:06 blunck2 * SOAPpy/Client.py: changed namespace regular expression so that it matches what is returned from a stateful (*shiver*) soap server. for example, the namespace returned from a stateful soap server looks like: urn:echo@rO0ABXNyACJ3ZWJsb2.... where urn:echo was the original namespace. 2003-05-21 11:33 tag SOAPpy_0_10_1 2003-05-21 11:33 warnes * CHANGELOG, RELEASE_INFO: - Updated CHANGELOG and RELEASE_INFO for 0.10.1 release. 2003-05-21 10:52 warnes * tests/: SOAPtest.py, TCtest.py, alanbushTest.py, echoClient.py, echoServer.py, excelTest.py, newsTest.py, quoteTest.py, speedTest.py, storageTest.py, translateTest.py, weatherTest.py, whoisTest.py, xmethods.py: - Add ".." to python module path so that the local SOAPpy code will be used instead of the globally installed code when running tests. 2003-05-21 10:51 warnes * setup.py: - Update setup.py to get version string from SOAPpy/version.__version__. 2003-05-21 10:37 warnes * SOAPpy/version.py: - I forgot to update the version number associated with the addition of the file version.py. 2003-05-21 10:34 warnes * SOAPpy/: Client.py, Errors.py, Server.py, version.py: - Added file 'version.py' whose sole purpose is to hold the definition of __version__ in a single place. - Modified Server.py and Client.py to 'from version import __version__'. - Removed __version__ definition from Error.py, which never used it. 2003-05-20 17:25 tag SOAPpy_0_10_0 2003-05-20 17:25 warnes * RELEASE_INFO: Updated for release 0.10.0. 2003-05-20 17:10 warnes * SOAPpy/wstools/: TimeoutSocket.py, Utility.py, WSDLTools.py, XMLSchema.py, XMLname.py, __init__.py: - Added ident string containing CVS version to all files that were lacking this. 2003-05-20 17:04 warnes * CHANGELOG, TODO, setup.py, SOAPpy/SOAP.py, SOAPpy/Types.py, SOAPpy/WSDL.py, SOAPpy/__init__.py: - Added ident string containing CVS version to all files that were lacking this. 2003-05-20 16:08 warnes * SOAPpy/Client.py: - Fix bug in getNS that caused loss of namespace by using better pattern matching to find the namespace in the SOAP message. 2003-05-20 08:47 warnes * setup.py: - Removed or changed dashes to underscores in version numbers to make RPM happy. 2003-05-19 13:45 warnes * SOAPpy/Server.py: - Added ThreadingSOAPServer which inherits from ThreadingTCPServer server so that muliple clients will be automatically multiplexed. 2003-05-15 20:31 boverhof * SOAPpy/wstools/XMLSchema.py: Modified Files: XMLSchema.py ---------------------------------------------------------------------- fixed an obvious bug, added a SchemaError class so it can actually be thrown. ---------------------------------------------------------------------- 2003-05-13 20:22 blunck2 * SOAPpy/wstools/WSDLTools.py: changed references to classes that exist within this module. 2003-05-09 08:46 warnes * README, TODO, setup.py, SOAPpy/Client.py, SOAPpy/Config.py, SOAPpy/Errors.py, SOAPpy/NS.py, SOAPpy/Parser.py, SOAPpy/SOAP.py, SOAPpy/SOAPBuilder.py, SOAPpy/Server.py, SOAPpy/Types.py, SOAPpy/Utilities.py, SOAPpy/WSDL.py, SOAPpy/__init__.py, tests/SOAPtest.py, tests/TCtest.py, tests/alanbushTest.py, tests/cardClient.py, tests/cardServer.py, tests/echoClient.py, tests/echoServer.py, tests/excelTest.py, tests/fortuneTest.py, tests/guidTest.py, tests/itimeTest.py, tests/newsTest.py, tests/quoteTest.py, tests/quoteTest1.py, tests/quoteTest2.py, tests/speedTest.py, tests/storageTest.py, tests/testWSDL.py, tests/translateTest.py, tests/weatherTest.py, tests/whoisTest.py, tests/wordFindTest.py, tests/xmethods.py: - Merge changes splitting SOAP.py file into 10 separate files. This should make the source much easier to navigate. 2003-05-09 03:17 warnes * setup.py, SOAPpy/Client.py, SOAPpy/Parser.py, SOAPpy/SOAP.py, SOAPpy/Server.py, SOAPpy/Utilities.py, SOAPpy/WSDL.py, SOAPpy/__init__.py, tests/SOAPtest.py, tests/TCtest.py, tests/alanbushTest.py, tests/cardClient.py, tests/cardServer.py, tests/echoClient.py, tests/echoServer.py, tests/excelTest.py, tests/newsTest.py, tests/quoteTest.py, tests/speedTest.py, tests/storageTest.py, tests/testWSDL.py, tests/translateTest.py, tests/weatherTest.py: - Many changes associated with splitting SOAP.py into separate files. - Added Mark Bucciarelli's patch to provide wsdl code on properly structured .GET requests 2003-05-09 02:41 warnes * tests/translateTest.py: - Added code to check for http_proxy environment variable and 'do the right thing' (tm). 2003-05-09 02:39 warnes * tests/whoisTest.py: - Updated to use whois SOAP service provided by www.SoapClient.com 2003-05-09 02:23 warnes * tests/wordFindTest.py: - Service no longer exists. 2003-05-09 02:16 warnes * tests/: quoteTest1.py, quoteTest2.py: - Service no longer exists. 2003-05-09 02:13 warnes * tests/xmethods.py: - Added test out to xmethods.net, which looks like a stable site with lots of useful SOAP/WSDL/... stuff. 2003-05-09 02:13 warnes * tests/itimeTest.py: - Service no longer exists. 2003-05-08 23:44 warnes * tests/guidTest.py: - The target SOAP server no longer exists. 2003-05-08 23:14 warnes * tests/fortuneTest.py: - The target server no longer exists. Delete test. 2003-05-08 17:32 warnes * TODO: - Add TODO file. 2003-05-08 17:29 warnes * README, setup.py, SOAPpy/Client.py, SOAPpy/Config.py, SOAPpy/Errors.py, SOAPpy/NS.py, SOAPpy/Parser.py, SOAPpy/SOAP.py, SOAPpy/SOAPBuilder.py, SOAPpy/Server.py, SOAPpy/Types.py, SOAPpy/Utilities.py, SOAPpy/__init__.py, tests/cardClient.py, tests/excelTest.py, tests/testWSDL.py: - Split up the monolithic SOAPpy/SOAP.py into separate files. This should make SOAPpy easier to maintain. - Other incidental changes.. 2003-05-08 13:26 rsalz * SOAPpy/: WSDL.py, wstools/ServiceProxy.py, wstools/__init__.py: Finish up what Mark Bucciarelli kicked off and I started with commit a little while ago. :) That is, wstools is now independant of SOAPpy and ZSI. This commit does the following: wstools/ServiceProxy.py is now ZSI/ServiceProxy.py, so some imports and ZSI docs had to change. ZSI needs some changing, in case I didn't patch up all the imports right. 2003-05-08 12:58 rsalz * SOAPpy/wstools/: ServiceProxy.py, WSDLTools.py: Move some stuff from ServiceProxy (which imports ZSI) to WSDLTools (which doesn't), so that SOAPpy can use wstools without needing ZSI around... which is kinda the point of generic common-code. :) class SOAPCallInfo: class ParameterInfo: class HeaderInfo(ParameterInfo): def callInfoFromWSDL(port, name): Next step is to move what's left of wstools/ServiceProxy.py into the ZSI module (and fix up the imports), so that wstools has *no* soap-stack-specific code in it. 2003-05-07 17:07 warnes * SOAPpy/SOAP.py: - Fixed XML parse error memory leak fix to still raise the error... 2003-05-07 12:50 warnes * SOAPpy/SOAP.py: - Applied patch by bstpierre, which he suggested to fix memory leaks in bug report 544572 (see http://sourceforge.net/tracker/index.php?func=detail&aid=544572&group_id=26590&atid=387667). The leaks seem to have been corrected by other patches, but the suggested code is cleaner, so I've applied it anyway. 2003-05-07 11:34 warnes * SOAPpy/SOAP.py: - Applied patch by Mark Bucciarelli to fix memory leak when the SAX parser throws an exception. 2003-05-07 10:39 warnes * SOAPpy/SOAP.py: - Commit memory leak fix patch submitted by Jeremy Fincher (jemfinch). 2003-04-30 15:38 warnes * SOAPpy/SOAP.py: - Fixed display of exception when an internal error happens. 2003-04-29 10:53 rsalz * SOAPpy/wstools/: ServiceProxy.py, Utility.py: Remove DOS line-ending ^M chars 2003-04-28 10:59 rsalz * SOAPpy/wstools/.cvsignore: Move .cvsignore from ZSI/wsdl to wstools 2003-04-28 09:57 tag SOAPpy_0_9_9_pre5 2003-04-28 09:57 warnes * SOAPpy/SOAP.py: - Updated version number 2003-04-28 09:56 warnes * CHANGELOG, MANIFEST.in, README, SOAPpy/WSDL.py, SOAPpy/__init__.py, tests/TemperatureService.wsdl, tests/testWSDL.py: - Added client support for WSDL, ported from ZSI by Mark Bucciarelli 2003-04-24 22:50 warnes * setup.py, SOAPpy/SOAP.py, SOAPpy/__init__.py: - More changes associated with moving ZSI/SOAPpy common code into wstools CVS package. 2003-04-24 19:08 warnes * setup.py, SOAPpy/SOAP.py, SOAPpy/XMLname.py, SOAPpy/__init__.py, SOAPpy/ieee754.py: - Moved XMLname.py and ieee754 to the wstools CVS package. - Modified SOAPpy to include these files from thier new location. 2003-04-24 13:45 warnes * SOAPpy/wstools/: XMLname.py, __init__.py, ieee754.py: - Moved XMLname.py and ieee754.py into the wstools CVS package from SOAPpy/SOAPpy. 2003-04-24 13:03 rsalz * SOAPpy/wstools/: ServiceProxy.py, TimeoutSocket.py, Utility.py, WSDLTools.py, XMLSchema.py, ZPL, __init__.py: Import files from (now outdated) ZSI/wsdl directory 2003-03-27 11:36 warnes * CHANGELOG, SOAPpy/SOAP.py: Updated version to 0.9.9-pre3 and added reason to changelog. 2003-03-27 11:22 warnes * SOAPpy/SOAP.py: - Only define SOAPUnixSocketServer if the Unix domain sockets are supported 2003-03-27 08:10 tag REL_0_9_9_pre2 2003-03-27 08:10 warnes * CHANGELOG: - Added named scope change. 2003-03-27 08:07 warnes * SOAPpy/SOAP.py: - New argument handling codes needs nested scopes. 2003-03-27 07:32 warnes * CHANGELOG, README, RELEASE_INFO: - Updated text files for 0.9.9-pre2 release. 2003-03-26 16:12 warnes * SOAPpy/SOAP.py: - Update version number to 0.9.9-pre2 2003-03-26 12:55 warnes * SOAPpy/__init__.py: - Added import of ieee754. 2003-03-26 12:54 warnes * SOAPpy/ieee754.py: - Fixed type in __doc__ text. 2003-03-26 11:29 warnes * SOAPpy/SOAP.py: - Split class SOAPServer into SOAPServerBase and two sublcasses, SOAPServer and SOAPUnixSocketServer. SOAPServer has the same functionality as before, while SOAPUnixSocketServer connects over a Unix domain socket instead of to a (public) TCP/IP port. 2003-03-26 00:02 tag REL_0_9_9_pre1 2003-03-26 00:02 warnes * CHANGELOG: - Updated to note addition of ieee754 module and changes enablein MS-Windows support 2003-03-25 23:51 warnes * SOAPpy/: SOAP.py, ieee754.py: - Added ieee754.py, which handles checking for IEEE 754 special values: Inf, -Inf, NaN, ... - Updated SOAP.py to use the new ieee754 module instead of the old (broken) windows hack. 2003-03-25 15:53 warnes * SOAPpy/SOAP.py: - Reversed version string to 0.9.9-pre1. 2003-03-25 15:45 warnes * CHANGELOG, README.MethodParameterNaming, SOAPpy/SOAP.py: - specialArgs handling is now enabled by default. 2003-03-25 15:26 warnes * setup.py: - Modified setup.py to get version number directly from SOAPpy/SOAP.py's __version__ variable. 2003-03-25 12:53 warnes * SOAPpy/SOAP.py: - Changed all references from actzero.com to pywebsvcs.sf.net. 2003-03-25 12:02 warnes * SOAPpy/SOAP.py: - Unnamed arguments which were lists were being incorrectly given the name 'Result'. 2003-03-12 03:14 tag REL_0_9_8 2003-03-12 03:14 warnes * MANIFEST.in: - Added MANIFEST.in: needed by setup.py to create source distribution. 2003-03-12 02:53 warnes * tests/: SOAPtest.py, TCtest.py, echoClient.py, echoServer.py, excelTest.py, speedTest.py: - Updates related to change in structure to allow installation using python distutils (i.e. setup.py) 2003-03-12 02:47 warnes * setup.py: - Updated version number to 0.9.8 2003-03-12 02:38 warnes * CHANGELOG: - Noted directory restructuring in CHANGELOG. 2003-03-08 00:10 warnes * CHANGELOG, README, setup.py, SOAPpy/__init__.py, bid/inventoryClient.py, bid/inventoryServer.py, bid/monitorClient.py, contrib/soap_cli.py, contrib/soap_handler.py, tests/alanbushTest.py, tests/cardClient.py, tests/cardServer.py, tests/fortuneTest.py, tests/guidTest.py, tests/itimeTest.py, tests/newsTest.py, tests/quoteTest.py, tests/quoteTest1.py, tests/quoteTest2.py, tests/storageTest.py, tests/translateTest.py, tests/weatherTest.py, tests/whoisTest.py, tests/wordFindTest.py, validate/silabclient.py, validate/silabserver.py, validate/soapware.py: - Updates related to change in structure to allow installation using python distutils (i.e. setup.py) 2003-03-08 00:07 warnes * SOAPpy/SOAP.py: - implemented an experimental method of handling method argument names. 2003-03-08 00:00 warnes * README.MethodParameterNaming: - Fixed typos, improved wording and formatting. 2003-03-05 16:43 warnes * setup.py: - Initial version of setup.py. Not yet tested! 2003-02-10 12:06 rsalz * SOAPpy.spec: Add RPM spec file from Antonio Beamud Montero (http://www.agoratechnologies.com). Temporary fix until a setup.py file is written. 2002-08-06 14:26 tag Release_1_0_0_beta3 2002-08-06 14:26 blunck2 * SOAPpy/SOAP.py: - Changed invoke method in SOAPProxy class to return the value from the __call invocation (there was previously no way to extract the return values from the call) 2002-07-30 22:28 blunck2 * SOAPpy/SOAP.py: HTTPTransport.call(..) returns the response message from the HTTP request regardless of the value of config.dumpSOAPIn. I removed the conditional logic around the fetching of the response message so that prior to the call to getNS, the data is guaranteed to be there. 2002-07-30 20:30 warnes * CHANGELOG, README, SOAPpy/SOAP.py: - Added 'no namespace' check to namespace-rewriting code to avoid problems when no namespace is specified. - Updated CHANGELOG and README - Added noroot parameter to the SOAPBuilder and SOAPProxy objects in order to provide compatibility with an older version of EasySOAP (v0.2) that balked if the SOAP-ENC:root parameter was included.(Brad Knotwell) 2002-07-25 17:38 blunck2 * SOAPpy/SOAP.py: - Added support for namespace-rewriting (used by Apache v2.x SOAP server for error conditions as well as stateful communication) - Added string <-> str conversion for array types (Python 2.2+) - Added convenience method (invoke) to SOAPProxy that calls __call (not sure if it is necessary - feel free to remove if you want) 2002-07-25 15:43 warnes * SOAPpy/SOAP.py: - Python 'float' are equivalent to SOAP 'double'. Modified dump_float and dump_list to use SOAP type string 'double' appropriately. 2002-06-27 15:44 tag Release_0_1_b2 2002-06-27 15:44 tag Release_0_1b2 2002-06-27 15:44 warnes * SOAPpy/SOAP.py: - Patch from Brad Knotwell [b.knotwell@f5.com] to add basic authentication: Hi Gregory-- This is untested (except for running some of the example programs to ensure it didn't break anything). However, it's trivial enough (and copied almost verbatim from ZSI. . .I helped Rich with Authorization there as well) that I would be pretty confident about committing it. My primary assumption in saying this is that the Authorization header can show up *anywhere* in the header stream and that I've inserted the putheader in the right method call. --Brad 2002-05-24 17:38 warnes * SOAPpy/SOAP.py: Fixes to enble proper handling of SOAP faults by the client. - Fixed test of whether message content is text/xml when recieving a fault. - Added __call__ method to exception classes to match the current API. - The faultType.__repr__() method now print details if present 2002-05-10 10:56 warnes * SOAPpy/: SOAP.py, XMLname.py, __init__.py: - Added XMLnam.py which provides toXMLname() and fromXMLname() for properly encoding xml tag names per the SOAP 2.1 (draft) specification. - Added calls to toXMLname() and fromXMLname() so that tags names are properly encoded. This resolves bug [ 548785 ] 'Error passing dict keys containing space.' - Added code to cgi encode contents of tags when they are not a recognized type. Fixes bug [ 549551 ] 'Error when passing non-standard types'. - Added __init__.py, so that SOAPpy can be used like a standard python module. 2002-02-26 22:19 gliptak * SOAPpy/SOAP.py, tests/SOAPtest.py: Use array for string concat when building messages 2002-02-26 21:33 gliptak * SOAPpy/SOAP.py, tests/SOAPtest.py: Correcting arrayType struct typo 2002-02-26 20:14 gliptak * tests/quoteTest2.py: Another quote test using mybubble.com 2002-02-26 20:13 gliptak * tests/SOAPtest.py: Added test for parameter ordering 2002-02-26 20:11 gliptak * SOAPpy/SOAP.py: Support for explicit parameter ordering 2002-02-25 22:34 gliptak * tests/translateTest.py: Correcting URL and URN 2002-02-25 22:25 gliptak * tests/guidTest.py: Correcting URL 2002-02-25 22:17 gliptak * tests/alanbushTest.py: Correct URI and list categories 2002-02-25 22:06 gliptak * tests/SOAPtest.py: Modified to use PyUnit 2002-02-25 16:47 gliptak * tests/SOAPtest.py: Do not fail for large double parsing for Python 2.2 2002-02-25 10:57 gliptak * SOAPpy/SOAP.py: Fixing abs(None) traceback 2002-02-24 21:50 gliptak * tests/quoteTest1.py: Another quote service test 2002-02-24 21:48 gliptak * tests/wordFindTest.py: Corrected import path 2002-02-24 21:46 gliptak * SOAPpy/SOAP.py: Aliases for Python 2.2 (lib\types.py definitions changed) 2001-11-05 14:19 tag REL_0_9_9_pre5 2001-11-05 14:19 tag v1_2RC4 2001-11-05 14:19 tag v1_2RC5 2001-11-05 14:19 tag v1_2RC6 2001-11-05 14:19 rsalz * .cvsignore, bid/.cvsignore, contrib/.cvsignore, tests/.cvsignore, tools/.cvsignore, validate/.cvsignore: add .cvsignore 2001-07-06 14:03 tag v1_2RC1 2001-07-06 14:03 tag v1_2RC2 2001-07-06 14:03 tag v1_2RC3 2001-07-06 14:03 cullman * SOAPpy/SOAP.py: Fixed the memory leak. 2001-06-28 16:13 cullman * SOAPpy/SOAP.py: Fixed the 500 return code is always a SOAP response "issue". 2001-06-27 18:33 tag REL_0_9_6 2001-06-27 18:33 cullman * CHANGELOG: More changelog changes. 2001-06-27 18:30 cullman * contrib/soap_handler.py: Adding the contributed soap_handler. 2001-06-27 18:29 cullman * contrib/soap_cli.py: Added the medusa example files contributed by Ng. 2001-06-27 18:13 cullman * CHANGELOG: Added a description of the latest release. 2001-06-27 17:36 tag start 2001-06-27 17:36 cullman * CHANGELOG, README, SOAPpy/SOAP.py, bid/inventory.servers, bid/inventoryClient.py, bid/inventoryServer.py, bid/monitorClient.py, docs/quickstart.txt, docs/simpleTypes.txt, tests/SOAPtest.py, tests/TCtest.py, tests/echoClient.py, tests/echoServer.py, tests/excelTest.py, tests/speedTest.py, docs/attrs.txt, docs/complexTypes.txt, tests/alanbushTest.py, tests/cardClient.py, tests/cardServer.py, tests/fortuneTest.py, tests/guidTest.py, tests/itimeTest.py, tests/newsTest.py, tests/quoteTest.py, tests/storageTest.py, tests/translateTest.py, tests/weatherTest.py, tests/whoisTest.py, tests/wordFindTest.py, tools/interop2html.py, validate/server.pem, validate/silab.servers, validate/silabclient.py, validate/silabserver.py, validate/soapware.py: Initial SOAP.py check in. 2001-06-27 17:36 cullman * CHANGELOG, README, SOAPpy/SOAP.py, bid/inventory.servers, bid/inventoryClient.py, bid/inventoryServer.py, bid/monitorClient.py, docs/quickstart.txt, docs/simpleTypes.txt, tests/SOAPtest.py, tests/TCtest.py, tests/echoClient.py, tests/echoServer.py, tests/excelTest.py, tests/speedTest.py, docs/attrs.txt, docs/complexTypes.txt, tests/alanbushTest.py, tests/cardClient.py, tests/cardServer.py, tests/fortuneTest.py, tests/guidTest.py, tests/itimeTest.py, tests/newsTest.py, tests/quoteTest.py, tests/storageTest.py, tests/translateTest.py, tests/weatherTest.py, tests/whoisTest.py, tests/wordFindTest.py, tools/interop2html.py, validate/server.pem, validate/silab.servers, validate/silabclient.py, validate/silabserver.py, validate/soapware.py: Initial revision SOAPpy-0.12.0/LICENSE0100644001604000501700000000440610202425154013533 0ustar warnegclinical============================================== SOAPpy - Simple to use SOAP library for Python ============================================== Current Maintainers: Gregory R. Warnes Christopher Blunck Original Authors: Cayce Ullman Brian Matthews Contributions by: Brad Knotwell Mark Bucciarelli (ported WSDL client from ZSI) Ivan R. Judson (Globus support) Kirk Strauser Antonio Beamud Montero (patches for integrating SOAPpy into Zope) Copyright (c) 2002-2003, Pfizer, Inc. Copyright (c) 2001, Cayce Ullman. Copyright (c) 2001, Brian Matthews. All rights reserved. LICENSE: ---------------------------------------------------------------------------- Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. Neither the name of actzero, inc. nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. SOAPpy-0.12.0/README0100644001604000501700000001476310206653253013424 0ustar warnegclinical============================================== SOAPpy - Simple to use SOAP library for Python ============================================== Current Maintainer: Gregory R. Warnes Original Authors: Cayce Ullman Brian Matthews Contributions by: Christopher Blunck Brad Knotwell Mark Bucciarelli (ported WSDL client from ZSI) Ivan R. Judson (Globus support) Kirk Strauser Antonio Beamud Montero (patches for integrating SOAPpy into Zope) And others. Copyright (c) 2002-2005, Pfizer, Inc. Copyright (c) 2001, Cayce Ullman. Copyright (c) 2001, Brian Matthews. All rights reserved, see the file LICENSE for conditions of use. INTRODUCTION ============ The goal of the SOAPpy team is to provide a full-featured SOAP library for Python that is very simple to use and that fully supports dynamic interaction between clients and servers. INCLUDED -------- - General SOAP Parser based on sax.xml - General SOAP Builder - SOAP Proxy for RPC client code - SOAP Server framework for RPC server code FEATURES -------- - Handles all SOAP 1.0 types - Handles faults - Allows namespace specification - Allows SOAPAction specification - Homogeneous typed arrays - Supports multiple schemas - Header support (mustUnderstand and actor) - XML attribute support - Multi-referencing support (Parser/Builder) - Understands SOAP-ENC:root attribute - Good interop, passes all client tests for Frontier, SOAP::LITE, SOAPRMI - Encodings - SSL clients (with Python compiled with OpenSSL support) - SSL servers (with Python compiled with OpenSSL support and M2Crypto installed) - Encodes XML tags per SOAP 1.2 name mangling specification (Gregory Warnes) - Automatic stateful SOAP server support (Apache v2.x) (blunck2) - WSDL client support - WSDL server support TODO (See RELEASE_INFO and CHANGELOG for recent changes) ---- - Timeout on method calls - Advanced arrays (sparse, multidimensional and partial) - Attachments - mod_python example - medusa example - Improved documentation MANIFEST -------- Files README This file RELEASE_NOTES General information about each release ChangeLog Detailed list of changes TODO List of tasks that need to be done setup.py Python installation control files MANIFEST MANIFEST.in SOAPpy.spec* RPM package control file Directories SOAPpy/* Source code for the package SOAPpy/wstools/* Source code for WSDL tools tests/* unit tests and examples validate/* interop client and servers bid/* N+I interop client and server doc/* Documentation contrib/ Contributed examples (also see test/) docs/ Documentation tools/ Misc tools useful for the SOAPpy developers zope/ Patches to Zope allowing it to provide SOAP services INSTALLATION ============ REQUIRED PACKAGES: ----------------- - fpconst 0.6.0 or later, - pyXML 0.8.3 or later, OPTIONAL PACKAGES ----------------- - pyGlobus, optional support for Globus, - M2Crypto.SSL, optional support for server-side SSL - If Python is compiled with SSL support (Python 2.3 does so by default), client-side use of SSL is supported INSTALLATION STEPS ------------------ As of version 0.9.8 SOAPpy can be installed using the standard python package installation tools. To install: 1) Unpack the distribution package: On Windows, use your favorite zip file uncompression tool. On Unix: $ tar -xvzf SOAPpy-$VERSION$.tar.gz if you have gnu tar, otherwise $ gzcat SOAPpy-$VERSION$.tar.gz | tar -xvf - 2) Change into the source directory $ cd SOAPpy-$VERSION$ 3) Compile the package $ python setup.py build 4) Install the package On Windows: $ python setup.py install On Unix install as the owner of the python directories (usally root): $ su root Password: XXXXXX $ python setup.py install DOCUMENTATION ============= QUICK START ----------- A simple "Hello World" http SOAP server: import SOAPpy def hello(): return "Hello World" server = SOAPpy.SOAPServer(("localhost", 8080)) server.registerFunction(hello) server.serve_forever() And the corresponding client: import SOAPpy server = SOAPpy.SOAPProxy("http://localhost:8080/") print server.hello() BASIC TUTORIAL -------------- Mark Pilgrims' _Dive Into Python_, published in printed form by Apress and online at at http://diveintopython.org provides a nice tutorial for SOAPpy in Chapter 12, "SOAP Web Services". See http://diveintopython.org/soap_web_services . OTHER DOCUMENTATION ------------------- For further information see the files in the docs/ directory. Note that documentation is one of SOAPpy's current weak points. Please help us out! GETTING HELP ============ REPORTING BUGS -------------- Please submit bug reports, feature requests, patches, etc at the Python Web Services web site: http://pywebsvcs.sourceforge.net. MAILING LIST ============ Please address questions and general discussion to the pywebsvcs-talk mailing list, pywebsvcs-talk@lists.sourceforge.net. For subscription information visit http://lists.sourceforge.net/lists/listinfo/pywebsvcs-talk. List archives are available at http://sourceforge.net/mailarchive/forum.php?forum=pywebsvcs-talk Please remember that the authors do have day jobs, so please try the mailing list before contacting them directy. $Id: README,v 1.18 2005/02/22 15:58:35 warnes Exp $ SOAPpy-0.12.0/RELEASE_INFO0100644001604000501700000005113210206653006014345 0ustar warnegclinical Release 0.12.0 of SOAPpy ------------------------ This release primarily foces on bug fixes. Primary changes: - Fixes for bug reports that have accumulated over the last year [ 916265] "Arrays of unicode do not serialize correctly (patch included)" [ 918216] "Parsing faults in SOAPpy 0.11.3" [ 925077] "SOAPpy prints out SOAP fault" (even when Config.debug is off). [1001646] "SOAPpy stomps headers when sending multirefs" [1001646] "SOAPpy stomps headers when sending multirefs. [1064233] "Bug fixes for complex types" [1064248] "Bugs in _asdict() and _asarray() in Types.py" [1078051] "Arrays of complex types (doc/lit)" [1096971] "Parse error: missing HTTP header 'Content-length'" [1106450] "Floats are truncated to 10 digits, causing precision loss" [1122991] "error from SOAPpy/Client.py for content_length evaluation?" - Fixes for 'rules' which allow control of the data types of *incoming* messages. As a consequence TCtest.py now passes all tests. - WSDL support has been improving, due to work on the 'wstools' module which is shared between ZSI and SOAPpy. - Some work has been done to improve documentation. Release 0.11.6 of SOAPpy ------------------------ Changes to URLs and email addresses in documentation. Release 0.11.5 of SOAPpy ------------------------ - Bug fixes - Fix string format error in fault handling Release 0.11.4 of SOAPpy ------------------------ - Bug fixes: - SOAPpy/Server.py: Check if header information contains SOAPAction key before checking its value. - Fixes for generating SOAP from complexType arrays, contributed by antonio.beamud@linkend.com - Fixed bug that caused typedArrayTypes to lose their type information when rendered to SOAP and added corresponding test case. - New Features - Enhancements to fault handling: The faultType Faultstring is now a non-variable string (i.e. no nsmethod in it) so that it can be programmatically checked. In addition fault handlers can now be registered to handle specific types of faults. - SOAPpy/Server.py: Modified unregsiterObject function to take optional namespace/path args to be consistent with registerObject. - SOAPpy/Server.py: Added an unregisterObject function - Changes to allow SOAPBuilder so it can handle a 'raw' Python object. Release 0.11.2 of SOAPpy ------------------------ - News: Ivan R. Judson has joined the SOAPpy team. He is focused on Globus support but is also responsible for a lot of other work for this release, - Bug fixes: - Code in Types.py assumes nested scopes, so I added the proper import so this will work under python 2.2.x - Fixing namespace collision - Fixed handing of named arguments bug introduced in 0.11.1. - Fix memory leak when exceptions are raised. - Fix bug when content-length is not present in parsed SOAP message. - Fix bug #888345: Python 2.3 boolean type serialized as int - Fix bug #875977: no escaping of bad tagnames for NoneTypes - New features: - Improved Globus support and documentation. Thanks Ivan! - Added context handling - Changed the use of SOAPAction, it used to default to setting it to "", now it defaults to setting it to the method (not the nsmethod). There is a clause in Server.py that catches 'old style' SOAPActions (aka "") and sets them to the method. When this is confirmed to be what everyone wants and we decide it's alright to (possibly) break client/server interop, we can take the clause out of Server.py and just handle SOAPActions of "" as a possible error/warning. - Additional test code. - Raise a SOAPException instead of returning a SOAPpy.faultType when a SOAP Fault is encountered and simplify_objects is enabled. Release 0.11.1 of SOAPpy ------------------------ - Bug fixes: - Fixed bug [ 792258 ] "SOAPBuilder.SOAPBuilder.dump can catch wrong exceptions" in SOAPBuilder.dump() submitted by Greg Chapman (glchapman). - Changes suggested by Richard Au (richardau) to fix ssl support. See bug report [ 752882 ] "SSL SOAP Server no longer working." - Remove call to gentag from 'dump' and add to 'dump_float', per bug report [ 792600 ] "SOAPBuilder.SOAPBuilder.dump possibly should not call gentag" by Greg Chapman (glchapman). - Add a tests for handling of nil="true" and nil="false". This fixes bug [ pywebsvcs-Bugs-858168 ] 'xsi:nil="true" causes exception' reported by Robert Zimmermann (robertzett): - testClient1.py now works properly. It had been failing to start the server thread on the second unit test. It turned out that the variable 'quit' needed to be reset to zero after the SOAP server thread for the first unit test exited. With the solution of this problem testClient1 can now be extended to run unit tests of both client and server components. - Added 'strict' option to the WSDL class. If strict is true, a RuntimeException will be raised if an unrecogned message is recieved. If strict is false, a warning will be printed to the console, the message type will be added to the WSDL schema, and processing will continue. This is in response to the second half of bug report [ 817331 ] "Some WSDL.py changes", submitted by Rudolf Ruland. Release 0.11.0 of SOAPpy ------------------------ - New/Changed configuration settings: - Config.simplify_objects=1 now converts all SOAPpy objects into basic Python types (list, dictionary, tuple, double, float, etc.). By default, Config.simplify_objects=0 for backward compatibility. - Config.dict_encoding='ascii' converts the keys of dictionaries (e.g. created when Config.simplify_objects=1) to ascii == plain python strings instead of unicode strings. This variable can be set to any encoding known to string.encode(). - Config.strict_range=1 forces the SOAP parsing routines to perform range checks on recieved SOAP float and double objects. When Config.strict_range=0, the default, parsing does not perform range checking (except for detecting overflows, which always occurs). In either case, range checking is performed when generating SOAP float and double objects. - Fixes for WSDLProxy. - Scripts in the test/ directory - Verbose debugging messages have been turned off.. - SOAPtest.py now functions when Config.simplify_objects=1 - SOAPtest.py now sets Config.strict_range=1 so that range checks are be properly tested. - New README file listing what test scripts fail and why. - Initial support for Globus via pyGlobus contributed by Ivan R. Judson . Release 0.10.4 of SOAPpy ------------------------ Dramatic performance improvements for large data transfers. Release 0.10.1 of SOAPpy ------------------------ only minor changes 1) Code now uses a single file to store version number 2) Client and server now report 'SOAPpy' as the server/user-agent. 3) All test scripts now use the local SOAPpy source instead of the globally installed version. Release 0.10.0 of SOAPpy ------------------------ Enhancements: 1) The new name handling mechanism has been enabled by default. The primary purpose of this release is to allow users to test this to see if it causes problems. Please take the time to do so. If there are no problems reported by April 15, 2003, 0.9.9 will be released with this feature enabled by default. Note that running a client under an old release of SOAPpy and a server under this release will be likely to generate errors due to the different name handling mechanisms. 2) MS-Windows systems should now be fully supported. This required implementing a new module, ieee754, which provides functions for detecting and generating IEEE 754 special floating point values (+Inf, -Inf, NaN) which are not properly handled by the Windows implementation of the float() function. 3) Code reorganization: The huge file SOAPpy/SOAP.py (4,122 lines, 131K) has been split into 10 separate files. In addition code shared with ZSI has been moved into a separate subdirectory and a separate CVS module. 4) Fixed bug 678239 which caused loss of namespace information in the client. 5) Mark Bucciarelli's has ported client support for WSDL from ZSI, as well as providing a mechanism for SOAPpy servers to provide WSDL on properly structured .GET requests. 6) Added ThreadingSOAPServer which inherits from ThreadingTCPServer server so that multiple clients will be automatically multiplexed. VERSION 0.10.4 -------------- - Integrated a simple patch submitted by Erik Westra that dramatically improves parser performance. - WSDL tools now uses m2crypto for SSL if it's installed. - Various other WSDL changes. VERSION 0.10.3 -------------- - Removed import of obsoleted ieee753.py. Now use the fpconst module proposed by PEP 754, available from - SOAPpy should no longer depend on pyXML. VERSION 0.10.2 -------------- - Fixed client support for basic authentication - Fixed import error in Client.py - Improved Client parsing of namespaces to support stateful SOAP servers. VERSION 0.10.1 -------------- - Modified setup.py, Server.py, and Client.py to obtain SOAPpy version number from a new file, version.py. - SOAP server/user-agent is now to 'SOAPpy' instead of 'SOAP.py'. - Added ident string containing CVS version to all files that were lacking this. VERSION 0.10.0 -------------- CHANGES SINCE VERSION 0.9.9-pre5 - Major Change: The huge file SOAPpy/SOAP.py (4,122 lines, 131K) has been split into 10 separate files: Client.py NS.py SOAPBuilder.py Utilities.py Config.py Parser.py Server.py Errors.py SOAP.py Types.py This should ease navigation and maintenance. - A new CVS module 'wstools' was created to hold code which is used by both ZSI and SOAPpy. While this module is stored separately in CVS, it will be distributed as an integral part of both ZSI and SOAPpy, and will be included as an 'internal' module by both. In the SOAPpy source, it lives in the directory SOAPpy/wstools. - The files XMLname.py, ieee754.py, have been moved into SOAPpy/wstools. - Added TODO file - Fix bug in getNS that caused loss of namespace by using better pattern matching to find the namespace in the SOAP message. Fixes bug 678239 - Added Mark Bucciarelli's patch to provide wsdl code on properly structured .GET requests to the server. - Added client support for WSDL, ported from ZSI by Mark Bucciarelli - Added ThreadingSOAPServer which inherits from ThreadingTCPServer server so that muliple clients will be automatically multiplexed. - Removed some files from /test for services that no longer exist. CHANGES SINCE VERSION 0.9.9-pre4 -------------------------------- - Added client support for WSDL, ported from ZSI by Mark Bucciarelli . CHANGES SINCE VERSION 0.9.9-pre3 -------------------------------- - Code shared between SOAPpy and ZSI now lives in SOAPpy/SOAPpy/wstools and is stored in a separate CVS package. This will allow ZSI and SOAPpy to keep these files synchronized. CHANGES SINCE VERSION 0.9.9-pre2 -------------------------------- - Fixed trivial compilation bug on Win32: Only define SOAPUnixSocketServer if the Unix domain sockets are supported CHANGES SINCE VERSION 0.9.9-pre1 -------------------------------- - Added request for nested scopes, should now work properly in python 2.1 with named argument calls. - Fixed bug caused by omission of the ieee754 module from __init__.py. - SOAPpy now provides a SOAPUnixSocketServer class, which uses a unix domain socket instead of a network TCP/IP socket for communication. A corresponding client will be provided in the future. [This class has not yet been tested.] CHANGES SINCE VERSION 0.9.8 --------------------------- - IEEE 754 floating point specials (Inf, -Inf, NaN) should now be properly and consistently handled on all platforms. Added code to explicitly check for and handle IEEE 754 floating point specials (Inf, -Inf, NaN). This replaces an ugly hack for systems whose python float() doesn't understand the strings "Inf", "NaN", etc. Floating point specials should now be properly handled on all operating systems. ***SOAPpy should now work properly on all versions of Microsoft Windows.*** A new module, ieee754 contains the functions required to detect and create NaN, Inf, and -Inf values. This module should be usable in other contexts. - *** The new argument handling method (via SOAPpy.SOAP.Config.specialArgs=1) is now enabled by default.*** - Changed all references to actzero.com in SOAP.py to pywebscvs.sf.net. - Fixed a bug where lists included as parameters to SOAP method calls were being incorrectly named 'Results' even when another name was given. CHANGES SINCE VERSION 0.9.7 --------------------------- - Modified structure to allow installation using Python distutils (i.e. setup.py). Access to the SOAPpy library now requires: from SOAPpy import SOAP - I (Gregory R. Warnes) have implemented an experimental and non-standard method of handling named and unnamed arguments. This mechanism is enabled in SOAPpy by setting SOAPpy.SOAP.Config.specialArgs=1. When enabled, parameters with names of the form _#### (i.e., matching the regexp "^_[0-9]+") are assumed to be unnamed parameters and are passed to the method in numeric order. All other parameters are assumed to be named and are passed using the xml tag id as the parameter name. Outgoing SOAP method calls now always generate names in this way--whether or not specialArgs is enabled--instead of using the pattern v#####. See the file README.MethodParameterNaming for more details. - Added noroot parameter to the SOAPBuilder and SOAPProxy objects in order to provide compatibility with an older version of EasySOAP (v0.2) that balked if the SOAP-ENC:root parameter was included.(Brad Knotwell) - Added support for namespace-rewriting (used by Apache v2.x SOAP server for error conditions as well as stateful communication) (Christopher Blunck) - Added string <-> str conversion for array types (Python 2.2+) (Christopher Blunck) - Added convenience method (invoke) to SOAPProxy that calls __call (not sure if it is necessary - feel free to remove if you want) (Christopher Blunck) - Python 'float' are equivalent to SOAP 'double'. Modified dump_float and dump_list to use SOAP type string 'double' appropriately. (Gregory R. Warnes) - Add basic authentication (Brad Knotwell) - Fixes to enable proper handling of SOAP faults by the client: - Fixed test of whether message content is text/xml when recieving a fault. - Added __call__ method to exception classes to match the current API. - The faultType.__repr__() method now print details if present (Gregory R. Warnes) - Added XMLnam.py which provides toXMLname() and fromXMLname() for properly encoding xml tag names per the SOAP 2.1 (draft) specification. (Gregory R. Warnes) - Added calls to toXMLname() and fromXMLname() so that tags names are properly encoded. This resolves bug [ 548785 ] 'Error passing dict keys containing space.' (Gregory R. Warnes) - Added code to cgi encode contents of tags when they are not a recognized type. Fixes bug [ 549551 ] 'Error when passing non-standard types'. (Gregory R. Warnes) - Added __init__.py, so that SOAPpy can be used like a standard python module. (Gregory R. Warnes) VERSION 0.9.7 (6/27/01) ----------------------- - Fixed the unamed ordered parameters bug - Added the ability to specify a http_proxy - Added a patch provided by Tim MiddelKoop to allow printing of proxy objects - Added the contrib directory and included a medusa implementation of a SOAP.py server by Ng Pheng Siong VERSION 0.9.6 (6/08/01) ----------------------- - The date and time types now check their initial values when the type is created, not when the data is marshalled. - The date and time types are now parsed and returned as tuples (for multi-element types) or scalars (for single element types) in UTC and thus can represent the entire range of SOAP dates. - If an element doesn't have a type but has a name with a namespace, the name is tried as the type. - Untyped compound types with more than one element and all the elements the same name are turned into an array when parsing. - When parsing a structType, elements with the same name are placed in a list instead of saving just the last one. _getItemsAsList can be used to get an element of a structure as a list, whether there was one or many occurances of the item. - Added schemaNamespace, schemaNamespaceURI, and namespaceStyle configuration options. namespaceStyle takes one of 1999, 2000, or 2001, and sets typesNamespace, typesNamespaceURI, schemaNamespace, and schemaNamespaceURI. - Normalized the type class names, replacing Compound with compoundType, Struct with structType, Header with headerType, Body with bodyType, Array with arrayType, TypedArray with typedArrayType, Fault with faultType, and urType with anyType. - Attributes now appear on an element itself instead of the element's parent. For elements parsed to builtin python types, the attributes are stored in a dictionary keyed by the element's python id. The dictionary is in the Context object, can be returned from parseSOAP*, and can be returned from method calls if the returnAllAttrs configuration option is set. - isinstance is used to check for a class, so classes can be subtyped. - An encoding of None can be specified to not include encoding information. - Problems with the SOAPProxy URL are now reported when the SOAPProxy instance is created instead of when the first method call is made. - The Binary, Boolean and DateTime types have been removed in favor of binaryType, booleanType, and dateTimeType. VERSION 0.9.5 (5/16/01) ----------------------- - Should parse and build all 1999, 2000, 2001, and SOAP-ENC datatypes. - Initial handling of multi-dimensional, partial, and sparse arrays. - Supports SSL clients (if Python built with OpenSSL). - Supports SSL servers (if M2Crypto installed). - Applies defaults to SOAPproxy URLs (nice for command-line tools). - Added the _SOAPContext object, gives registered server functions more info about the current call. - Now assumes that any type that isn't in a schema could be a struct. - Added the Config object, now config options can be set globally or on an individual call level. - Deprecated the DateTime, Binary and Boolean types, should now use dateTimeType, binaryType and booleanType. - Includes N+I interop suite. - Various bug fixes and improvements. VERSION 0.9 (5/01/01) ----------------------- - The Envelope now just contains definitions for namespaces actually used (Builder) - Namespace definitions are inherited by children but not siblings (Builder) - Further improved multi-reference parsing -- it handles circular references (Parser) - Added support for building recursive and circular types using references (Builder) - More types - Proper handling of overflow and underflow integral and floating point types (Parser) - More interop - Various bug fixes and improvements VERSION 0.8.5 (4/25/01) ----------------------- - buildSOAP, SOAPProxy, SOAPServer now taking encoding argument - Much improved multi-referencing (Parser) - Added base64 and dateTime to interop suite - Various bug fixes VERSION 0.8 (4/23/01) ----------------------- - Added more types - Early multi-referencing support (Parser) - Reorganized the parser, much cleaner now - Preserve whitepsace in strings (per the standard) - Full XML attribute support (Parser/Builder) - Object (de)serialization now maintains element order - Fixed the zero-length array problem - Made indentation uniform (spaces not tabs) - Made Header and Body work more like real structs - Changed the parseSOAP api, now returns the body structure, instead of a list of body elements - Changed the soapaction and namespaces for the interop server - New silabclient options - Initial encoding support VERSION 0.7 (4/19/01) ----------------------- - Fixed a bug that caused nothing to work with Python 2.1 - Float work arounds for WIN32 (others?) - DateTime parsing for WIN32 - Beginnings of XML attribute support - Better interop VERSION 0.6 (4/18/01) ----------------------- - Fixed numerous bugs (dateTime, float precision, Response Element, null strings) - Added more types - Homogeneous typed arrays - Added support for more schemas - Early Header support and mustUnderstand and actor - Added interop suite - Passes validator - Interop greatly improved, passes all client tests for Frontier, SOAP::LITE. VERSION 0.5 (4/17/01) ----------------------- - Initial public release SOAPpy-0.12.0/TODO0100644001604000501700000000053610202425154013216 0ustar warnegclinical# $Id: TODO,v 1.6 2003/12/23 10:19:12 warnes Exp $ - figure out why parsing rules are broken - generate a test harness that will run all of the test code. - create unit-tests for all features, as well as for reported bugs. - write better documentation (!!!) - topics: WSDL, Globus, Authentication, ... - general introduction article - ... SOAPpy-0.12.0/setup.py0100644001604000501700000000127610204422026014237 0ustar warnegclinical#!/usr/bin/env python # # $Id: setup.py,v 1.11 2005/02/15 16:32:22 warnes Exp $ CVS=0 from distutils.core import setup, Command, Extension from SOAPpy.version import __version__ url="http://pywebsvcs.sf.net/" long_description="SOAPpy provides tools for building SOAP clients and servers. For more information see " + url if CVS: import time __version__ += "_CVS_" + time.strftime('%Y_%m_%d') setup(name="SOAPpy", version=__version__, description="SOAP Services for Python", maintainer="Gregory Warnes", maintainer_email="Gregory.R.Warnes@Pfizer.com", url = url, long_description=long_description, packages=['SOAPpy','SOAPpy/wstools'] ) SOAPpy-0.12.0/PKG-INFO0100644001604000501700000000053210206655324013627 0ustar warnegclinicalMetadata-Version: 1.0 Name: SOAPpy Version: 0.12.0 Summary: SOAP Services for Python Home-page: http://pywebsvcs.sf.net/ Author: Gregory Warnes Author-email: Gregory.R.Warnes@Pfizer.com License: UNKNOWN Description: SOAPpy provides tools for building SOAP clients and servers. For more information see http://pywebsvcs.sf.net/ Platform: UNKNOWN