Sergey A. Bozhenkov  committed ef82678

1. small clean ups. 2. fix docs

  • Participants
  • Parent commits 42d9299
  • Branches default
  • Tags v0.1.5

Comments (0)

Files changed (9)

+.. automodule:: osa.xmlschema
+   :show-inheritance:
+   :members:
 .. _methods:
 Methods wrapper
-.. automodule:: osa.methods
+.. automodule:: osa.message
+   :show-inheritance:
+   :members:
+.. automodule:: osa.method
 # General information about the project.
 project = u'osa'
-copyright = u'2011, Sergey Bozhenkov'
+copyright = u'2013, Sergey Bozhenkov'
 # The version info for the project you're documenting, acts as replacement for
 # |version| and |release|, also used in various other places throughout the
 # built documents.
 # The short X.Y version.
-version = '0.1'
+version = '0.1.5'
 # The full version, including alpha/beta/rc tags.
-release = '0.1'
+release = '0.1.5'
 # The language for content autogenerated by Sphinx. Refer to documentation
 # for a list of supported languages.

File doc/index.rst

 At the moment the library is limited to wrapped document/literal `SOAP 1.1`_
 convention. To include other call conventions one has to extend the
 :py:func:`to_xml` and :py:func:`from_xml` methods of the :py:class:`Message`
-:ref:`class <methods>`. The structure of the library is briefly explained
+:ref:`class <message>`. The structure of the library is briefly explained
 :ref:`here <Structure>`. The *XML* processing is performed with the
 help of :py:mod:`cElementTree` module.

File doc/overview.rst

 class used to consume a service by a normal user. The client
 is initialized by full address of a `WSDL 1.1`_ document::
-    >>> cl = osa.Client("http://lxpowerboz:88/services/python/HelloWorldService?wsdl")
+    >>> cl = osa.Client("http://.../HelloWorldService?wsdl")
-Convenience print functions are available at levels, e.g. to find information
+Convenience print functions are available at several levels, e.g. to find information
 about the client one can enter::
     >>> cl
 which returns names of all found services in the `WSDL 1.1`_ document and
 location of the service::
-    HelloWorldService at:
-        http://lxpowerboz:88/services/python/HelloWorldService?wsdl
+    service HelloWorldService from:
+        http://.../HelloWorldService?wsdl
 The top level client is a container for class definitions constructed from
 *XML* types in the supplied `WSDL 1.1`_ focument and for remote method
 which lists all known types and help if available::
-        None
+        no documentation
-        None
+        no documentation
         str[] result | None = sayHello(sayHello msg)
         str[] result | None = sayHello(Person person , int time...
-    giveMessage
-        str result  = giveMessage(giveMessage msg)
-        str result  = giveMessage()
-        str result  = giveMessage()
-        N...
-    faultyThing
-        str result  = faultyThing(faultyThing msg)
-        str result  = faultyThing()
-        str result  = faultyThing()
-        ...
         str result  = echoString(echoString msg)
         str result  = echoString(str msg )
         str result  = echoString...
+        ...
 It is worth noting once more that if any documentation is available in
 the initial `WSDL 1.1`_ document it is propagated to types and methods.
 The top level :ref:`Client <client>` class is simply a container.
 On construction it creates an instance of :ref:`WSDLParser <wsdl>`
 and processes the service description by calling its
-methods :py:func:`get_types` and :py:func:`get_methods`. Afterwards
-the parser is deleted. As a result of initial processing
+methods :py:func:`parse`. Afterwards
+the parser is deleted. As a result of the initial processing
 two dictionaries are available: containing newly created types
 and methods.
-Types and methods are generated by the parser.
+Types and methods are generated by the :ref:`WSDLParser <wsdl>`, for types
+it internally uses :ref:`XMLSchemaParser <wsdl>`.
 The types are constructed by using meta-class :ref:`ComplexTypeMeta <types>`.
 This meta-class has a special convention to pass children names and types.
 The methods are wrapped as instances of :ref:`Method <methods>` class.
 to add the brackets *()*. The attributes of
 the :py:data:`service` container are callable method wrappers.
-To allow correct :py:data:`anyType` processing the
-:ref:`Client <client>` constructor also passes known types
-to :ref:`XMLAny <types>` class definition. To be more precise, a new
-:ref:`XMLAny <types>` class is generated with set types. This is
-done to prevent cross-talks between different services initialized
-at the same time.
+To allow a correct :py:data:`anyType` processing the
+:ref:`WSDLParser <wsdl>` updates special dictionary of
+:ref:`XMLAny <types>` class by all discovered classes.
 Every function call is processed by :py:func:`__call__` method
 of a :ref:`Method <methods>` instance. The call method uses
 *XML* string (:py:func:`to_xml`). Afterwards *urllib2* is used to send the
 request to service. The service response is deserialized by
 using the output message :py:attr:`output` (:py:func:`from_xml`).
-The desirialized result is returned to the user.
+The deserialized result is returned to the user.
 The input points for serialization is a :ref:`Message <methods>`
 instance. The message first analyzes the input arguments and
 propagate the call to their children and so on. The process
 is continued until the bottom of the hierarchy is reached.
 Only the primitive :ref:`types` set the real text tag.
-The desirialization process is similar: in this case
+The deserialization process is similar: in this case
 :py:func:`from_xml` is propagated and all children
 classes are constructed. In addition the output message
 parser expands the response wrapper, so that the user sees

File osa.pdf

Binary file modified.

File osa/

 import xmlnamespace
-import xmltypes
 import wsdl
 def str_for_containers(self):

File osa/

 import xmlnamespace
 import xmlparser
-import message
 from urllib2 import urlopen, Request, HTTPError
 import xml.etree.cElementTree as etree

File osa/

             XMLSchemaParser.create_alias(name, base_type, xtypes, types)
+    def get_type_by_name(name, xtypes, types):
+        """
+            Return requested class from primmap or as created from xml.
+            Parameters
+            ----------
+            name : str
+                Type name.
+            xtypes : dict
+                List of xml elements to look in.
+            types : dict
+                List of already created classes to look in.
+            Returns
+            -------
+            out : class
+        """
+        if name is None:
+            return
+        elif xmltypes.primmap.has_key(name):
+            cl = xmltypes.primmap[name]
+        elif types.has_key(name):
+            cl = types[name]
+        elif not(xtypes.has_key(name)):
+            raise ValueError(" Class %s not found in anywhere" %(name))
+        else:
+            XMLSchemaParser.create_type(name,
+                            xtypes[name], xtypes, types)
+            cl = types[name]
+        return cl
+    @staticmethod
     def get_doc(x):
             Extract documentation from element.
             types : dictionary of classes
                 The new aliases is appended here.
-        alias = None
-        if alias_type is None:
+        alias = XMLSchemaParser.get_type_by_name(alias_type, xtypes, types)
+        if alias is None:
-        elif xmltypes.primmap.has_key(alias_type):
-            alias = xmltypes.primmap[alias_type]
-        elif types.has_key(alias_type):
-            alias = types[alias_type]
-        elif not(xtypes.has_key(alias_type)):
-            raise ValueError(" Alias class %s not found in schema" %(alias_type))
-        else:
-            XMLSchemaParser.create_type(alias_type,
-                            xtypes[alias_type], xtypes, types)
-            alias = types[alias_type]
         cls_name = xmlnamespace.get_local_name(name)
         cls_ns = xmlnamespace.get_ns(name)
         #create new type since the namespace may be different
         if exts is not None:
             for ext in exts:
                 parent_name = ext.get("base", None) 
-                if parent_name is None:
-                    continue
-                elif types.has_key(parent_name):
-                    parent = types[parent_name]
-                elif not(xtypes.has_key(parent_name)):
-                    raise ValueError(" Parent class not found in schema for:\n %s" %(etree.tostring(element)))
-                else:
-                    XMLSchemaParser.create_type(parent_name,
-                                    xtypes[parent_name], xtypes, types)
-                    parent = types[parent_name]
+                parent = XMLSchemaParser.get_type_by_name(parent_name, xtypes, types)
         #find sequence/choice/all
                         type_name = child_name
-                if xmltypes.primmap.has_key(type_name):
-                    type = xmltypes.primmap[type_name]
-                elif types.has_key(type_name):
-                    type = types[type_name]
-                elif not(xtypes.has_key(type_name)):
-                    raise ValueError("Type %s not found for:\n %s" %(type_name,etree.tostring(element)))
-                else:
-                    XMLSchemaParser.create_type(type_name,
-                                    xtypes[type_name], xtypes, types)
-                    type = types[type_name]
+                type = XMLSchemaParser.get_type_by_name(type_name, xtypes, types)
                 minOccurs = int(s.get('minOccurs', 1))
                 maxOccurs = s.get('maxOccurs', 1)
                 if maxOccurs != 'unbounded':
                     maxOccurs = int(maxOccurs)
-                children.append({ "name":child_name,
-                                 'type' : type,
-                                 'min' : minOccurs,
-                                 'max' : maxOccurs})
+                children.append({ "name":child_name, 'type' : type,
+                                 'min' : minOccurs, 'max' : maxOccurs})
         #get doc
         doc = XMLSchemaParser.get_doc(element)

File osa/

                 If constraints are not satisfied.
         if n<min_occurs:
-            raise ValueError("Number of values is less than min_occurs")
+            raise ValueError("Number of values n=%d is less than min_occurs=%d"\
+                                        %(n, min_occurs))
         if n > max_occurs:
-            raise ValueError("Number of values is more than max_occurs")
+            raise ValueError("Number of values n=%d is more than max_occurs n=%s"\
+                                        %(n, str(max_occurs)))
     def to_xml(self, parent, name):
             full_name = ns + child_name #name with namespace
             for single in val:
-                try:
-                    single.to_xml(element, full_name)
-                    if child["type"] is XMLAny:
-                        #append type information
-                        element[-1].set("{%s}type" %xmlnamespace.NS_XSI, 
-                                "{%s}%s" %(single._namespace,
-                                           single.__class__.__name__) )
-                except Exception:
+                if not(hasattr(single, "to_xml")):
                     single = child['type'](single)
-                    single.to_xml(element, full_name)
-                #if not(isinstance(single, child['type'])):
-                    ##useful for primitive types:  python int, e.g.,
-                    ##can be passed directly. If str is used instead
-                    ##an exception is fired up.
+                single.to_xml(element, full_name)
+                if child["type"] is XMLAny:
+                    #append type information
+                    element[-1].set("{%s}type" %xmlnamespace.NS_XSI, 
+                            "{%s}%s" %(single._namespace,
+                                       single.__class__.__name__) )
+                #try:
+                    #single.to_xml(element, full_name)
+                    #if child["type"] is XMLAny:
+                        ##append type information
+                        #element[-1].set("{%s}type" %xmlnamespace.NS_XSI, 
+                                #"{%s}%s" %(single._namespace,
+                                           #single.__class__.__name__) )
+                #except Exception:
                     #single = child['type'](single)
-                #single.to_xml(element, full_name)
+                    #single.to_xml(element, full_name)
     def from_xml(self, element):
         for subel in element:
-            name = xmlnamespace.get_local_name(subel.tag)
+            #name = xmlnamespace.get_local_name(subel.tag)
+            name = subel.tag
+            name = name[name.find("}")+1:]
             ind = all_children_names.index(name)
             #used for conversion. for primitive types we receive back built-ins