Browse Source

SOAPpy v0.12.0

Revival of SOAPpy. v0.12.0
main
jeffkit 14 years ago
parent
commit
80ac4d79d3
88 changed files with 25273 additions and 0 deletions
  1. +3195
    -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. +1067
    -0
      SOAPpy/Parser.py
  12. +40
    -0
      SOAPpy/SOAP.py
  13. +634
    -0
      SOAPpy/SOAPBuilder.py
  14. +706
    -0
      SOAPpy/Server.py
  15. +1736
    -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. +1348
    -0
      SOAPpy/wstools/Utility.py
  25. +1602
    -0
      SOAPpy/wstools/WSDLTools.py
  26. +2879
    -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. +3807
    -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

+ 3195
- 0
ChangeLog
File diff suppressed because it is too large
View File


+ 56
- 0
LICENSE View File

@@ -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.


+ 10
- 0
PKG-INFO View File

@@ -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

+ 237
- 0
README View File

@@ -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 $

+ 590
- 0
RELEASE_INFO View File

@@ -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



+ 495
- 0
SOAPpy/Client.py View File

@@ -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))

+ 202
- 0
SOAPpy/Config.py View File

@@ -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()

+ 79
- 0
SOAPpy/Errors.py View File

@@ -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


+ 143
- 0
SOAPpy/GSIServer.py View File

@@ -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


+ 104
- 0
SOAPpy/NS.py View File

@@ -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"




+ 1067
- 0
SOAPpy/Parser.py
File diff suppressed because it is too large
View File


+ 40
- 0
SOAPpy/SOAP.py View File

@@ -0,0 +1,40 @@
"""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)

+ 634
- 0
SOAPpy/SOAPBuilder.py View File

@@ -0,0 +1,634 @@
"""
################################################################################
# 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 = '<?xml version="1.0"?>\n'
_xml_enc_top = '<?xml version="1.0" encoding="%s"?>\n'
_env_top = ( '%(ENV_T)s:Envelope\n' + \
' %(ENV_T)s:encodingStyle="%(ENC)s"\n' ) % \
NS.__dict__
_env_bot = '</%(ENV_T)s:Envelope>\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("</%s%s>\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("</%sBody>\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</%(tag)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('</%s>\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('</%s>\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>
<faultcode>%s</faultcode>
<faultstring>%s</faultstring>
''' % (vns, cns, vdecl, cdecl, obj.faultcode, obj.faultstring))
if hasattr(obj, "detail"):
self.dump(obj.detail, "detail", typed, ns_map)
self.out.append("</%sFault>\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></%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('</%s>\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</%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('</%s>\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()

+ 706
- 0
SOAPpy/Server.py View File

@@ -0,0 +1,706 @@
"""
################################################################################
#
# 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 '<a href="http://pywebsvcs.sf.net">' + \
'SOAPpy ' + __version__ + '</a> (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('''\
<title>
<head>Error!</head>
</title>

<body>
<h1>Oops!</h1>

<p>
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.
</p>


</body>''')
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)

+ 1736
- 0
SOAPpy/Types.py
File diff suppressed because it is too large
View File


+ 23
- 0
SOAPpy/URLopener.py View File

@@ -0,0 +1,23 @@
"""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

+ 178
- 0
SOAPpy/Utilities.py View File

@@ -0,0 +1,178 @@
"""
################################################################################
# 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()

+ 119
- 0
SOAPpy/WSDL.py View File

@@ -0,0 +1,119 @@
"""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


+ 15
- 0
SOAPpy/__init__.py View File

@@ -0,0 +1,15 @@

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

+ 2
- 0
SOAPpy/version.py View File

@@ -0,0 +1,2 @@
__version__="0.12.0"


+ 125
- 0
SOAPpy/wstools/Namespaces.py View File

@@ -0,0 +1,125 @@
#! /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/'

+ 179
- 0
SOAPpy/wstools/TimeoutSocket.py View File

@@ -0,0 +1,179 @@
"""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 <scott@chronis.pobox.com>
Lloyd Zusman <ljz@asfast.com>
Phil Mayes <pmayes@olivebr.com>
Piers Lauder <piers@cs.su.oz.au>
Radovan Garabik <garabik@melkor.dnp.fmph.uniba.sk>
"""

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

+ 99
- 0
SOAPpy/wstools/UserTuple.py View File

@@ -0,0 +1,99 @@
"""
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
<http://www.ndh.net/home/sschwarzer/python/python_software.html>, 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__


+ 1348
- 0
SOAPpy/wstools/Utility.py
File diff suppressed because it is too large
View File


+ 1602
- 0
SOAPpy/wstools/WSDLTools.py
File diff suppressed because it is too large
View File


+ 2879
- 0
SOAPpy/wstools/XMLSchema.py
File diff suppressed because it is too large
View File


+ 90
- 0
SOAPpy/wstools/XMLname.py View File

@@ -0,0 +1,90 @@
"""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, <http://www.w3.org/TR/soap12-part2/#namemap>

Also see <http://www.w3.org/2000/xp/Group/xmlp-issues>.

Author: Gregory R. Warnes <Gregory.R.Warnes@Pfizer.com>
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

+ 9
- 0
SOAPpy/wstools/__init__.py View File

@@ -0,0 +1,9 @@
#! /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


+ 536
- 0
SOAPpy/wstools/c14n.py View File

@@ -0,0 +1,536 @@
#! /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('</%s>' % 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("&", "&amp;") \
.replace("<", "&lt;") \
.replace(">", "&gt;") \
.replace("\015", "&#xD;")
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('<?')
W(node.nodeName)
s = node.data
if s:
W(' ')
W(s)
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('<!--')
W(node.data)
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("&", "&amp;") \
.replace("<", "&lt;") \
.replace('"', '&quot;') \
.replace('\011', '&#x9') \
.replace('\012', '&#xA') \
.replace('\015', '&#xD')
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('</%s>' % 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

+ 85
- 0
SOAPpy/wstools/logging.py View File

@@ -0,0 +1,85 @@
#! /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)



+ 5
- 0
SOAPpy/wstools/test/__init__.py View File

@@ -0,0 +1,5 @@
#! /usr/bin/env python
"""wstools.WSDLTools.WSDLReader tests directory."""

import utils


+ 20
- 0
SOAPpy/wstools/test/test_t1.py View File

@@ -0,0 +1,20 @@
############################################################################
# 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()


+ 160
- 0
SOAPpy/wstools/test/test_wsdl.py View File

@@ -0,0 +1,160 @@
#!/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()

+ 37
- 0
SOAPpy/wstools/test/test_wstools.py View File

@@ -0,0 +1,37 @@
#!/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()


+ 20
- 0
SOAPpy/wstools/test/test_wstools_net.py View File

@@ -0,0 +1,20 @@
#!/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()


+ 14
- 0
TODO View File

@@ -0,0 +1,14 @@
# $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
- ...



+ 291
- 0
bid/inventoryClient.py View File

@@ -0,0 +1,291 @@
#!/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()


+ 149
- 0
bid/inventoryServer.py View File

@@ -0,0 +1,149 @@
#!/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

+ 50
- 0
bid/monitorClient.py View File

@@ -0,0 +1,50 @@
from 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()


+ 19
- 0
contrib/soap_cli.py View File

@@ -0,0 +1,19 @@
#!/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)




+ 233
- 0
contrib/soap_handler.py View File

@@ -0,0 +1,233 @@

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()


+ 186
- 0
docs/GettingStarted.txt View File

@@ -0,0 +1,186 @@

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 <http://www.pobox.org.sg/home/ngps/m2/>) must be
installed. Also see tests/silabserver.py.

$Id: GettingStarted.txt,v 1.4 2005/02/21 20:09:29 warnes Exp $

+ 97
- 0
docs/GlobusSupport.txt View File

@@ -0,0 +1,97 @@

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 <mailto:judson@mcs.anl.gov>


$Id: GlobusSupport.txt,v 1.3 2005/02/21 20:09:32 warnes Exp $

+ 71
- 0
docs/MethodParameterNaming.txt View File

@@ -0,0 +1,71 @@

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 <Gregory.R.Warnes@Pfizer.com>
2003-03-07 (updated 2003-11-14)


+ 104
- 0
docs/UsingHeaders.txt View File

@@ -0,0 +1,104 @@
Using 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 $

+ 22
- 0
docs/WSDL.txt View File

@@ -0,0 +1,22 @@

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 $

+ 15
- 0
docs/attrs.txt View File

@@ -0,0 +1,15 @@

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 $

+ 19
- 0
docs/complexTypes.txt View File

@@ -0,0 +1,19 @@
COMPLEX 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.)



+ 220
- 0
docs/simpleTypes.txt View File

@@ -0,0 +1,220 @@
Simple 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 $

+ 29
- 0
setup.py View File

@@ -0,0 +1,29 @@
#!/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']
)


+ 32
- 0
tests/BabelfishWSDLTest.py View File

@@ -0,0 +1,32 @@
#!/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."

+ 75
- 0
tests/Bug1001646.py View File

@@ -0,0 +1,75 @@
"""
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!"


+ 43
- 0
tests/Bug916265.py View File

@@ -0,0 +1,43 @@
"""
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"

+ 38
- 0
tests/Bug918216.py View File

@@ -0,0 +1,38 @@
import sys
sys.path.insert(1, "..")
from SOAPpy import *

detailed_fault = \
"""
<?xml version="1.0" encoding="UTF-8"?>
<SOAP-ENV:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/" xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" SOAP-ENV:encodingStyle="http://schemas.microsoft.com/soap/encoding/clr/1.0 http://schemas.xmlsoap.org/soap/encoding/" xmlns:a1="http://schemas.microsoft.com/clr/ns/System.Runtime.Serialization.Formatters">
<SOAP-ENV:Body>
<SOAP-ENV:Fault id="ref-1">

<faultcode>soapenv:Server.generalException</faultcode>
<faultstring>Exception thrown on Server</faultstring>

<detail>
<loginFailureFault href="#id0"/>
<exceptionName xsi:type="xsd:string">...</exceptionName>
</detail>

</SOAP-ENV:Fault>

<multiRef id="id0">
<description xsi:type="xsd:string">Login failure (504):Unknown User</description>
<module xsi:type="xsd:string"> ... </module>
<timestamp xsi:type="xsd:string">...</timestamp>
<faultcode xsi:type="xsd:string"> ...</faultcode>
<parameter xsi:type="xsd:string"> ... </parameter>
</multiRef>

</SOAP-ENV:Body>
</SOAP-ENV:Envelope>
"""

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"

+ 26
- 0
tests/ComplexTypes.py View File

@@ -0,0 +1,26 @@
import 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)


+ 11
- 0
tests/GoogleTest.py View File

@@ -0,0 +1,11 @@
from 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 )

+ 3807
- 0
tests/SOAPtest.py
File diff suppressed because it is too large
View File


+ 147
- 0
tests/TCtest.py View File

@@ -0,0 +1,147 @@
#!/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 = """<?xml version="1.0" encoding="utf-8"?>
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<soap:Body
soap:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
<SomeMethod>
<Result>
<Book>
<title>My Life and Work</title>
</Book>
<Person>
<name>Henry Ford</name>
<age> 49 </age>
<height> 5.5 </height>
</Person>
</Result>
</SomeMethod>
</soap:Body>
</soap:Envelope>
"""

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 = '''<SOAP-ENV:Envelope
SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"
xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/"
xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:xsd="http://www.w3.org/1999/XMLSchema"
xmlns:xsi="http://www.w3.org/1999/XMLSchema-instance">
<SOAP-ENV:Body>
<Bounds>
<param>
<item>12</item>
<item>23</item>
<item>0</item>
<item>-31</item>
</param>
<param1 xsi:null="1"></param1>
</Bounds>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>
'''

# 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 = '''<SOAP-ENV:Envelope
SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"
xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/"
xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:xsd="http://www.w3.org/1999/XMLSchema"
xmlns:xsi="http://www.w3.org/1999/XMLSchema-instance">

<SOAP-ENV:Body>
<Bounds>
<param>
<item xsi:type="xsd:int">12</item>
<item xsi:type="xsd:string">23</item>
<item xsi:type="xsd:float">0</item>
<item xsi:type="xsd:int">-31</item>
</param>
<param1 xsi:null="1"></param1>
</Bounds>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>
'''

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()

+ 33
- 0
tests/TemperatureService.wsdl View File

@@ -0,0 +1,33 @@
<?xml version="1.0"?>
<definitions name="TemperatureService" targetNamespace="http://www.xmethods.net/sd/TemperatureService.wsdl" xmlns:tns="http://www.xmethods.net/sd/TemperatureService.wsdl" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" xmlns="http://schemas.xmlsoap.org/wsdl/">
<message name="getTempRequest">
<part name="zipcode" type="xsd:string"/>
</message>
<message name="getTempResponse">
<part name="return" type="xsd:float"/>
</message>
<portType name="TemperaturePortType">
<operation name="getTemp">
<input message="tns:getTempRequest"/>
<output message="tns:getTempResponse"/>
</operation>
</portType>
<binding name="TemperatureBinding" type="tns:TemperaturePortType">
<soap:binding style="rpc" transport="http://schemas.xmlsoap.org/soap/http"/>
<operation name="getTemp">
<soap:operation soapAction=""/>
<input>
<soap:body use="encoded" namespace="urn:xmethods-Temperature" encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"/>
</input>
<output>
<soap:body use="encoded" namespace="urn:xmethods-Temperature" encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"/>
</output>
</operation>
</binding>
<service name="TemperatureService">
<documentation>Returns current temperature in a given U.S. zipcode </documentation>
<port name="TemperaturePort" binding="tns:TemperatureBinding">
<soap:address location="http://services.xmethods.net:80/soap/servlet/rpcrouter"/>
</port>
</service>
</definitions>

+ 8
- 0
tests/ZeroLengthArray.py View File

@@ -0,0 +1,8 @@
import 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 )

+ 34
- 0
tests/alanbushTest.py View File

@@ -0,0 +1,34 @@
#!/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

+ 30
- 0
tests/cardClient.py View File

@@ -0,0 +1,30 @@
#!/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()


+ 112
- 0
tests/cardServer.py View File

@@ -0,0 +1,112 @@
#!/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

+ 102
- 0
tests/echoClient.py View File

@@ -0,0 +1,102 @@
#!/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()

+ 23
- 0
tests/echoHeader.py View File

@@ -0,0 +1,23 @@
#!/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()

+ 198
- 0
tests/echoServer.py View File

@@ -0,0 +1,198 @@
#!/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

+ 71
- 0
tests/esj_test_client.py View File

@@ -0,0 +1,71 @@
#!/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()

+ 48
- 0
tests/esj_test_server.py View File

@@ -0,0 +1,48 @@
#!/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()

+ 18
- 0
tests/excelTest.py View File

@@ -0,0 +1,18 @@
#!/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()








+ 50
- 0
tests/largeDataTest.py View File

@@ -0,0 +1,50 @@
#!/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()

+ 46
- 0
tests/newsTest.py View File

@@ -0,0 +1,46 @@
#!/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()

+ 40
- 0
tests/quoteTest.py View File

@@ -0,0 +1,40 @@
#!/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')

+ 10
- 0
tests/simpleWSDL.py View File

@@ -0,0 +1,10 @@
import 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

+ 83
- 0
tests/speedTest.py View File

@@ -0,0 +1,83 @@
#!/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='''<SOAP-ENV:Envelope
xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:xsi="http://www.w3.org/1999/XMLSchema-instance"
xmlns:xsd="http://www.w3.org/1999/XMLSchema">
<SOAP-ENV:Body>
<ns1:getRate xmlns:ns1="urn:demo1:exchange" SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
<country1 xsi:type="xsd:string">USA</country1>
<country2 xsi:type="xsd:string">japan</country2>
</ns1:getRate>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>'''

x2='''<SOAP-ENV:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/" xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" SOAP-ENV:encodingStyle="http://schemas.microsoft.com/soap/encoding/clr/1.0 http://schemas.xmlsoap.org/soap/encoding/" xmlns:i3="http://soapinterop.org/xsd" xmlns:i2="http://soapinterop.org/">
<SOAP-ENV:Body>
<i2:echoStructArray id="ref-1">
<return href="#ref-4"/>
</i2:echoStructArray>
<SOAP-ENC:Array id="ref-4" SOAP-ENC:arrayType="i3:SOAPStruct[3]">
<item href="#ref-5"/>
<item href="#ref-6"/>
<item href="#ref-7"/>
</SOAP-ENC:Array>
<i3:SOAPStruct id="ref-5">
<varString xsi:type="xsd:string">West Virginia</varString>
<varInt xsi:type="xsd:int">-546</varInt>
<varFloat xsi:type="xsd:float">-5.398</varFloat>
</i3:SOAPStruct>
<i3:SOAPStruct id="ref-6">
<varString xsi:type="xsd:string">New Mexico</varString>
<varInt xsi:type="xsd:int">-641</varInt>
<varFloat xsi:type="xsd:float">-9.351</varFloat>
</i3:SOAPStruct>
<i3:SOAPStruct id="ref-7">
<varString xsi:type="xsd:string">Missouri</varString>
<varInt xsi:type="xsd:int">-819</varInt>
<varFloat xsi:type="xsd:float">1.495</varFloat>
</i3:SOAPStruct>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>
'''

# 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)

+ 126
- 0
tests/storageTest.py View File

@@ -0,0 +1,126 @@
#!/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=['<html><title>bennett@actzero.com home page</title><body>' +
'<a href=again.html>Hello Earth</a></body></html>',
'<html><title>bennett@actzero.com home page</title><body>' +
'<a href=index.html>Hello Earth Again</a></body></html>'])
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=['<html><title>bennett@actzero.com home page</title><body>' +
'<a href=again.html>Hello Bennett</a></body></html>'])
if printstatus("saveMultipleFiles", reg):
print "Files stored:"
for file in reg.urlList:
print " %s" % file

os.waitpid(pid, 0)

+ 118
- 0
tests/testClient1.py View File

@@ -0,0 +1,118 @@
import 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()

+ 112
- 0
tests/testWSDL.py View File

@@ -0,0 +1,112 @@
#!/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 = '''<?xml version="1.0"?>
<definitions name="TemperatureService" targetNamespace="http://www.xmethods.net/sd/TemperatureService.wsdl" xmlns:tns="http://www.xmethods.net/sd/TemperatureService.wsdl" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" xmlns="http://schemas.xmlsoap.org/wsdl/">
<message name="getTempRequest">
<part name="zipcode" type="xsd:string"/>
</message>
<message name="getTempResponse">
<part name="return" type="xsd:float"/>
</message>
<portType name="TemperaturePortType">
<operation name="getTemp">
<input message="tns:getTempRequest"/>
<output message="tns:getTempResponse"/>
</operation>
</portType>
<binding name="TemperatureBinding" type="tns:TemperaturePortType">
<soap:binding style="rpc" transport="http://schemas.xmlsoap.org/soap/http"/>
<operation name="getTemp">
<soap:operation soapAction=""/>
<input>
<soap:body use="encoded" namespace="urn:xmethods-Temperature" encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"/>
</input>
<output>
<soap:body use="encoded" namespace="urn:xmethods-Temperature" encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"/>
</output>
</operation>
</binding>
<service name="TemperatureService">
<documentation>Returns current temperature in a given U.S. zipcode </documentation>
<port name="TemperaturePort" binding="tns:TemperatureBinding">
<soap:address location="http://services.xmethods.net:80/soap/servlet/rpcrouter"/>
</port>
</service>
</definitions>
'''

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()


+ 21
- 0
tests/testleak.py View File

@@ -0,0 +1,21 @@
#!/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'

+ 25
- 0
tests/translateTest.py View File

@@ -0,0 +1,25 @@
#!/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")

+ 25
- 0
tests/weatherTest.py View File

@@ -0,0 +1,25 @@
#!/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')

+ 25
- 0
tests/whoisTest.py View File

@@ -0,0 +1,25 @@
#!/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")


+ 34
- 0
tests/xmethods.py View File

@@ -0,0 +1,34 @@
#!/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

+ 76
- 0
tools/interop2html.py View File

@@ -0,0 +1,76 @@
#!/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 "<html><body>"
print "<script>function popup(text) {"
print "text = '<html><head><title>Test Detail</title></head><body><p>' + text + '</p></body></html>';"
print "newWin=window.open('','win1','location=no,menubar=no,width=400,height=200');"
print "newWin.document.open();"
print "newWin.document.write(text);"
print "newWin.focus(); } </script>"
print "<br><table style='font-family: Arial; color: #cccccc'><tr><td colspan=2><font face=arial color=#cccccc><b>Summary</b></font></td></tr>"
for x in tally:
z = x[:-1].split(":",1)
print "<tr><td><font face=arial color=#cccccc>",z[0],"</font></td><td><font face=arial color=#cccccc>",z[1],"</font></td></tr>"
print "</table><br>"
c = 0
totalmethods = len(table[table.keys()[0]])
while c < totalmethods:
print "<br><table width='95%' style='font-family: Arial'>"
print "<tr><td width='27%' bgcolor='#cccccc'></td>"
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 "<td width ='17%' align='center' bgcolor='#cccccc'><b>",header,"</b></td>"
print "</tr>"
l = table.keys()
l.sort()
for key in l:
print "<tr><td bgcolor='#cccccc'>", key , "</td>"
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("'","&#39;").replace('"',"&#34;")) + '"'
status = "<a title='" + hreftitle + "' href='javascript:popup(" + popuphtml + ")'>Failed (expected)</a>"
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("'","&#39;").replace('"',"&#34;")) + '"'
status = "<a title='" + hreftitle + "' href='javascript:popup(" + popuphtml + ")'>Failed</a>"
print "<td align='center' bgcolor=" , bgcolor , ">" , status , "</td>"
print "</tr>"
print "</table>"
c = c + len(cols)
print "</body></html>"

+ 60
- 0
validate/server.pem View File

@@ -0,0 +1,60 @@
$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 <newreq.pem >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-----

+ 264
- 0
validate/silab.servers View File

@@ -0,0 +1,264 @@
# 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 '&lt;&amp;&gt;"
Nonfunctional: echoStringArray server responds with fault when an array
element is '&lt;&amp;&gt;"
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

+ 699
- 0
validate/silabclient.py View File

@@ -0,0 +1,699 @@
#!/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)

+ 141
- 0
validate/silabserver.py View File

@@ -0,0 +1,141 @@
#!/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)

+ 118
- 0
validate/soapware.py View File

@@ -0,0 +1,118 @@
#!/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)

Loading…
Cancel
Save