Commits

Sergey A. Bozhenkov  committed 5f8ce2e

1. remove old methods.py. 2. Implement basic handling of restrictions without enumerations: simply create the base class of a restriction without any limitation, let the serve dance

  • Participants
  • Parent commits f29d9e2

Comments (0)

Files changed (4)

File osa/methods.py

-"""
-    Classes required for remote method calls: messages and method wrappers.
-"""
-import xmlnamespace
-from urllib2 import urlopen, Request, HTTPError
-import xml.etree.cElementTree as etree
-
-#some standard stuff
-SOAP_BODY = '{%s}Body' % xmlnamespace.NS_SOAP_ENV
-SOAP_FAULT = '{%s}Fault' % xmlnamespace.NS_SOAP_ENV
-SOAP_HEADER = '{%s}Header' % xmlnamespace.NS_SOAP_ENV
-
-class Message(object):
-    """
-        Message for input and output of service operations.
-
-        Messages perform conversion of Python to xml and backwards
-        of the calls and returns.
-
-        A message instance knows about used style/literal convention and can
-        use it to perform transformations. At the moment only
-        document/literal wrapped is implemented. You can improve this class
-        to have the others.
-
-        .. warning::
-            Only document/literal wrapped convention is implemented at the moment.
-
-        Parameters
-        ----------
-        tag : str
-            Name of the message.
-        namespafe : str
-            Namespace of the message.
-        parts : list
-            List of message parts in the form
-            (part name, part type class).
-            This description is usually found in message part of a WSDL document.
-        style : str
-            Operation style document/rpc.
-        literal : bool
-            True = literal, False = encoded.
-    """
-    def __init__(self, tag, namespace, parts, style, literal):
-        self.tag = tag
-        self.namespace = namespace
-        self.parts = parts
-        self.style = style
-        self.literal = literal
-
-
-    def __str__(self, switch = "wrap"):
-        """
-            String representation of the message in three forms:
-                - wrapped message
-                - positional sub-arguments
-                - keyword sub-arguments.
-                - out - the only child of wrapped message. This applicable
-                        to output message extraction.
-
-            Parameters
-            ----------
-            switch : str, optional
-                Specifies which form to return: wrap, positional, keyword, out.
-        """
-        if self.style != "document" or not(self.literal):
-            raise RuntimeError(
-                "Only document/literal are supported. Improve Message class!")
-        #assumed wrapped convention
-        p = self.parts[0][1] #message type
-        res = ''
-        if switch == "positional":
-            for child in p._children:
-                opt = ''
-                array = ''
-                if child['max']>1:
-                     # 'unbounded'>1
-                     array = '[]'
-                if child['min']==0:
-                    opt = '| None'
-                type = xmlnamespace.get_local_name(child['type'].__name__)
-                res = res + ', %s%s %s %s'\
-                        %(type, array, child["name"], opt)
-        elif switch == "keyword":
-            for child in p._children:
-                opt = ''
-                array = ''
-                if child['max']>1:
-                     # 'unbounded'>1
-                     array = '[]'
-                if child['min']==0:
-                    opt = '| None'
-                type = xmlnamespace.get_local_name(child['type'].__name__)
-                res = res + ', %s=%s%s %s'\
-                        %(child['name'], type, array, opt)
-        elif switch == 'out' and len(p._children) == 1:
-            child = p._children[0]
-            opt = ''
-            array = ''
-            if child['max']>1:
-                 # 'unbounded'>1
-                 array = '[]'
-            if child['min']==0:
-                opt = '| None'
-            type = xmlnamespace.get_local_name(child['type'].__name__)
-            res = '%s%s %s %s'  %(type, array, 'result', opt)
-        else:
-            res = '%s %s' %(p.__name__, 'msg')
-
-        if len(res)>2 and res[0] == ',':
-            res = res[2:]
-
-        return res
-
-    def to_xml(self, *arg, **kw):
-        """
-            Convert from Python into xml message.
-
-            This function accepts parameters as they are supplied
-            to the method call and tries to convert it to a message.
-            Arguments can be in one of  four forms:
-                - 1 argument of proper message type for this operation
-                - positional arguments - members of the proper message type
-                - keyword arguments - members of the message type.
-                - a mixture of positional and keyword arguments.
-
-            Keyword arguments must have at least one member: _body which
-            contains etree.Element to append the conversion result to.
-        """
-        if self.style != "document" or not(self.literal):
-            raise RuntimeError(
-                "Only document/literal are supported. Improve Message class!")
-
-        #assumed wrapped convention
-        p = self.parts[0][1]() #encoding instance
-
-        #wrapped message is supplied
-        if len(arg) == 1 and isinstance(arg[0], self.parts[0][1]):
-            for child in p._children:
-                setattr(p, child['name'], getattr(arg[0], child['name'], None))
-        else:
-            #reconstruct wrapper from expanded input
-            counter = 0
-            for child in p._children:
-                name = child["name"]
-                #first try keyword
-                val = kw.get(name, None)
-                if val is None: #not keyword
-                    if counter < len(arg):
-                        #assume this is positional argument
-                        val = arg[counter]
-                        counter = counter + 1
-                if val is None: #check if nillable
-                    if child["min"] == 0:
-                        continue
-                    else:
-                        raise ValueError(\
-                                "Non-nillable parameter %s is not present"\
-                                                                    %name)
-                setattr(p, name, val)
-
-        #the real conversion is done by ComplexType
-        p.to_xml(kw["_body"], "{%s}%s" %(self.namespace, self.tag))
-
-    def from_xml(self, body, header = None):
-        """
-            Convert from xml message to Python.
-        """
-        if self.style != "document" or not(self.literal):
-            raise RuntimeError(
-                "Only document/literal are supported. Improve Message class.")
-
-        #assumed wrapped convention
-        p = self.parts[0][1]() #decoding instance
-
-        res = p.from_xml(body)
-
-        #for wrapped doc style (the only one implemented) we know, that
-        #wrapper has only one child, get it
-        if len(p._children) == 1:
-            return getattr(res, p._children[0]["name"], None)
-        else:
-            return res
-
-class Method(object):
-    """
-        Definition of a single SOAP method, including location, action, name
-        and input and output classes.
-
-        Parameters
-        ----------
-        location : str
-            Location as found in service part of WSDL.
-        name : str
-            Name of operation
-        action : str
-            Action (?) as found in binding part of WSDL.
-        input : `osa.methods.Message` instance
-            Input message description.
-        output : `osa.methods.Message` instance
-            Output message description.
-        doc : str, optional - default to None
-            Documentation of the method as found in portType section of WSDL.
-    """
-    def __init__(self, location, name, action, input, output, doc=None):
-        self.location = location
-        self.name = name
-        self.action = action
-        self.input = input
-        self.output = output
-        #add call signatures to doc
-        sign = '%s\n%s\n%s' %(self.__str__(),
-                                            self.__str__(switch="positional"),
-                                            self.__str__(switch="keyword"))
-        self.__doc__ = '%s\n%s' %(sign, doc)
-
-    def __str__(self, switch = 'wrap'):
-        """
-            String representation of the call in three forms:
-                - wrapped message
-                - positional sub-arguments
-                - keyword sub-arguments.
-
-            Parameters
-            ----------
-            switch : str, optional
-                Specifies which form to return: wrap, positional, keyword.
-        """
-        input_msg = self.input.__str__(switch = switch)
-        if self.output is None:
-            output_msg = ""
-        else:
-            output_msg = self.output.__str__(switch = 'out')
-
-        return '%s = %s(%s)' %(output_msg, self.name, input_msg)
-
-
-    def __call__(self, *arg, **kw):
-        """
-            Process rpc-call.
-        """
-        #create soap-wrap around our message
-        env = etree.Element('{%s}Envelope' %NS_SOAP_ENV)
-        header = etree.SubElement(env, '{%s}Header' %NS_SOAP_ENV)
-        body = etree.SubElement(env, '{%s}Body' %NS_SOAP_ENV)
-
-        #compose call message - convert all parameters and encode the call
-        kw["_body"] = body
-        self.input.to_xml(*arg, **kw)
-
-        text_msg = etree.tostring(env) #message to send
-        del env
-
-        #http stuff
-        request = Request(self.location, text_msg,
-                                {'Content-Type': 'text/xml',
-                                'SOAPAction': self.action})
-        del text_msg
-
-        #real rpc
-        try:
-            response = urlopen(request).read()
-            del request
-            #string to xml
-            xml = etree.fromstring(response)
-            del response
-            #find soap body
-            body = xml.find(SOAP_BODY)
-            if body is None:
-                raise RuntimeError("No SOAP body found in response")
-            body = body[0] # hacky? get the first real element
-        except HTTPError, e:
-            if e.code in (202,204):
-                return None
-            elif e.code == 500:
-                #read http error body and make xml from it
-                try:
-                    xml = etree.fromstring(e.fp.read())
-                except Exception:
-                    print(e)
-                    return None
-                body = xml.find(SOAP_BODY)
-                if body is None:
-                    raise
-                #process service fault
-                fault = body.find(SOAP_FAULT)
-                if fault is not None:
-                    code = fault.find('faultcode')
-                    if code is not None:
-                        code = code.text or ''
-                    string = fault.find('faultstring')
-                    if string is not None:
-                        string = string.text or ''
-                    detail = fault.find('detail')
-                    if detail is not None:
-                        detail = detail.text or ''
-                    raise RuntimeError("SOAP Fault %s:%s <%s> %s%s"\
-                            %(self.location, self.name, code, string, detail))
-                else:
-                    raise
-            else:
-                raise
-
-        return self.output.from_xml(body)
-
 import xmltypes
 import message
 import method
-import methods
 import xml.etree.cElementTree as etree
 
 class WSDLParser(object):

File osa/xmlparser.py

 import xml.etree.cElementTree as etree
 import urllib2
 
-default_attr = ["type", "base", "element", "message", "binding"]
+default_attr = ["type", "base", "element", "message", "binding", "ref"]
 
 def parse_qualified(f, attr = None):
     """

File osa/xmlschema.py

         #find and initialize imported ones
         self.imported = [] 
         imports = self.schema.findall('.//{%s}import' %xmlnamespace.NS_XSD)
+        imports.extend(self.schema.findall('.//{%s}include' %xmlnamespace.NS_XSD))
         for schema in imports:
             loc = schema.get("schemaLocation", None)
             #basically says that types from that namespace will be used, no real
         elif element.tag == "{%s}simpleType" %xmlnamespace.NS_XSD and\
                 element[0].tag == "{%s}restriction" %xmlnamespace.NS_XSD \
                 and element[0].get("base", None) == "{%s}string" %xmlnamespace.NS_XSD \
+                and len(element[0])>0 \
                 and element[0][0].tag == "{%s}enumeration" %xmlnamespace.NS_XSD:
             XMLSchemaParser.create_string_enumeration(name, element, types)
+        elif element.tag == "{%s}simpleType" %xmlnamespace.NS_XSD and\
+                element[0].tag == "{%s}restriction" %xmlnamespace.NS_XSD \
+                and element[0].get("base", None) is not None:
+            base_type = element[0].get("base")
+            XMLSchemaParser.create_alias(name, base_type,
+                                         xtypes, types)
 
     @staticmethod
     def get_doc(x):
         if seq is not None:
             for s in seq:
                 #iterate over sequence, do not consider in place defs
-                type_name = s.get('type', None)
+                ref = s.get("ref", None) #reference to another element
+                if ref is not None:
+                    type_name = ref
+                    child_name = xmlnamespace.get_local_name(ref)
+                else:
+                    type_name = s.get('type', None)
+                    child_name = s.get('name', 'unknown')
+
                 if type_name is None:
-                    continue
-                elif xmltypes.primmap.has_key(type_name):
+                    compl = s.find("./{%s}complexType" %(xmlnamespace.NS_XSD))
+                    simpl = s.find("./{%s}simpleType" %(xmlnamespace.NS_XSD))
+                    if compl is not None:
+                        XMLSchemaParser.create_type(child_name, compl, xtypes, types)
+                        type_name = child_name
+                    elif simpl is not None:
+                        XMLSchemaParser.create_type(child_name, simpl, xtypes, types)
+                        type_name = child_name
+                    else:
+                        continue
+
+                if xmltypes.primmap.has_key(type_name):
                     type = xmltypes.primmap[type_name]
                 elif types.has_key(type_name):
                     type = types[type_name]
                     XMLSchemaParser.create_type(type_name,
                                     xtypes[type_name], xtypes, types)
                     type = types[type_name]
-                child_name = s.get('name', 'unknown')
                 minOccurs = int(s.get('minOccurs', 1))
                 maxOccurs = s.get('maxOccurs', 1)
                 if maxOccurs != 'unbounded':