Skip to content
Browse files

initial commit, suds 0.4 content

  • Loading branch information...
0 parents commit 44b57ad8766dd54a740e855498a406d450267431 @htj committed Apr 19, 2012
Showing with 16,653 additions and 0 deletions.
  1. +165 −0 LICENSE
  2. +578 −0 README
  3. +71 −0 makefile
  4. +210 −0 python-suds.spec
  5. +2 −0 setup.cfg
  6. +33 −0 setup.py
  7. +154 −0 suds/__init__.py
  8. +20 −0 suds/bindings/__init__.py
  9. +538 −0 suds/bindings/binding.py
  10. +160 −0 suds/bindings/document.py
  11. +126 −0 suds/bindings/multiref.py
  12. +98 −0 suds/bindings/rpc.py
  13. +121 −0 suds/builder.py
  14. +337 −0 suds/cache.py
  15. +785 −0 suds/client.py
  16. +62 −0 suds/metrics.py
  17. +59 −0 suds/mx/__init__.py
  18. +316 −0 suds/mx/appender.py
  19. +48 −0 suds/mx/basic.py
  20. +158 −0 suds/mx/core.py
  21. +133 −0 suds/mx/encoded.py
  22. +291 −0 suds/mx/literal.py
  23. +123 −0 suds/mx/typer.py
  24. +123 −0 suds/options.py
  25. +257 −0 suds/plugin.py
  26. +543 −0 suds/properties.py
  27. +169 −0 suds/reader.py
  28. +496 −0 suds/resolver.py
  29. +109 −0 suds/sax/__init__.py
  30. +181 −0 suds/sax/attribute.py
  31. +378 −0 suds/sax/date.py
  32. +61 −0 suds/sax/document.py
  33. +1,147 −0 suds/sax/element.py
  34. +79 −0 suds/sax/enc.py
  35. +139 −0 suds/sax/parser.py
  36. +116 −0 suds/sax/text.py
  37. +248 −0 suds/servicedefinition.py
  38. +86 −0 suds/serviceproxy.py
  39. +72 −0 suds/soaparray.py
  40. +594 −0 suds/store.py
  41. +390 −0 suds/sudsobject.py
  42. +130 −0 suds/transport/__init__.py
  43. +187 −0 suds/transport/http.py
  44. +98 −0 suds/transport/https.py
  45. +57 −0 suds/transport/options.py
  46. +56 −0 suds/umx/__init__.py
  47. +88 −0 suds/umx/attrlist.py
  48. +41 −0 suds/umx/basic.py
  49. +216 −0 suds/umx/core.py
  50. +128 −0 suds/umx/encoded.py
  51. +141 −0 suds/umx/typed.py
  52. +922 −0 suds/wsdl.py
  53. +212 −0 suds/wsse.py
  54. +86 −0 suds/xsd/__init__.py
  55. +140 −0 suds/xsd/deplist.py
  56. +226 −0 suds/xsd/doctor.py
  57. +208 −0 suds/xsd/query.py
  58. +422 −0 suds/xsd/schema.py
  59. +669 −0 suds/xsd/sxbase.py
  60. +825 −0 suds/xsd/sxbasic.py
  61. +274 −0 suds/xsd/sxbuiltin.py
  62. +25 −0 tests/__init__.py
  63. +343 −0 tests/axis1.py
  64. +215 −0 tests/axis2.py
  65. +549 −0 tests/builtin.py
  66. +54 −0 tests/jasper.py
  67. +289 −0 tests/public.py
  68. +220 −0 tests/rhq.py
  69. +56 −0 tests/saxenc.py
165 LICENSE
@@ -0,0 +1,165 @@
+ GNU LESSER GENERAL PUBLIC LICENSE
+ Version 3, 29 June 2007
+
+ Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+
+ This version of the GNU Lesser General Public License incorporates
+the terms and conditions of version 3 of the GNU General Public
+License, supplemented by the additional permissions listed below.
+
+ 0. Additional Definitions.
+
+ As used herein, "this License" refers to version 3 of the GNU Lesser
+General Public License, and the "GNU GPL" refers to version 3 of the GNU
+General Public License.
+
+ "The Library" refers to a covered work governed by this License,
+other than an Application or a Combined Work as defined below.
+
+ An "Application" is any work that makes use of an interface provided
+by the Library, but which is not otherwise based on the Library.
+Defining a subclass of a class defined by the Library is deemed a mode
+of using an interface provided by the Library.
+
+ A "Combined Work" is a work produced by combining or linking an
+Application with the Library. The particular version of the Library
+with which the Combined Work was made is also called the "Linked
+Version".
+
+ The "Minimal Corresponding Source" for a Combined Work means the
+Corresponding Source for the Combined Work, excluding any source code
+for portions of the Combined Work that, considered in isolation, are
+based on the Application, and not on the Linked Version.
+
+ The "Corresponding Application Code" for a Combined Work means the
+object code and/or source code for the Application, including any data
+and utility programs needed for reproducing the Combined Work from the
+Application, but excluding the System Libraries of the Combined Work.
+
+ 1. Exception to Section 3 of the GNU GPL.
+
+ You may convey a covered work under sections 3 and 4 of this License
+without being bound by section 3 of the GNU GPL.
+
+ 2. Conveying Modified Versions.
+
+ If you modify a copy of the Library, and, in your modifications, a
+facility refers to a function or data to be supplied by an Application
+that uses the facility (other than as an argument passed when the
+facility is invoked), then you may convey a copy of the modified
+version:
+
+ a) under this License, provided that you make a good faith effort to
+ ensure that, in the event an Application does not supply the
+ function or data, the facility still operates, and performs
+ whatever part of its purpose remains meaningful, or
+
+ b) under the GNU GPL, with none of the additional permissions of
+ this License applicable to that copy.
+
+ 3. Object Code Incorporating Material from Library Header Files.
+
+ The object code form of an Application may incorporate material from
+a header file that is part of the Library. You may convey such object
+code under terms of your choice, provided that, if the incorporated
+material is not limited to numerical parameters, data structure
+layouts and accessors, or small macros, inline functions and templates
+(ten or fewer lines in length), you do both of the following:
+
+ a) Give prominent notice with each copy of the object code that the
+ Library is used in it and that the Library and its use are
+ covered by this License.
+
+ b) Accompany the object code with a copy of the GNU GPL and this license
+ document.
+
+ 4. Combined Works.
+
+ You may convey a Combined Work under terms of your choice that,
+taken together, effectively do not restrict modification of the
+portions of the Library contained in the Combined Work and reverse
+engineering for debugging such modifications, if you also do each of
+the following:
+
+ a) Give prominent notice with each copy of the Combined Work that
+ the Library is used in it and that the Library and its use are
+ covered by this License.
+
+ b) Accompany the Combined Work with a copy of the GNU GPL and this license
+ document.
+
+ c) For a Combined Work that displays copyright notices during
+ execution, include the copyright notice for the Library among
+ these notices, as well as a reference directing the user to the
+ copies of the GNU GPL and this license document.
+
+ d) Do one of the following:
+
+ 0) Convey the Minimal Corresponding Source under the terms of this
+ License, and the Corresponding Application Code in a form
+ suitable for, and under terms that permit, the user to
+ recombine or relink the Application with a modified version of
+ the Linked Version to produce a modified Combined Work, in the
+ manner specified by section 6 of the GNU GPL for conveying
+ Corresponding Source.
+
+ 1) Use a suitable shared library mechanism for linking with the
+ Library. A suitable mechanism is one that (a) uses at run time
+ a copy of the Library already present on the user's computer
+ system, and (b) will operate properly with a modified version
+ of the Library that is interface-compatible with the Linked
+ Version.
+
+ e) Provide Installation Information, but only if you would otherwise
+ be required to provide such information under section 6 of the
+ GNU GPL, and only to the extent that such information is
+ necessary to install and execute a modified version of the
+ Combined Work produced by recombining or relinking the
+ Application with a modified version of the Linked Version. (If
+ you use option 4d0, the Installation Information must accompany
+ the Minimal Corresponding Source and Corresponding Application
+ Code. If you use option 4d1, you must provide the Installation
+ Information in the manner specified by section 6 of the GNU GPL
+ for conveying Corresponding Source.)
+
+ 5. Combined Libraries.
+
+ You may place library facilities that are a work based on the
+Library side by side in a single library together with other library
+facilities that are not Applications and are not covered by this
+License, and convey such a combined library under terms of your
+choice, if you do both of the following:
+
+ a) Accompany the combined library with a copy of the same work based
+ on the Library, uncombined with any other library facilities,
+ conveyed under the terms of this License.
+
+ b) Give prominent notice with the combined library that part of it
+ is a work based on the Library, and explaining where to find the
+ accompanying uncombined form of the same work.
+
+ 6. Revised Versions of the GNU Lesser General Public License.
+
+ The Free Software Foundation may publish revised and/or new versions
+of the GNU Lesser General Public License from time to time. Such new
+versions will be similar in spirit to the present version, but may
+differ in detail to address new problems or concerns.
+
+ Each version is given a distinguishing version number. If the
+Library as you received it specifies that a certain numbered version
+of the GNU Lesser General Public License "or any later version"
+applies to it, you have the option of following the terms and
+conditions either of that published version or of any later version
+published by the Free Software Foundation. If the Library as you
+received it does not specify a version number of the GNU Lesser
+General Public License, you may choose any version of the GNU Lesser
+General Public License ever published by the Free Software Foundation.
+
+ If the Library as you received it specifies that a proxy can decide
+whether future versions of the GNU Lesser General Public License shall
+apply, that proxy's public statement of acceptance of any version is
+permanent authorization for you to choose that version for the
+Library.
578 README
@@ -0,0 +1,578 @@
+OVERVIEW
+
+The "Suds" web services client is a lightweight soap-based client for python
+the is licensed under LGPL.
+
+For details, visit:
+
+ * Project site: https://fedorahosted.org/suds/
+ * Documentation: https://fedorahosted.org/suds/wiki/Documentation
+ * Epydocs: http://jortel.fedorapeople.org/suds/doc/
+
+
+RELEASE-NOTES:
+=================================================
+
+version 0.3.6 (04-31-09):
+ * Change hard coded /tmp/suds to tempfile.gettempdir() and create suds/ on demand.
+ * Fix return type for Any.get_attribute().
+ * Update http caching to ignore file:// urls.
+ * Better logging of messages when only the reply is injected.
+ * Fix XInteger and XFloat types to translate returned arrays properly.
+ * Fix xs:import schema with same namespace.
+ * Update parser to not load external references and add Import.bind() for XMLSchema.xsd location.
+ * Add schema doctor - used to patch XSDs at runtime. (See Option.doctor)
+ * Fix deprecation warnings in python 2.6.
+ * Add behavior for @default defined on <element/>.
+ * Change @xsi:type value to always be qualified for doc/literal. (reverts 0.3.5 change).
+ * Add Option.xstq option to control when @xsi:type is qualified.
+ * Fixed Tickets: #64, #129, #205, #206, #217, #221, #222, #224, #225, #228, #229, #230
+
+version 0.3.5 (04-16-09):
+ * Adds http caching. Default is (1) day. Does not apply to method invocation. See: documentation for details.
+ * Removed checking fedora version check in spec since no longer building < fc9.
+ * Updated makefile to roll tarball with tar.sh.
+ * Moved bare/wrapped determination to wsdl for document/literal.
+ * Refactored Transport into a package (provides better logging of http headers).
+ * Fixed Tickets: #207, #209, #210, #212, #214, #215
+
+version 0.3.4 (02-24-09):
+ * Static (automatic) Import.bind('http://schemas.xmlsoap.org/soap/encoding/'),
+ users no longer need to do this.
+ * Basic ws-security with {{{UsernameToken}}} and clear-text password only.
+ * Add support for ''sparse'' soap headers via passing dictionary
+ * Add support for arbitrary user defined soap headers
+ * Fixes service operations with multiple soap header entries.
+ * Schema loading and dereferencing algorithm enhancements.
+ * Nested soap multirefs fixed.
+ * Better (true) support for elementFormDefault="unqualified" provides more
+ accurate namespaing.
+ * WSDL part types no longer default to WSDL targetNamespace.
+ * Fixed Tickets: #4, #6, #21, #32, #62, #66, #71, #72, #114, #155, #201.
+
+version 0.3.3 (11-31-08):
+ * No longer installs (tests) package.
+ * Implements API-3 proposal ( https://fedorahosted.org/suds/wiki/Api3Proposal )
+ - Pluggable transport
+ - Keyword method arguments
+ - Baisc http authentication in default transport
+ * Add namespace prefix normalization in soap message.
+ * Better soap message pruning of empty nodes.
+ * Fixed Tickets: #51 - #60
+
+
+version 0.3.2 (11-7-08):
+ * SOAP {{{MultiRef}}} support ''(1st pass added r300)''
+ * Add support for new schema tags:
+ * <xs:include/>
+ * <xs:simpleContent/>
+ * <xs:group/>
+ * <xs:attributeGroup/>
+ * Added support for new xs <--> python type conversions:
+ * xs:int
+ * xs:long
+ * xs:float
+ * xs:double
+ * Revise marshaller and binding to further sharpen the namespacing of nodes produced.
+ * Infinite recursion fixed in ''xsd'' package dereference() during schema loading.
+ * Add support for <wsdl:import/> of schema files into the wsdl root <definitions/>.
+ * Fix double encoding of (&)
+ * Add Client API:
+ * setheaders() - same as keyword but works for all invocations.
+ * addprefix() - mapping of namespace prefixes.
+ * setlocation() - Override the location in the wsdl; same as keyword except for all calls.
+ * setproxy() - same as proxy keyword but for all invocations.
+ * Add proper namespace prefix for soap headers.
+ * Fixed Tickets: #5, #12, #34, #37, #40, #44, #45, #46, #48, #49, #50, #51
+
+
+version 0.3.1 (10-1-08):
+
+ * Quick follow up to the 0.3 release that made working multi-port service definitions
+ harder then necessary. After consideration (and a good night sleep),
+ it seemed obvious that a few changes would make this much easier: 1) filter out
+ the non-soap bindings - they were causing the real trouble; 2) since most servers
+ are happy with any of the soap bindings (soap 1.1 and 1.2), ambigious references to methods
+ when invoking then without the port qualification will work just fine in almost every
+ case. So, why not just allow suds to select the port. Let's not make the user do it
+ when it's not necessary. In most cases, uses on 0.2.9 and earlier will not have to
+ update there code when moving to 0.3.1 as they might have in 0.3.
+
+
+version 0.3 (9-30-08):
+
+ * Extends the support for multi-port services introduced in 0.2.9. This addition,
+ provides for multiple services to define the *same* method and suds will
+ handle it properly. See section 'SERVICES WITH MULTIPLE PORTS:'
+
+ * Add support for multi-document document/literal soap binding style.
+ See section 'MULTI-DOCUMENT Docuemnt/Literal:'
+
+ * Add support for (xs:group, xs:attributeGroup) tags.
+
+ * Add Client.last_sent() and Client.last_received().
+
+version 0.2.9 (9-09-08):
+
+ * Support for multiple ports within a service.
+ * Attribute references <xs:attribute ref=""/>
+ * Make XML special character encoder in sax package - pluggable
+
+
+version 0.2.8 (8-28-08):
+
+ * Update document/literal binding to always send the document root referenced by the <part/>.
+ After yet another review of the space and user input, seems like the referenced
+ element is ALWAYS the document root.
+
+ * Add support for 'binding' schemaLocations to namespace-uri.
+ This is for imports that don's specify a schemaLocation and still expect the schema
+ to be downloaded. Eg: Axis references 'http://schemas.xmlsoap.org/soap/encoding/'
+ without a schemaLocation. So, by doing this:
+ >
+ > from suds.xsd.sxbasic import Import.
+ > Import.bind('http://schemas.xmlsoap.org/soap/encoding/')
+ >
+ The schema is bound to a schemaLocation and it is downloaded.
+
+ * Basic unmarshaller doesn't need a /schema/.
+ Should have been removed during refactoring but was missed.
+
+ * Update client to pass kwargs to send() and add /location/ kwarg for overriding the
+ service location in the wsdl.
+
+ * Update marshaller to NOT emit XML for object attributes that represent elements and/or attributes that
+ are *both* optional and value=None.
+ * Update factory (builder) to include all attributes.
+ * Add optional() method to SchemaObject.
+
+ * Update wsdl to override namespace in operation if specified.
+
+ * Fix schema loading issue - build all schemas before processing imports.
+
+ * Update packaging in preparation of submission to fedora
+
+
+version 0.2.7 (8-11-08):
+
+ * Add detection/support for document/literal - wrapped and unwrapped.
+ * Update document/literal {wrapped} to set document root (under <body/>) to be the
+ wrapper element (w/ proper namespace).
+ * Add support for <sequence/>, <all/> and <choice/> having maxOccurs and have the
+ which causes the unmarshaller to set values for elements contained in an unbounded
+ collection as a list.
+ * Update client.factory (builder) to omit children of <choice/> since the 'user' really needs
+ to decide which children to include.
+ * Update flattening algorithm to prevent re-flattening of types from imported schemas.
+ * Adjustments to flattening/merging algorithms.
+
+
+version 0.2.6 (8-5-08):
+
+ * Fix ENUMs broken during xsd package overhaul.
+ * Fix type as defined in ticket #24.
+ * Fix duplicate param names in method signatures as reported in ticket #30.
+ * Suds licensed as LGPL.
+ * Remove logging setup in suds.__init__() as suggested by patch in ticket #31. Users will
+ now need to configure the logger.
+ * Add support for Client.Factory.create() alt: syntax for fully qualifying the type to be
+ built as: {namespace}name. Eg: client.factory.create('{http://blabla.com/ns}Person')
+
+
+version 0.2.5 (8-01-08):
+
+ * Overhauled the (XSD) package. This new (merging) approach is simpler and should be
+ more reliable and maintainable. Also, should provide better performance since the merged
+ schema performes lookups via dictionary lookup.
+
+ This overhaul should fix current TypeNotFound and <xs:extension/> problems, I hope :-).
+
+ * Fixed dateTime printing bug.
+
+ * Added infinite recursion prevention in builder.Builder for xsd types that contain themselves.
+
+
+version 0.2.4 (7-28-08):
+
+ * Added support for WSDL imports: <wsdl:import/>
+ * Added support for xsd<->python type conversions (thanks: Nathan Van Gheem) for:
+ * xs:date
+ * xs:time
+ * xs:dateTime
+ * Fixed:
+ * Bug: Schema <import/> with schemaLocation specified.
+ * Bug: Namespaces specified in service description not valid until client/proxy is printed.
+
+
+version 0.2.3 (7-23-08):
+
+ * Optimizations.
+
+
+version 0.2.2 (7-8-08):
+
+ * Update exceptions to be more /standard/ python by using Exception.__init__() to set Exception.message as
+ suggested by Ticket #14; update bindings to raise WebFault passing (p)
+
+ * Add capability in bindings to handle multiple root nodes in the returned values;
+ returned as a composite object unlike when lists are returned
+
+ * Fix soapAction to be enclosed by quotes
+
+ * Add support for <xs:all/>
+
+ * Fix unbounded() method in SchemaObject
+
+ * Refactored schema into new (xsd) package. Files just getting too big. Added execute() to
+ Query and retrofitted suds to execute() query instead of using Schema.find() directly.
+ Also, move hokey start() methods from schema, as well as, query incrementation.
+
+ * Add inject keyword used to inject outbound soap messages and/or inbound reply messages.
+ Refactor SoapClient and
+ 1) rename send() to invoke()
+ 2) split message sending from invoke() and place in send();
+ Add TestClient which allows for invocation kwargs to have inject={'msg=, and reply='} for message
+ and reply injection
+
+ * Add Namespace class to sax for better management of namespace behavior;
+ retrofix suds to import and use Namespace
+
+ * Change the default namespace used to resolve referenced types (having attribues @base="",@type="")
+ so that when no prefix is specified: uses XML (node) namesapce instead of the targetNamespace.
+
+ * Apply fix as defined by davidglick@onenw.org in ticket #13
+
+ * Update service definition to print to display service methods as ' my_method(xs:int arg0, Person arg1) '
+ instead of ' my_method(arg0{xs:int}, arg1{Person}) ' which is more like traditional method signatures
+
+ * Add xsd/python type converstion to unmarshaller (XBoolean only); refactor unmarshaller to use Content
+ class which makes apis cleaner, adds symmetry between marshaller(s) and unmarshaller(s),
+ provides good mechanism for schema-property based type conversions
+
+ * Refactor marshaller with Appenders; add nobuiltin flag to resolve() to support fix for
+ returned_type() and returnes_collection() in bindings.
+
+ * Add support for (202,204) http codes
+
+ * Add XBoolean and mappings; add findattr() to TreeResolver in preparation for type conversions
+
+ * Updated schema and schema property loading (deep recusion stopped); Changed Imported schemas so then no
+ longer copy imported schemas, rather the import proxies find requests; Add ServiceDefinition class which
+ provides better service inspection; also provides namespace mapping and show types; schema property api simplified;
+ support for xs:any and xs:anyType added; Some schema lookup problems fixed; Binding classes refactored slightly;
+ A lot of debug logging added (might have to comment some out for performance - some of the args are expensive).
+
+ * Add sudsobject.Property; a property is a special Object that contains a (value) attributeand is returned by the
+ Builder (factory) for schema-types without children such as: <element/> and <simpleType/>; Builder, Marshallers
+ and Resolvers updated to handle Properties; Resolver, Schema also updated to handle attribute lookups (this was missing)
+
+ * Add groundwork for user defined soap headers.
+
+ * Fix elementFormDefault per ticket #7
+
+ * Remove unused kwargs from bindings; cache bindings in wsdl; retrofit legacy ServiceProxy to delegate to {new} Client API;
+ remove keyword nil_supported in favor of natural handling by 'nillable' attribute on <element/> within schemas
+
+ * Add support for <element/> attribute flags (nillable and form)
+
+ * Add the Proxy (2nd generation API) class
+
+ * Add accessor/conversion functions to that user don't need to access __x__ attributes.
+ Also add todict() and get_items() for easy conversion to dictionary and iteration
+
+ * Search top-level elements for @ref before looking deeper
+
+ * Add derived() to SchemaObject. This is needed to ensure that all derived types (wsdl classes)
+ are qualified by xsi:type without specifying the xsi:type for all custom types as did in earlier
+ releases of suds. Update the literal marshaller to only add the xsi:type when the type needs
+ to be specified.
+
+ * Change ns promotion in sax to prevent ns promoted to parent when parent has the prefix.
+
+ * Changed binding returned_type() to return the (unresolved) Element
+
+ * In order to support the new features and fix reported bugs,
+ I'm in the process of refactoring and hopefully evolving the components
+ in Suds that provide the input/output translations:
+
+ * Builder ( translates: XSD objects => python objects )
+ * Marshaller ( translates: python objects => XML/SOAP )
+ * Unmarshaller ( translates: soap/xml => python objects )
+
+ This evolution will provide better symmetry between these components as follows:
+
+ The Builder and Unmarshaller will produce python
+ (subclass of sudsobject.Object) objects with:
+
+ * __metadata__.__type__ = XSD type (SchemaObject)
+ * subclass name ( __class__.__name__ ) = schema-type name.
+
+ and
+
+ The Marshaller(s), while consuming python objects produced by the Builder or
+ Unmarshaller, will leverage this standard information to
+ produce the appropriate output ( XML/SOAP ).
+
+ The 0.2.1 code behaves *mostly* like this but ... not quite.
+ Also, the implementations have some redundancy.
+
+ While doing this, it made sense to factor out the common schema-type "lookup"
+ functionality used by the Builder, Marshallers and Unmarshaller classes into a
+ hierarchy of "Resolver" classes. This reduces the complexity and redundancy
+ of the Builder, Marshallers and Unmarshaller classes and allows for better
+ modularity. Once this refactoring was complete, the difference between the
+ literal/encoded Marshallers became very small. Given that the amount of code
+ in the bindings.literal and bindings.encoded packages was small (and getting smaller)
+ and in the interest of keeping the Suds code base compact, I moved all of the
+ marshalling classes to the bindings.marshaller module.
+ All of the bindings.XX sub-packages will be removed.
+
+ The net effect:
+
+ All of the Suds major components:
+
+ * client (old: service proxy)
+ * wsdl
+ * schema (xsd package)
+ * resolvers
+ * output (marshalling)
+ * builder
+ * input (unmarshalling)
+
+ Now have better:
+
+ * modularity
+ * symmetry with regard to Object metadata.
+ * code re-use (< 1% code duplication --- i hope)
+ * looser coupling
+
+ ... and better provide for the following features/bug-fixes:
+
+ * (fix) Proper level of XML element qualification based on
+ <schema elementFormDefault=""/> attribute. This will ensure that when
+ elementFormDefault="qualified", Suds will include the proper namespace on
+ root elements for both literal and encoded bindings. In order for this to
+ work properly, the literal marshaller (like the encoded marshaller) needed
+ to be schema-type aware. Had i added the same schema-type lookup as the
+ encoded marshaller instead of the refactoring described above, the two
+ classes would have been almost a complete duplicate of each other :-(
+
+ * The builder and unmarshaller used the schema.Schema.find()
+ to resolve schema-types. They constructed a path as "person.name.first"
+ to resolve types in proper context. Since the Schema.find() was stateless,
+ it resolved the intermediate path elements on every call. The new resolver
+ classes are statefull and resolve child types *much* more efficiently.
+
+ * Prevent name collisions in sudsobject.Object like the items() method. I've moved all
+ methods (including class methods) to a Factory class that is included in the Object class
+ as a class attr ( __factory__ ). Now that *all* attributes have python built-in naming,
+ we should not have any more name collisions. This of course assumes that no wsdl/schema
+ entity names will have a name with the python built-in naming convention
+ but I have to draw the line somewhere :-)
+
+
+version 0.2.1 (5-8-08):
+
+ * Update the schema.py SchemaProperty loading sequence so that the schema is loaded in 3 steps:
+ 1) build the raw tree.
+ 2) resolve dependancies such as @ref and @base.
+ 3) promote grandchildren as needed to flatten (denormalize) the tree.
+
+ The wsdl was also changed to only load the schema once and store it. The schema collection was
+ changed to load schemas in 2 steps:
+ 1) create all raw schema objects.
+ 2) load schemas.
+
+ This ensure that local <import/>'d schemas can be found when referenced out of order.
+ The sax.py Element interface changed: attribute() replaced by get() and set().
+ Also, __getitem__ and __setitem__ can be used to access attribute values.
+ Epydocs updated for sax.py. And ... last <element ref=/> now supported properly.
+
+ * fix logging by: NOT setting to info in suds.__init__.logger(); set handler on root logger
+ only; moved logger (log) from classes to modules and use __name__ for logger name.
+ NOTE: This means that to enable soap message logging:
+ >
+ > logger('suds.serviceproxy').setLevel(logging.DEBUG)
+ >
+ -- instead of --
+ >
+ > logger('serviceproxy').setLevel(logging.DEBUG)
+ >
+
+ * Add support for (xsd) schema <attribute/> nodes which primarily affects objects returned by the Builder
+
+ * Update serviceproxy.py:set_proxies() to log DEBUG instead of INFO.
+
+ * Enhance schema __str__ to show both the raw xml and the model (mostly for debugging).
+
+
+version-0.2 (04-28-08):
+
+ * Contains the first cut at the rpc/encoded soap style.
+
+ * Replaced Property class with suds.sudsobject.Object. The Property class was developed a long time
+ ago with a slightly different purpose. The suds Object is a simpler (more straight forward) approach that
+ requires less code and works better in the debugger.
+
+ * The Binding (and the encoding) is selected on a per-method basis which is more consistent with the wsdl.
+ In <= 0.1.7, the binding was selected when the ServiceProxy was constructed and used for all service
+ methods. The binding was stored as self.binding. Since the WSDL provides for a separate binding style and
+ encoding for each operation, Suds needed to be change to work the same way.
+
+ * The (nil_supported) and (faults) flag(s) passed into the service proxy using **kwargs. In addition to these
+ flags, a (http_proxy) flag has been added and is passed to the urllib2.Request object. The following args
+ are supported:
+ * faults = Raise faults raised by server (default:True), else return tuple from service method invocation
+ as (http code, object).
+ * nil_supported = The bindings will set the xsi:nil="true" on nodes that have a value=None when this
+ flag is True (default:True). Otherwise, an empty node <x/> is sent.
+ * proxy = An http proxy to be specified on requests (default:{}).
+ The proxy is defined as {protocol:proxy,}
+
+ * Http proxy supported (see above).
+
+ * ServiceProxy refactored to delegate to a SoapClient. Since the service proxy exposes web services via getattr(),
+ any attribute (including methods) provided by the ServiceProxy class hides WS operations defined by the
+ wsdl. So, by moving everything to the SoapClient, wsdl operations are no longer hidden without
+ having to use *hoky* names for attributes and methods in the service proxy. Instead, the service proxy has
+ __client__ and __factory__ attributes (which really should be at low risk for name collision). For now the
+ get_instance() and get_enum() methods have not been moved to preserve backward compatibility. Although,
+ the prefered API change would to replace:
+
+ > service = ServiceProxy('myurl')
+ > person = service.get_instance('person')
+
+ ... with something like ...
+
+ > service = ServiceProxy('myurl')
+ > person = service.__factory__.get_instance('person')
+
+ After a few releases giving time for users to switch the new API, the get_instance() and get_enum()
+ methods may be removed with a notice in big letters.
+
+ * Fixed problem where a wsdl doesn't define a <schema/> section and Suds can't resolve the prefixes for the
+ http://www.w3.org/2001/XMLSchema namespace to detect builtin types such as (xs:string).
+
+
+version-0.1.7 (04-08-08):
+
+ * Added Binding.nil_supported to controls how property values (out) = None and empty tag (in) are processed.
+ * service.binding.nil_supported = True -- means that property values = None are marshalled (out) as
+ <x xsi:nil=true/> and <x/> is unmarshalled as '' and <x xsi:nil/> is unmarshalled as None.
+ * service.binding.nil_supported = False -- means that property values = None are marshalled (out) as
+ <x/> and <x/> *and* <x xsi:nil=true/> is unmarshalled as None.
+ The xsi:nil is really ignored.
+ * THE DEFAULT IS (TRUE)
+
+ * Sax handler updated to handle multiple character() callbacks when the sax parser "chunks" the text.
+ When the node.text is None, the node.text is set to the characters. Else, the characters are appended.
+ Thanks - andrea.spinelli@imteam.it
+
+ * Replaced special (text) attribute with __text__ to allow for natural elements named "text"
+
+ * Add unicode support by:
+ * Add __unicode__ to all classes with __str__
+ * Replace all str() calls with unicode().
+ * __str__() returns UTF-8 encoded result of __unicode__.
+
+ * XML output encoded as UTF-8 which matches the HTTP header and supports unicode.
+
+ * SchemaCollection changed to provide the builtin() and custom() methods. To support this, findPrefixes() was added to the
+ Element in sax.py. This is a better approach anyway since the wsdl and schemas may have many prefixes
+ to http://www.w3.org/2001/XMLSchema. Tested with both doc/lit and rpc/lit bindings
+
+ * Refactored bindings packages from document & rpc to literal & encoded
+
+ * Contains the completion of *full* namespace support as follows:
+
+ * Namespace prefixes are no longer stripped from attribute values that
+ reference types defined in the wsdl.
+ * Schema's imported using <import/> should properly handle namespace and prefix
+ mapping and re-mapping as needed.
+ * All types are resolved, using fully qualified (w/ namespaces) lookups.
+ * Schema.get_type() supports paths with and without ns prefixes. When no prefix
+ is specified the type is matched using the schema's target namespace.
+
+ * Property maintains attribute names (keys) in the order added. This also means
+ that get_item() and get_names() return ordered values.
+ ( Although, I suspect ordering really needs to be done in the marshaller using the
+ order specified in the wsdl/schema )
+
+ Major refactoring of the schema.py. The primary goals is perparation for type lookups that are
+ fully qualified by namespace. Once completed, the prefixes on attribute values will not longer
+ be stripped (purged).
+ Change Summary:
+ 1) SchemaProperty overlay classes created at __init__ instead of on-demand.
+ 2) schema imports performed by new Import class instead of by Schema.
+ 3) Schema loads top level properties using a factory.
+ 4) All SchemaProperty /children/ lists are sorted by __cmp__ in SchemaProperty derived classes.
+ This ensures that types with the same name are resolved in the following order (Import, Complex, Simple, Element).
+ 5) All /children/ SchemaProperty lists are constructed at __init__ instead of on-demand.
+ 6) The SchemaGroup created and WSDL class updated. This works better then having the wsdl aggregate the <schema/>
+ nodes which severs linkage to the wsdl parent element that have namespace prefix mapping.
+ 7) <import/> element handles properly in that both namespace remapping and prefix re-mapping of the imported schema's
+ targetNamespace and associated prefix mapping - is performed.
+ Eg: SCHMEA-A has prefix (tns) mapped as xmlns:tns=http://nsA and has targetNamespace=http://nsA.
+ SCHEMA-B is importing schema A and has prefix (abc) mapped as xmlns:abc=http://nsABC.
+ SCHEMA-B imports A as <import namespace=http://nsB xxx schemaLocation=http://nsA/schema-a.xsd>.
+ So, since SCHEMA-B will be referencing elements of SCHEMA-A with prefix (abc) such as abc:something, SCHEMA-A's
+ targetNamespace must be updated as http://nsABC and all element with type=tns:something must be updated to be
+ type=abc:something so then can be resolved.
+
+ * Fixes unmarshalling problem where nodes are added to property as (text, value). This as introduced when the
+ bindings were refactored.
+
+ * Fixed various Property print problems.
+
+ Notes:
+
+ Thanks to Jesper Noehr of Coniuro for the majority of the rpc/literal binding and
+ for lots of collaboration on #suds.
+
+
+version-0.1.6 (03-06-08):
+
+ * Provides proper handling of wsdls that contain schema sections containing
+ xsd schema imports: <import namespace="" schemaLocation=""?>. The
+ referenced schemas are imported when a schemaLocation is specified.
+* Raises exceptions for http status codes not already handled.
+
+
+version-0.1.5( 02-21-08 ):
+
+ * Provides better logging in the modules get logger by hierarchal names.
+ * Refactored as needed to truely support other bindings.
+ * Add sax module which replaces ElementTree. This is faster, simpler and
+ handles namespaces (prefixes) properly.
+
+
+version-0.1.4 (12-21-07):
+
+ * Provides for service method parameters to be None.
+ * Add proper handling of method params that are lists of property
+ objects.
+
+
+version-0.1.3 (12-19-07):
+
+ * Fixes problem where nodes marked as a collection (maxOccurs > 1) not
+ creating property objects with value=[] when mapped-in with < 2
+ values by the DocumentReader. Caused by missing the
+ bindings.Document.ReplyHint.stripns() (which uses the DocumentReader.stripns())
+ conversion to DocumentReader.stripn() now returning a tuple (ns,tag) as
+ of 0.1.2.
+
+
+version-0.1.2 (12-18-07):
+
+ This release contains an update to property adds:
+ * metadata support
+ * overrides: __getitem__, __setitem__, __contans__
+ * changes property(reader|writer) to use the property.metadata
+ to handle namespaces for XML documents.
+ * fixes setup.py requires.
+
+
+version-0.1.1 (12-17-07):
+
+ This release marks the first release in fedora hosted.
71 makefile
@@ -0,0 +1,71 @@
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the (LGPL) GNU Lesser General Public License as
+# published by the Free Software Foundation; either version 3 of the
+# License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Library Lesser General Public License for more details at
+# ( http://www.gnu.org/licenses/lgpl.html ).
+#
+# You should have received a copy of the GNU Lesser General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+# written by: Jeff Ortel ( jortel@redhat.com )
+#
+
+PKG = python-suds
+SPEC = $(PKG).spec
+SETUP = setup.py
+DOCTAR = suds-docs.tar.gz
+FEDORAPEOPLE = jortel@fedorapeople.org
+
+all : rpm docs
+
+dist : clean
+ mkdir dist
+ ./sdist
+ ./sdist python
+
+rpm : dist
+ cp dist/$(PKG)*.gz /usr/src/redhat/SOURCES
+ rpmbuild -ba $(SPEC)
+ cp /usr/src/redhat/RPMS/noarch/$(PKG)*.rpm dist
+ cp /usr/src/redhat/SRPMS/$(PKG)*.rpm dist
+ rpmlint -i dist/$(PKG)*.rpm
+
+release : rpm rdocs
+ scp dist/python*.tar.gz fedorahosted.org:suds
+ scp dist/python*.rpm fedorahosted.org:suds
+
+register :
+ python setup.py sdist bdist_egg register upload
+
+rdocs : docs
+ scp /tmp/$(DOCTAR) $(FEDORAPEOPLE):
+ ssh $(FEDORAPEOPLE) 'cd public_html/suds; rm -rf doc; tar xmzvf ~/$(DOCTAR)'
+
+docs :
+ rm -rf doc
+ rm -f /tmp/$(DOCTAR)
+ epydoc -vo doc `find suds -name "*.py"`
+ tar czvf /tmp/$(DOCTAR) doc
+
+pdf :
+ epydoc -vo doc --pdf `find suds -name \*.py`
+ mv doc/api.pdf doc/sudsapi.pdf
+
+clean :
+ rm -rf dist
+ rm -rf build
+ rm -rf doc
+ rm -rf *.egg-info
+ rm -rf /usr/src/redhat/BUILD/$(PKG)*
+ rm -rf /usr/src/redhat/RPMS/noarch/$(PKG)*
+ rm -rf /usr/src/redhat/SOURCES/$(PKG)*
+ rm -rf /usr/src/redhat/SRPMS/$(PKG)*
+ find . -name "*.pyc" -exec rm -f {} \;
+ find . -name "*~" -exec rm -f {} \;
+
+.PHONY : clean register docs pdf
210 python-suds.spec
@@ -0,0 +1,210 @@
+%{!?python_sitelib: %define python_sitelib %(%{__python} -c "from distutils.sysconfig import get_python_lib; print get_python_lib()")}
+
+Summary: A python SOAP client
+Name: python-suds
+Version: 0.4
+Release: 1%{?dist}
+Source0: https://fedorahosted.org/releases/s/u/suds/%{name}-%{version}.tar.gz
+License: LGPLv3+
+Group: Development/Libraries
+BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-buildroot
+BuildArch: noarch
+Requires: python >= 2.4
+BuildRequires: python-setuptools-devel
+Url: https://fedorahosted.org/suds
+
+%description
+The suds project is a python soap web services client lib. Suds leverages
+python meta programming to provide an intuitive API for consuming web
+services. Objectification of types defined in the WSDL is provided
+without class generation. Programmers rarely need to read the WSDL since
+services and WSDL based objects can be easily inspected.
+
+%prep
+%setup -q
+
+%build
+python setup.py sdist
+
+%install
+rm -rf $RPM_BUILD_ROOT
+python setup.py install --optimize=1 --root=$RPM_BUILD_ROOT
+
+%clean
+rm -rf $RPM_BUILD_ROOT
+
+%files
+%defattr(-,root,root,-)
+%{python_sitelib}/suds*.egg-info
+%dir %{python_sitelib}/suds
+%dir %{python_sitelib}/suds/bindings
+%dir %{python_sitelib}/suds/sax
+%dir %{python_sitelib}/suds/xsd
+%dir %{python_sitelib}/suds/mx
+%dir %{python_sitelib}/suds/umx
+%dir %{python_sitelib}/suds/transport
+%{python_sitelib}/suds/*.py*
+%{python_sitelib}/suds/bindings/*.py*
+%{python_sitelib}/suds/sax/*.py*
+%{python_sitelib}/suds/xsd/*.py*
+%{python_sitelib}/suds/mx/*.py*
+%{python_sitelib}/suds/umx/*.py*
+%{python_sitelib}/suds/transport/*.py*
+
+%doc README LICENSE
+
+%changelog
+* Thu Sep 8 2010 jortel <jortel@redhat.com> - 0.4-1
+- Fix spelling errors in spec description.
+- Fix source0 URL warning.
+- Updated caching to not cache intermediate wsdls.
+- Added DocumentCache which caches verified XML documents as text. User can choose.
+- Added cachingpolicy option to allow user to specify whether to cache XML documents or the WSDL object.
+- Provided for repeating values in reply for message parts consistent with way handled in nested objects.
+- Added charset=utf-8 to stock content-type http header.
+- Added <?xml version="1.0" encoding="UTF-8"?> to outgoing SOAP messages.
+- Detection of faults in successful (http=200) replies and raise WebFault. Search for <soapenv:Fault/>.
+- Add plugins facility.
+- Fixed Tickets: #251, #313, #314, #334
+
+* Thu Jul 22 2010 David Malcolm <dmalcolm@redhat.com> - 0.3.9-2
+- Rebuilt for https://fedoraproject.org/wiki/Features/Python_2.7/MassRebuild
+
+* Thu Dec 17 2009 jortel <jortel@redhat.com> - 0.3.9-1
+- Bumped python requires to 2.4
+- Replaced stream-based caching in the transport package with document-based caching.
+- Caches pickled Document objects instead of XML text. 2x Faster!
+- No more SAX parsing exceptions on damaged or incomplete cached files.
+- Cached WSDL objects. Entire Definitions object including contained Schema object cached via pickle.
+- Copy of soap encoding schema packaged with suds.
+- Refactor Transports to use ProxyHandler instead of urllib2.Request.set_proxy().
+- Added WSSE enhancements <Timestamp/> and <Expires/> support. See: Timestamp token.
+- Fixed Tickets: #256, #291, #294, #295, #296
+
+* Wed Dec 9 2009 jortel <jortel@redhat.com> - 0.3.8-1
+- Includeds Windows NTLM Transport.
+- Add missing self.messages in Client.clone().
+- Changed default behavior for WSDL PartElement to be optional.
+- Add support for services/ports defined without <address/> element in WSDL.
+- Fix sax.attribute.Element.attrib() to find by name only when ns is not specified; renamed to Element.getAttribute().
+- Update HttpTransport to pass timeout parameter to urllib2 open() methods when supported by urllib2.
+- Add null class to pass explicit NULL values for parameters and optional elements.
+- Soap encoded array (soap-enc:Array) enhancement for rpc/encoded.
+ Arrays passed as python arrays - works like document/literal now.
+ No more using the factory to create the Array.
+ Automatically includes arrayType attribute. Eg: soap-enc:arrayType="Array[2]".
+ Reintroduced ability to pass complex (objects) using python dict instead of suds object via factory.
+- Fixed tickets: #84, #261, #262, #263, #265, #266, #278, #280, #282.
+
+* Thu Oct 16 2009 jortel <jortel@redhat.com> - 0.3.7-1
+- Better soap header support
+- Added new transport HttpAuthenticated for active (not passive) basic authentication.
+- New options (prefixes, timeout, retxml)
+- WSDL processing enhancements.
+- Expanded builtin XSD type support.
+- Fixed <xs:iniclude/>
+- Better XML date/datetime conversion.
+- Client.clone() method added for lightweight copy of client object.
+- XSD processing fixes/enhancements.
+- Better <simpleType/> by <xs:restriction/> support.
+- Performance enhancements.
+- Fixed tickets: #65, #232, #233, #235, #241, #242, #244, #247, #254, #254, #256, #257, #258
+
+* Sun Jul 26 2009 Fedora Release Engineering <rel-eng@lists.fedoraproject.org> - 0.3.6-2
+- Rebuilt for https://fedoraproject.org/wiki/Fedora_12_Mass_Rebuild
+
+* Wed May 1 2009 jortel <jortel@redhat.com> - 0.3.6-1
+- Change hard coded /tmp/suds to tempfile.gettempdir() and create suds/ on demand.
+- Fix return type for Any.get_attribute().
+- Update http caching to ignore file:// urls.
+- Better logging of messages when only the reply is injected.
+- Fix XInteger and XFloat types to translate returned arrays properly.
+- Fix xs:import schema with same namespace.
+- Update parser to not load external references and add Import.bind() for XMLSchema.xsd location.
+- Add schema doctor - used to patch XSDs at runtime. (See Options.doctor)
+- Fix deprecation warnings in python 2.6.
+- Add behavior for @default defined on <element/>.
+- Change @xsi:type value to always be qualified for doc/literal.
+- Add Option.xstq option to control when @xsi:type is qualified.
+- Fixed Tickets: #64, #129, #205, #206, #217, #221, #222, #224, #225, #228, #229, #230
+
+* Wed Feb 25 2009 jortel <jortel@redhat.com> - 0.3.5-1
+- Adds http caching. Default is (1) day.
+- Removed checking fc version in spec since no longer building < fc9.
+- Updated makefile to roll tarball with tar.sh.
+- Moved bare/wrapped determination to wsdl for document/literal.
+- Refactored Transport to provide better visibility into http headers.
+- Fixed Tickets: #207, #207, #209, #210, #212, #214, #215
+
+* Mon Dec 08 2008 jortel <jortel@redhat.com> - 0.3.4-1
+- Static (automatic) Import.bind('http://schemas.xmlsoap.org/soap/encoding/')
+- Basic ws-security with {{{UsernameToken}}} and clear-text password only.
+- Add support for ''sparse'' soap headers via passing dictionary
+- Add support for arbitrary user defined soap headers
+- Fixes service operations with multiple soap header entries.
+- Schema loading and dereferencing algorithm enhancements.
+- Nested soap multirefs fixed.
+- Better (true) support for elementFormDefault="unqualified" provides more accurate namespaing.
+- WSDL part types no longer default to WSDL targetNamespace.
+- Fixed Tickets: #4, #6, #21, #32, #62, #66, #71, #72, #114, #155, #201.
+
+* Wed Dec 04 2008 jortel <jortel@redhat.com> - 0.3.3-2
+- Rebuild for Python 2.6
+
+* Wed Dec 04 2008 jortel <jortel@redhat.com> - 0.3.3-1
+- No longer installs (tests) package.
+- Implements API-3 proposal
+ Pluggable transport
+ Keyword method arguments
+ Baisc http authentication in default transport
+- Add namespace prefix normalization in soap message.
+- Better soap message pruning of empty nodes.
+- Fixed Tickets: #51 - #60.
+
+* Sat Nov 29 2008 Ignacio Vazquez-Abrams <ivazqueznet+rpm@gmail.com> - 0.3.2-2
+- Rebuild for Python 2.6
+
+* Fri Nov 06 2008 jortel <jortel@redhat.com> - 0.3.2-1
+- Add SOAP MultiRef support
+- Add support for new schema tags:
+ <xs:include/>
+ <xs:simpleContent/>
+ <xs:group/>
+ <xs:attributeGroup/>
+- Added support for new xs <--> python type conversions:
+ xs:int
+ xs:long
+ xs:float
+ xs:double
+- Revise marshaller and binding to further sharpen the namespacing of nodes produced.
+- Infinite recursion fixed in ''xsd'' package dereference() during schema loading.
+- Add support for <wsdl:import/> of schema files into the wsdl root <definitions/>.
+- Fix double encoding of (&)
+- Add Client API:
+ setheaders() - Same as keyword but works for all invocations.
+ addprefix() - Mapping of namespace prefixes.
+ setlocation() - Override the location in the wsdl.
+ setproxy() - Same as proxy keyword but for all invocations.
+- Add proper namespace prefix for soap headers.
+- Fixed Tickets: #5, #12, #34, #37, #40, #44, #45, #46, #48, #49, #50, #51
+
+* Fri Nov 03 2008 jortel <jortel@redhat.com> - 0.3.1-5
+- Add LICENSE to %%doc.
+
+* Fri Oct 28 2008 jortel <jortel@redhat.com> - 0.3.1-4
+- Changes acc. #466496 Comment #8
+
+* Fri Oct 27 2008 jortel <jortel@redhat.com> - 0.3.1-3
+- Add "rm -rf $RPM_BUILD_ROOT" to install
+
+* Fri Oct 16 2008 jortel <jortel@redhat.com> - 0.3.1-2
+- Changes acc. #466496 Comment #1
+
+* Fri Oct 10 2008 jortel <jortel@redhat.com> - 0.3.1-1
+- Extends the support for multi-port services introduced earlier. This addition,
+ provides for multiple services to define the *same* method and suds will
+ handle it properly. See section 'SERVICES WITH MULTIPLE PORTS:'
+- Add support for multi-document document/literal soap binding style.
+ See section 'MULTI-DOCUMENT Docuemnt/Literal:'
+- Add support for (xs:group, xs:attributeGroup) tags.
+- Add Client.last_sent() and Client.last_received().
2 setup.cfg
@@ -0,0 +1,2 @@
+[install]
+optimize = 1
33 setup.py
@@ -0,0 +1,33 @@
+#!/usr/bin/python
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the (LGPL) GNU Lesser General Public License as
+# published by the Free Software Foundation; either version 3 of the
+# License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Library Lesser General Public License for more details at
+# ( http://www.gnu.org/licenses/lgpl.html ).
+#
+# You should have received a copy of the GNU Lesser General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+# written by: Jeff Ortel ( jortel@redhat.com )
+
+import sys
+import suds
+from setuptools import setup, find_packages
+
+setup(
+ name="suds",
+ version=suds.__version__,
+ description="Lightweight SOAP client",
+ author="Jeff Ortel",
+ author_email="jortel@redhat.com",
+ maintainer="Jeff Ortel",
+ maintainer_email="jortel@redhat.com",
+ packages=find_packages(exclude=['tests']),
+ url="https://fedorahosted.org/suds",
+)
154 suds/__init__.py
@@ -0,0 +1,154 @@
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the (LGPL) GNU Lesser General Public License as
+# published by the Free Software Foundation; either version 3 of the
+# License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Library Lesser General Public License for more details at
+# ( http://www.gnu.org/licenses/lgpl.html ).
+#
+# You should have received a copy of the GNU Lesser General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+# written by: Jeff Ortel ( jortel@redhat.com )
+
+"""
+Suds is a lightweight SOAP python client that provides a
+service proxy for Web Services.
+"""
+
+import os
+import sys
+
+#
+# Project properties
+#
+
+__version__ = '0.4'
+__build__="GA R699-20100913"
+
+#
+# Exceptions
+#
+
+class MethodNotFound(Exception):
+ def __init__(self, name):
+ Exception.__init__(self, "Method not found: '%s'" % name)
+
+class PortNotFound(Exception):
+ def __init__(self, name):
+ Exception.__init__(self, "Port not found: '%s'" % name)
+
+class ServiceNotFound(Exception):
+ def __init__(self, name):
+ Exception.__init__(self, "Service not found: '%s'" % name)
+
+class TypeNotFound(Exception):
+ def __init__(self, name):
+ Exception.__init__(self, "Type not found: '%s'" % tostr(name))
+
+class BuildError(Exception):
+ msg = \
+ """
+ An error occured while building a instance of (%s). As a result
+ the object you requested could not be constructed. It is recommended
+ that you construct the type manually using a Suds object.
+ Please open a ticket with a description of this error.
+ Reason: %s
+ """
+ def __init__(self, name, exception):
+ Exception.__init__(self, BuildError.msg % (name, exception))
+
+class SoapHeadersNotPermitted(Exception):
+ msg = \
+ """
+ Method (%s) was invoked with SOAP headers. The WSDL does not
+ define SOAP headers for this method. Retry without the soapheaders
+ keyword argument.
+ """
+ def __init__(self, name):
+ Exception.__init__(self, self.msg % name)
+
+class WebFault(Exception):
+ def __init__(self, fault, document):
+ if hasattr(fault, 'faultstring'):
+ Exception.__init__(self, "Server raised fault: '%s'" % fault.faultstring)
+ self.fault = fault
+ self.document = document
+
+#
+# Logging
+#
+
+class Repr:
+ def __init__(self, x):
+ self.x = x
+ def __str__(self):
+ return repr(self.x)
+
+#
+# Utility
+#
+
+def tostr(object, encoding=None):
+ """ get a unicode safe string representation of an object """
+ if isinstance(object, basestring):
+ if encoding is None:
+ return object
+ else:
+ return object.encode(encoding)
+ if isinstance(object, tuple):
+ s = ['(']
+ for item in object:
+ if isinstance(item, basestring):
+ s.append(item)
+ else:
+ s.append(tostr(item))
+ s.append(', ')
+ s.append(')')
+ return ''.join(s)
+ if isinstance(object, list):
+ s = ['[']
+ for item in object:
+ if isinstance(item, basestring):
+ s.append(item)
+ else:
+ s.append(tostr(item))
+ s.append(', ')
+ s.append(']')
+ return ''.join(s)
+ if isinstance(object, dict):
+ s = ['{']
+ for item in object.items():
+ if isinstance(item[0], basestring):
+ s.append(item[0])
+ else:
+ s.append(tostr(item[0]))
+ s.append(' = ')
+ if isinstance(item[1], basestring):
+ s.append(item[1])
+ else:
+ s.append(tostr(item[1]))
+ s.append(', ')
+ s.append('}')
+ return ''.join(s)
+ try:
+ return unicode(object)
+ except:
+ return str(object)
+
+class null:
+ """
+ The I{null} object.
+ Used to pass NULL for optional XML nodes.
+ """
+ pass
+
+def objid(obj):
+ return obj.__class__.__name__\
+ +':'+hex(id(obj))
+
+
+import client
20 suds/bindings/__init__.py
@@ -0,0 +1,20 @@
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the (LGPL) GNU Lesser General Public License as
+# published by the Free Software Foundation; either version 3 of the
+# License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Library Lesser General Public License for more details at
+# ( http://www.gnu.org/licenses/lgpl.html ).
+#
+# You should have received a copy of the GNU Lesser General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+# written by: Jeff Ortel ( jortel@redhat.com )
+
+"""
+Provides modules containing classes to support Web Services (SOAP)
+bindings.
+"""
538 suds/bindings/binding.py
@@ -0,0 +1,538 @@
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the (LGPL) GNU Lesser General Public License as
+# published by the Free Software Foundation; either version 3 of the
+# License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Library Lesser General Public License for more details at
+# ( http://www.gnu.org/licenses/lgpl.html ).
+#
+# You should have received a copy of the GNU Lesser General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+# written by: Jeff Ortel ( jortel@redhat.com )
+
+"""
+Provides classes for (WS) SOAP bindings.
+"""
+
+from logging import getLogger
+from suds import *
+from suds.sax import Namespace
+from suds.sax.parser import Parser
+from suds.sax.document import Document
+from suds.sax.element import Element
+from suds.sudsobject import Factory, Object
+from suds.mx import Content
+from suds.mx.literal import Literal as MxLiteral
+from suds.umx.basic import Basic as UmxBasic
+from suds.umx.typed import Typed as UmxTyped
+from suds.bindings.multiref import MultiRef
+from suds.xsd.query import TypeQuery, ElementQuery
+from suds.xsd.sxbasic import Element as SchemaElement
+from suds.options import Options
+from suds.plugin import PluginContainer
+from copy import deepcopy
+
+log = getLogger(__name__)
+
+envns = ('SOAP-ENV', 'http://schemas.xmlsoap.org/soap/envelope/')
+
+
+class Binding:
+ """
+ The soap binding class used to process outgoing and imcoming
+ soap messages per the WSDL port binding.
+ @cvar replyfilter: The reply filter function.
+ @type replyfilter: (lambda s,r: r)
+ @ivar wsdl: The wsdl.
+ @type wsdl: L{suds.wsdl.Definitions}
+ @ivar schema: The collective schema contained within the wsdl.
+ @type schema: L{xsd.schema.Schema}
+ @ivar options: A dictionary options.
+ @type options: L{Options}
+ """
+
+ replyfilter = (lambda s,r: r)
+
+ def __init__(self, wsdl):
+ """
+ @param wsdl: A wsdl.
+ @type wsdl: L{wsdl.Definitions}
+ """
+ self.wsdl = wsdl
+ self.multiref = MultiRef()
+
+ def schema(self):
+ return self.wsdl.schema
+
+ def options(self):
+ return self.wsdl.options
+
+ def unmarshaller(self, typed=True):
+ """
+ Get the appropriate XML decoder.
+ @return: Either the (basic|typed) unmarshaller.
+ @rtype: L{UmxTyped}
+ """
+ if typed:
+ return UmxTyped(self.schema())
+ else:
+ return UmxBasic()
+
+ def marshaller(self):
+ """
+ Get the appropriate XML encoder.
+ @return: An L{MxLiteral} marshaller.
+ @rtype: L{MxLiteral}
+ """
+ return MxLiteral(self.schema(), self.options().xstq)
+
+ def param_defs(self, method):
+ """
+ Get parameter definitions.
+ Each I{pdef} is a tuple (I{name}, L{xsd.sxbase.SchemaObject})
+ @param method: A servic emethod.
+ @type method: I{service.Method}
+ @return: A collection of parameter definitions
+ @rtype: [I{pdef},..]
+ """
+ raise Exception, 'not implemented'
+
+ def get_message(self, method, args, kwargs):
+ """
+ Get the soap message for the specified method, args and soapheaders.
+ This is the entry point for creating the outbound soap message.
+ @param method: The method being invoked.
+ @type method: I{service.Method}
+ @param args: A list of args for the method invoked.
+ @type args: list
+ @param kwargs: Named (keyword) args for the method invoked.
+ @type kwargs: dict
+ @return: The soap envelope.
+ @rtype: L{Document}
+ """
+
+ content = self.headercontent(method)
+ header = self.header(content)
+ content = self.bodycontent(method, args, kwargs)
+ body = self.body(content)
+ env = self.envelope(header, body)
+ if self.options().prefixes:
+ body.normalizePrefixes()
+ env.promotePrefixes()
+ else:
+ env.refitPrefixes()
+ return Document(env)
+
+ def get_reply(self, method, reply):
+ """
+ Process the I{reply} for the specified I{method} by sax parsing the I{reply}
+ and then unmarshalling into python object(s).
+ @param method: The name of the invoked method.
+ @type method: str
+ @param reply: The reply XML received after invoking the specified method.
+ @type reply: str
+ @return: The unmarshalled reply. The returned value is an L{Object} for a
+ I{list} depending on whether the service returns a single object or a
+ collection.
+ @rtype: tuple ( L{Element}, L{Object} )
+ """
+ reply = self.replyfilter(reply)
+ sax = Parser()
+ replyroot = sax.parse(string=reply)
+ plugins = PluginContainer(self.options().plugins)
+ plugins.message.parsed(reply=replyroot)
+ soapenv = replyroot.getChild('Envelope')
+ soapenv.promotePrefixes()
+ soapbody = soapenv.getChild('Body')
+ self.detect_fault(soapbody)
+ soapbody = self.multiref.process(soapbody)
+ nodes = self.replycontent(method, soapbody)
+ rtypes = self.returned_types(method)
+ if len(rtypes) > 1:
+ result = self.replycomposite(rtypes, nodes)
+ return (replyroot, result)
+ if len(rtypes) == 1:
+ if rtypes[0].unbounded():
+ result = self.replylist(rtypes[0], nodes)
+ return (replyroot, result)
+ if len(nodes):
+ unmarshaller = self.unmarshaller()
+ resolved = rtypes[0].resolve(nobuiltin=True)
+ result = unmarshaller.process(nodes[0], resolved)
+ return (replyroot, result)
+ return (replyroot, None)
+
+ def detect_fault(self, body):
+ """
+ Detect I{hidden} soapenv:Fault element in the soap body.
+ @param body: The soap envelope body.
+ @type body: L{Element}
+ @raise WebFault: When found.
+ """
+ fault = body.getChild('Fault', envns)
+ if fault is None:
+ return
+ unmarshaller = self.unmarshaller(False)
+ p = unmarshaller.process(fault)
+ if self.options().faults:
+ raise WebFault(p, fault)
+ return self
+
+
+ def replylist(self, rt, nodes):
+ """
+ Construct a I{list} reply. This mehod is called when it has been detected
+ that the reply is a list.
+ @param rt: The return I{type}.
+ @type rt: L{suds.xsd.sxbase.SchemaObject}
+ @param nodes: A collection of XML nodes.
+ @type nodes: [L{Element},...]
+ @return: A list of I{unmarshalled} objects.
+ @rtype: [L{Object},...]
+ """
+ result = []
+ resolved = rt.resolve(nobuiltin=True)
+ unmarshaller = self.unmarshaller()
+ for node in nodes:
+ sobject = unmarshaller.process(node, resolved)
+ result.append(sobject)
+ return result
+
+ def replycomposite(self, rtypes, nodes):
+ """
+ Construct a I{composite} reply. This method is called when it has been
+ detected that the reply has multiple root nodes.
+ @param rtypes: A list of known return I{types}.
+ @type rtypes: [L{suds.xsd.sxbase.SchemaObject},...]
+ @param nodes: A collection of XML nodes.
+ @type nodes: [L{Element},...]
+ @return: The I{unmarshalled} composite object.
+ @rtype: L{Object},...
+ """
+ dictionary = {}
+ for rt in rtypes:
+ dictionary[rt.name] = rt
+ unmarshaller = self.unmarshaller()
+ composite = Factory.object('reply')
+ for node in nodes:
+ tag = node.name
+ rt = dictionary.get(tag, None)
+ if rt is None:
+ if node.get('id') is None:
+ raise Exception('<%s/> not mapped to message part' % tag)
+ else:
+ continue
+ resolved = rt.resolve(nobuiltin=True)
+ sobject = unmarshaller.process(node, resolved)
+ value = getattr(composite, tag, None)
+ if value is None:
+ if rt.unbounded():
+ value = []
+ setattr(composite, tag, value)
+ value.append(sobject)
+ else:
+ setattr(composite, tag, sobject)
+ else:
+ if not isinstance(value, list):
+ value = [value,]
+ setattr(composite, tag, value)
+ value.append(sobject)
+ return composite
+
+ def get_fault(self, reply):
+ """
+ Extract the fault from the specified soap reply. If I{faults} is True, an
+ exception is raised. Otherwise, the I{unmarshalled} fault L{Object} is
+ returned. This method is called when the server raises a I{web fault}.
+ @param reply: A soap reply message.
+ @type reply: str
+ @return: A fault object.
+ @rtype: tuple ( L{Element}, L{Object} )
+ """
+ reply = self.replyfilter(reply)
+ sax = Parser()
+ faultroot = sax.parse(string=reply)
+ soapenv = faultroot.getChild('Envelope')
+ soapbody = soapenv.getChild('Body')
+ fault = soapbody.getChild('Fault')
+ unmarshaller = self.unmarshaller(False)
+ p = unmarshaller.process(fault)
+ if self.options().faults:
+ raise WebFault(p, faultroot)
+ return (faultroot, p.detail)
+
+ def mkparam(self, method, pdef, object):
+ """
+ Builds a parameter for the specified I{method} using the parameter
+ definition (pdef) and the specified value (object).
+ @param method: A method name.
+ @type method: str
+ @param pdef: A parameter definition.
+ @type pdef: tuple: (I{name}, L{xsd.sxbase.SchemaObject})
+ @param object: The parameter value.
+ @type object: any
+ @return: The parameter fragment.
+ @rtype: L{Element}
+ """
+ marshaller = self.marshaller()
+ content = \
+ Content(tag=pdef[0],
+ value=object,
+ type=pdef[1],
+ real=pdef[1].resolve())
+ return marshaller.process(content)
+
+ def mkheader(self, method, hdef, object):
+ """
+ Builds a soapheader for the specified I{method} using the header
+ definition (hdef) and the specified value (object).
+ @param method: A method name.
+ @type method: str
+ @param hdef: A header definition.
+ @type hdef: tuple: (I{name}, L{xsd.sxbase.SchemaObject})
+ @param object: The header value.
+ @type object: any
+ @return: The parameter fragment.
+ @rtype: L{Element}
+ """
+ marshaller = self.marshaller()
+ if isinstance(object, (list, tuple)):
+ tags = []
+ for item in object:
+ tags.append(self.mkheader(method, hdef, item))
+ return tags
+ content = Content(tag=hdef[0], value=object, type=hdef[1])
+ return marshaller.process(content)
+
+ def envelope(self, header, body):
+ """
+ Build the B{<Envelope/>} for an soap outbound message.
+ @param header: The soap message B{header}.
+ @type header: L{Element}
+ @param body: The soap message B{body}.
+ @type body: L{Element}
+ @return: The soap envelope containing the body and header.
+ @rtype: L{Element}
+ """
+ env = Element('Envelope', ns=envns)
+ env.addPrefix(Namespace.xsins[0], Namespace.xsins[1])
+ env.append(header)
+ env.append(body)
+ return env
+
+ def header(self, content):
+ """
+ Build the B{<Body/>} for an soap outbound message.
+ @param content: The header content.
+ @type content: L{Element}
+ @return: the soap body fragment.
+ @rtype: L{Element}
+ """
+ header = Element('Header', ns=envns)
+ header.append(content)
+ return header
+
+ def bodycontent(self, method, args, kwargs):
+ """
+ Get the content for the soap I{body} node.
+ @param method: A service method.
+ @type method: I{service.Method}
+ @param args: method parameter values
+ @type args: list
+ @param kwargs: Named (keyword) args for the method invoked.
+ @type kwargs: dict
+ @return: The xml content for the <body/>
+ @rtype: [L{Element},..]
+ """
+ raise Exception, 'not implemented'
+
+ def headercontent(self, method):
+ """
+ Get the content for the soap I{Header} node.
+ @param method: A service method.
+ @type method: I{service.Method}
+ @return: The xml content for the <body/>
+ @rtype: [L{Element},..]
+ """
+ n = 0
+ content = []
+ wsse = self.options().wsse
+ if wsse is not None:
+ content.append(wsse.xml())
+ headers = self.options().soapheaders
+ if not isinstance(headers, (tuple,list,dict)):
+ headers = (headers,)
+ if len(headers) == 0:
+ return content
+ pts = self.headpart_types(method)
+ if isinstance(headers, (tuple,list)):
+ for header in headers:
+ if isinstance(header, Element):
+ content.append(deepcopy(header))
+ continue
+ if len(pts) == n: break
+ h = self.mkheader(method, pts[n], header)
+ ns = pts[n][1].namespace('ns0')
+ h.setPrefix(ns[0], ns[1])
+ content.append(h)
+ n += 1
+ else:
+ for pt in pts:
+ header = headers.get(pt[0])
+ if header is None:
+ continue
+ h = self.mkheader(method, pt, header)
+ ns = pt[1].namespace('ns0')
+ h.setPrefix(ns[0], ns[1])
+ content.append(h)
+ return content
+
+ def replycontent(self, method, body):
+ """
+ Get the reply body content.
+ @param method: A service method.
+ @type method: I{service.Method}
+ @param body: The soap body
+ @type body: L{Element}
+ @return: the body content
+ @rtype: [L{Element},...]
+ """
+ raise Exception, 'not implemented'
+
+ def body(self, content):
+ """
+ Build the B{<Body/>} for an soap outbound message.
+ @param content: The body content.
+ @type content: L{Element}
+ @return: the soap body fragment.
+ @rtype: L{Element}
+ """
+ body = Element('Body', ns=envns)
+ body.append(content)
+ return body
+
+ def bodypart_types(self, method, input=True):
+ """
+ Get a list of I{parameter definitions} (pdef) defined for the specified method.
+ Each I{pdef} is a tuple (I{name}, L{xsd.sxbase.SchemaObject})
+ @param method: A service method.
+ @type method: I{service.Method}
+ @param input: Defines input/output message.
+ @type input: boolean
+ @return: A list of parameter definitions
+ @rtype: [I{pdef},]
+ """
+ result = []
+ if input:
+ parts = method.soap.input.body.parts
+ else:
+ parts = method.soap.output.body.parts
+ for p in parts:
+ if p.element is not None:
+ query = ElementQuery(p.element)
+ else:
+ query = TypeQuery(p.type)
+ pt = query.execute(self.schema())
+ if pt is None:
+ raise TypeNotFound(query.ref)
+ if p.type is not None:
+ pt = PartElement(p.name, pt)
+ if input:
+ if pt.name is None:
+ result.append((p.name, pt))
+ else:
+ result.append((pt.name, pt))
+ else:
+ result.append(pt)
+ return result
+
+ def headpart_types(self, method, input=True):
+ """
+ Get a list of I{parameter definitions} (pdef) defined for the specified method.
+ Each I{pdef} is a tuple (I{name}, L{xsd.sxbase.SchemaObject})
+ @param method: A service method.
+ @type method: I{service.Method}
+ @param input: Defines input/output message.
+ @type input: boolean
+ @return: A list of parameter definitions
+ @rtype: [I{pdef},]
+ """
+ result = []
+ if input:
+ headers = method.soap.input.headers
+ else:
+ headers = method.soap.output.headers
+ for header in headers:
+ part = header.part
+ if part.element is not None:
+ query = ElementQuery(part.element)
+ else:
+ query = TypeQuery(part.type)
+ pt = query.execute(self.schema())
+ if pt is None:
+ raise TypeNotFound(query.ref)
+ if part.type is not None:
+ pt = PartElement(part.name, pt)
+ if input:
+ if pt.name is None:
+ result.append((part.name, pt))
+ else:
+ result.append((pt.name, pt))
+ else:
+ result.append(pt)
+ return result
+
+ def returned_types(self, method):
+ """
+ Get the L{xsd.sxbase.SchemaObject} returned by the I{method}.
+ @param method: A service method.
+ @type method: I{service.Method}
+ @return: The name of the type return by the method.
+ @rtype: [I{rtype},..]
+ """
+ result = []
+ for rt in self.bodypart_types(method, input=False):
+ result.append(rt)
+ return result
+
+
+class PartElement(SchemaElement):
+ """
+ A part used to represent a message part when the part
+ references a schema type and thus assumes to be an element.
+ @ivar resolved: The part type.
+ @type resolved: L{suds.xsd.sxbase.SchemaObject}
+ """
+
+ def __init__(self, name, resolved):
+ """
+ @param name: The part name.
+ @type name: str
+ @param resolved: The part type.
+ @type resolved: L{suds.xsd.sxbase.SchemaObject}
+ """
+ root = Element('element', ns=Namespace.xsdns)
+ SchemaElement.__init__(self, resolved.schema, root)
+ self.__resolved = resolved
+ self.name = name
+ self.form_qualified = False
+
+ def implany(self):
+ return self
+
+ def optional(self):
+ return True
+
+ def namespace(self, prefix=None):
+ return Namespace.default
+
+ def resolve(self, nobuiltin=False):
+ if nobuiltin and self.__resolved.builtin():
+ return self
+ else:
+ return self.__resolved
+
160 suds/bindings/document.py
@@ -0,0 +1,160 @@
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the (LGPL) GNU Lesser General Public License as
+# published by the Free Software Foundation; either version 3 of the
+# License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Library Lesser General Public License for more details at
+# ( http://www.gnu.org/licenses/lgpl.html ).
+#
+# You should have received a copy of the GNU Lesser General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+# written by: Jeff Ortel ( jortel@redhat.com )
+
+"""
+Provides classes for the (WS) SOAP I{document/literal}.
+"""
+
+from logging import getLogger
+from suds import *
+from suds.bindings.binding import Binding
+from suds.sax.element import Element
+
+log = getLogger(__name__)
+
+
+class Document(Binding):
+ """
+ The document/literal style. Literal is the only (@use) supported
+ since document/encoded is pretty much dead.
+ Although the soap specification supports multiple documents within the soap
+ <body/>, it is very uncommon. As such, suds presents an I{RPC} view of
+ service methods defined with a single document parameter. This is done so
+ that the user can pass individual parameters instead of one, single document.
+ To support the complete specification, service methods defined with multiple documents
+ (multiple message parts), must present a I{document} view for that method.
+ """
+
+ def bodycontent(self, method, args, kwargs):
+ #
+ # The I{wrapped} vs I{bare} style is detected in 2 ways.
+ # If there is 2+ parts in the message then it is I{bare}.
+ # If there is only (1) part and that part resolves to a builtin then
+ # it is I{bare}. Otherwise, it is I{wrapped}.
+ #
+ if not len(method.soap.input.body.parts):
+ return ()
+ wrapped = method.soap.input.body.wrapped
+ if wrapped:
+ pts = self.bodypart_types(method)
+ root = self.document(pts[0])
+ else:
+ root = []
+ n = 0
+ for pd in self.param_defs(method):
+ if n < len(args):
+ value = args[n]
+ else:
+ value = kwargs.get(pd[0])
+ n += 1
+ p = self.mkparam(method, pd, value)
+ if p is None:
+ continue
+ if not wrapped:
+ ns = pd[1].namespace('ns0')
+ p.setPrefix(ns[0], ns[1])
+ root.append(p)
+ return root
+
+ def replycontent(self, method, body):
+ wrapped = method.soap.output.body.wrapped
+ if wrapped:
+ return body[0].children
+ else:
+ return body.children
+
+ def document(self, wrapper):
+ """
+ Get the document root. For I{document/literal}, this is the
+ name of the wrapper element qualifed by the schema tns.
+ @param wrapper: The method name.
+ @type wrapper: L{xsd.sxbase.SchemaObject}
+ @return: A root element.
+ @rtype: L{Element}
+ """
+ tag = wrapper[1].name
+ ns = wrapper[1].namespace('ns0')
+ d = Element(tag, ns=ns)
+ return d
+
+ def mkparam(self, method, pdef, object):
+ #
+ # Expand list parameters into individual parameters
+ # each with the type information. This is because in document
+ # arrays are simply unbounded elements.
+ #
+ if isinstance(object, (list, tuple)):
+ tags = []
+ for item in object:
+ tags.append(self.mkparam(method, pdef, item))
+ return tags
+ else:
+ return Binding.mkparam(self, method, pdef, object)
+
+ def param_defs(self, method):
+ #
+ # Get parameter definitions for document literal.
+ # The I{wrapped} vs I{bare} style is detected in 2 ways.
+ # If there is 2+ parts in the message then it is I{bare}.
+ # If there is only (1) part and that part resolves to a builtin then
+ # it is I{bare}. Otherwise, it is I{wrapped}.
+ #
+ pts = self.bodypart_types(method)
+ wrapped = method.soap.input.body.wrapped
+ if not wrapped:
+ return pts
+ result = []
+ # wrapped
+ for p in pts:
+ resolved = p[1].resolve()
+ for child, ancestry in resolved:
+ if child.isattr():
+ continue
+ if self.bychoice(ancestry):
+ log.debug(
+ '%s\ncontained by <choice/>, excluded as param for %s()',
+ child,
+ method.name)
+ continue
+ result.append((child.name, child))
+ return result
+
+ def returned_types(self, method):
+ result = []
+ wrapped = method.soap.output.body.wrapped
+ rts = self.bodypart_types(method, input=False)
+ if wrapped:
+ for pt in rts:
+ resolved = pt.resolve(nobuiltin=True)
+ for child, ancestry in resolved:
+ result.append(child)
+ break
+ else:
+ result += rts
+ return result
+
+ def bychoice(self, ancestry):
+ """
+ The ancestry contains a <choice/>
+ @param ancestry: A list of ancestors.
+ @type ancestry: list
+ @return: True if contains <choice/>
+ @rtype: boolean
+ """
+ for x in ancestry:
+ if x.choice():
+ return True
+ return False
126 suds/bindings/multiref.py
@@ -0,0 +1,126 @@
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the (LGPL) GNU Lesser General Public License as
+# published by the Free Software Foundation; either version 3 of the
+# License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Library Lesser General Public License for more details at
+# ( http://www.gnu.org/licenses/lgpl.html ).
+#
+# You should have received a copy of the GNU Lesser General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+# written by: Jeff Ortel ( jortel@redhat.com )
+
+"""
+Provides classes for handling soap multirefs.
+"""
+
+from logging import getLogger
+from suds import *
+from suds.sax.element import Element
+
+log = getLogger(__name__)
+
+soapenc = (None, 'http://schemas.xmlsoap.org/soap/encoding/')
+
+class MultiRef:
+ """
+ Resolves and replaces multirefs.
+ @ivar nodes: A list of non-multiref nodes.
+ @type nodes: list
+ @ivar catalog: A dictionary of multiref nodes by id.
+ @type catalog: dict
+ """
+
+ def __init__(self):
+ self.nodes = []
+ self.catalog = {}
+
+ def process(self, body):
+ """
+ Process the specified soap envelope body and replace I{multiref} node
+ references with the contents of the referenced node.
+ @param body: A soap envelope body node.
+ @type body: L{Element}
+ @return: The processed I{body}
+ @rtype: L{Element}
+ """
+ self.nodes = []
+ self.catalog = {}
+ self.build_catalog(body)
+ self.update(body)
+ body.children = self.nodes
+ return body
+
+ def update(self, node):
+ """
+ Update the specified I{node} by replacing the I{multiref} references with
+ the contents of the referenced nodes and remove the I{href} attribute.
+ @param node: A node to update.
+ @type node: L{Element}
+ @return: The updated node
+ @rtype: L{Element}
+ """
+ self.replace_references(node)
+ for c in node.children:
+ self.update(c)
+ return node
+
+ def replace_references(self, node):
+ """
+ Replacing the I{multiref} references with the contents of the
+ referenced nodes and remove the I{href} attribute. Warning: since
+ the I{ref} is not cloned,
+ @param node: A node to update.
+ @type node: L{Element}
+ """
+ href = node.getAttribute('href')
+ if href is None:
+ return
+ id = href.getValue()
+ ref = self.catalog.get(id)
+ if ref is None:
+ log.error('soap multiref: %s, not-resolved', id)
+ return
+ node.append(ref.children)
+ node.setText(ref.getText())
+ for a in ref.attributes:
+ if a.name != 'id':
+ node.append(a)
+ node.remove(href)
+
+ def build_catalog(self, body):
+ """
+ Create the I{catalog} of multiref nodes by id and the list of
+ non-multiref nodes.
+ @param body: A soap envelope body node.
+ @type body: L{Element}
+ """
+ for child in body.children:
+ if self.soaproot(child):
+ self.nodes.append(child)
+ id = child.get('id')
+ if id is None: continue
+ key = '#%s' % id
+ self.catalog[key] = child
+
+ def soaproot(self, node):
+ """
+ Get whether the specified I{node} is a soap encoded root.
+ This is determined by examining @soapenc:root='1'.
+ The node is considered to be a root when the attribute
+ is not specified.
+ @param node: A node to evaluate.
+ @type node: L{Element}
+ @return: True if a soap encoded root.
+ @rtype: bool
+ """
+ root = node.getAttribute('root', ns=soapenc)
+ if root is None:
+ return True
+ else:
+ return ( root.value == '1' )
+
98 suds/bindings/rpc.py
@@ -0,0 +1,98 @@
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the (LGPL) GNU Lesser General Public License as
+# published by the Free Software Foundation; either version 3 of the
+# License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Library Lesser General Public License for more details at
+# ( http://www.gnu.org/licenses/lgpl.html ).
+#
+# You should have received a copy of the GNU Lesser General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+# written by: Jeff Ortel ( jortel@redhat.com )
+
+"""
+Provides classes for the (WS) SOAP I{rpc/literal} and I{rpc/encoded} bindings.
+"""
+
+from logging import getLogger
+from suds import *
+from suds.mx.encoded import Encoded as MxEncoded
+from suds.umx.encoded import Encoded as UmxEncoded
+from suds.bindings.binding import Binding, envns
+from suds.sax.element import Element
+
+log = getLogger(__name__)
+
+
+encns = ('SOAP-ENC', 'http://schemas.xmlsoap.org/soap/encoding/')
+
+class RPC(Binding):
+ """
+ RPC/Literal binding style.
+ """
+
+ def param_defs(self, method):
+ return self.bodypart_types(method)
+
+ def envelope(self, header, body):
+ env = Binding.envelope(self, header, body)
+ env.addPrefix(encns[0], encns[1])
+ env.set('%s:encodingStyle' % envns[0],
+ 'http://schemas.xmlsoap.org/soap/encoding/')
+ return env
+
+ def bodycontent(self, method, args, kwargs):
+ n = 0
+ root = self.method(method)
+ for pd in self.param_defs(method):
+ if n < len(args):
+ value = args[n]
+ else:
+ value = kwargs.get(pd[0])
+ p = self.mkparam(method, pd, value)
+ if p is not None:
+ root.append(p)
+ n += 1
+ return root
+
+ def replycontent(self, method, body):
+ return body[0].children
+
+ def method(self, method):
+ """
+ Get the document root. For I{rpc/(literal|encoded)}, this is the
+ name of the method qualifed by the schema tns.
+ @param method: A service method.
+ @type method: I{service.Method}
+ @return: A root element.
+ @rtype: L{Element}
+ """
+ ns = method.soap.input.body.namespace
+ if ns[0] is None:
+ ns = ('ns0', ns[1])
+ method = Element(method.name, ns=ns)
+ return method
+
+
+class Encoded(RPC):
+ """
+ RPC/Encoded (section 5) binding style.
+ """
+
+ def marshaller(self):
+ return MxEncoded(self.schema())
+
+ def unmarshaller(self, typed=True):
+ """
+ Get the appropriate XML decoder.
+ @return: Either the (basic|typed) unmarshaller.
+ @rtype: L{UmxTyped}
+ """
+ if typed:
+ return UmxEncoded(self.schema())
+ else:
+ return RPC.unmarshaller(self, typed)
121 suds/builder.py
@@ -0,0 +1,121 @@
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the (LGPL) GNU Lesser General Public License as
+# published by the Free Software Foundation; either version 3 of the
+# License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Library Lesser General Public License for more details at
+# ( http://www.gnu.org/licenses/lgpl.html ).
+#
+# You should have received a copy of the GNU Lesser General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+# written by: Jeff Ortel ( jortel@redhat.com )
+
+"""
+The I{builder} module provides an wsdl/xsd defined types factory
+"""
+
+from logging import getLogger
+from suds import *
+from suds.sudsobject import Factory
+
+log = getLogger(__name__)
+
+
+class Builder:
+ """ Builder used to construct an object for types defined in the schema """
+
+ def __init__(self, resolver):
+ """
+ @param resolver: A schema object name resolver.
+ @type resolver: L{resolver.Resolver}
+ """
+ self.resolver = resolver
+
+ def build(self, name):
+ """ build a an object for the specified typename as defined in the schema """
+ if isinstance(name, basestring):
+ type = self.resolver.find(name)
+ if type is None:
+ raise TypeNotFound(name)
+ else:
+ type = name
+ cls = type.name
+ if type.mixed():
+ data = Factory.property(cls)
+ else:
+ data = Factory.object(cls)
+ resolved = type.resolve()
+ md = data.__metadata__
+ md.sxtype = resolved
+ md.ordering = self.ordering(resolved)
+ history = []
+ self.add_attributes(data, resolved)
+ for child, ancestry in type.children():
+ if self.skip_child(child, ancestry):
+ continue
+ self.process(data, child, history[:])
+ return data
+
+ def process(self, data, type, history):
+ """ process the specified type then process its children """
+ if type in history:
+ return
+ if type.enum():
+ return
+ history.append(type)
+ resolved = type.resolve()
+ value = None
+ if type.unbounded():
+ value = []
+ else:
+ if len(resolved) > 0:
+ if resolved.mixed():
+ value = Factory.property(resolved.name)
+ md = value.__metadata__
+ md.sxtype = resolved
+ else:
+ value = Factory.object(resolved.name)
+ md = value.__metadata__
+ md.sxtype = resolved
+ md.ordering = self.ordering(resolved)
+ setattr(data, type.name, value)
+ if value is not None:
+ data = value
+ if not isinstance(data, list):
+ self.add_attributes(data, resolved)
+ for child, ancestry in resolved.children():
+ if self.skip_child(child, ancestry):
+ continue
+ self.process(data, child, history[:])
+
+ def add_attributes(self, data, type):
+ """ add required attributes """
+ for attr, ancestry in type.attributes():
+ name = '_%s' % attr.name
+ value = attr.get_default()
+ setattr(data, name, value)
+
+ def skip_child(self, child, ancestry):
+ """ get whether or not to skip the specified child """
+ if child.any(): return True
+ for x in ancestry:
+ if x.choice():
+ return True
+ return False
+
+ def ordering(self, type):
+ """ get the ordering """
+ result = []
+ for child, ancestry in type.resolve():
+ name = child.name
+ if child.name is None:
+ continue
+ if child.isattr():
+ name = '_%s' % child.name
+ result.append(name)
+ return result
+
337 suds/cache.py
@@ -0,0 +1,337 @@
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the (LGPL) GNU Lesser General Public License as
+# published by the Free Software Foundation; either version 3 of the
+# License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Library Lesser General Public License for more details at
+# ( http://www.gnu.org/licenses/lgpl.html ).
+#
+# You should have received a copy of the GNU Lesser General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+# written by: Jeff Ortel ( jortel@redhat.com )
+
+"""
+Contains basic caching classes.
+"""
+
+import os
+import suds
+from tempfile import gettempdir as tmp
+from suds.transport import *
+from suds.sax.parser import Parser
+from suds.sax.element import Element
+from datetime import datetime as dt
+from datetime import timedelta
+from cStringIO import StringIO
+from logging import getLogger
+try:
+ import cPickle as pickle
+except:
+ import pickle
+
+log = getLogger(__name__)
+
+
+class Cache:
+ """
+ An object object cache.
+ """
+
+ def get(self, id):
+ """
+ Get a object from the cache by ID.
+ @param id: The object ID.
+ @type id: str
+ @return: The object, else None
+ @rtype: any
+ """
+ raise Exception('not-implemented')
+
+ def getf(self, id):
+ """
+ Get a object from the cache by ID.
+ @param id: The object ID.
+ @type id: str
+ @return: The object, else None
+ @rtype: any
+ """
+ raise Exception('not-implemented')
+
+ def put(self, id, object):
+ """
+ Put a object into the cache.
+ @param id: The object ID.
+ @type id: str
+ @param object: The object to add.
+ @type object: any
+ """
+ raise Exception('not-implemented')
+
+ def putf(self, id, fp):
+ """
+ Write a fp into the cache.
+ @param id: The object ID.
+ @type id: str
+ @param fp: File pointer.
+ @type fp: file-like object.
+ """
+ raise Exception('not-implemented')
+
+ def purge(self, id):
+ """
+ Purge a object from the cache by id.
+ @param id: A object ID.
+ @type id: str
+ """
+ raise Exception('not-implemented')
+
+ def clear(self):
+ """
+ Clear all objects from the cache.
+ """
+ raise Exception('not-implemented')
+
+
+class NoCache(Cache):
+ """
+ The passthru object cache.
+ """
+
+ def get(