Example #1
0
class TypeWriter(SchemaItemWriter):
    """contains/generates a single definition"""
    logger = _GetLogger("TypeWriter")

    def fromSchemaItem(self, item):
        if item.isDefinition() is False or item.isLocal() is True:
            raise TypeError, \
                'expecting global type definition not: %s' %item.getItemTrace()

        self.content = None
        if item.isSimple():
            if item.content.isRestriction():
                self.content = RestrictionContainer()
            elif item.content.isUnion():
                self.content = UnionContainer()
            elif item.content.isList():
                self.content = ListContainer()
            else:
                raise Wsdl2PythonError,\
                    'unknown simple type definition: %s' %item.getItemTrace()

            self.content.setUp(item)
            return

        if item.isComplex():
            kw = {}
            if item.content is None or item.content.isModelGroup():
                self.content = \
                    ComplexTypeContainer(\
                        do_extended=self.do_extended,
                        extPyClasses=self.extPyClasses
                        )
                kw['empty'] = item.content is None
            elif item.content.isSimple():
                self.content = ComplexTypeSimpleContentContainer()
            elif item.content.isComplex():
                self.content = \
                    ComplexTypeComplexContentContainer(\
                        do_extended=self.do_extended
                        )
            else:
                raise Wsdl2PythonError,\
                    'unknown complex type definition: %s' %item.getItemTrace()

            self.logger.debug(
                'TypeWriter setUp container "%r", Schema Item "%s"' %
                (self.content, item.getItemTrace()))

            try:
                self.content.setUp(item, **kw)
            except Exception, ex:
                args = ['Failure in setUp: %s' % item.getItemTrace()]
                args += ex.args
                ex.args = tuple(args)
                raise

            return

        raise TypeError,\
            'expecting SimpleType or ComplexType: %s' %item.getItemTrace()
Example #2
0
class SchemaDescription:
    """generates classes for defs and decs in the schema instance.
    """
    logger = _GetLogger("SchemaDescription")

    def __init__(self, do_extended=False, extPyClasses=None):
        self.classHead = NamespaceClassHeaderContainer()
        self.classFoot = NamespaceClassFooterContainer()
        self.items = []
        self.__types = []
        self.__elements = []
        self.targetNamespace = None
        self.do_extended = do_extended
        self.extPyClasses = extPyClasses

    def fromSchema(self, schema):
        ''' Can be called multiple times, but will not redefine a
        previously defined type definition or element declaration.
        '''
        ns = schema.getTargetNamespace()
        assert self.targetNamespace is None or self.targetNamespace == ns,\
            'SchemaDescription instance represents %s, not %s'\
            %(self.targetNamespace, ns)

        if self.targetNamespace is None:
            self.targetNamespace = ns

        self.classHead.ns = self.classFoot.ns = ns
        for item in [
                t for t in schema.types
                if t.getAttributeName() not in self.__types
        ]:
            self.__types.append(item.getAttributeName())
            self.items.append(
                TypeWriter(do_extended=self.do_extended,
                           extPyClasses=self.extPyClasses))
            self.items[-1].fromSchemaItem(item)

        for item in [
                e for e in schema.elements
                if e.getAttributeName() not in self.__elements
        ]:
            self.__elements.append(item.getAttributeName())
            self.items.append(ElementWriter(do_extended=self.do_extended))
            self.items[-1].fromSchemaItem(item)

    def getTypes(self):
        return self.__types

    def getElements(self):
        return self.__elements

    def write(self, fd):
        """write out to file descriptor.
        """
        print >> fd, self.classHead
        for t in self.items:
            print >> fd, t
        print >> fd, self.classFoot
Example #3
0
class Struct(ComplexType):
    '''Struct is a complex type for accessors identified by name. 
       Constraint: No element may have the same name as any other,
       nor may any element have a maxOccurs > 1.
       
      <xs:group name="Struct" >
        <xs:sequence>
          <xs:any namespace="##any" minOccurs="0" maxOccurs="unbounded" processContents="lax" />
        </xs:sequence>
      </xs:group>

      <xs:complexType name="Struct" >
        <xs:group ref="tns:Struct" minOccurs="0" />
        <xs:attributeGroup ref="tns:commonAttributes"/>
      </xs:complexType> 
    '''
    logger = _GetLogger('ZSI.TCcompound.Struct')

    def __init__(self,
                 pyclass,
                 ofwhat,
                 pname=None,
                 inorder=False,
                 inline=False,
                 mutable=True,
                 **kw):
        '''pyclass -- the Python class to hold the fields
        ofwhat -- a list of fields to be in the struct
        inorder -- fields must be in exact order or not
        inline -- don't href/id when serializing
        mutable -- object could change between multiple serializations
        '''
        ComplexType.__init__(self,
                             pyclass,
                             ofwhat,
                             pname=pname,
                             inorder=inorder,
                             inline=inline,
                             mutable=mutable,
                             **kw)

        # Check Constraints
        whats = [(what.nspname, what.pname) for what in self.ofwhat]
        for idx in range(len(self.ofwhat)):
            what = self.ofwhat[idx]
            key = (what.nspname, what.pname)
            if not isinstance(what, AnyElement) and what.maxOccurs > 1:
                raise TypeError(
                    'Constraint: no element can have a maxOccurs>1')
            if key in whats[idx + 1:]:
                raise TypeError(
                    'Constraint: No element may have the same name as any other'
                )
Example #4
0
class NamedParamBinding(Binding):
    '''Like Binding, except the argument list for invocation is
    named parameters.
    '''
    logger = _GetLogger('ZSI.client.Binding')

    def __getattr__(self, name):
        '''Return a callable object that will invoke the RPC method
        named by the attribute.
        '''
        if name[:2] == '__' and len(name) > 5 and name[-2:] == '__':
            if hasattr(self, name): return getattr(self, name)
            return getattr(self.__class__, name)
        return _NamedParamCaller(self, name, self.namespace)
Example #5
0
class AttachmentRef(SimpleType):
    '''Type code for Attachment. This attachment will work only with axis...
    '''

    logger = _GetLogger('ZSI.TC.Attachment')
    type = (Apache.NS, "DataHandler")
    parselist = [(Apache.NS, "DataHandler")]

    #seriallist = [ types.FileType ]

    def __init__(self, pname=None, format='%s', **kw):
        TypeCode.__init__(self, pname, **kw)
        self.format = format

    def parse(self, elt, ps):
        #never invoked ???
        #print "elt is: " + str(elt)
        #print "while ps: " + str(ps)
        return

    def get_formatted_content(self, pyobj):
        return self.format % pyobj

    def serialize(self, elt, sw, pyobj, name=None, orig=None, **kw):
        '''This function is in charge of serializing the attachment
           fist it add the <attachment href=""/> tag
           then it wraps up everything

           pyobj is the file descriptor pointing to the file we wanna attach
           elt is the ElementProxy containing the <inputFile> tag with the attachment tag
           sw SoapWriter
        '''
        #print "serialize called with pyobj: "  + str(pyobj)
        #adding the attachment tag
        if pyobj is None:
            return
        if not sw.Known(pyobj):
            sw.addAttachment(pyobj)
            idhref = id(pyobj)
            attachmentElement = elt.createAppendElement(None,
                                                        "attachment",
                                                        prefix="")
            attachmentElement.setAttributeNS(None, "href",
                                             "cid:" + str(idhref))
        else:
            #print "the file " + pyobj + " was already attached"
            #do nothing
            #this should not happen
            pass
Example #6
0
class SchemaItemWriter:
    """contains/generates a single declaration"""
    logger = _GetLogger("SchemaItemWriter")

    def __init__(self, do_extended=False, extPyClasses=None):
        self.content = None
        self.do_extended=do_extended
        self.extPyClasses=extPyClasses

    def __str__(self):
        '''this appears to set up whatever is in self.content.localElements,
        local elements simpleType|complexType.
        '''
        assert self.content is not None, 'Must call fromSchemaItem to setup.'
        return str(self.content)

    def fromSchemaItem(self, item):
        raise NotImplementedError('')
Example #7
0
class ElementWriter(SchemaItemWriter):
    """contains/generates a single declaration"""
    logger = _GetLogger("ElementWriter")

    def fromSchemaItem(self, item):
        """set up global elements.
        """
        if item.isElement() is False or item.isLocal() is True:
            raise TypeError, 'expecting global element declaration: %s' % item.getItemTrace(
            )

        local = False
        qName = item.getAttribute('type')
        if not qName:
            etp = item.content
            local = True
        else:
            etp = item.getTypeDefinition('type')

        if etp is None:
            if local is True:
                self.content = ElementLocalComplexTypeContainer(
                    do_extended=self.do_extended)
            else:
                self.content = ElementSimpleTypeContainer()
        elif etp.isLocal() is False:
            self.content = ElementGlobalDefContainer()
        elif etp.isSimple() is True:
            self.content = ElementLocalSimpleTypeContainer()
        elif etp.isComplex():
            self.content = ElementLocalComplexTypeContainer(
                do_extended=self.do_extended)
        else:
            raise Wsdl2PythonError, "Unknown element declaration: %s" % item.getItemTrace(
            )

        self.logger.debug(
            'ElementWriter setUp container "%r", Schema Item "%s"' %
            (self.content, item.getItemTrace()))

        self.content.setUp(item)
Example #8
0
class MessageWriter:
    logger = _GetLogger("MessageWriter")

    def __init__(self, do_extended=False):
        """Representation of a WSDL Message and associated WSDL Binding.
        operation --
        boperation --
        input --
        rpc --
        literal --
        simple --
        """
        self.content = None
        self.do_extended = do_extended

    def __str__(self):
        if not self.content:
            raise Wsdl2PythonError('Must call setUp.')
        return self.content.getvalue()

    def setUp(self, soc, port, input=False):
        assert isinstance(soc, ServiceOperationContainer),\
            'expecting a ServiceOperationContainer instance'
        assert isinstance(port, WSDLTools.Port),\
            'expecting a WSDL.Port instance'

        rpc,literal = soc.isRPC(), soc.isLiteral(input)
        kw,klass = {}, None

        if rpc and literal:
            klass = ServiceRPCLiteralMessageContainer
        elif not rpc and literal:
            kw['do_extended'] = self.do_extended
            klass = ServiceDocumentLiteralMessageContainer
        elif rpc and not literal:
            klass = ServiceRPCEncodedMessageContainer
        else:
            raise WsdlGeneratorError('doc/enc not supported.')

        self.content = klass(**kw)
        self.content.setUp(port, soc, input)
class ComplexType(TypeCode):
    '''Represents an element of complexType, potentially containing other 
    elements.
    '''
    logger = _GetLogger('ZSI.TCcompound.ComplexType')
    
    def __init__(self, pyclass, ofwhat, pname=None, inorder=False, inline=False,
    mutable=True, mixed=False, mixed_aname='_text', **kw):
        '''pyclass -- the Python class to hold the fields
        ofwhat -- a list of fields to be in the complexType
        inorder -- fields must be in exact order or not
        inline -- don't href/id when serializing
        mutable -- object could change between multiple serializations
        type -- the (URI,localname) of the datatype
        mixed -- mixed content model? True/False
        mixed_aname -- if mixed is True, specify text content here. Default _text
        '''
        TypeCode.__init__(self, pname, pyclass=pyclass, **kw)
        self.inorder = inorder
        self.inline = inline
        self.mutable = mutable
        self.mixed = mixed
        self.mixed_aname = None
        if mixed is True:
            self.mixed_aname = mixed_aname

        if self.mutable is True: self.inline = True
        self.type = kw.get('type') or _get_xsitype(self)
        t = type(ofwhat)
        if t not in _seqtypes:
            raise TypeError(
                'Struct ofwhat must be list or sequence, not ' + str(t))
        self.ofwhat = tuple(ofwhat)
        if TypeCode.typechecks:
            # XXX Not sure how to determine if new-style class..
            if self.pyclass is not None and \
                type(self.pyclass) is not types.ClassType and not isinstance(self.pyclass, object):
                raise TypeError('pyclass must be None or an old-style/new-style class, not ' +
                        str(type(self.pyclass)))
            _check_typecode_list(self.ofwhat, 'ComplexType')

    def parse(self, elt, ps):
        debug = self.logger.debugOn()
        debug and self.logger.debug('parse')
        
        xtype = self.checkname(elt, ps)
        if self.type and xtype not in [ self.type, (None,None) ]:
            if not isinstance(self, TypeDefinition):
                raise EvaluateException(\
                    'ComplexType for %s has wrong type(%s), looking for %s' %
                        (self.pname, self.checktype(elt,ps), self.type), 
                                        ps.Backtrace(elt))
            else:
                #TODO: mabye change MRO to handle this 
                debug and self.logger.debug('delegate to substitute type')
                what = TypeDefinition.getSubstituteType(self, elt, ps)
                return what.parse(elt, ps)
            
        href = _find_href(elt)
        if href:
            if _children(elt):
                raise EvaluateException('Struct has content and HREF',
                        ps.Backtrace(elt))
            elt = ps.FindLocalHREF(href, elt)
        c = _child_elements(elt)
        count = len(c)
        if self.nilled(elt, ps): return Nilled

        # Create the object.
        v = {}

        # parse all attributes contained in attribute_typecode_dict (user-defined attributes),
        # the values (if not None) will be keyed in self.attributes dictionary.
        attributes = self.parse_attributes(elt, ps)
        if attributes:
            v[self.attrs_aname] = attributes

        #MIXED
        if self.mixed is True:
            v[self.mixed_aname] = self.simple_value(elt,ps, mixed=True)

        # Clone list of kids (we null it out as we process)
        c, crange = c[:], range(len(c))
        # Loop over all items we're expecting
        
        if debug:
            self.logger.debug("ofwhat: %s",str(self.ofwhat))
            
        any = None
        for i,what in [ (i, self.ofwhat[i]) for i in range(len(self.ofwhat)) ]:
            
            # retrieve typecode if it is hidden
            if callable(what): what = what()
            
            # Loop over all available kids
            if debug: 
                self.logger.debug("what: (%s,%s)", what.nspname, what.pname)
                
            for j,c_elt in [ (j, c[j]) for j in crange if c[j] ]:
                if debug:
                    self.logger.debug("child node: (%s,%s)", c_elt.namespaceURI, 
                                      c_elt.tagName)
                if what.name_match(c_elt):
                    # Parse value, and mark this one done. 
                    try:
                        value = what.parse(c_elt, ps)
                    except EvaluateException, e:
                        #what = _get_substitute_element(c_elt, what)
                        #value = what.parse(c_elt, ps)
                        raise
                    if what.maxOccurs > 1:
                        if v.has_key(what.aname):
                            v[what.aname].append(value)
                        else:
                            v[what.aname] = [value]
                        c[j] = None
                        continue
                    else:
                        v[what.aname] = value
                    c[j] = None
                    break
                else:
                    if debug:
                        self.logger.debug("no element (%s,%s)",
                                          what.nspname, what.pname)

                # No match; if it was supposed to be here, that's an error.
                if self.inorder is True and i == j:
                    raise EvaluateException('Out of order complexType',
                            ps.Backtrace(c_elt))
            else:
                # only supporting 1 <any> declaration in content.
                if isinstance(what,AnyElement):
                    any = what
                elif hasattr(what, 'default'):
                    v[what.aname] = what.default
                elif what.minOccurs > 0 and not v.has_key(what.aname):
                    raise EvaluateException('Element "' + what.aname + \
                        '" missing from complexType', ps.Backtrace(elt))

        # Look for wildcards and unprocessed children
        # XXX Stick all this stuff in "any", hope for no collisions
        if any is not None:
            occurs = 0
            v[any.aname] = []
            for j,c_elt in [ (j, c[j]) for j in crange if c[j] ]:
                value = any.parse(c_elt, ps)
                if any.maxOccurs == UNBOUNDED or any.maxOccurs > 1:
                    v[any.aname].append(value)
                else:
                    v[any.aname] = value

                occurs += 1

            # No such thing as nillable <any>
            if any.maxOccurs == 1 and occurs == 0:
                v[any.aname] = None
            elif occurs < any.minOccurs or (any.maxOccurs!=UNBOUNDED and any.maxOccurs<occurs):
                raise EvaluateException('occurances of <any> elements(#%d) bound by (%d,%s)' %(
                    occurs, any.minOccurs,str(any.maxOccurs)), ps.Backtrace(elt))

        if not self.pyclass: 
            return v

        # type definition must be informed of element tag (nspname,pname),
        # element declaration is initialized with a tag.
        try:
            pyobj = self.pyclass()
        except Exception, e:
            raise TypeError("Constructing element (%s,%s) with pyclass(%s), %s" \
                %(self.nspname, self.pname, self.pyclass.__name__, str(e)))
class Array(TypeCode):
    '''An array.
        atype -- arrayType, (namespace,ncname) 
        mutable -- object could change between multiple serializations
        undeclared -- do not serialize/parse arrayType attribute.
    '''
    logger = _GetLogger('ZSI.TCcompound.Array')
    
    def __init__(self, atype, ofwhat, pname=None, dimensions=1, fill=None,
    sparse=False, mutable=False, size=None, nooffset=0, undeclared=False,
    childnames=None, **kw):
        TypeCode.__init__(self, pname, **kw)
        self.dimensions = dimensions
        self.atype = atype
        if undeclared is False and self.atype[1].endswith(']') is False:
            self.atype = (self.atype[0], '%s[]' %self.atype[1])
        # Support multiple dimensions
        if self.dimensions != 1:
            raise TypeError("Only single-dimensioned arrays supported")
        self.fill = fill
        self.sparse = sparse
        #if self.sparse: ofwhat.minOccurs = 0
        self.mutable = mutable
        self.size = size
        self.nooffset = nooffset
        self.undeclared = undeclared
        self.childnames = childnames
        if self.size:
            t = type(self.size)
            if t in _inttypes:
                self.size = (self.size,)
            elif t in _seqtypes:
                self.size = tuple(self.size)
            elif TypeCode.typechecks:
                raise TypeError('Size must be integer or list, not ' + str(t))

        if TypeCode.typechecks:
            if self.undeclared is False and type(atype) not in _seqtypes and len(atype) == 2:
                raise TypeError("Array type must be a sequence of len 2.")
            t = type(ofwhat)
            if not isinstance(ofwhat, TypeCode):
                raise TypeError(
                    'Array ofwhat outside the TypeCode hierarchy, ' +
                    str(ofwhat.__class__))
            if self.size:
                if len(self.size) != self.dimensions:
                    raise TypeError('Array dimension/size mismatch')
                for s in self.size:
                    if type(s) not in _inttypes:
                        raise TypeError('Array size "' + str(s) +
                                '" is not an integer.')
        self.ofwhat = ofwhat

    def parse_offset(self, elt, ps):
        o = _find_arrayoffset(elt)
        if not o: return 0
        if not _offset_pat.match(o):
            raise EvaluateException('Bad offset "' + o + '"',
                        ps.Backtrace(elt))
        return int(o[1:-1])

    def parse_position(self, elt, ps):
        o = _find_arrayposition(elt)
        if not o: return None
        if o.find(',') > -1:
            raise EvaluateException('Sorry, no multi-dimensional arrays',
                    ps.Backtrace(elt))
        if not _position_pat.match(o):
            raise EvaluateException('Bad array position "' + o + '"',
                    ps.Backtrace(elt))
        return int(o[1:-1])

    def parse(self, elt, ps):
        href = _find_href(elt)
        if href:
            if _children(elt):
                raise EvaluateException('Array has content and HREF',
                        ps.Backtrace(elt))
            elt = ps.FindLocalHREF(href, elt)
        if self.nilled(elt, ps): return Nilled
        if not _find_arraytype(elt) and self.undeclared is False:
            raise EvaluateException('Array expected', ps.Backtrace(elt))
        t = _find_type(elt)
        if t:
            pass # XXX should check the type, but parsing that is hairy.
        offset = self.parse_offset(elt, ps)
        v, vlen = [], 0
        if offset and not self.sparse:
            while vlen < offset:
                vlen += 1
                v.append(self.fill)
        for c in _child_elements(elt):
            item = self.ofwhat.parse(c, ps)
            position = self.parse_position(c, ps) or offset
            if self.sparse:
                v.append((position, item))
            else:
                while offset < position:
                    offset += 1
                    v.append(self.fill)
                v.append(item)
            offset += 1
        return v

    def serialize(self, elt, sw, pyobj, name=None, childnames=None, **kw):
        debug = self.logger.debugOn()
        if debug:
            self.logger.debug("serialize: %r" %pyobj)
        
        if self.mutable is False and sw.Known(pyobj): return
        objid = _get_idstr(pyobj)
        ns,n = self.get_name(name, objid)
        el = elt.createAppendElement(ns, n)

        # nillable
        if self.nillable is True and pyobj is None:
            self.serialize_as_nil(el)
            return None

        # other attributes
        self.set_attributes(el, pyobj)

        # soap href attribute
        unique = self.unique or kw.get('unique', False)
        if unique is False and sw.Known(pyobj):
            self.set_attribute_href(el, objid)
            return None

        # xsi:type attribute 
        if kw.get('typed', self.typed) is True:
            self.set_attribute_xsi_type(el, **kw)

        # soap id attribute
        if self.unique is False:
            self.set_attribute_id(el, objid)

        offset = 0
        if self.sparse is False and self.nooffset is False:
            offset, end = 0, len(pyobj)
            while offset < end and pyobj[offset] == self.fill:
                offset += 1
            if offset: 
                el.setAttributeNS(SOAP.ENC, 'offset', '[%d]' %offset)

        if self.undeclared is False:
            el.setAttributeNS(SOAP.ENC, 'arrayType', 
                '%s:%s' %(el.getPrefix(self.atype[0]), self.atype[1])
            )

        if debug:
            self.logger.debug("ofwhat: %r" %self.ofwhat)

        d = {}
        kn = childnames or self.childnames
        if kn:
            d['name'] = kn
        elif not self.ofwhat.aname:
            d['name'] = 'element'
            
        if self.sparse is False:
            for e in pyobj[offset:]: self.ofwhat.serialize(el, sw, e, **d)
        else:
            position = 0
            for pos, v in pyobj:
                if pos != position:
                    el.setAttributeNS(SOAP.ENC, 'position', '[%d]' %pos)
                    position = pos

                self.ofwhat.serialize(el, sw, v, **d)
                position += 1
Example #11
0
class ComplexType(TypeCode):
    '''Represents an element of complexType, potentially containing other 
    elements.
    '''
    logger = _GetLogger('ZSI.TCcompound.ComplexType')

    class _DictHolder:
        pass

    def __init__(self,
                 pyclass,
                 ofwhat,
                 pname=None,
                 inorder=False,
                 inline=False,
                 mutable=True,
                 mixed=False,
                 mixed_aname='_text',
                 **kw):
        '''pyclass -- the Python class to hold the fields
        ofwhat -- a list of fields to be in the complexType
        inorder -- fields must be in exact order or not
        inline -- don't href/id when serializing
        mutable -- object could change between multiple serializations
        type -- the (URI,localname) of the datatype
        mixed -- mixed content model? True/False
        mixed_aname -- if mixed is True, specify text content here. Default _text
        '''
        TypeCode.__init__(self, pname, pyclass=pyclass, **kw)
        self.inorder = inorder
        self.inline = inline
        self.mutable = mutable
        self.mixed = mixed
        self.mixed_aname = None
        if mixed is True:
            self.mixed_aname = mixed_aname

        if self.mutable is True: self.inline = True
        self.type = kw.get('type') or _get_xsitype(self)
        t = type(ofwhat)
        if t not in _seqtypes:
            raise TypeError('Struct ofwhat must be list or sequence, not ' +
                            str(t))
        self.ofwhat = tuple(ofwhat)
        if TypeCode.typechecks:
            # XXX Not sure how to determine if new-style class..
            if self.pyclass is not None and \
                type(self.pyclass) is not types.ClassType and not isinstance(self.pyclass, object):
                raise TypeError(
                    'pyclass must be None or an old-style/new-style class, not '
                    + str(type(self.pyclass)))
            _check_typecode_list(self.ofwhat, 'ComplexType')

    def parse(self, elt, ps):
        debug = self.logger.debugOn()
        debug and self.logger.debug('parse')

        xtype = self.checkname(elt, ps)
        if self.type and xtype not in [self.type, (None, None)]:
            if not isinstance(self, TypeDefinition):
                raise EvaluateException(\
                    'ComplexType for %s has wrong type(%s), looking for %s' %
                        (self.pname, self.checktype(elt,ps), self.type),
                                        ps.Backtrace(elt))
            else:
                #TODO: mabye change MRO to handle this
                debug and self.logger.debug('delegate to substitute type')
                what = TypeDefinition.getSubstituteType(self, elt, ps)
                return what.parse(elt, ps)

        href = _find_href(elt)
        if href:
            if _children(elt):
                raise EvaluateException('Struct has content and HREF',
                                        ps.Backtrace(elt))
            elt = ps.FindLocalHREF(href, elt)
        c = _child_elements(elt)
        count = len(c)
        if self.nilled(elt, ps): return Nilled

        # Create the object.
        if self.pyclass:
            # type definition must be informed of element tag (nspname,pname),
            # element declaration is initialized with a tag.
            try:
                pyobj = self.pyclass()
            except Exception, e:
                raise TypeError("Constructing element (%s,%s) with pyclass(%s), %s" \
                    %(self.nspname, self.pname, self.pyclass.__name__, str(e)))
        else:
Example #12
0
class WriteServiceModule:
    """top level driver class invoked by wsd2py
    class variables:
        client_module_suffix -- suffix of client module.
        types_module_suffix -- suffix of types module.
    """
    client_module_suffix = '_client'
    messages_module_suffix = '_messages'
    types_module_suffix = '_types'
    logger = _GetLogger("WriteServiceModule")

    def __init__(self, wsdl, addressing=False, notification=False,
                 do_extended=False, extPyClasses=None, configParser = None):
        self._wsdl = wsdl
        self._addressing = addressing
        self._notification = notification
        self._configParser = configParser
        self.usedNamespaces = None
        self.services = []
        self.client_module_path = None
        self.types_module_name = None
        self.types_module_path = None
        self.messages_module_path = None # used in extended generation
        self.do_extended = do_extended
        self.extPyClasses = extPyClasses

    def getClientModuleName(self):
        """client module name.
        """
        name = GetModuleBaseNameFromWSDL(self._wsdl)
        if not name:
            raise WsdlGeneratorError('could not determine a service name')

        if self.client_module_suffix is None:
            return name

        return '%s%s' %(name, self.client_module_suffix)

#    def getMessagesModuleName(self):
#        name = GetModuleBaseNameFromWSDL(self._wsdl)
#        if not name:
#            raise WsdlGeneratorError, 'could not determine a service name'
#
#        if self.messages_module_suffix is None:
#            return name
#
#        if len(self.messages_module_suffix) == 0:
#            return self.getClientModuleName()
#
#        return '%s%s' %(name, self.messages_module_suffix)

    def setTypesModuleName(self, name):
        self.types_module_name = name

    def getTypesModuleName(self):
        """types module name.
        """
        if self.types_module_name is not None:
            return self.types_module_name

        name = GetModuleBaseNameFromWSDL(self._wsdl)
        if not name:
            raise WsdlGeneratorError('could not determine a service name')

        if self.types_module_suffix is None:
            return name

        return '%s%s' %(name, self.types_module_suffix)

    def setClientModulePath(self, path):
        """setup module path to where client module before calling fromWsdl.
        module path to types module eg. MyApp.client
        """
        self.client_module_path = path

    def getTypesModulePath(self):
        """module path to types module eg. MyApp.types
        """
        return self.types_module_path

#    def getMessagesModulePath(self):
#        '''module path to messages module
#           same as types path
#        '''
#        return self.messages_module_path

    def setTypesModulePath(self, path):
        """setup module path to where service module before calling fromWsdl.
        module path to types module eg. MyApp.types
        """
        self.types_module_path = path

#    def setMessagesModulePath(self, path):
#        """setup module path to where message module before calling fromWsdl.
#        module path to types module eg. MyApp.types
#        """
#        self.messages_module_path = path

    def gatherNamespaces(self):
        '''This method must execute once..  Grab all schemas
        representing each targetNamespace.
        '''
        if self.usedNamespaces is not None:
            return

        self.logger.debug('gatherNamespaces')
        self.usedNamespaces = {}

        # Add all schemas defined in wsdl
        # to used namespace and to the Alias dict
        for schema in self._wsdl.types.values():
            tns = schema.getTargetNamespace()
            self.logger.debug('Register schema(%s) -- TNS(%s)'\
                %(_get_idstr(schema), tns),)
            if not tns in self.usedNamespaces:
                self.usedNamespaces[tns] = []
            self.usedNamespaces[tns].append(schema)
            NAD.add(tns)

        # Add all xsd:import schema instances
        # to used namespace and to the Alias dict
        for k,v in SchemaReader.namespaceToSchema.items():
            self.logger.debug('Register schema(%s) -- TNS(%s)'\
                %(_get_idstr(v), k),)
            if k not in self.usedNamespaces:
                self.usedNamespaces[k] = []
            self.usedNamespaces[k].append(v)
            NAD.add(k)

    def writeClient(self, fd, sdClass=None, **kw):
        """write out client module to file descriptor.
        Parameters and Keywords arguments:
            fd -- file descriptor
            sdClass -- service description class name
            imports -- list of imports
            readerclass -- class name of ParsedSoap reader
            writerclass -- class name of SoapWriter writer
        """
        sdClass = sdClass or ServiceDescription
        assert issubclass(sdClass, ServiceDescription), \
            'parameter sdClass must subclass ServiceDescription'

#        header = '%s \n# %s.py \n# generated by %s\n%s\n'\
#                  %('#'*50, self.getClientModuleName(), self.__module__, '#'*50)
        print('#'*50, file=fd)
        print('# file: %s.py' %self.getClientModuleName(), file=fd)
        print('# ', file=fd)
        print('# client stubs generated by "%s"' %self.__class__, file=fd)
        print('#     %s' %' '.join(sys.argv), file=fd)
        print('# ', file=fd)
        print('#'*50, file=fd)

        self.services = []
        for service in self._wsdl.services:
            sd = sdClass(self._addressing, do_extended=self.do_extended,
                         wsdl=self._wsdl)
            if len(self._wsdl.types) > 0:
                sd.setTypesModuleName(self.getTypesModuleName(),
                                      self.getTypesModulePath())
#                sd.setMessagesModuleName(self.getMessagesModuleName(),
#                                         self.getMessagesModulePath())

            self.gatherNamespaces()
            sd.fromWsdl(service, **kw)
            sd.write(fd)
            self.services.append(sd)

    def writeTypes(self, fd):
        """write out types module to file descriptor.
        """
        print('#'*50, file=fd)
        print('# file: %s.py' %self.getTypesModuleName(), file=fd)
        print('#', file=fd)
        print('# schema types generated by "%s"' %self.__class__, file=fd)
        print('#    %s' %' '.join(sys.argv), file=fd)
        print('#', file=fd)
        print('#'*50, file=fd)

        print(TypesHeaderContainer(), file=fd)
        self.gatherNamespaces()
        for l in list(self.usedNamespaces.values()):
            sd = SchemaDescription(do_extended=self.do_extended,
                                   extPyClasses=self.extPyClasses)
            for schema in l:
                sd.fromSchema(schema)
            sd.write(fd)
Example #13
0
class ComplexType(TypeCode):
    '''Represents an element of complexType, potentially containing other 
    elements.
    '''
    logger = _GetLogger('ZSI.TCcompound.ComplexType')

    def __init__(self,
                 pyclass,
                 ofwhat,
                 pname=None,
                 inorder=False,
                 inline=False,
                 mutable=True,
                 mixed=False,
                 mixed_aname='_text',
                 **kw):
        '''pyclass -- the Python class to hold the fields
        ofwhat -- a list of fields to be in the complexType
        inorder -- fields must be in exact order or not
        inline -- don't href/id when serializing
        mutable -- object could change between multiple serializations
        type -- the (URI,localname) of the datatype
        mixed -- mixed content model? True/False
        mixed_aname -- if mixed is True, specify text content here. Default _text
        '''
        TypeCode.__init__(self, pname, pyclass=pyclass, **kw)
        self.inorder = inorder
        self.inline = inline
        self.mutable = mutable
        self.mixed = mixed
        self.mixed_aname = None
        if mixed is True:
            self.mixed_aname = mixed_aname

        if self.mutable is True: self.inline = True
        self.type = kw.get('type') or _get_xsitype(self)
        t = type(ofwhat)
        if t not in _seqtypes:
            raise TypeError('Struct ofwhat must be list or sequence, not ' +
                            str(t))
        self.ofwhat = tuple(ofwhat)
        if TypeCode.typechecks:
            # XXX Not sure how to determine if new-style class..
            if self.pyclass is not None and \
                type(self.pyclass) is not type and not isinstance(self.pyclass, object):
                raise TypeError(
                    'pyclass must be None or an old-style/new-style class, not '
                    + str(type(self.pyclass)))
            _check_typecode_list(self.ofwhat, 'ComplexType')

    def parse(self, elt, ps):
        debug = self.logger.debugOn()
        debug and self.logger.debug('parse')

        xtype = self.checkname(elt, ps)
        if self.type and xtype not in [self.type, (None, None)]:
            if not isinstance(self, TypeDefinition):
                raise EvaluateException(\
                    'ComplexType for %s has wrong type(%s), looking for %s' %
                        (self.pname, self.checktype(elt,ps), self.type),
                                        ps.Backtrace(elt))
            else:
                #TODO: mabye change MRO to handle this
                debug and self.logger.debug('delegate to substitute type')
                what = TypeDefinition.getSubstituteType(self, elt, ps)
                return what.parse(elt, ps)

        href = _find_href(elt)
        if href:
            if _children(elt):
                raise EvaluateException('Struct has content and HREF',
                                        ps.Backtrace(elt))
            elt = ps.FindLocalHREF(href, elt)
        c = _child_elements(elt)
        count = len(c)
        if self.nilled(elt, ps): return Nilled

        # Create the object.
        v = {}

        # parse all attributes contained in attribute_typecode_dict (user-defined attributes),
        # the values (if not None) will be keyed in self.attributes dictionary.
        attributes = self.parse_attributes(elt, ps)
        if attributes:
            v[self.attrs_aname] = attributes

        #MIXED
        if self.mixed is True:
            v[self.mixed_aname] = self.simple_value(elt, ps, mixed=True)

        # Clone list of kids (we null it out as we process)
        c, crange = c[:], list(range(len(c)))
        # Loop over all items we're expecting

        if debug:
            self.logger.debug("ofwhat: %s", str(self.ofwhat))

        any = None
        for i, what in [(i, self.ofwhat[i]) for i in range(len(self.ofwhat))]:

            # retrieve typecode if it is hidden
            if isinstance(what, collections.Callable): what = what()

            # Loop over all available kids
            if debug:
                self.logger.debug("what: (%s,%s)", what.nspname, what.pname)

            for j, c_elt in [(j, c[j]) for j in crange if c[j]]:
                if debug:
                    self.logger.debug("child node: (%s,%s)",
                                      c_elt.namespaceURI, c_elt.tagName)
                if what.name_match(c_elt):
                    # Parse value, and mark this one done.
                    try:
                        value = what.parse(c_elt, ps)
                    except EvaluateException as e:
                        #what = _get_substitute_element(c_elt, what)
                        #value = what.parse(c_elt, ps)
                        raise
                    if what.maxOccurs > 1:
                        if what.aname in v:
                            v[what.aname].append(value)
                        else:
                            v[what.aname] = [value]
                        c[j] = None
                        continue
                    else:
                        v[what.aname] = value
                    c[j] = None
                    break
                else:
                    if debug:
                        self.logger.debug("no element (%s,%s)", what.nspname,
                                          what.pname)

                # No match; if it was supposed to be here, that's an error.
                if self.inorder is True and i == j:
                    raise EvaluateException('Out of order complexType',
                                            ps.Backtrace(c_elt))
            else:
                # only supporting 1 <any> declaration in content.
                if isinstance(what, AnyElement):
                    any = what
                elif hasattr(what, 'default'):
                    v[what.aname] = what.default
                elif what.minOccurs > 0 and what.aname not in v:
                    raise EvaluateException('Element "' + what.aname + \
                        '" missing from complexType', ps.Backtrace(elt))

        # Look for wildcards and unprocessed children
        # XXX Stick all this stuff in "any", hope for no collisions
        if any is not None:
            occurs = 0
            v[any.aname] = []
            for j, c_elt in [(j, c[j]) for j in crange if c[j]]:
                value = any.parse(c_elt, ps)
                if any.maxOccurs == UNBOUNDED or any.maxOccurs > 1:
                    v[any.aname].append(value)
                else:
                    v[any.aname] = value

                occurs += 1

            # No such thing as nillable <any>
            if any.maxOccurs == 1 and occurs == 0:
                v[any.aname] = None
            elif occurs < any.minOccurs or (any.maxOccurs != UNBOUNDED
                                            and any.maxOccurs < occurs):
                raise EvaluateException(
                    'occurances of <any> elements(#%d) bound by (%d,%s)' %
                    (occurs, any.minOccurs, str(any.maxOccurs)),
                    ps.Backtrace(elt))

        if not self.pyclass:
            return v

        # type definition must be informed of element tag (nspname,pname),
        # element declaration is initialized with a tag.
        try:
            pyobj = self.pyclass()
        except Exception as e:
            raise TypeError("Constructing element (%s,%s) with pyclass(%s), %s" \
                %(self.nspname, self.pname, self.pyclass.__name__, str(e)))
        for key in list(v.keys()):
            setattr(pyobj, key, v[key])
        return pyobj

    def serialize(self, elt, sw, pyobj, inline=False, name=None, **kw):
        if inline or self.inline:
            self.cb(elt, sw, pyobj, name=name, **kw)
        else:
            objid = _get_idstr(pyobj)
            ns, n = self.get_name(name, objid)
            el = elt.createAppendElement(ns, n)
            el.setAttributeNS(None, 'href', "#%s" % objid)
            sw.AddCallback(self.cb, elt, sw, pyobj)

    def cb(self, elt, sw, pyobj, name=None, **kw):
        debug = self.logger.debugOn()
        if debug:
            self.logger.debug("cb: %s" % str(self.ofwhat))

        objid = _get_idstr(pyobj)
        ns, n = self.get_name(name, objid)
        if pyobj is None:
            if self.nillable is True:
                elem = elt.createAppendElement(ns, n)
                self.serialize_as_nil(elem)
                return
            raise EvaluateException('element(%s,%s) is not nillable(%s)' %
                                    (self.nspname, self.pname, self.nillable))

        if self.mutable is False and sw.Known(pyobj):
            return

        if debug:
            self.logger.debug("element: (%s, %s)", str(ns), n)

        if n is not None:
            elem = elt.createAppendElement(ns, n)
            self.set_attributes(elem, pyobj)
            if kw.get('typed', self.typed) is True:
                self.set_attribute_xsi_type(elem)

            #MIXED For now just stick it in front.
            if self.mixed is True and self.mixed_aname is not None:
                if hasattr(pyobj, self.mixed_aname):
                    textContent = getattr(pyobj, self.mixed_aname)
                    if hasattr(textContent, 'typecode'):
                        textContent.typecode.serialize_text_node(
                            elem, sw, textContent)
                    elif type(textContent) in _stringtypes:
                        if debug:
                            self.logger.debug("mixed text content:\n\t%s",
                                              textContent)
                        elem.createAppendTextNode(textContent)
                    else:
                        raise EvaluateException(
                            'mixed test content in element (%s,%s) must be a string type'
                            % (self.nspname, self.pname), sw.Backtrace(elt))
                else:
                    if debug:
                        self.logger.debug("mixed NO text content in %s",
                                          self.mixed_aname)
        else:
            #For information items w/o tagNames
            #  ie. model groups,SOAP-ENC:Header
            elem = elt

        if self.inline:
            pass
        elif not self.inline and self.unique:
            raise EvaluateException(
                'Not inline, but unique makes no sense. No href/id.',
                sw.Backtrace(elt))
        elif n is not None:
            self.set_attribute_id(elem, objid)

        if self.pyclass and type(self.pyclass) is type:
            f = lambda attr: getattr(pyobj, attr, None)
        elif self.pyclass:
            d = pyobj.__dict__
            f = lambda attr: d.get(attr)
        else:
            d = pyobj
            f = lambda attr: pyobj.get(attr)
            if TypeCode.typechecks and type(d) != dict:
                raise TypeError("Classless struct didn't get dictionary")

        indx, lenofwhat = 0, len(self.ofwhat)
        if debug:
            self.logger.debug('element declaration (%s,%s)', self.nspname,
                              self.pname)
            if self.type:
                self.logger.debug('xsi:type definition (%s,%s)', self.type[0],
                                  self.type[1])
            else:
                self.logger.warning('NO xsi:type')

        while indx < lenofwhat:
            occurs = 0
            what = self.ofwhat[indx]

            # retrieve typecode if hidden
            if isinstance(what, collections.Callable): what = what()

            if debug:
                self.logger.debug('serialize what -- %s',
                                  what.__class__.__name__)

            # No way to order <any> instances, so just grab any unmatched
            # anames and serialize them.  Only support one <any> in all content.
            # Must be self-describing instances

            # Regular handling of declared elements
            aname = what.aname
            v = f(aname)
            indx += 1
            if what.minOccurs == 0 and v is None:
                continue

            # Default to typecode, if self-describing instance, and check
            # to make sure it is derived from what.
            whatTC = what
            if whatTC.maxOccurs > 1 and v is not None:
                if type(v) not in _seqtypes:
                    raise EvaluateException(
                        'pyobj (%s,%s), aname "%s": maxOccurs %s, expecting a %s'
                        % (self.nspname, self.pname, what.aname,
                           whatTC.maxOccurs, _seqtypes), sw.Backtrace(elt))

                for v2 in v:
                    occurs += 1
                    if occurs > whatTC.maxOccurs:
                        raise EvaluateException(
                            'occurances (%d) exceeded maxOccurs(%d) for <%s>' %
                            (occurs, whatTC.maxOccurs, what.pname),
                            sw.Backtrace(elt))

                    what = _get_type_or_substitute(whatTC, v2, sw, elt)
                    if debug and what is not whatTC:
                        self.logger.debug('substitute derived type: %s' %
                                          what.__class__)

                    what.serialize(elem, sw, v2, **kw)


#                    try:
#                        what.serialize(elem, sw, v2, **kw)
#                    except Exception, e:
#                        raise EvaluateException('Serializing %s.%s, %s %s' %
#                            (n, whatTC.aname or '?', e.__class__.__name__, str(e)))

                if occurs < whatTC.minOccurs:
                    raise EvaluateException(\
                        'occurances(%d) less than minOccurs(%d) for <%s>' %
                        (occurs, whatTC.minOccurs, what.pname), sw.Backtrace(elt))

                continue

            if v is not None or what.nillable is True:
                what = _get_type_or_substitute(whatTC, v, sw, elt)
                if debug and what is not whatTC:
                    self.logger.debug('substitute derived type: %s' %
                                      what.__class__)
                what.serialize(elem, sw, v, **kw)
                #                try:
                #                    what.serialize(elem, sw, v, **kw)
                #                except (ParseException, EvaluateException), e:
                #                    raise
                #                except Exception, e:
                #                    raise EvaluateException('Serializing %s.%s, %s %s' %
                #                        (n, whatTC.aname or '?', e.__class__.__name__, str(e)),
                #                        sw.Backtrace(elt))
                continue

            raise EvaluateException(
                'Got None for nillable(%s), minOccurs(%d) element (%s,%s), %s'
                % (what.nillable, what.minOccurs, what.nspname, what.pname,
                   elem), sw.Backtrace(elt))

    def setDerivedTypeContents(self, extensions=None, restrictions=None):
        """For derived types set appropriate parameter and 
        """
        if extensions:
            ofwhat = list(self.ofwhat)
            if type(extensions) in _seqtypes:
                ofwhat += list(extensions)
            else:
                ofwhat.append(extensions)
        elif restrictions:
            if type(restrictions) in _seqtypes:
                ofwhat = restrictions
            else:
                ofwhat = (restrictions, )
        else:
            return
        self.ofwhat = tuple(ofwhat)
        self.lenofwhat = len(self.ofwhat)
Example #14
0
class ServiceDescription:
    """client interface - locator, port, etc classes"""
    separate_messages = False
    logger = _GetLogger("ServiceDescription")

    def __init__(self, addressing=False, do_extended=False, wsdl=None):
        self.typesModuleName = None
        self.messagesModuleName = None
        self.wsAddressing = addressing
        self.imports   = ServiceHeaderContainer()
        self.messagesImports   = ServiceHeaderContainer()
        self.locator   = ServiceLocatorContainer()
        self.bindings   = []
        self.messages  = []
        self.do_extended=do_extended
        self._wsdl = wsdl # None unless do_extended == True

    def setTypesModuleName(self, name, modulePath=None):
        """The types module to be imported.
        Parameters
        name -- name of types module
        modulePath -- optional path where module is located.
        """
        self.typesModuleName = '%s' %name
        if modulePath is not None:
            self.typesModuleName = '%s.%s' %(modulePath,name)

#    def setMessagesModuleName(self, name, modulePath=None):
#        '''The types module to be imported.
#        Parameters
#        name -- name of types module
#        modulePath -- optional path where module is located.
#        '''
#        self.messagesModuleName = '%s' %name
#        if modulePath is not None:
#            self.messagesModuleName = '%s.%s' %(modulePath,name)

    def fromWsdl(self, service, **kw):
        self.imports.setTypesModuleName(self.typesModuleName)
#        if self.separate_messages:
#            self.messagesImports.setMessagesModuleName(self.messagesModuleName)
        self.imports.appendImport(kw.get('imports', []))

        self.locator.setUp(service)

        try:
            bindings =  [p.binding for p in service.ports]
        except:
            warnings.warn('not all ports have binding declared,')
            bindings = ()

        for port in service.ports:
            if port.binding not in bindings:
                continue
            while port.binding in bindings:
                bindings.remove(port.binding)

            desc = BindingDescription(useWSA=self.wsAddressing,
                                      do_extended=self.do_extended,
                                      wsdl=self._wsdl)
            try:
                desc.setUp(port.getBinding())
            except Wsdl2PythonError as ex:
                self.logger.warning('Skipping port(%s)' %port.name)
                if len(ex.args):
                    self.logger.warning(ex.args[0])
                continue

            desc.setReaderClass(kw.get('readerclass'))
            desc.setWriterClass(kw.get('writerclass'))
            for soc in desc.operations:
                if soc.hasInput() is True:
                    mw = MessageWriter(do_extended=self.do_extended)
                    mw.setUp(soc, port, input=True)
                    self.messages.append(mw)

                    if soc.hasOutput() is True:
                        mw = MessageWriter(do_extended=self.do_extended)
                        mw.setUp(soc, port, input=False)
                        self.messages.append(mw)

            self.bindings.append(desc)


    def write(self, fd, msg_fd=None):
        """write out module to file descriptor.
        fd -- file descriptor to write out service description.
        msg_fd -- optional file descriptor for messages module.
        """
#        if msg_fd != None:
#            print >>fd, self.messagesImports
#            print >>msg_fd, self.imports
#        else:
        print(self.imports, file=fd)

        print(self.locator, file=fd)
        for m in self.bindings:
            print(m, file=fd)

#        if msg_fd != None:
#            for m in self.messages:
#                print >>msg_fd, m
#        else:
        for m in self.messages:
            print(m, file=fd)
Example #15
0
class _Binding:
    '''Object that represents a binding (connection) to a SOAP server.
    Once the binding is created, various ways of sending and
    receiving SOAP messages are available.
    '''
    defaultHttpTransport = httplib.HTTPConnection
    defaultHttpsTransport = httplib.HTTPSConnection
    logger = _GetLogger('ZSI.client.Binding')

    def __init__(self,
                 nsdict=None,
                 transport=None,
                 url=None,
                 tracefile=None,
                 readerclass=None,
                 writerclass=None,
                 soapaction='',
                 wsAddressURI=None,
                 sig_handler=None,
                 transdict=None,
                 **kw):
        '''Initialize.
        Keyword arguments include:
            transport -- default use HTTPConnection. 
            transdict -- dict of values to pass to transport.
            url -- URL of resource, POST is path 
            soapaction -- value of SOAPAction header
            auth -- (type, name, password) triplet; default is unauth
            nsdict -- namespace entries to add
            tracefile -- file to dump packet traces
            cert_file, key_file -- SSL data (q.v.)
            readerclass -- DOM reader class
            writerclass -- DOM writer class, implements MessageInterface
            wsAddressURI -- namespaceURI of WS-Address to use.  By default 
            it's not used.
            sig_handler -- XML Signature handler, must sign and verify.
            endPointReference -- optional Endpoint Reference.
        '''
        self.data = None
        self.ps = None
        self.user_headers = []
        self.nsdict = nsdict or {}
        self.transport = transport
        self.transdict = transdict or {}
        self.url = url
        self.trace = tracefile
        self.readerclass = readerclass
        self.writerclass = writerclass
        self.soapaction = soapaction
        self.wsAddressURI = wsAddressURI
        self.sig_handler = sig_handler
        self.address = None
        self.endPointReference = kw.get('endPointReference', None)
        self.cookies = Cookie.SimpleCookie()
        self.http_callbacks = {}

        if kw.has_key('auth'):
            self.SetAuth(*kw['auth'])
        else:
            self.SetAuth(AUTH.none)

    def SetAuth(self, style, user=None, password=None):
        '''Change auth style, return object to user.
        '''
        self.auth_style, self.auth_user, self.auth_pass = \
            style, user, password
        return self

    def SetURL(self, url):
        '''Set the URL we post to.
        '''
        self.url = url
        return self

    def ResetHeaders(self):
        '''Empty the list of additional headers.
        '''
        self.user_headers = []
        return self

    def ResetCookies(self):
        '''Empty the list of cookies.
        '''
        self.cookies = Cookie.SimpleCookie()

    def AddHeader(self, header, value):
        '''Add a header to send.
        '''
        self.user_headers.append((header, value))
        return self

    def __addcookies(self):
        '''Add cookies from self.cookies to request in self.h
        '''
        for cname, morsel in self.cookies.items():
            attrs = []
            value = morsel.get('version', '')
            if value != '' and value != '0':
                attrs.append('$Version=%s' % value)
            attrs.append('%s=%s' % (cname, morsel.coded_value))
            value = morsel.get('path')
            if value:
                attrs.append('$Path=%s' % value)
            value = morsel.get('domain')
            if value:
                attrs.append('$Domain=%s' % value)
            self.h.putheader('Cookie', "; ".join(attrs))

    def RPC(self, url, opname, obj, replytype=None, **kw):
        '''Send a request, return the reply.  See Send() and Recieve()
        docstrings for details.
        '''
        self.Send(url, opname, obj, **kw)
        return self.Receive(replytype, **kw)

    def Send(self,
             url,
             opname,
             obj,
             nsdict={},
             soapaction=None,
             wsaction=None,
             endPointReference=None,
             soapheaders=(),
             **kw):
        '''Send a message.  If url is None, use the value from the
        constructor (else error). obj is the object (data) to send.
        Data may be described with a requesttypecode keyword, the default 
        is the class's typecode (if there is one), else Any.

        Try to serialize as a Struct, if this is not possible serialize an Array.  If 
        data is a sequence of built-in python data types, it will be serialized as an
        Array, unless requesttypecode is specified.

        arguments:
            url -- 
            opname -- struct wrapper
            obj -- python instance

        key word arguments:
            nsdict -- 
            soapaction --
            wsaction -- WS-Address Action, goes in SOAP Header.
            endPointReference --  set by calling party, must be an 
                EndPointReference type instance.
            soapheaders -- list of pyobj, typically w/typecode attribute.
                serialized in the SOAP:Header.
            requesttypecode -- 

        '''
        url = url or self.url
        endPointReference = endPointReference or self.endPointReference

        # Serialize the object.
        d = {}
        d.update(self.nsdict)
        d.update(nsdict)

        sw = SoapWriter(
            nsdict=d,
            header=True,
            outputclass=self.writerclass,
            encodingStyle=kw.get('encodingStyle'),
        )

        requesttypecode = kw.get('requesttypecode')
        if kw.has_key('_args'):  #NamedParamBinding
            tc = requesttypecode or TC.Any(pname=opname, aslist=False)
            sw.serialize(kw['_args'], tc)
        elif not requesttypecode:
            tc = getattr(obj, 'typecode', None) or TC.Any(pname=opname,
                                                          aslist=False)
            try:
                if type(obj) in _seqtypes:
                    obj = dict(map(lambda i: (i.typecode.pname, i), obj))
            except AttributeError:
                # can't do anything but serialize this in a SOAP:Array
                tc = TC.Any(pname=opname, aslist=True)
            else:
                tc = TC.Any(pname=opname, aslist=False)

            sw.serialize(obj, tc)
        else:
            sw.serialize(obj, requesttypecode)

        for i in soapheaders:
            sw.serialize_header(i)

        #
        # Determine the SOAP auth element.  SOAP:Header element
        if self.auth_style & AUTH.zsibasic:
            sw.serialize_header(_AuthHeader(self.auth_user, self.auth_pass),
                                _AuthHeader.typecode)

        #
        # Serialize WS-Address
        if self.wsAddressURI is not None:
            if self.soapaction and wsaction.strip('\'"') != self.soapaction:
                raise WSActionException, 'soapAction(%s) and WS-Action(%s) must match'\
                    %(self.soapaction,wsaction)

            self.address = Address(url, self.wsAddressURI)
            self.address.setRequest(endPointReference, wsaction)
            self.address.serialize(sw)

        #
        # WS-Security Signature Handler
        if self.sig_handler is not None:
            self.sig_handler.sign(sw)

        scheme, netloc, path, nil, nil, nil = urlparse.urlparse(url)
        transport = self.transport
        if transport is None and url is not None:
            if scheme == 'https':
                transport = self.defaultHttpsTransport
            elif scheme == 'http':
                transport = self.defaultHttpTransport
            else:
                raise RuntimeError, 'must specify transport or url startswith https/http'

        # Send the request.
        if issubclass(transport, httplib.HTTPConnection) is False:
            raise TypeError, 'transport must be a HTTPConnection'

        soapdata = str(sw)
        self.h = transport(netloc, None, **self.transdict)
        self.h.connect()
        self.SendSOAPData(soapdata, url, soapaction, **kw)

    def SendSOAPData(self, soapdata, url, soapaction, headers={}, **kw):
        # Tracing?
        if self.trace:
            print >> self.trace, "_" * 33, time.ctime(time.time()), "REQUEST:"
            print >> self.trace, soapdata

        url = url or self.url
        request_uri = _get_postvalue_from_absoluteURI(url)
        self.h.putrequest("POST", request_uri)
        self.h.putheader("Content-Length", "%d" % len(soapdata))
        self.h.putheader("Content-Type",
                         'text/xml; charset="%s"' % UNICODE_ENCODING)
        self.__addcookies()

        for header, value in headers.items():
            self.h.putheader(header, value)

        SOAPActionValue = '"%s"' % (soapaction or self.soapaction)
        self.h.putheader("SOAPAction", SOAPActionValue)
        if self.auth_style & AUTH.httpbasic:
            val = _b64_encode(self.auth_user + ':' + self.auth_pass) \
                        .replace("\012", "")
            self.h.putheader('Authorization', 'Basic ' + val)
        elif self.auth_style == AUTH.httpdigest and not headers.has_key('Authorization') \
            and not headers.has_key('Expect'):

            def digest_auth_cb(response):
                self.SendSOAPDataHTTPDigestAuth(response, soapdata, url,
                                                request_uri, soapaction, **kw)
                self.http_callbacks[401] = None

            self.http_callbacks[401] = digest_auth_cb

        for header, value in self.user_headers:
            self.h.putheader(header, value)
        self.h.endheaders()
        self.h.send(soapdata)

        # Clear prior receive state.
        self.data, self.ps = None, None

    def SendSOAPDataHTTPDigestAuth(self, response, soapdata, url, request_uri,
                                   soapaction, **kw):
        '''Resend the initial request w/http digest authorization headers.
        The SOAP server has requested authorization.  Fetch the challenge, 
        generate the authdict for building a response.
        '''
        if self.trace:
            print >> self.trace, "------ Digest Auth Header"
        url = url or self.url
        if response.status != 401:
            raise RuntimeError, 'Expecting HTTP 401 response.'
        if self.auth_style != AUTH.httpdigest:
            raise RuntimeError,\
                'Auth style(%d) does not support requested digest authorization.' %self.auth_style

        from ZSI.digest_auth import fetch_challenge,\
            generate_response,\
            build_authorization_arg,\
            dict_fetch

        chaldict = fetch_challenge(response.getheader('www-authenticate'))
        if dict_fetch(chaldict,'challenge','').lower() == 'digest' and \
            dict_fetch(chaldict,'nonce',None) and \
            dict_fetch(chaldict,'realm',None) and \
            dict_fetch(chaldict,'qop',None):
            authdict = generate_response(chaldict,
                                         request_uri,
                                         self.auth_user,
                                         self.auth_pass,
                                         method='POST')
            headers = {\
                'Authorization':build_authorization_arg(authdict),
                'Expect':'100-continue',
            }
            self.SendSOAPData(soapdata, url, soapaction, headers, **kw)
            return

        raise RuntimeError,\
            'Client expecting digest authorization challenge.'

    def ReceiveRaw(self, **kw):
        '''Read a server reply, unconverted to any format and return it.
        '''
        if self.data: return self.data
        trace = self.trace
        while 1:
            response = self.h.getresponse()
            self.reply_code, self.reply_msg, self.reply_headers, self.data = \
                response.status, response.reason, response.msg, response.read()
            if trace:
                print >> trace, "_" * 33, time.ctime(time.time()), "RESPONSE:"
                for i in (
                        self.reply_code,
                        self.reply_msg,
                ):
                    print >> trace, str(i)
                print >> trace, "-------"
                print >> trace, str(self.reply_headers)
                print >> trace, self.data
            saved = None
            for d in response.msg.getallmatchingheaders('set-cookie'):
                if d[0] in [' ', '\t']:
                    saved += d.strip()
                else:
                    if saved: self.cookies.load(saved)
                    saved = d.strip()
            if saved: self.cookies.load(saved)
            if response.status == 401:
                if not callable(self.http_callbacks.get(response.status,
                                                        None)):
                    raise RuntimeError, 'HTTP Digest Authorization Failed'
                self.http_callbacks[response.status](response)
                continue
            if response.status != 100: break

            # The httplib doesn't understand the HTTP continuation header.
            # Horrible internals hack to patch things up.
            self.h._HTTPConnection__state = httplib._CS_REQ_SENT
            self.h._HTTPConnection__response = None
        return self.data

    def IsSOAP(self):
        if self.ps: return 1
        self.ReceiveRaw()
        mimetype = self.reply_headers.type
        return mimetype == 'text/xml'

    def ReceiveSOAP(self, readerclass=None, **kw):
        '''Get back a SOAP message.
        '''
        if self.ps: return self.ps
        if not self.IsSOAP():
            raise TypeError('Response is "%s", not "text/xml"' %
                            self.reply_headers.type)
        if len(self.data) == 0:
            raise TypeError('Received empty response')

        self.ps = ParsedSoap(self.data,
                             readerclass=readerclass or self.readerclass,
                             encodingStyle=kw.get('encodingStyle'))

        if self.sig_handler is not None:
            self.sig_handler.verify(self.ps)

        return self.ps

    def IsAFault(self):
        '''Get a SOAP message, see if it has a fault.
        '''
        self.ReceiveSOAP()
        return self.ps.IsAFault()

    def ReceiveFault(self, **kw):
        '''Parse incoming message as a fault. Raise TypeError if no
        fault found.
        '''
        self.ReceiveSOAP(**kw)
        if not self.ps.IsAFault():
            raise TypeError("Expected SOAP Fault not found")
        return FaultFromFaultMessage(self.ps)

    def Receive(self, replytype, **kw):
        '''Parse message, create Python object.

        KeyWord data:
            faults   -- list of WSDL operation.fault typecodes
            wsaction -- If using WS-Address, must specify Action value we expect to
                receive.
        '''
        self.ReceiveSOAP(**kw)
        if self.ps.IsAFault():
            msg = FaultFromFaultMessage(self.ps)
            raise FaultException(msg)

        tc = replytype
        if hasattr(replytype, 'typecode'):
            tc = replytype.typecode

        reply = self.ps.Parse(tc)
        if self.address is not None:
            self.address.checkResponse(self.ps, kw.get('wsaction'))
        return reply

    def __repr__(self):
        return "<%s instance %s>" % (self.__class__.__name__, _get_idstr(self))
Example #16
0
class ServiceDescription:
    """client interface - locator, port, etc classes"""
    separate_messages = False
    logger = _GetLogger("ServiceDescription")

    def __init__(self, addressing=False, do_extended=False, wsdl=None):
        self.typesModuleName = None
        self.messagesModuleName = None
        self.wsAddressing = addressing
        self.imports = ServiceHeaderContainer()
        self.messagesImports = ServiceHeaderContainer()
        self.locator = ServiceLocatorContainer()
        self.methods = []
        self.messages = []
        self.do_extended = do_extended
        self._wsdl = wsdl  # None unless do_extended == True

    def setTypesModuleName(self, name, modulePath=None):
        """The types module to be imported.
        Parameters
        name -- name of types module
        modulePath -- optional path where module is located.
        """
        self.typesModuleName = '%s' % name
        if modulePath is not None:
            self.typesModuleName = '%s.%s' % (modulePath, name)

    def setMessagesModuleName(self, name, modulePath=None):
        '''The types module to be imported.
        Parameters
        name -- name of types module
        modulePath -- optional path where module is located.
        '''
        self.messagesModuleName = '%s' % name
        if modulePath is not None:
            self.messagesModuleName = '%s.%s' % (modulePath, name)

    def fromWsdl(self, service, **kw):
        self.imports.setTypesModuleName(self.typesModuleName)
        if self.separate_messages:
            self.messagesImports.setMessagesModuleName(self.messagesModuleName)
        self.imports.appendImport(kw.get('imports', []))

        self.locator.setUp(service)

        for port in service.ports:
            sop_container = ServiceOperationsClassContainer(
                useWSA=self.wsAddressing,
                do_extended=self.do_extended,
                wsdl=self._wsdl)
            try:
                sop_container.setUp(port)
            except Wsdl2PythonError, ex:
                self.logger.warning('Skipping port(%s)' % port.name)
                if len(ex.args):
                    self.logger.warning(ex.args[0])
            else:
                sop_container.setReaderClass(kw.get('readerclass'))
                sop_container.setWriterClass(kw.get('writerclass'))
                for soc in sop_container.operations:
                    if soc.hasInput() is True:
                        mw = MessageWriter(do_extended=self.do_extended)
                        mw.setUp(soc, port, input=True)
                        self.messages.append(mw)

                        if soc.hasOutput() is True:
                            mw = MessageWriter(do_extended=self.do_extended)
                            mw.setUp(soc, port, input=False)
                            self.messages.append(mw)

                self.methods.append(sop_container)
Example #17
0
class Binding(_Binding):
    '''Object that represents a binding (connection) to a SOAP server.  
    Can be used in the "name overloading" style.
    
    class attr:
        gettypecode -- funcion that returns typecode from typesmodule,
            can be set so can use whatever mapping you desire.
    '''
    gettypecode = staticmethod(
        lambda mod, e: getattr(mod, str(e.localName)).typecode)
    logger = _GetLogger('ZSI.client.Binding')

    def __init__(self, url, namespace=None, typesmodule=None, **kw):
        """
        Parameters:
            url -- location of service
            namespace -- optional root element namespace
            typesmodule -- optional response only. dict(name=typecode), 
                lookup for all children of root element.  
        """
        self.typesmodule = typesmodule
        self.namespace = namespace

        _Binding.__init__(self, url=url, **kw)

    def __getattr__(self, name):
        '''Return a callable object that will invoke the RPC method
        named by the attribute.
        '''
        if name[:2] == '__' and len(name) > 5 and name[-2:] == '__':
            if hasattr(self, name): return getattr(self, name)
            return getattr(self.__class__, name)
        return _Caller(self, name, self.namespace)

    def __parse_child(self, node):
        '''for rpc-style map each message part to a class in typesmodule
        '''
        try:
            tc = self.gettypecode(self.typesmodule, node)
        except:
            self.logger.debug(
                'didnt find typecode for "%s" in typesmodule: %s',
                node.localName, self.typesmodule)
            tc = TC.Any(aslist=1)
            return tc.parse(node, self.ps)

        self.logger.debug('parse child with typecode : %s', tc)
        try:
            return tc.parse(node, self.ps)
        except Exception:
            self.logger.debug('parse failed try Any : %s', tc)

        tc = TC.Any(aslist=1)
        return tc.parse(node, self.ps)

    def Receive(self, replytype, **kw):
        '''Parse message, create Python object.

        KeyWord data:
            faults   -- list of WSDL operation.fault typecodes
            wsaction -- If using WS-Address, must specify Action value we expect to
                receive.
        '''
        self.ReceiveSOAP(**kw)
        ps = self.ps
        tp = _find_type(ps.body_root)
        isarray = ((type(tp) in (tuple, list) and tp[1] == 'Array')
                   or _find_arraytype(ps.body_root))
        if self.typesmodule is None or isarray:
            return _Binding.Receive(self, replytype, **kw)

        if ps.IsAFault():
            msg = FaultFromFaultMessage(ps)
            raise FaultException(msg)

        tc = replytype
        if hasattr(replytype, 'typecode'):
            tc = replytype.typecode

        #Ignore response wrapper
        reply = {}
        for elt in _child_elements(ps.body_root):
            name = str(elt.localName)
            reply[name] = self.__parse_child(elt)

        if self.address is not None:
            self.address.checkResponse(ps, kw.get('wsaction'))

        return reply