Permalink
Browse files

SOAPpy v0.12.0

Revival of SOAPpy. v0.12.0
  • Loading branch information...
1 parent 0e7ff27 commit 80ac4d79d3cc7d1c899dd8cba7de699e3a08f099 @jeffkit jeffkit committed Dec 6, 2010
Showing with 25,273 additions and 0 deletions.
  1. +3,195 −0 ChangeLog
  2. +56 −0 LICENSE
  3. +10 −0 PKG-INFO
  4. +237 −0 README
  5. +590 −0 RELEASE_INFO
  6. +495 −0 SOAPpy/Client.py
  7. +202 −0 SOAPpy/Config.py
  8. +79 −0 SOAPpy/Errors.py
  9. +143 −0 SOAPpy/GSIServer.py
  10. +104 −0 SOAPpy/NS.py
  11. +1,067 −0 SOAPpy/Parser.py
  12. +40 −0 SOAPpy/SOAP.py
  13. +634 −0 SOAPpy/SOAPBuilder.py
  14. +706 −0 SOAPpy/Server.py
  15. +1,736 −0 SOAPpy/Types.py
  16. +23 −0 SOAPpy/URLopener.py
  17. +178 −0 SOAPpy/Utilities.py
  18. +119 −0 SOAPpy/WSDL.py
  19. +15 −0 SOAPpy/__init__.py
  20. +2 −0 SOAPpy/version.py
  21. +125 −0 SOAPpy/wstools/Namespaces.py
  22. +179 −0 SOAPpy/wstools/TimeoutSocket.py
  23. +99 −0 SOAPpy/wstools/UserTuple.py
  24. +1,348 −0 SOAPpy/wstools/Utility.py
  25. +1,602 −0 SOAPpy/wstools/WSDLTools.py
  26. +2,879 −0 SOAPpy/wstools/XMLSchema.py
  27. +90 −0 SOAPpy/wstools/XMLname.py
  28. +9 −0 SOAPpy/wstools/__init__.py
  29. +536 −0 SOAPpy/wstools/c14n.py
  30. +85 −0 SOAPpy/wstools/logging.py
  31. +5 −0 SOAPpy/wstools/test/__init__.py
  32. +20 −0 SOAPpy/wstools/test/test_t1.py
  33. +160 −0 SOAPpy/wstools/test/test_wsdl.py
  34. +37 −0 SOAPpy/wstools/test/test_wstools.py
  35. +20 −0 SOAPpy/wstools/test/test_wstools_net.py
  36. +14 −0 TODO
  37. +291 −0 bid/inventoryClient.py
  38. +149 −0 bid/inventoryServer.py
  39. +50 −0 bid/monitorClient.py
  40. +19 −0 contrib/soap_cli.py
  41. +233 −0 contrib/soap_handler.py
  42. +186 −0 docs/GettingStarted.txt
  43. +97 −0 docs/GlobusSupport.txt
  44. +71 −0 docs/MethodParameterNaming.txt
  45. +104 −0 docs/UsingHeaders.txt
  46. +22 −0 docs/WSDL.txt
  47. +15 −0 docs/attrs.txt
  48. +19 −0 docs/complexTypes.txt
  49. +220 −0 docs/simpleTypes.txt
  50. +29 −0 setup.py
  51. +32 −0 tests/BabelfishWSDLTest.py
  52. +75 −0 tests/Bug1001646.py
  53. +43 −0 tests/Bug916265.py
  54. +38 −0 tests/Bug918216.py
  55. +26 −0 tests/ComplexTypes.py
  56. +11 −0 tests/GoogleTest.py
  57. +3,807 −0 tests/SOAPtest.py
  58. +147 −0 tests/TCtest.py
  59. +33 −0 tests/TemperatureService.wsdl
  60. +8 −0 tests/ZeroLengthArray.py
  61. +34 −0 tests/alanbushTest.py
  62. +30 −0 tests/cardClient.py
  63. +112 −0 tests/cardServer.py
  64. +102 −0 tests/echoClient.py
  65. +23 −0 tests/echoHeader.py
  66. +198 −0 tests/echoServer.py
  67. +71 −0 tests/esj_test_client.py
  68. +48 −0 tests/esj_test_server.py
  69. +18 −0 tests/excelTest.py
  70. +50 −0 tests/largeDataTest.py
  71. +46 −0 tests/newsTest.py
  72. +40 −0 tests/quoteTest.py
  73. +10 −0 tests/simpleWSDL.py
  74. +83 −0 tests/speedTest.py
  75. +126 −0 tests/storageTest.py
  76. +118 −0 tests/testClient1.py
  77. +112 −0 tests/testWSDL.py
  78. +21 −0 tests/testleak.py
  79. +25 −0 tests/translateTest.py
  80. +25 −0 tests/weatherTest.py
  81. +25 −0 tests/whoisTest.py
  82. +34 −0 tests/xmethods.py
  83. +76 −0 tools/interop2html.py
  84. +60 −0 validate/server.pem
  85. +264 −0 validate/silab.servers
  86. +699 −0 validate/silabclient.py
  87. +141 −0 validate/silabserver.py
  88. +118 −0 validate/soapware.py
View
3,195 ChangeLog
3,195 additions, 0 deletions not shown because the diff is too large. Please use a local Git client to view these changes.
View
56 LICENSE
@@ -0,0 +1,56 @@
+==============================================
+SOAPpy - Simple to use SOAP library for Python
+==============================================
+
+Current Maintainers:
+
+ Gregory R. Warnes <Gregory.R.Warnes@Pfizer.com>
+ Christopher Blunck <blunck2@gst.com>
+
+Original Authors:
+
+ Cayce Ullman <c_ullman@yahoo.com>
+ Brian Matthews <blm@blmatthews.com>
+
+Contributions by:
+
+ Brad Knotwell <b.knotwell@f5.com>
+ Mark Bucciarelli <mark@hubcapconsulting.com> (ported WSDL
+ client from ZSI)
+ Ivan R. Judson <judson@mcs.anl.gov> (Globus support)
+ Kirk Strauser <kirk@daycos.com>
+ Antonio Beamud Montero <antonio.beamud@linkend.com> (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.
+
View
10 PKG-INFO
@@ -0,0 +1,10 @@
+Metadata-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
View
237 README
@@ -0,0 +1,237 @@
+==============================================
+SOAPpy - Simple to use SOAP library for Python
+==============================================
+
+Current Maintainer:
+
+ Gregory R. Warnes <Gregory.R.Warnes@Pfizer.com>
+
+Original Authors:
+
+ Cayce Ullman <c_ullman@yahoo.com>
+ Brian Matthews <blm@blmatthews.com>
+
+Contributions by:
+
+ Christopher Blunck <blunck2@gst.com>
+ Brad Knotwell <b.knotwell@f5.com>
+ Mark Bucciarelli <mark@hubcapconsulting.com> (ported WSDL
+ client from ZSI)
+ Ivan R. Judson <judson@mcs.anl.gov> (Globus support)
+ Kirk Strauser <kirk@daycos.com>
+ Antonio Beamud Montero <antonio.beamud@linkend.com> (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,
+ <http://research.warnes.net/projects/rzope/fpconst/>
+
+ - pyXML 0.8.3 or later, <http://pyxml.sourceforge.net>
+
+ OPTIONAL PACKAGES
+ -----------------
+
+ - pyGlobus, optional support for Globus,
+ <http://www-itg.lbl.gov/gtg/projects/pyGlobus/>
+
+ - M2Crypto.SSL, optional support for server-side SSL
+ <http://sandbox.rulemaker.net/ngps/m2/>
+
+ - 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 $
View
590 RELEASE_INFO
@@ -0,0 +1,590 @@
+
+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 <judson@mcs.anl.gov>.
+
+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 <mark@hubcapconsulting.com> 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
+ <http://research.warnes.net/Zope/projects/fpconst/>
+
+- 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 <mark@hubcapconsulting.com> patch to
+ provide wsdl code on properly structured .GET requests to the server.
+
+- Added client support for WSDL, ported from ZSI by Mark Bucciarelli
+ <mark@hubcapconsulting.com>
+
+- 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
+ <mark@hubcapconsulting.com>.
+
+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
+
+
View
495 SOAPpy/Client.py
@@ -0,0 +1,495 @@
+"""
+################################################################################
+#
+# 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 '<len>, <len>' 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))
View
202 SOAPpy/Config.py
@@ -0,0 +1,202 @@
+"""
+################################################################################
+# 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()
View
79 SOAPpy/Errors.py
@@ -0,0 +1,79 @@
+"""
+################################################################################
+#
+# 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 "<Error : %s>" % 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 "<HTTPError %s %s>" % (self.code, self.msg)
+ __repr__ = __str__
+ def __call___(self):
+ return (self.code, self.msg, )
+
+class UnderflowError(exceptions.ArithmeticError):
+ pass
+
View
143 SOAPpy/GSIServer.py
@@ -0,0 +1,143 @@
+"""
+GSIServer - Contributed by Ivan R. Judson <judson@mcs.anl.gov>
+
+
+################################################################################
+#
+# 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
+
View
104 SOAPpy/NS.py
@@ -0,0 +1,104 @@
+"""
+################################################################################
+#
+# 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"
+
+
+
View
1,067 SOAPpy/Parser.py
@@ -0,0 +1,1067 @@
+# 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: