From: <bov...@us...> - 2006-04-21 20:49:25
|
Revision: 1179 Author: boverhof Date: 2006-04-21 13:49:22 -0700 (Fri, 21 Apr 2006) ViewCVS: http://svn.sourceforge.net/pywebsvcs/?rev=1179&view=rev Log Message: ----------- M setup.py M README M CHANGES -If Python >= 2.4, build/install ZSI.twisted package else don't add to packages. Modified Paths: -------------- trunk/zsi/CHANGES trunk/zsi/README trunk/zsi/setup.py Modified: trunk/zsi/CHANGES =================================================================== --- trunk/zsi/CHANGES 2006-04-21 17:49:03 UTC (rev 1178) +++ trunk/zsi/CHANGES 2006-04-21 20:49:22 UTC (rev 1179) @@ -1,4 +1,6 @@ Change for xxx released xxx: + - Added ZSI.twisted package w/client and server, requires Python 2.4 + - If Python >= 2.4, build/install ZSI.twisted package - Make XMLSchema.py work in cases where threading isn't built in - Add client-side Cookie Support (Jorgen Frojk Kjaersgaard) - Add Typecode.typed to control xsi:type data system-wide Modified: trunk/zsi/README =================================================================== --- trunk/zsi/README 2006-04-21 17:49:03 UTC (rev 1178) +++ trunk/zsi/README 2006-04-21 20:49:22 UTC (rev 1179) @@ -14,8 +14,8 @@ invocation methods are supported. There are no known bugs. It's only known limitation is that it cannot handle multi-dimensional arrays. -ZSI is built on top of DOM. It requires Python 2.0 or later, and PyXML -0.6 or later. It is open source. We hope you find it useful. +ZSI is built on top of DOM. It requires Python 2.3 or later, and PyXML +0.8.3 or later. It is open source. We hope you find it useful. The documentation (in PDF and HTML) is accurate. We should probably restructure the document as a HOWTO. You probably can't usefully edit Modified: trunk/zsi/setup.py =================================================================== --- trunk/zsi/setup.py 2006-04-21 17:49:03 UTC (rev 1178) +++ trunk/zsi/setup.py 2006-04-21 20:49:22 UTC (rev 1179) @@ -1,8 +1,6 @@ #! /usr/bin/env python # $Header$ import sys -from distutils.command.build import build as _build -from distutils.command.build_py import build_py as _build_py try: from setuptools import setup except ImportError: @@ -30,46 +28,15 @@ print 'ZSI/version.py not found; run "make"' sys.exit(1) -_twisted_packages = ['ZSI.twisted'] -_twisted_options = [('twisted', None, 'build twisted packages')] +_packages = [ "ZSI", "ZSI.generate", "ZSI.wstools"] +if sys.version_info[0:2] >= (2, 4): + _packages.append("ZSI.twisted") -class build_py(_build_py): - user_options = _build_py.user_options[:] - user_options += _twisted_options - boolean_options = _build.boolean_options[:] - boolean_options.append(_twisted_options[0][0]) - - def initialize_options(self): - _build_py.initialize_options(self) - self.twisted = False - - def run(self): - if self.twisted: - self.distribution.packages += _twisted_packages - return _build_py.run(self) - - -class build(_build): - user_options = _build.user_options[:] - user_options += _twisted_options - boolean_options = _build.boolean_options[:] - boolean_options.append(_twisted_options[0][0]) - - def initialize_options(self): - _build.initialize_options(self) - self.twisted = False - - def run(self): - if self.twisted: - self.distribution.packages += _twisted_packages - return _build.run(self) - - setup( name="ZSI", version=_version, license="Python", - packages=[ "ZSI", "ZSI.generate", "ZSI.wstools"], + packages=_packages, scripts=["scripts/wsdl2py.py", "scripts/wsdl2dispatch.py"], description="Zolera SOAP Infrastructure", author="Rich Salz, et al", @@ -77,6 +44,5 @@ maintainer="Rich Salz, et al", maintainer_email="pyw...@li...", url=_url, - long_description='For additional information, please see ' + _url, - cmdclass={'build':build, 'build_py':build_py}, + long_description="For additional information, please see " + _url, ) This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <cm...@us...> - 2006-06-05 23:41:08
|
Revision: 1237 Author: cmoad Date: 2006-06-05 12:47:17 -0700 (Mon, 05 Jun 2006) ViewCVS: http://svn.sourceforge.net/pywebsvcs/?rev=1237&view=rev Log Message: ----------- renamed wsdl2xxx.py to wsdl2xx everywhere Modified Paths: -------------- trunk/zsi/ZSI/generate/commands.py trunk/zsi/doc/guide02-wsdl2py.tex trunk/zsi/setup.py trunk/zsi/test/wsdl2py/README trunk/zsi/test/wsdl2py/ServiceTest.py Modified: trunk/zsi/ZSI/generate/commands.py =================================================================== --- trunk/zsi/ZSI/generate/commands.py 2006-06-05 19:27:15 UTC (rev 1236) +++ trunk/zsi/ZSI/generate/commands.py 2006-06-05 19:47:17 UTC (rev 1237) @@ -76,7 +76,7 @@ # Basic options op.add_option("-f", "--file", action="store", dest="file", default=None, type="string", - help="file to load wsdl from") + help="FILE to load wsdl from") op.add_option("-u", "--url", action="store", dest="url", default=None, type="string", help="URL to load wsdl from") @@ -117,8 +117,8 @@ action="store", dest="types", default=None, type="string", help="file to load types from") op.add_option("-o", "--output-dir", - action="store", dest="output_directory", default=".", type="string", - help="file to load types from") + action="store", dest="output_dir", default=".", type="string", + help="Write generated files to OUTPUT_DIR") op.add_option("-s", "--simple-naming", action="store_true", dest="simple_naming", default=False, help="Simplify generated naming.") @@ -202,17 +202,17 @@ if options.types != None: wsm.setTypesModuleName(options.types) if options.schema is False: - fd = open(os.path.join(options.output_directory, '%s.py' %wsm.getClientModuleName()), 'w+') + fd = open(os.path.join(options.output_dir, '%s.py' %wsm.getClientModuleName()), 'w+') # simple naming writes the messages to a separate file if not options.simple_naming: wsm.writeClient(fd) else: # provide a separate file to store messages to. - msg_fd = open(os.path.join(options.output_directory, '%s.py' %wsm.getMessagesModuleName()), 'w+') + msg_fd = open(os.path.join(options.output_dir, '%s.py' %wsm.getMessagesModuleName()), 'w+') wsm.writeClient(fd, msg_fd=msg_fd) msg_fd.close() fd.close() - fd = open( os.path.join(options.output_directory, '%s.py' %wsm.getTypesModuleName()), 'w+') + fd = open( os.path.join(options.output_dir, '%s.py' %wsm.getTypesModuleName()), 'w+') wsm.writeTypes(fd) fd.close() @@ -243,9 +243,9 @@ help="debug output") op.add_option("-t", "--types", action="store", dest="types", default=None, type="string", - help="file to load types from") + help="Write generated files to OUTPUT_DIR") op.add_option("-o", "--output-dir", - action="store", dest="output_directory", default=".", type="string", + action="store", dest="output_dir", default=".", type="string", help="file to load types from") op.add_option("-s", "--simple-naming", action="store_true", dest="simple_naming", default=False, @@ -285,6 +285,6 @@ ss = ServiceDescription(do_extended=options.extended) ss.fromWSDL(wsdl) - fd = open( os.path.join(options.output_directory, ss.getServiceModuleName()+'.py'), 'w+') + fd = open( os.path.join(options.output_dir, ss.getServiceModuleName()+'.py'), 'w+') ss.write(fd) fd.close() Modified: trunk/zsi/doc/guide02-wsdl2py.tex =================================================================== --- trunk/zsi/doc/guide02-wsdl2py.tex 2006-06-05 19:27:15 UTC (rev 1236) +++ trunk/zsi/doc/guide02-wsdl2py.tex 2006-06-05 19:47:17 UTC (rev 1237) @@ -20,6 +20,7 @@ \item[-x, ---schema] Just process a schema (xsd) file and generate the types mapping file. \item[-d, ---debug] Output verbose debugging messages during code generation. +\item[-o OUTPUT_DIR, ---output-dir=OUTPUT_DIR] Write generated files to OUTPUT_DIR. \end{description} \subsubsection{Typecode Extensions (Stable) } @@ -194,7 +195,7 @@ \url{http://mathworld.wolfram.com/}, among others. \begin{verbatim} -wsdl2py.py --complexType --url=http://webservices.wolfram.com/services/SearchServices/WolframSearch2.wsdl +wsdl2py --complexType --url=http://webservices.wolfram.com/services/SearchServices/WolframSearch2.wsdl \end{verbatim} Run the above command to generate the service and type files. wsdl2py uses Modified: trunk/zsi/setup.py =================================================================== --- trunk/zsi/setup.py 2006-06-05 19:27:15 UTC (rev 1236) +++ trunk/zsi/setup.py 2006-06-05 19:47:17 UTC (rev 1237) @@ -47,7 +47,7 @@ # non-setuptools else: - additional_params['scripts'] = ["scripts/wsdl2py.py", "scripts/wsdl2dispatch.py"] + additional_params['scripts'] = ["scripts/wsdl2py", "scripts/wsdl2dispatch"] setup( name="ZSI", Modified: trunk/zsi/test/wsdl2py/README =================================================================== --- trunk/zsi/test/wsdl2py/README 2006-06-05 19:27:15 UTC (rev 1236) +++ trunk/zsi/test/wsdl2py/README 2006-06-05 19:47:17 UTC (rev 1237) @@ -21,7 +21,7 @@ To run only "network" tests: %./runTests.py net -To run only tests against the wsdl2dispatch.py tool: +To run only tests against the wsdl2dispatch tool: %./runTests.py dispatch @@ -89,7 +89,7 @@ "tracefile" -- show XML of individual messages as serialized/parsed. "debug" -- turn on verbose debugging information. - "skip" -- skip generation (wsdl2py.py and wsdl2dispatch.py) + "skip" -- skip generation (wsdl2py and wsdl2dispatch) "twisted" -- use twisted.web.client [dispatch] Modified: trunk/zsi/test/wsdl2py/ServiceTest.py =================================================================== --- trunk/zsi/test/wsdl2py/ServiceTest.py 2006-06-05 19:27:15 UTC (rev 1236) +++ trunk/zsi/test/wsdl2py/ServiceTest.py 2006-06-05 19:47:17 UTC (rev 1237) @@ -238,7 +238,7 @@ _wsdl = {} def _generate(self): - """call the wsdl2py.py and wsdl2dispatch.py scripts and + """call the wsdl2py and wsdl2dispatch scripts and automatically add the "-f" or "-u" argument. Other args can be appended via the "wsdl2py_args" and "wsdl2dispatch_args" instance attributes. @@ -266,7 +266,7 @@ try: # Client Stubs - wsdl2py = ['wsdl2py.py'] + args + self.wsdl2py_args + wsdl2py = ['wsdl2py'] + args + self.wsdl2py_args try: exit = subprocess.call(wsdl2py) except OSError, ex: @@ -280,7 +280,7 @@ # Service Stubs if '-x' not in self.wsdl2py_args: - wsdl2dispatch = (['wsdl2dispatch.py'] + args + + wsdl2dispatch = (['wsdl2dispatch'] + args + self.wsdl2dispatch_args) try: exit = subprocess.call(wsdl2dispatch) This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <bov...@us...> - 2006-06-28 22:14:12
|
Revision: 1241 Author: boverhof Date: 2006-06-28 15:14:03 -0700 (Wed, 28 Jun 2006) ViewCVS: http://svn.sourceforge.net/pywebsvcs/?rev=1241&view=rev Log Message: ----------- M test/wsdl2py/config.txt M test/wsdl2py/ServiceTest.py M test/wsdl2py/test_OpcDaGateway.py M ZSI/generate/pyclass.py M ZSI/generate/commands.py M ZSI/generate/containers.py M ZSI/TC.py M ZSI/TCcompound.py M ZSI/address.py M CHANGES Added an option "--lazy" to wsdl2py tooling, using this option causes typecodes (complexTypes) to be evaluated during serialization/parsing, thus can be used when importing generated code takes too much time or when max recursion errors occur because types contain references to themselves. Modified Paths: -------------- trunk/zsi/CHANGES trunk/zsi/ZSI/TC.py trunk/zsi/ZSI/TCcompound.py trunk/zsi/ZSI/address.py trunk/zsi/ZSI/generate/commands.py trunk/zsi/ZSI/generate/containers.py trunk/zsi/ZSI/generate/pyclass.py trunk/zsi/test/wsdl2py/ServiceTest.py trunk/zsi/test/wsdl2py/config.txt trunk/zsi/test/wsdl2py/test_OpcDaGateway.py Modified: trunk/zsi/CHANGES =================================================================== --- trunk/zsi/CHANGES 2006-06-27 13:28:26 UTC (rev 1240) +++ trunk/zsi/CHANGES 2006-06-28 22:14:03 UTC (rev 1241) @@ -1,15 +1,18 @@ Change for xxx released xxx: - - Added ZSI.twisted package w/client and server, requires Python 2.4 - - If Python >= 2.4, build/install ZSI.twisted package - Make XMLSchema.py work in cases where threading isn't built in - Add client-side Cookie Support (Jorgen Frojk Kjaersgaard) - - Add Typecode.typed to control xsi:type data system-wide - For cookies, getheaders() is Python 2.3; use getallmatchingheaders - In SoapWriter, put nsdecls on body, not envelope - Record facets (restrictions) in XMLSchema.py <vc...@da...> - Remove Send()'s kwargs out of _args list <ef...@bo...> - Replace many/most id() with _get_idstr() to hide negative numbers +Change for 2.0.0 released xxx: + - Added ZSI.twisted package w/client and server, requires Python 2.4 + - If Python >= 2.4, build/install ZSI.twisted package + - Add Typecode.typed to control xsi:type data system-wide + - Replace many/most id() with _get_idstr() to hide negative numbers + Changes for 1.7 released 16-Feb-2005: - Add support for jonpy (http://jonpy.sourceforge.net) FastCGI courtesy of Guan Yang Modified: trunk/zsi/ZSI/TC.py =================================================================== --- trunk/zsi/ZSI/TC.py 2006-06-27 13:28:26 UTC (rev 1240) +++ trunk/zsi/ZSI/TC.py 2006-06-28 22:14:03 UTC (rev 1241) @@ -36,8 +36,8 @@ return (None,None) -def _get_type_definition(namespaceURI, name): - return SchemaInstanceType.getTypeDefinition(namespaceURI, name) +def _get_type_definition(namespaceURI, name, **kw): + return SchemaInstanceType.getTypeDefinition(namespaceURI, name, **kw) def _get_global_element_declaration(namespaceURI, name, **kw): return SchemaInstanceType.getElementDeclaration(namespaceURI, name, **kw) @@ -49,6 +49,7 @@ return SchemaInstanceType.getTypeDefinition(namespaceURI, name) is not None + class SchemaInstanceType(type): '''Register all types/elements, when hit already defined class dont create a new one just give back reference. Thus @@ -94,7 +95,7 @@ raise TypeError, 'SchemaInstanceType must be an ElementDeclaration or TypeDefinition ' - def getTypeDefinition(cls, namespaceURI, name): + def getTypeDefinition(cls, namespaceURI, name, lazy=False): '''Grab a type definition, returns a typecode class definition because the facets (name, minOccurs, maxOccurs) must be provided. @@ -102,10 +103,13 @@ namespaceURI -- name -- ''' - return cls.types.get((namespaceURI, name), None) + klass = cls.types.get((namespaceURI, name), None) + if lazy and klass is not None: + return _Mirage(klass) + return klass getTypeDefinition = classmethod(getTypeDefinition) - def getElementDeclaration(cls, namespaceURI, name, isref=False): + def getElementDeclaration(cls, namespaceURI, name, isref=False, lazy=False): '''Grab an element declaration, returns a typecode instance representation or a typecode class definition. An element reference has its own facets, and is local so it will not be @@ -118,7 +122,10 @@ ''' key = (namespaceURI, name) if isref: - return cls.elements.get(key,None) + klass = cls.elements.get(key,None) + if klass is not None and lazy is True: + return _Mirage(klass) + return klass typecode = cls.element_typecode_cache.get(key, None) if typecode is None: @@ -139,8 +146,8 @@ literal = NCName ''' __metaclass__ = SchemaInstanceType + - class TypeDefinition: '''Typecodes subclass to represent a Global Type Definition by setting class variable type. @@ -148,7 +155,7 @@ type = (namespaceURI, NCName) ''' __metaclass__ = SchemaInstanceType - + def getSubstituteType(self, elt, ps): '''if xsi:type does not match the instance type attr, check to see if it is a derived type substitution. @@ -205,7 +212,8 @@ ''' tag = None type = (None,None) - typechecks = True + #typechecks = True + typechecks = False attribute_typecode_dict = None logger = _GetLogger('ZSI.TC.TypeCode') @@ -1988,6 +1996,55 @@ el.createAppendTextNode(textNode) +class _Mirage: + '''Used with SchemaInstanceType for lazy evaluation, eval during serialize or + parse as needed. Mirage is callable, TypeCodes are not. When called it returns the + typecode. + ''' + def __init__(self, klass): + self.pyclass = True + self.klass = klass + if issubclass(klass, ElementDeclaration): + self.__call__ = self._hide_element + + def _hide_type(self, pname, aname, minOccurs=0, maxOccurs=1, nillable=False, **kw): + self.__call__ = self._reveal_type + + # store all attributes, make some visable for pyclass_type + self.__kw = kw + self.minOccurs,self.maxOccurs,self.nillable = minOccurs,maxOccurs,nillable + self.nspname,self.pname,self.aname = None,pname,aname + if type(self.pname) in (tuple,list): + self.nspname,self.pname = pname + + return self + + def _hide_element(self, minOccurs=0, maxOccurs=1, nillable=False, **kw): + self.__call__ = self._reveal_element + + # store all attributes, make some visable for pyclass_type + self.__kw = kw + self.nspname = self.klass.schema + self.pname = self.klass.literal + #TODO: Fix hack + self.aname = '_%s' %self.pname + self.minOccurs,self.maxOccurs,self.nillable = minOccurs,maxOccurs,nillable + + return self + + def _reveal_type(self, *args, **kw): + return self.klass(pname=self.pname, + aname=self.aname, minOccurs=self.minOccurs, + maxOccurs=self.maxOccurs, nillable=self.nillable, + **self.__kw) + + def _reveal_element(self, *args, **kw): + return self.klass(minOccurs=self.minOccurs, + maxOccurs=self.maxOccurs, nillable=self.nillable, + **self.__kw) + __call__ = _hide_type + + class _GetPyobjWrapper: '''Get a python object that wraps data and typecode. Used by <any> parse routine, so that typecode information discovered @@ -2036,6 +2093,7 @@ from TCtimes import * from TCcompound import * from TCapache import * + f = lambda x: type(x) == types.ClassType and issubclass(x, TypeCode) and getattr(x, 'type', None) is not None TYPES = filter(f, map(lambda y:eval(y),dir())) Modified: trunk/zsi/ZSI/TCcompound.py =================================================================== --- trunk/zsi/ZSI/TCcompound.py 2006-06-27 13:28:26 UTC (rev 1240) +++ trunk/zsi/ZSI/TCcompound.py 2006-06-28 22:14:03 UTC (rev 1241) @@ -77,8 +77,10 @@ continue any_keys.append(aname) return any_keys + + class ComplexType(TypeCode): '''Represents an element of complexType, potentially containing other elements. @@ -181,6 +183,10 @@ 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) @@ -360,6 +366,10 @@ while indx < lenofwhat: occurs = 0 what = self.ofwhat[indx] + + # retrieve typecode if hidden + if callable(what): what = what() + if debug: self.logger.debug('serialize what -- %s', what.__class__.__name__) Modified: trunk/zsi/ZSI/address.py =================================================================== --- trunk/zsi/ZSI/address.py 2006-06-27 13:28:26 UTC (rev 1240) +++ trunk/zsi/ZSI/address.py 2006-06-28 22:14:03 UTC (rev 1241) @@ -5,7 +5,7 @@ import time, urlparse, socket from ZSI import _seqtypes, EvaluateException, WSActionException -from ZSI.TC import _get_global_element_declaration, _get_type_definition, \ +from ZSI.TC import _get_global_element_declaration as GED, _get_type_definition as GTD, \ _has_type_definition, AnyElement, AnyType, TypeCode from ZSI.TCcompound import ComplexType from ZSI.wstools.Namespaces import WSA_LIST @@ -13,6 +13,10 @@ class Address(object): '''WS-Address + + Implemented is dependent on the default "wsdl2py" convention of generating aname, + so the attributes representing element declaration names should be prefixed with + an underscore. ''' def __init__(self, addressTo=None, wsAddressURI=None, action=None): self.wsAddressURI = wsAddressURI @@ -107,7 +111,7 @@ try: for nsuri,elements in kw.items(): for el in elements: - typecode = _get_global_element_declaration(nsuri, el) + typecode = GED(nsuri, el) if typecode is None: raise WSActionException, 'Missing namespace, import "%s"' %nsuri @@ -153,19 +157,19 @@ # Set Message Information Headers # MessageID - typecode = _get_global_element_declaration(namespaceURI, "MessageID") + typecode = GED(namespaceURI, "MessageID") pyobjs.append(typecode.pyclass(messageID)) # Action - typecode = _get_global_element_declaration(namespaceURI, "Action") + typecode = GED(namespaceURI, "Action") pyobjs.append(typecode.pyclass(action)) # To - typecode = _get_global_element_declaration(namespaceURI, "To") + typecode = GED(namespaceURI, "To") pyobjs.append(typecode.pyclass(addressTo)) # From - typecode = _get_global_element_declaration(namespaceURI, "From") + typecode = GED(namespaceURI, "From") mihFrom = typecode.pyclass() mihFrom._Address = self.anonymousURI pyobjs.append(mihFrom) @@ -175,33 +179,15 @@ raise EvaluateException, 'endPointReference must have a typecode attribute' if isinstance(endPointReference.typecode, \ - _get_type_definition(namespaceURI ,'EndpointReferenceType')) is False: + GTD(namespaceURI ,'EndpointReferenceType')) is False: raise EvaluateException, 'endPointReference must be of type %s' \ - %_get_type_definition(namespaceURI ,'EndpointReferenceType') + %GTD(namespaceURI ,'EndpointReferenceType') - find = lambda what: isinstance(what,tc) - ncname = 'ReferencePropertiesType' - tc = _get_type_definition(namespaceURI, ncname) - what = filter(find, endPointReference.typecode.ofwhat) - if len(what) != 1: - raise EvaluateException,\ - 'EPR must contain one element of type (%s,%s)' %(namespaceURI,ncname) + ReferenceProperties = endPointReference._ReferenceProperties + any = ReferenceProperties._any or [] + #if not (what.maxOccurs=='unbounded' and type(any) in _seqtypes): + # raise EvaluateException, 'ReferenceProperties <any> assumed maxOccurs unbounded' - what = what[0] - ReferenceProperties = getattr(endPointReference, what.aname) - - #Assuming maxOccurs=1 - tc = AnyElement - what = filter(find, what.ofwhat) - if len(what) != 1: - raise EvaluateException, 'EPR must contain one <any>' - - what = what[0] - any = getattr(ReferenceProperties, what.aname) - - if not (what.maxOccurs=='unbounded' and type(any) in _seqtypes): - raise EvaluateException, 'ReferenceProperties <any> assumed maxOccurs unbounded' - for v in any: if not hasattr(v,'typecode'): raise EvaluateException, '<any> element, instance missing typecode attribute' @@ -227,10 +213,10 @@ (namespaceURI, "RelatesTo", address.getMessageID()), (namespaceURI, "To", self.anonymousURI),): - typecode = _get_global_element_declaration(nsuri, name) + typecode = GED(nsuri, name) pyobjs.append(typecode.pyclass(value)) - typecode = _get_global_element_declaration(nsuri, "From") + typecode = GED(nsuri, "From") pyobj = typecode.pyclass() pyobj._Address = self.From pyobjs.append(pyobj) Modified: trunk/zsi/ZSI/generate/commands.py =================================================================== --- trunk/zsi/ZSI/generate/commands.py 2006-06-27 13:28:26 UTC (rev 1240) +++ trunk/zsi/ZSI/generate/commands.py 2006-06-28 22:14:03 UTC (rev 1241) @@ -36,6 +36,11 @@ ServiceHeaderContainer.imports.remove('from ZSI import client') ServiceHeaderContainer.imports.append('from ZSI.twisted import client') + +def SetUpLazyEvaluation(option, opt, value, parser, *args, **kwargs): + from ZSI.generate.containers import TypecodeContainerBase + TypecodeContainerBase.lazy = True + def formatSchemaObject(fname, schemaObj): """ In the case of a 'schema only' generation (-s) this creates @@ -99,6 +104,12 @@ 'metaclass':'pyclass_type'}, help="add convenience functions for complexTypes, including Getters, Setters, factory methods, and properties (via metaclass). *** DONT USE WITH --simple-naming ***") + # Lazy Evaluation of Typecodes (done at serialization/parsing when needed). + op.add_option("-l", "--lazy", + action="callback", callback=SetUpLazyEvaluation, + callback_kwargs={}, + help="EXPERIMENTAL: recursion error solution, lazy evalution of typecodes") + # Use Twisted op.add_option("-w", "--twisted", action="callback", callback=SetUpTwistedClient, Modified: trunk/zsi/ZSI/generate/containers.py =================================================================== --- trunk/zsi/ZSI/generate/containers.py 2006-06-27 13:28:26 UTC (rev 1240) +++ trunk/zsi/ZSI/generate/containers.py 2006-06-28 22:14:03 UTC (rev 1241) @@ -1036,6 +1036,7 @@ 'import ZSI', 'import ZSI.TCcompound', 'from ZSI.TC import ElementDeclaration,TypeDefinition', + 'from ZSI.TC import _get_type_definition as GTD, _get_global_element_declaration as GED', ] logger = _GetLogger("TypesHeaderContainer") @@ -1087,6 +1088,7 @@ mixed_content_aname = 'text' attributes_aname = 'attrs' metaclass = None + lazy = False logger = _GetLogger("TypecodeContainerBase") def __init__(self, do_extended=False, extPyClasses=None): @@ -1111,12 +1113,14 @@ self.extraFlags = '' self.attrComponents = None + # --> EXTENDED # Used if an external pyclass was specified for this type. self.do_extended = do_extended if extPyClasses is None: self.extPyClasses = {} else: self.extPyClasses = extPyClasses + # <-- def getvalue(self): out = ContainerBase.getvalue(self) @@ -1193,38 +1197,46 @@ return self.mangle( classname ) + # --> EXTENDED def hasExtPyClass(self): if self.name in self.extPyClasses: return True else: return False + # <-- def getPyClass(self): '''Name of generated inner class that will be specified as pyclass. ''' + # --> EXTENDED if self.hasExtPyClass(): classInfo = self.extPyClasses[self.name] return ".".join(classInfo) - else: - return 'Holder' + # <-- + + return 'Holder' def getPyClassDefinition(self): '''Return a list containing pyclass definition. ''' kw = KW.copy() + + # --> EXTENDED if self.hasExtPyClass(): classInfo = self.extPyClasses[self.name] kw['classInfo'] = classInfo[0] return ["%(ID3)simport %(classInfo)s" %kw ] + # <-- kw['pyclass'] = self.getPyClass() - definition = [] definition.append('%(ID3)sclass %(pyclass)s:' %kw) if self.metaclass is not None: kw['type'] = self.metaclass definition.append('%(ID4)s__metaclass__ = %(type)s' %kw) definition.append('%(ID4)stypecode = self' %kw) + + #TODO: Remove pyclass holder __init__ --> definition.append('%(ID4)sdef __init__(self):' %kw) definition.append('%(ID5)s# pyclass' %kw) @@ -1236,8 +1248,9 @@ kw['element'] = el definition.append('%(ID2)s%(element)s' %kw) definition.append('%(ID5)sreturn' %kw) - - # JRB give pyclass a descriptive name + # <-- + + # pyclass descriptive name if self.name is not None: kw['name'] = self.name definition.append(\ @@ -1291,7 +1304,9 @@ def _setUpElements(self): - """This method ONLY sets up the instance attributes. + """TODO: Remove this method + + This method ONLY sets up the instance attributes. Dependency instance attribute: mgContent -- expected to be either a complex definition with model group content, a model group, or model group @@ -1530,23 +1545,26 @@ if ns in SCHEMA.XSD_LIST: tpc = BTI.get_typeclass(global_type[1],global_type[0]) tc.klass = tpc - elif (self.ns,self.name) == global_type: - # elif self._isRecursiveElement(c) - # TODO: Remove this, it only works for 1 level. - tc.setStyleRecursion() +# elif (self.ns,self.name) == global_type: +# # elif self._isRecursiveElement(c) +# # TODO: Remove this, it only works for 1 level. +# tc.setStyleRecursion() else: - tc.klass = '%s.%s' % (NAD.getAlias(ns), - type_class_name(global_type[1])) + tc.setGlobalType(*global_type) +# tc.klass = '%s.%s' % (NAD.getAlias(ns), +# type_class_name(global_type[1])) del ns elif content is not None and content.isLocal() and content.isComplex(): tc.name = c.getAttribute('name') - tc.klass = 'self.__class__.%s' % (element_class_name(tc.name) ) + tc.klass = 'self.__class__.%s' % (element_class_name(tc.name)) + #TODO: Not an element reference, confusing nomenclature tc.setStyleElementReference() self.localTypes.append(c) elif content is not None and content.isLocal() and content.isSimple(): # Local Simple Type tc.name = c.getAttribute('name') tc.klass = 'self.__class__.%s' % (element_class_name(tc.name)) + #TODO: Not an element reference, confusing nomenclature tc.setStyleElementReference() self.localTypes.append(c) else: @@ -1554,10 +1572,11 @@ elif c.isReference(): # element references - ns = c.getAttribute('ref')[0] - tc.klass = '%s.%s' % (NAD.getAlias(ns), - element_class_name(c.getAttribute('ref')[1]) ) + ref = c.getAttribute('ref') +# tc.klass = '%s.%s' % (NAD.getAlias(ref[0]), +# element_class_name(ref[1]) ) tc.setStyleElementReference() + tc.setGlobalType(*ref) else: raise ContainerError, 'unexpected item: %s' % c.getItemTrace() @@ -1723,6 +1742,7 @@ self.qualified = qualified self.name = None self.klass = None + self.global_type = None self.min = None self.max = None @@ -1738,6 +1758,9 @@ def setProcessContents(self, processContents): self.processContents = processContents + def setGlobalType(self, namespace, name): + self.global_type = (namespace, name) + def setStyleElementDeclaration(self): '''set the element style. standard -- GED or local element @@ -1758,9 +1781,7 @@ self.style = 'anyElement' def setStyleRecursion(self): - '''set the element style. - recursion -- do lazy evaluation of element/type because - the element contains an instance of itself. + '''TODO: Change name or remove. For Element Declarations? not recursion ''' self.style = 'recursion' @@ -1778,22 +1799,39 @@ % (self.processContents) def _getvalue(self): + kw = {'occurs':self._getOccurs(), + 'aname':self.getAttributeName(self.name), + 'klass':self.klass, + 'lazy':TypecodeContainerBase.lazy, + 'typed':'typed=False', + 'encoded':'encoded=kw.get("encoded")'} + + gt = self.global_type + if gt is not None: + kw['nsuri'],kw['type'] = gt + if self.style == 'standard': - pname = '"%s"' %self.name + kw['pname'] = '"%s"' %self.name if self.qualified is True: - pname = '(ns,"%s")' %self.name - return '%s(pname=%s, aname="%s", %s, encoded=kw.get("encoded"))' \ - % (self.klass, pname, - self.getAttributeName(self.name), self._getOccurs()) - elif self.style == 'ref': - return '%s(%s, encoded=kw.get("encoded"))' % (self.klass, self._getOccurs()) - elif self.style == 'anyElement': - return 'ZSI.TC.AnyElement(aname="%s", %s, %s)' \ - %(self.getAttributeName(self.name), self._getOccurs(), self._getProcessContents()) - elif self.style == 'recursion': - return 'ZSI.TC.AnyElement(aname="%s", %s, %s)' \ - % (self.getAttributeName(self.name), self._getOccurs(), self._getProcessContents()) + kw['pname'] = '(ns,"%s")' %self.name + if gt is None: + return '%(klass)s(pname=%(pname)s, aname="%(aname)s", %(occurs)s, %(typed)s, %(encoded)s)' %kw + return 'GTD("%(nsuri)s","%(type)s",lazy=%(lazy)s)(pname=%(pname)s, aname="%(aname)s", %(occurs)s, %(typed)s, %(encoded)s)' %kw + + if self.style == 'ref': + if gt is None: + return '%(klass)s(%(occurs)s, %(encoded)s)' %kw + return 'GED("%(nsuri)s","%(type)s",lazy=%(lazy)s, isref=True)(%(occurs)s, %(encoded)s)' %kw + + kw['process'] = self._getProcessContents() + if self.style == 'anyElement': + return 'ZSI.TC.AnyElement(aname="%(aname)s", %(occurs)s, %(process)s)' %kw + + if self.style == 'recursion': + return 'ZSI.TC.AnyElement(aname="%(aname)s", %(occurs)s, %(process)s)' %kw + raise RuntimeError, 'Must set style for typecode list generation' + def __str__(self): return self._getvalue() @@ -1819,7 +1857,7 @@ pname = '"%s"' %self.name if self.qualified is True: pname = '(ns,"%s")' %self.name - return '%s(pname=%s, aname="%s", encoded=%s, %s)' \ + return '%s(pname=%s, aname="%s", typed=False, encoded=%s, %s)' \ %(self.klass, pname, self.getAttributeName(self.name), encoded, self._getOccurs()) elif self.style == 'ref': Modified: trunk/zsi/ZSI/generate/pyclass.py =================================================================== --- trunk/zsi/ZSI/generate/pyclass.py 2006-06-27 13:28:26 UTC (rev 1240) +++ trunk/zsi/ZSI/generate/pyclass.py 2006-06-28 22:14:03 UTC (rev 1241) @@ -143,7 +143,6 @@ return type.__new__(cls,classname,bases,classdict) def __create_functions_from_what(what): - def get(self): return getattr(self, what.aname) get.im_func = 'get_element_%s' %what.aname @@ -151,34 +150,54 @@ if what.maxOccurs > 1: def set(self, value): if not (value is None or hasattr(value, '__iter__')): - value = [value] + raise TypeError, 'expecting an iterable instance' setattr(self, what.aname, value) else: def set(self, value): setattr(self, what.aname, value) - pyclass = what.pyclass if isinstance(what, TC.ComplexType) or isinstance(what, TC.Array): + def new_func(self): '''returns a mutable type ''' - return pyclass() + return what.pyclass() new_func.__name__ = 'new%s' %what.aname - elif pyclass is None: + + elif not callable(what): + def new_func(self, value): '''value -- initialize value - NOT IMPLEMENTED FOR %s, UNSUPPORTED TYPECODE. - ''' %what.__class__ - raise NotImplementedError,\ - 'no support built in for %s right now' %what.__class__ - - new_func = None + returns an immutable type + ''' + return what.pyclass(value) + new_func.__name__ = 'new%s' %what.aname + + elif (issubclass(what.klass, TC.ComplexType) or + issubclass(what.klass, TC.Array)): + + def new_func(self): + '''returns a mutable type + ''' + return what().pyclass() + new_func.__name__ = 'new%s' %what.aname + +# elif what.pyclass is None: +# def new_func(self, value): +# '''value -- initialize value +# NOT IMPLEMENTED FOR %s, UNSUPPORTED TYPECODE. +# ''' %what.__class__ +# raise NotImplementedError,\ +# 'no support built in for %s right now' %what.__class__ +# +# new_func = None else: + def new_func(self, value): '''value -- initialize value returns an immutable type ''' - return pyclass(value) + return what().pyclass(value) new_func.__name__ = 'new%s' %what.aname get.func_name = 'get_element_%s' %what.aname Modified: trunk/zsi/test/wsdl2py/ServiceTest.py =================================================================== --- trunk/zsi/test/wsdl2py/ServiceTest.py 2006-06-27 13:28:26 UTC (rev 1240) +++ trunk/zsi/test/wsdl2py/ServiceTest.py 2006-06-28 22:14:03 UTC (rev 1241) @@ -42,6 +42,7 @@ DEBUG = CONFIG_PARSER.getboolean(SECTION_CONFIGURATION, 'debug') SKIP = CONFIG_PARSER.getboolean(SECTION_CONFIGURATION, 'skip') TWISTED = CONFIG_PARSER.getboolean(SECTION_CONFIGURATION, 'twisted') +LAZY = CONFIG_PARSER.getboolean(SECTION_CONFIGURATION, 'lazy') OUTPUT = CONFIG_PARSER.get(SECTION_CONFIGURATION, 'output') or sys.stdout if DEBUG: @@ -155,6 +156,9 @@ if TWISTED: self.wsdl2py_args.append('--twisted') + if LAZY: + self.wsdl2py_args.append('--lazy') + unittest.TestCase.__init__(self, methodName) write = lambda self, arg: self.out.write(arg) @@ -271,6 +275,7 @@ exit = subprocess.call(wsdl2py) except OSError, ex: warnings.warn("TODO: Not sure what is going on here?") + exit = -1 #TODO: returncode WINDOWS? self.failUnless(os.WIFEXITED(exit), Modified: trunk/zsi/test/wsdl2py/config.txt =================================================================== --- trunk/zsi/test/wsdl2py/config.txt 2006-06-27 13:28:26 UTC (rev 1240) +++ trunk/zsi/test/wsdl2py/config.txt 2006-06-28 22:14:03 UTC (rev 1241) @@ -8,6 +8,7 @@ # debug -- turn on debugging # skip -- skip generation steps, code generated don't generate again # twisted -- Use twisted web client +# lazy -- use lazy typecode evaluation # output -- file name where output will be stored, if unspecified test output goes to stdout # # [dispatch] -- configuration for test_dispatch* tests @@ -22,7 +23,8 @@ debug = False skip = False twisted = False -output = +lazy = False +output = [dispatch] host = localhost Modified: trunk/zsi/test/wsdl2py/test_OpcDaGateway.py =================================================================== --- trunk/zsi/test/wsdl2py/test_OpcDaGateway.py 2006-06-27 13:28:26 UTC (rev 1240) +++ trunk/zsi/test/wsdl2py/test_OpcDaGateway.py 2006-06-28 22:14:03 UTC (rev 1241) @@ -66,7 +66,8 @@ import time pyobj = self.client_module.ReadSoapOut() pyobj.RItemList = pyobj.new_RItemList() - item = pyobj.RItemList.Items = pyobj.RItemList.new_Items() + item = pyobj.RItemList.new_Items() + pyobj.RItemList.Items = [item,] item.typecode.ofwhat[1].processContents = 'lax' item.Value = 123 s = str(ZSI.SoapWriter().serialize(pyobj)) This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <bov...@us...> - 2006-10-13 00:12:36
|
Revision: 1265 http://svn.sourceforge.net/pywebsvcs/?rev=1265&view=rev Author: boverhof Date: 2006-10-12 17:12:32 -0700 (Thu, 12 Oct 2006) Log Message: ----------- M doc/c06-tc.tex M doc/c03-except.tex -- updates to typecode chapter, thru Any "Dynamic Typing" M ZSI/__init__.py M ZSI/TC.py M ZSI/parse.py M ZSI/TCcompound.py M CHANGES -- some formatting and changes to booleans for consistency. -- major updates for TC.Any, removed some unused/unimportant code and combined some functions into one. Improved readability and purpose of much of this code. Modified Paths: -------------- trunk/zsi/CHANGES trunk/zsi/ZSI/TC.py trunk/zsi/ZSI/TCcompound.py trunk/zsi/ZSI/__init__.py trunk/zsi/ZSI/parse.py trunk/zsi/doc/c03-except.tex trunk/zsi/doc/c06-tc.tex Modified: trunk/zsi/CHANGES =================================================================== --- trunk/zsi/CHANGES 2006-10-11 22:58:45 UTC (rev 1264) +++ trunk/zsi/CHANGES 2006-10-13 00:12:32 UTC (rev 1265) @@ -5,9 +5,13 @@ - In SoapWriter, put nsdecls on body, not envelope - Record facets (restrictions) in XMLSchema.py <vc...@da...> - Remove Send()'s kwargs out of _args list <ef...@bo...> - - Replace many/most id() with _get_idstr() to hide negative numbers Change for 2.0.0 released xxx: + - Removed "requestclass" keyword argument to Binding.Send + - simplified and retooled Binding/NamedParamBinding and dispatch. + +Change for 2.0.0rc2 released 28-March-2006: + - Replace many/most id() with _get_idstr() to hide negative numbers - Added ZSI.twisted package w/client and server, requires Python 2.4 - If Python >= 2.4, build/install ZSI.twisted package - Add Typecode.typed to control xsi:type data system-wide Modified: trunk/zsi/ZSI/TC.py =================================================================== --- trunk/zsi/ZSI/TC.py 2006-10-11 22:58:45 UTC (rev 1264) +++ trunk/zsi/ZSI/TC.py 2006-10-13 00:12:32 UTC (rev 1265) @@ -196,10 +196,6 @@ return subclass((self.nspname, self.pname)) -#class Nilled: -# '''Just a placeholder for nilled elements. -# ''' -# __init__ = None Nilled = None class TypeCode: @@ -216,11 +212,11 @@ generated if/when needed seriallist -- list of Python types or user-defined classes that this typecode can serialize. + logger -- logger instance for this class. ''' tag = None type = (None,None) - #typechecks = True - typechecks = False + typechecks = True attribute_typecode_dict = None logger = _GetLogger('ZSI.TC.TypeCode') @@ -256,7 +252,6 @@ self.unique = unique self.attrs_aname = attrs_aname self.pyclass = pyclass - #if kw.has_key('default'): self.default = kw['default'] # Need this stuff for rpc/encoded. encoded = kw.get('encoded') @@ -308,7 +303,7 @@ href = _find_href(elt) if not href: if self.minOccurs is 0: return None - raise EvaluateException('Non-optional ' + tag + ' missing', + raise EvaluateException('Required' + tag + ' missing', ps.Backtrace(elt)) return ps.FindLocalHREF(href, elt, 0) @@ -573,7 +568,7 @@ # No content, no HREF, and is NIL... if self.nillable is True: return Nilled - raise EvaluateException('Non-optional string missing', + raise EvaluateException('Requiredstring missing', ps.Backtrace(elt)) if href[0] != '#': @@ -665,23 +660,17 @@ logger = _GetLogger('ZSI.TC.Any') parsemap, serialmap = {}, {} - def __init__(self, pname=None, aslist=0, **kw): - TypeCode.__init__(self, pname, **kw) + def __init__(self, pname=None, aslist=False, minOccurs=0, **kw): + TypeCode.__init__(self, pname, minOccurs=minOccurs, **kw) self.aslist = aslist self.kwargs = {'aslist':aslist} self.kwargs.update(kw) - # If not derived, and optional isn't set, make us optional - # so that None can be parsed. - if self.__class__ == Any and not kw.has_key('optional'): - self.optional = 1 - - #self.asarray = True self.unique = False # input arg v should be a list of tuples (name, value). def listify(self, v): if self.aslist: return [ k for j,k in v ] - else: return dict(v) + return dict(v) def parse_into_dict_or_list(self, elt, ps): c = _child_elements(elt) @@ -698,8 +687,8 @@ if self.nilled(elt, ps): return Nilled for c_elt in c: - # append (name,value) tuple to list - v.append( (str(c_elt.localName), self.__class__(**self.kwargs).parse(c_elt, ps) ) ) + v.append((str(c_elt.localName), self.__class__(**self.kwargs).parse(c_elt, ps))) + return self.listify(v) def parse(self, elt, ps): @@ -708,12 +697,12 @@ if len(_children(elt)) == 0: href = _find_href(elt) if not href: - if self.optional: + if self.minOccurs < 1: if _is_xsd_or_soap_ns(ns): parser = Any.parsemap.get((None,type)) if parser: return parser.parse(elt, ps) return None - raise EvaluateException('Non-optional Any missing', + raise EvaluateException('Required Any missing', ps.Backtrace(elt)) elt = ps.FindLocalHREF(href, elt) (ns,type) = self.checktype(elt, ps) @@ -774,13 +763,13 @@ "xsd:anyType[" + str(len(pyobj)) + "]" ) for o in pyobj: #TODO maybe this should take **self.kwargs... - serializer = getattr(o, 'typecode', self.__class__()) # also used by AnyLax() + serializer = getattr(o, 'typecode', self.__class__()) # also used by _AnyLax() serializer.serialize(array, sw, o, name='element', **kw) else: struct = elt.createAppendElement(ns, n) for o in pyobj: #TODO maybe this should take **self.kwargs... - serializer = getattr(o, 'typecode', self.__class__()) # also used by AnyLax() + serializer = getattr(o, 'typecode', self.__class__()) # also used by _AnyLax() serializer.serialize(struct, sw, o, **kw) return @@ -844,92 +833,6 @@ #serializer.pname = None -def RegisterType(C, clobber=0, *args, **keywords): - instance = apply(C, args, keywords) - for t in C.__dict__.get('parselist', []): - prev = Any.parsemap.get(t) - if prev: - if prev.__class__ == C: continue - if not clobber: - raise TypeError( - str(C) + ' duplicating parse registration for ' + str(t)) - Any.parsemap[t] = instance - for t in C.__dict__.get('seriallist', []): - ti = type(t) - if ti in [ types.TypeType, types.ClassType]: - key = t - elif ti in _stringtypes: - key = (types.ClassType, t) - else: - raise TypeError(str(t) + ' is not a class name') - prev = Any.serialmap.get(key) - if prev: - if prev.__class__ == C: continue - if not clobber: - raise TypeError( - str(C) + ' duplicating serial registration for ' + str(t)) - Any.serialmap[key] = instance - -def _DynamicImport(moduleName, className): - ''' - Utility function for RegisterTypeWithSchemaAndClass - ''' - mod = __import__(moduleName) - components = moduleName.split('.') - for comp in components[1:]: - mod = getattr(mod, comp) - return getattr(mod, className) - -def _RegisterTypeWithSchemaAndClass(importedSchemaTypes, schemaTypeName, classModuleName, className, generatedClassSuffix="_"): - ''' - Used by RegisterGeneratedTypesWithMapping. - Helps register classes so they can be serialized and parsed as "any". - Register a type by providing its schema and class. This allows - Any and AnyType to reconstruct objects made up of your own classes. - Note: The class module should be able to be imported (by being in your - pythonpath). Your classes __init__ functions shoud have default arguments - for all extra parameters. - Example of use: - import SchemaToPyTypeMap # Mapping written by you. Also used with wsdl2py -m - # mapping = {"SomeDescription" : ("Descriptions", "SomeDescription"), - # # schemaTypeName : moduleName , className - # The module on the next line is generated by wsdl2py - from EchoServer_services_types import urn_ZSI_examples as ExampleTypes - - for key,value in SchemaToPyTypeMap.mapping.items(): - ZSI.TC.RegisterTypeWithSchemaAndClass(importedSchemaTypes = ExampleTypes, schemaTypeName=key, classModuleName=value[0], className=value[1]) - - - ''' - # Doing this: (schemaTypeName="ExampleTypes", classModuleName="Description", - # className="SomeDescription") - # sd_instance = ExampleTypes.SomeDescription_(pname="SomeDescription") - # Any.serialmap[Descriptions.SomeDescription] = sd_instance - # Any.parsemap[(None,'SomeDescription')] = sd_instance - classDef = _DynamicImport(classModuleName, className) - interfaceDef = getattr(importedSchemaTypes, schemaTypeName + generatedClassSuffix) - - instance = interfaceDef(pname=className) - Any.serialmap[classDef] = instance - Any.parsemap[(None,schemaTypeName)] = instance - -def RegisterGeneratedTypesWithMapping(generatedTypes, mapping, generatedClassSuffix="_"): - """ - Helps register your classes so they can be serialized and parsed as "any". - generatedTypes is a class containing typecode classes generated by zsi. - mapping is a dictionary that maps {schemaTypeName : moduleName, className} - and is also used with wsdl2py -m - - Example of use: - import SchemaToPyTypeMap # See RegisterTypeWithSchemaAndClass for description - # The module on the next line is generated by wsdl2py and contains generated typecodes. - from EchoServer_services_types import urn_ZSI_examples as ExampleTypes - ZSI.TC.RegisterGeneratedTypesWithMapping(generatedTypes = ExampleTypes, mapping=SchemaToPyTypeMap.mapping) - """ - for key,value in mapping.items(): - _RegisterTypeWithSchemaAndClass(importedSchemaTypes = generatedTypes, schemaTypeName=key, classModuleName=value[0], className=value[1], generatedClassSuffix=generatedClassSuffix) - - class String(SimpleType): '''A string type. ''' @@ -1507,126 +1410,8 @@ xmlelt.setAttributeNS(SOAP.ENC, 'encodingStyle', '""') Canonicalize(pyobj, sw, unsuppressedPrefixes=unsuppressedPrefixes, comments=self.comments) + -# Base class for AnyStrict and AnyLax -class AnyConcrete(Any): - ''' Base class for handling unspecified types when using concrete schemas. - ''' - logger = _GetLogger('ZSI.TC.AnyConcrete') - def __init__(self, pname=None, aslist=False, **kw): - TypeCode.__init__(self, pname, **kw) - self.aslist = aslist - self.asarray = False # don't use arrayType - self.unique = True # don't print id - self.optional = kw.get('optional', True) # Any constructor is not called - - -class AnyStrict(AnyConcrete): - ''' Handles an unspecified types when using a concrete schemas and - processContents = "strict". - ''' - logger = _GetLogger('ZSI.TC.AnyStrict') - - def __init__(self, pname=None, aslist=False, **kw): - AnyConcrete.__init__(self, pname=pname, aslist=aslist, **kw) - - def serialize(self, elt, sw, pyobj, name=None, **kw): - tc = type(pyobj) - if tc == types.DictType and not self.aslist: - raise EvaluateException, 'Serializing dictionaries not implemented when processContents=\"strict\". Try as a list or use processContents=\"lax\".' - else: - - AnyConcrete.serialize(self, elt=elt,sw=sw,pyobj=pyobj,name=name, **kw) - -class AnyLax(AnyConcrete): - ''' Handles unspecified types when using a concrete schemas and - processContents = "lax". - ''' - logger = _GetLogger('ZSI.TC.AnyLax') - - def __init__(self, pname=None, aslist=False, **kw): - AnyConcrete.__init__(self, pname=pname, aslist=aslist, **kw) - - def parse_into_dict_or_list(self, elt, ps): - c = _child_elements(elt) - count = len(c) - v = [] - if count == 0: - href = _find_href(elt) - if not href: return {} - elt = ps.FindLocalHREF(href, elt) - self.checktype(elt, ps) - c = _child_elements(elt) - count = len(c) - if count == 0: return self.listify([]) - if self.nilled(elt, ps): return Nilled - - # group consecutive elements with the same name together - # We treat consecutive elements with the same name as lists. - groupedElements = [] # tuples of (name, elementList) - previousName = "" - currentElementList = None - for ce in _child_elements(elt): - name = ce.localName - if (name != previousName): # new name, so new group - if currentElementList != None: # store previous group if there is one - groupedElements.append( (previousName, currentElementList) ) - currentElementList = list() - currentElementList.append(ce) # append to list - previousName = name - # add the last group if necessary - if currentElementList != None: # store previous group if there is one - groupedElements.append( (previousName, currentElementList) ) - - # parse the groups of names - if len(groupedElements) < 1: # should return earlier - return None - # return a list if there is one name and multiple data - elif (len(groupedElements) == 1) and (len(groupedElements[0][0]) > 1): - self.aslist = 0 - # else return a dictionary - - for name,eltList in groupedElements: - lst = [] - for elt in eltList: - #aslist = self.aslist - lst.append( self.parse(elt, ps) ) - #self.aslist = aslist # restore the aslist setting - if len(lst) > 1: # consecutive elements with the same name means a list - v.append( (name, lst) ) - elif len(lst) == 1: - v.append( (name, lst[0]) ) - - return self.listify(v) - - def checkname(self, elt, ps): - '''See if the name and type of the "elt" element is what we're - looking for. Return the element's type. - Since this is AnyLax, it's ok if names don't resolve. - ''' - - parselist,errorlist = self.get_parse_and_errorlist() - ns, name = _get_element_nsuri_name(elt) - if ns == SOAP.ENC: - # Element is in SOAP namespace, so the name is a type. - if parselist and \ - (None, name) not in parselist and (ns, name) not in parselist: - raise EvaluateException( - 'Element mismatch (got %s wanted %s) (SOAP encoding namespace)' % \ - (name, errorlist), ps.Backtrace(elt)) - return (ns, name) - - # Not a type, check name matches. - if self.nspname and ns != self.nspname: - raise EvaluateException('Element NS mismatch (got %s wanted %s)' % \ - (ns, self.nspname), ps.Backtrace(elt)) - - #if self.pname and name != self.pname: - # this is ok since names don't need to be resolved with AnyLax - - return self.checktype(elt, ps) - - class AnyType(TypeCode): """XML Schema xsi:anyType type definition wildCard. class variables: @@ -1641,7 +1426,8 @@ def __init__(self, pname=None, namespaces=['#all'], minOccurs=1, maxOccurs=1, strip=1, **kw): - TypeCode.__init__(self, pname=pname, minOccurs=minOccurs, maxOccurs=maxOccurs, **kw) + TypeCode.__init__(self, pname=pname, minOccurs=minOccurs, + maxOccurs=maxOccurs, **kw) self.namespaces = namespaces def get_formatted_content(self, pyobj): @@ -1664,29 +1450,32 @@ def serialize(self, elt, sw, pyobj, **kw): nsuri,typeName = _get_xsitype(pyobj) if self.all not in self.namespaces and nsuri not in self.namespaces: - raise EvaluateException, '<anyType> unsupported use of namespaces %s' %self.namespaces - what = pyobj - if hasattr(what, 'typecode'): - what = pyobj.typecode - elif not isinstance(what, TypeCode): + raise EvaluateException( + '<anyType> unsupported use of namespaces "%s"' %self.namespaces) + + what = getattr(pyobj, 'typecode', None) + if what is None: # TODO: resolve this, "strict" processing but no # concrete schema makes little sense. - what = AnyStrict(pname=(self.nspname,self.pname), aslist=False) + #what = _AnyStrict(pname=(self.nspname,self.pname)) + what = Any(pname=(self.nspname,self.pname), unique=True, + aslist=False) kw['typed'] = True what.serialize(elt, sw, pyobj, **kw) return # Namespace if element AnyType was namespaced. - if self.nspname != what.nspname: - what.nspname = self.nspname +# if self.nspname != what.nspname: +# what.nspname = self.nspname +# +# if self.pname != what.pname: +# raise EvaluateException, \ +# 'element name of typecode(%s) must match element name of AnyType(%s)' \ +# %(what.pname,self.pname) - if self.pname != what.pname: - raise EvaluateException, \ - 'element name of typecode(%s) must match element name of AnyType(%s)' \ - %(what.pname,self.pname) + what.serialize(elt, sw, pyobj, + name=(self.nspname or what.nspname, self.pname or what.pname), **kw) - what.serialize(elt, sw, pyobj, **kw) - def parse(self, elt, ps): #element name must be declared .. nspname,pname = _get_element_nsuri_name(elt) @@ -1700,7 +1489,7 @@ pyclass = _get_type_definition(namespaceURI, typeName) if not pyclass: if _is_xsd_or_soap_ns(namespaceURI): - pyclass = AnyStrict + pyclass = _AnyStrict elif (str(namespaceURI).lower()==str(Apache.Map.type[0]).lower())\ and (str(typeName).lower() ==str(Apache.Map.type[1]).lower()): pyclass = Apache.Map @@ -1720,20 +1509,18 @@ tag -- global element declaration """ tag = (SCHEMA.XSD3, 'any') - + logger = _GetLogger('ZSI.TC.AnyElement') + def __init__(self, namespaces=['#all'],pname=None, - minOccurs=1, maxOccurs=1, strip=1, processContents='strict',**kw): + minOccurs=1, maxOccurs=1, strip=1, processContents='strict', + **kw): + + if processContents not in ('lax', 'skip', 'strict'): + raise ValueError('processContents(%s) must be lax, skip, or strict') + self.processContents = processContents AnyType.__init__(self, namespaces=namespaces,pname=pname, minOccurs=minOccurs, maxOccurs=maxOccurs, strip=strip, **kw) - - def getProcessContents(self, processContents): - return self._processContents - def setProcessContents(self, processContents): - if processContents not in ('lax', 'skip', 'strict'): - raise EvaluateException, '<any> processContents(%s) is not understood.' %processContents - self._processContents = processContents - processContents = property(getProcessContents, setProcessContents, None, '<any> processContents') def serialize(self, elt, sw, pyobj, **kw): '''Must provice typecode to AnyElement for serialization, else @@ -1741,33 +1528,26 @@ based on the data type of pyobj w/o reference to XML schema instance. ''' - what = None - if hasattr(pyobj, 'typecode'): - what = getattr(pyobj, 'typecode') - #May want to look thru containers and try to find a match - elif type(pyobj) == types.InstanceType: + if isinstance(pyobj, TypeCode): + raise TypeError, 'pyobj is a typecode instance.' + + what = getattr(pyobj, 'typecode', None) + if what is not None and type(pyobj) is types.InstanceType: tc = pyobj.__class__ what = Any.serialmap.get(tc) if not what: tc = (types.ClassType, pyobj.__class__.__name__) what = Any.serialmap.get(tc) - if what == None: - if isinstance(pyobj, TypeCode): - raise EvaluateException, '<any> pyobj is a typecode instance.' - #elif type(pyobj) in (list,tuple,dict): - # raise EvaluateException, '<any> can\'t serialize pyobj %s' \ - # %type(pyobj) - elif kw.has_key('pname'): - if self.processContents=='lax': - what = AnyLax(pname=(kw.get('nspname'),kw['pname'])) - else: - what = AnyStrict(pname=(kw.get('nspname'),kw['pname'])) + + # failed to find a registered type for class + if what is None: + #TODO: seems incomplete. what about facets. + if self.processContents == 'strict': + what = _AnyStrict(pname=(self.nspname,self.pname)) else: - if self.processContents=='lax': - what = AnyLax() - else: - what = AnyStrict() - self.logger.debug('AnyElement.serialize with %s', what.__class__.__name__) + what = _AnyLax(pname=(self.nspname,self.pname)) + + self.logger.debug('serialize with %s', what.__class__.__name__) what.serialize(elt, sw, pyobj, **kw) def parse(self, elt, ps): @@ -1778,54 +1558,52 @@ not found return DOM node. 3) if 'strict' get declaration, or raise. ''' + skip = self.processContents == 'skip' nspname,pname = _get_element_nsuri_name(elt) what = _get_global_element_declaration(nspname, pname) - if what is None: - # if self.processContents == 'strict': raise - # Allow use of "<any>" element declarations w/ local element declarations - prefix, typeName = SplitQName(_find_type(elt)) - if typeName: - namespaceURI = _resolve_prefix(elt, prefix or 'xmlns') - # First look thru user defined namespaces, if don't find - # look for 'primitives'. - pyclass = _get_type_definition(namespaceURI, typeName) - if pyclass is None: - if not _is_xsd_or_soap_ns(namespaceURI): - raise EvaluateException('<any> cant find typecode for type (%s,%s)' %( - namespaceURI,typeName), ps.Backtrace(elt)) - if self.getProcessContents=='lax': - pyclass = AnyLax - else: - pyclass = AnyStrict - - what = pyclass(pname=(nspname,pname)) - pyobj = what.parse(elt, ps) - try: - pyobj.typecode = what - except AttributeError, ex: - # Assume this means builtin type. - pyobj = Wrap(pyobj, what) - else: - if self.processContents == 'lax': - what = AnyLax(pname=(nspname,pname)) - else: # processContents == 'skip' - # All else fails, not typed, attempt to use XML, String - what = XML(pname=(nspname,pname), wrapped=False) - try: - pyobj = what.parse(elt, ps) - except EvaluateException, ex: - self.logger.error("Give up, parse (%s,%s) as a String", what.nspname, what.pname) - # Try returning "elt" - what = String(pname=(nspname,pname)) - pyobj = Wrap(what.parse(elt, ps), what) - else: + if not skip and what is not None: pyobj = what.parse(elt, ps) try: pyobj.typecode = what except AttributeError, ex: # Assume this means builtin type. pyobj = _GetPyobjWrapper.Wrap(pyobj, what) + return pyobj + + # Allow use of "<any>" element declarations w/ local + # element declarations + prefix, typeName = SplitQName(_find_type(elt)) + if not skip and typeName: + namespaceURI = _resolve_prefix(elt, prefix or 'xmlns') + # First look thru user defined namespaces, if don't find + # look for 'primitives'. + pyclass = _get_type_definition(namespaceURI, typeName) or Any + what = pyclass(pname=(nspname,pname)) + pyobj = what.parse(elt, ps) + try: + pyobj.typecode = what + except AttributeError, ex: + # Assume this means builtin type. + pyobj = Wrap(pyobj, what) + + what.typed = True + return pyobj + if skip: + what = XML(pname=(nspname,pname), wrapped=False) + elif self.processContents == 'lax': + what = _AnyLax(pname=(nspname,pname)) + else: + what = _AnyStrict(pname=(nspname,pname)) + + try: + pyobj = what.parse(elt, ps) + except EvaluateException, ex: + self.logger.error("Give up, parse (%s,%s) as a String", + what.nspname, what.pname) + what = String(pname=(nspname,pname), typed=False) + pyobj = Wrap(what.parse(elt, ps), what) + return pyobj @@ -1985,7 +1763,7 @@ # No content, no HREF, and is NIL... if self.nillable is True: return Nilled - raise EvaluateException('Non-optional string missing', + raise EvaluateException('Required string missing', ps.Backtrace(elt)) if href[0] != '#': return ps.ResolveHREF(href, self) @@ -2022,6 +1800,115 @@ el.createAppendTextNode(textNode) +class _AnyStrict(Any): + ''' Handles an unspecified types when using a concrete schemas and + processContents = "strict". + ''' + #WARNING: unstable + logger = _GetLogger('ZSI.TC._AnyStrict') + + def __init__(self, pname=None, aslist=False, **kw): + TypeCode.__init__(self, pname=pname, **kw) + self.aslist = aslist + self.unique = True + + def serialize(self, elt, sw, pyobj, name=None, **kw): + if not (type(pyobj) is dict and not self.aslist): + Any.serialize(self, elt=elt,sw=sw,pyobj=pyobj,name=name, **kw) + + raise EvaluateException( + 'Serializing dictionaries not implemented when processContents=\"strict\".' + + 'Try as a list or use processContents=\"lax\".' + ) + + +class _AnyLax(Any): + ''' Handles unspecified types when using a concrete schemas and + processContents = "lax". + ''' + logger = _GetLogger('ZSI.TC._AnyLax') + + def __init__(self, pname=None, aslist=False, **kw): + TypeCode.__init__(self, pname=pname, **kw) + self.aslist = aslist + self.unique = True + + def parse_into_dict_or_list(self, elt, ps): + c = _child_elements(elt) + count = len(c) + v = [] + if count == 0: + href = _find_href(elt) + if not href: return {} + elt = ps.FindLocalHREF(href, elt) + self.checktype(elt, ps) + c = _child_elements(elt) + count = len(c) + if count == 0: return self.listify([]) + if self.nilled(elt, ps): return Nilled + + # group consecutive elements with the same name together + # We treat consecutive elements with the same name as lists. + groupedElements = [] # tuples of (name, elementList) + previousName = "" + currentElementList = None + for ce in _child_elements(elt): + name = ce.localName + if (name != previousName): # new name, so new group + if currentElementList != None: # store previous group if there is one + groupedElements.append( (previousName, currentElementList) ) + currentElementList = list() + currentElementList.append(ce) # append to list + previousName = name + # add the last group if necessary + if currentElementList != None: # store previous group if there is one + groupedElements.append( (previousName, currentElementList) ) + + # parse the groups of names + if len(groupedElements) < 1: # should return earlier + return None + # return a list if there is one name and multiple data + elif (len(groupedElements) == 1) and (len(groupedElements[0][0]) > 1): + self.aslist = False + # else return a dictionary + + for name,eltList in groupedElements: + lst = [] + for elt in eltList: + #aslist = self.aslist + lst.append( self.parse(elt, ps) ) + #self.aslist = aslist # restore the aslist setting + if len(lst) > 1: # consecutive elements with the same name means a list + v.append( (name, lst) ) + elif len(lst) == 1: + v.append( (name, lst[0]) ) + + return self.listify(v) + + def checkname(self, elt, ps): + '''See if the name and type of the "elt" element is what we're + looking for. Return the element's type. + Since this is _AnyLax, it's ok if names don't resolve. + ''' + + parselist,errorlist = self.get_parse_and_errorlist() + ns, name = _get_element_nsuri_name(elt) + if ns == SOAP.ENC: + if parselist and \ + (None, name) not in parselist and (ns, name) not in parselist: + raise EvaluateException( + 'Element mismatch (got %s wanted %s) (SOAP encoding namespace)' % \ + (name, errorlist), ps.Backtrace(elt)) + return (ns, name) + + # Not a type, check name matches. + if self.nspname and ns != self.nspname: + raise EvaluateException('Element NS mismatch (got %s wanted %s)' % \ + (ns, self.nspname), ps.Backtrace(elt)) + + return self.checktype(elt, ps) + + class _Mirage: '''Used with SchemaInstanceType for lazy evaluation, eval during serialize or parse as needed. Mirage is callable, TypeCodes are not. When called it returns the @@ -2042,16 +1929,6 @@ if issubclass(self.klass, ElementDeclaration): msg = "<Mirage id=%s, GED %s>" return msg %(id(self), self.klass) - -# def __getattr__(self, attr): -# '''try to look just like the typecode. -# ''' -# if self.__reveal is False: -# if self.__cache is None: self.__call__() -# return getattr(self.__cache, attr) -# -# raise AttributeError('Missing attribute "%s", mirage must hide item before it can be revealed' % -# attr) def _hide_type(self, pname, aname, minOccurs=0, maxOccurs=1, nillable=False, **kw): @@ -2106,21 +1983,36 @@ and thus can be serialized. ''' types_dict = {} - for builtin_type in [int,float,str,tuple,list,unicode]: - class Wrapper(builtin_type): pass - types_dict[builtin_type] = Wrapper - + + def RegisterBuiltin(cls, arg): + '''register a builtin, create a new wrapper. + ''' + if arg in cls.types_dict: + raise RuntimeError, '%s already registered' %arg + class _Wrapper(arg): + 'Wrapper for builtin %s\n%s' %(arg, cls.__doc__) + _Wrapper.__name__ = '_%sWrapper' %arg + cls.types_dict[arg] = _Wrapper + RegisterBuiltin = classmethod(RegisterBuiltin) + def RegisterAnyElement(cls): + '''clobber all existing entries in Any serialmap, + replace with Wrapper classes. + ''' for k,v in cls.types_dict.items(): what = Any.serialmap.get(k) if what is None: continue - if v in what.__class__.seriallist: - continue + if v in what.__class__.seriallist: continue what.__class__.seriallist.append(v) RegisterType(what.__class__, clobber=1) RegisterAnyElement = classmethod(RegisterAnyElement) def Wrap(cls, pyobj, what): + '''return a wrapper for pyobj, with typecode attribute set. + Parameters: + pyobj -- instance of builtin type (immutable) + what -- typecode describing the data + ''' d = cls.types_dict if type(pyobj) is bool: pyclass = d[int] @@ -2128,7 +2020,8 @@ pyclass = d[type(pyobj)] else: raise TypeError,\ - 'Expecting a built-in type in %s (got %s).' %(d.keys(),type(pyobj)) + 'Expecting a built-in type in %s (got %s).' %( + d.keys(),type(pyobj)) newobj = pyclass(pyobj) newobj.typecode = what @@ -2137,12 +2030,61 @@ def Wrap(pyobj, what): + '''Wrap immutable instance so a typecode can be + set, making it self-describing ie. serializable. + ''' return _GetPyobjWrapper.Wrap(pyobj, what) + +def RegisterBuiltin(arg): + '''Add a builtin to be registered, and register it + with the Any typecode. + ''' + _GetPyobjWrapper.RegisterBuiltin(arg) + _GetPyobjWrapper.RegisterAnyElement() + + def RegisterAnyElement(): + '''register all Wrapper classes with the Any typecode. + This allows instances returned by Any to be self-describing. + ie. serializable. AnyElement falls back on Any to parse + anything it doesn't understand. + ''' return _GetPyobjWrapper.RegisterAnyElement() +def RegisterType(C, clobber=0, *args, **keywords): + instance = apply(C, args, keywords) + for t in C.__dict__.get('parselist', []): + prev = Any.parsemap.get(t) + if prev: + if prev.__class__ == C: continue + if not clobber: + raise TypeError( + str(C) + ' duplicating parse registration for ' + str(t)) + Any.parsemap[t] = instance + for t in C.__dict__.get('seriallist', []): + ti = type(t) + if ti in [ types.TypeType, types.ClassType]: + key = t + elif ti in _stringtypes: + key = (types.ClassType, t) + else: + raise TypeError(str(t) + ' is not a class name') + prev = Any.serialmap.get(key) + if prev: + if prev.__class__ == C: continue + if not clobber: + raise TypeError( + str(C) + ' duplicating serial registration for ' + str(t)) + Any.serialmap[key] = instance + + +# Load up Wrappers for builtin types +for i in [int,float,str,tuple,list,unicode]: + _GetPyobjWrapper.RegisterBuiltin(i) + + from TCnumbers import * from TCtimes import * from TCcompound import * Modified: trunk/zsi/ZSI/TCcompound.py =================================================================== --- trunk/zsi/ZSI/TCcompound.py 2006-10-11 22:58:45 UTC (rev 1264) +++ trunk/zsi/ZSI/TCcompound.py 2006-10-13 00:12:32 UTC (rev 1265) @@ -5,7 +5,8 @@ from ZSI import _copyright, _children, _child_elements, \ _inttypes, _stringtypes, _seqtypes, _find_arraytype, _find_href, \ - _find_type, _find_xmlns_prefix, _get_idstr, EvaluateException + _find_type, _find_xmlns_prefix, _get_idstr, EvaluateException, \ + ParseException from ZSI.TC import _get_element_nsuri_name, \ _get_substitute_element, _get_type_definition, _get_xsitype, \ TypeCode, Any, AnyElement, AnyType, ElementDeclaration, TypeDefinition, \ @@ -25,6 +26,8 @@ '''Check a list of typecodes for compliance with Struct requirements.''' for o in ofwhat: + if callable(o): #skip if _Mirage + continue if not isinstance(o, TypeCode): raise TypeError( tcname + ' ofwhat outside the TypeCode hierarchy, ' + @@ -408,11 +411,13 @@ if debug and what is not whatTC: self.logger.debug('substitute derived type: %s' % what.__class__) - 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))) + + 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(\ @@ -426,13 +431,15 @@ if debug and what is not whatTC: self.logger.debug('substitute derived type: %s' % what.__class__) - - try: - what.serialize(elem, sw, v, **kw) - except Exception, e: - raise EvaluateException('Serializing %s.%s, %s %s' % - (n, whatTC.aname or '?', e.__class__.__name__, str(e)), - sw.Backtrace(elt)) + 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' % Modified: trunk/zsi/ZSI/__init__.py =================================================================== --- trunk/zsi/ZSI/__init__.py 2006-10-11 22:58:45 UTC (rev 1264) +++ trunk/zsi/ZSI/__init__.py 2006-10-13 00:12:32 UTC (rev 1265) @@ -177,8 +177,8 @@ try: from xml.dom import EMPTY_NAMESPACE _empty_nsuri_list = [ EMPTY_NAMESPACE ] - if '' not in _empty_nsuri_list: __empty_nsuri_list.append('') - if None not in _empty_nsuri_list: __empty_nsuri_list.append(None) + #if '' not in _empty_nsuri_list: __empty_nsuri_list.append('') + #if None not in _empty_nsuri_list: __empty_nsuri_list.append(None) except: _empty_nsuri_list = [ None, '' ] def _find_attr(E, attr): @@ -226,7 +226,7 @@ _find_xmlns_prefix = lambda E, attr: E.getAttributeNS(_XMLNS.BASE, attr) _find_default_namespace = lambda E: E.getAttributeNS(_XMLNS.BASE, None) -_textprotect = lambda s: s.replace('&', '&').replace('<', '<') +#_textprotect = lambda s: s.replace('&', '&').replace('<', '<') _get_element_nsuri_name = lambda E: (E.namespaceURI, E.localName) Modified: trunk/zsi/ZSI/parse.py =================================================================== --- trunk/zsi/ZSI/parse.py 2006-10-11 22:58:45 UTC (rev 1264) +++ trunk/zsi/ZSI/parse.py 2006-10-13 00:12:32 UTC (rev 1265) @@ -34,15 +34,15 @@ ''' defaultReaderClass = None - def __init__(self, input, readerclass=None, keepdom=0, - trailers=0, resolver=None, envelope=True, **kw): + def __init__(self, input, readerclass=None, keepdom=False, + trailers=False, resolver=None, envelope=True, **kw): '''Initialize. Keyword arguments: trailers -- allow trailer elments (default is zero) resolver -- function (bound method) to resolve URI's readerclass -- factory class to create a reader keepdom -- do not release the DOM - envelope -- do not loop for a SOAP envelope. + envelope -- look for a SOAP envelope. ''' self.readerclass = readerclass Modified: trunk/zsi/doc/c03-except.tex =================================================================== --- trunk/zsi/doc/c03-except.tex 2006-10-11 22:58:45 UTC (rev 1264) +++ trunk/zsi/doc/c03-except.tex 2006-10-13 00:12:32 UTC (rev 1265) @@ -1,12 +1,13 @@ \chapter{Exceptions} \begin{excdesc}{ZSIException} -Base class for all ZSI Exceptions. +Base class for all ZSI Exceptions, it is a subtype of the Python +\exception{Exception} class. \end{excdesc} \begin{excdesc}{ParseException} \ZSI{} can raise this exception while creating a \class{ParsedSoap} object. -It is a subtype of Python's \exception{Exception} class. +It is a subtype of the \exception{ZSIException} class. The string form of a \exception{ParseException} object consists of a line of human-readable text. If the backtrace is available, it will be concatenated as a second line. Modified: trunk/zsi/doc/c06-tc.tex =================================================================== --- trunk/zsi/doc/c06-tc.tex 2006-10-11 22:58:45 UTC (rev 1264) +++ trunk/zsi/doc/c06-tc.tex 2006-10-13 00:12:32 UTC (rev 1265) @@ -10,68 +10,55 @@ All typecodes classes have the prefix \code{TC.}, to avoid name clashes. \ZSI{} provides fine-grain control over the names used when parsing and -serializing XML into local Python objects, through the use of three -attributes: the \code{pname}, the \code{aname}, and the \code{oname} -(in approximate order of importance). They specify the name expected on -the XML element being parsed, the name to use for the analogous attribute -in the local Python object, and the name to use for the output element -when serializing. +serializing XML into local Python objects, through the use of two +attributes: the \code{pname}, the \code{aname}. The \code{pname} specifies the +name expected on the XML element being parsed and the name to use for the output element +when serializing. The \code{aname} is the name to use for the analogous +attribute in the local Python object. The \code{pname} is the parameter name. It specifies the incoming XML element name and the default values for the Python attribute -and serialized names. All typecodes take name argument, known as -\code{name}, for the \code{pname}. This name can be specified as -either a list or a string. When specified as a list, it must have two -elements which are interpreted as a ``(namespace-URI, localname)'' pair. +and serialized names. All typecodes take the \code{pname} argument. This name can be +specified as either a list or a string. When specified as a list, it must have +two elements which are interpreted as a ``(namespace-URI, localname)'' pair. If specified this way, both the namespace and the local element name must match for the parse to succeed. For the Python attribute, and -when generating output, only the ``localname'' is used. (Because the -output name is not namespace-qualified, it may be necessary to set the -default namespace, such as through the \code{nsdict} parameter of the -\class{SoapWriter} class. When the name is specified as a string, it -can be either a simple XML name (such as ``foo''), or a colon-separated -XML qualified name (such as ``tns:foo''). If a qualified name is used, -the namespace prefix is ignore on input and for the Python attribute, -but the full qualified name is used for output; this \emph{requires} -the namespace prefix to be specified. +when generating output, only the ``localname'' is used. If a namespace-URI is +specified then the full qualified name is used for output, and it is required +for input; this \emph{requires} the namespace prefix to be specified. The \code{aname} is the attribute name. This parameter overrides -any value implied by the \code{pname}. Typecodes nested in a the -\class{TC.Struct} or \class{TC.Choice} can use this parameter to specify +any value implied by the \code{pname}. Typecodes nested in a \class{TC.Struct} +or \class{TC.ComplexType} can use this parameter to specify the tag, dictionary key, or instance attribute to set. -The final name, \code{oname}, specifies the name to use for the XML element -when serializing. This is most useful when using the same typecode for -both parsing and serializing operations. It can be any string, and is -output directly; a name like ``tns:foo'' implies that the \code{nsdict} -parameter to the \class{SoapWriter} construct should have an entry for -``tns,'' otherwise the resulting output will not be well-formed XML. +The \code{nsdict} parameter to the \class{SoapWriter} construct can be used to +specify prefix to namespace-URI mappings, these are otherwise handled automatically. -\begin{classdesc}{TypeCode}{name, **keywords} -The \code{name} parameter is the name of the object; this is only -required when a typecode appears within a \class{TC.Struct} as it defines -the attribute name used to hold the data, or within a \class{TC.Choice} -as it determines the data type. -(Since SOAP RPC models transfer as structures, this essentially means that -a the \code{name} parameter can never be \code{None}.) +\begin{classdesc}{TypeCode}{**keywords} +The \code{pname} The following keyword arguments may be used: \begin{tableiii}{l|c|p{30em}}{textrm}{Keyword}{Default}{Description} -\lineiii{\code{aname}}{\-}{See name discussion above.} -\lineiii{\code{default}}{n/a}{Value if the element is not specified.} -\lineiii{\code{optional}}{\code{0}}{The element is optional; see below.} -\lineiii{\code{oname}}{\-}{See name discussion above.} -\lineiii{\code{repeatable}}{\code{0}}{If multiple instances of this -occur in a \class{TC.Struct}, collect the values into a list. -\versionadded{1.2}} -\lineiii{\code{typed}}{\code{1}}{Output type information (in the -\code{xsi:type} attribute) when serializing. By special dispensation, -typecodes within a \class{TC.Struct} object inherit this from the -container.} +\lineiii{\code{pname}}{\code{None}}{parameter name of the object} +\lineiii{\code{aname}}{\code{None}}{attribute name of the object} +\lineiii{\code{minOccurs}}{\code{1}}{schema facet minimum occurances} +\lineiii{\code{maxOccurs}}{\code{1}}{schema facet maximum occurances} +\lineiii{\code{nillable}}{\code{False}}{schema facet is this nillable (\code{xsi:nil="true"})} +\lineiii{\code{typed}}{\code{True}}{Output type information (in the \code{xsi:type} +attribute) when serializing. By special dispensation, typecodes within a +\class{TC.Struct} object inherit this from the container.} \lineiii{\code{unique}}{\code{0}}{If true, the object is unique and will never be ``aliased'' with another object, so the \code{id} attribute need not be output.} + +\lineiii{\code{pyclass}}{\code{None}}{when parsing data, instances of this class +can be created to store the data. Default behavior is reflective of specific +TypeCode classes.} +\lineiii{\code{attrs_aname}}{\code{'_attrs'}}{attribute name of the object where +attribute values are stored. Used for serialization and parsing.} + \end{tableiii} Optional elements are those which do not have to be an incoming @@ -91,17 +78,26 @@ rigorous type-checking on their parameters. \end{memberdesc} -\begin{memberdesc}{typed} +\begin{memberdesc}{tag} This is a class attribute. -This sets the default value for whether or not typecodes output -typing (\code{xsi:type} attribute) information. -The default is none-zero. +Specifies the global element declaration this typecode represents, the value is +a \samp{(namespace, name)} tuple. \end{memberdesc} +\begin{memberdesc}{type} +This is a class attribute. +Specifies the global type definition this typecode represents, the value is +a \samp{(namespace, name)} tuple. +\end{memberdesc} + +\begin{memberdesc}{logger} +This is a class attribute. +logger instance for this class. +\end{memberdesc} + The following methods are useful for defining new typecode classes; -see the section on dynamic typing for more details. -In all of the following, the \code{ps} parameter is a \class{ParsedSoap} -object. +see the section on dynamic typing for more details. In all of the following, +the \code{ps} parameter is a \class{ParsedSoap} object. \begin{methoddesc}{checkname}{elt, ps} Checks if the name and type of the element \code{elt} are @@ -117,16 +113,19 @@ \end{methoddesc} \begin{methoddesc}{nilled}{elt, ps} -If the element \code{elt} has data, this returns \code{0}. +If the element \code{elt} has data, this returns \code{False}. If it has no data, and the typecode is not optional, an \exception{EvaluateException} is raised; if it is optional, -a \code{1} is returned. +a \code{True} is returned. \end{methoddesc} -\begin{methoddesc}{simple_value}{elt, ps} +\begin{methoddesc}{simple_value}{elt, ps, mixed=False} Returns the text content of the element \code{elt}. If no value is present, or the element has non-text children, an -\exception{EvaluateException} is raised. +\exception{EvaluateException} is raised. If \code{mixed} is \code{False} if +child elements are discovered an \exception{EvaluateException} is raised, else +join all text nodes and return the result. + \end{methoddesc} \section{\class{TC.Any} --- the basis of dynamic typing} @@ -136,9 +135,10 @@ schema. For example, the following are all possible ways of encoding an integer element \code{i} with a value of \code{12}: +\subsection{simple data} -- requires type information \begin{verbatim} <tns:i xsi:type="SOAP-ENC:integer">12</tns:i> -<tns:i xsi:type="xsi:nonNegativeInteger">12</tns:i> +<tns:i xsi:type="xsd:nonNegativeInteger">12</tns:i> <SOAP-ENC:integer>12</SOAP-ENC:integer> <tns:i>12</tns:i> \end{verbatim} @@ -146,19 +146,20 @@ The first three lines are examples of \emph{typed} elements. If \ZSI{} is asked to parse any of the above examples, and a \class{TC.Any} typecode is given, it will properly create a Python -integer for the first three, and raise a \exception{ParseException} +integer for the first three, and raise a \exception{EvaluateException} for the fourth. +\subsection{compound data} -- Struct or Array Compound data, such as a \code{struct}, may also be self-describing: \begin{verbatim} -<tns:foo xsi:type="tns:mytype"> +<tns:foo> <tns:i xsi:type="SOAP-ENC:integer">12</tns:i> <tns:name xsi:type="SOAP-ENC:string">Hello world</tns:name> </tns:foo> \end{verbatim} -If this is parsed with a \class{TC.Any} typecode, either a Python dictionary -or a sequence will be created: +If this is parsed with a \class{TC.Any} typecode, either a Python \code{dict} +is created or if \code{aslist} is True a \code{list}: \begin{verbatim} { 'name': u'Hello world', 'i': 12 } @@ -166,6 +167,7 @@ \end{verbatim} Note that one preserves order, while the other preserves the element names. +\subsection{class description} \begin{classdesc}{Any}{name\optional{, **keywords}} Used for parsing incoming SOAP data (that is typed), and serializing outgoing Python data. @@ -173,7 +175,7 @@ The following keyword arguments may be used: \begin{tableiii}{l|c|p{30em}}{textrm}{Keyword}{Default}{Description} -\lineiii{\code{aslist}}{\code{0}}{If true, then the data is (recursively) +\lineiii{\code{aslist}}{\code{False}}{If true, then the data is (recursively) treated as a list of values. The default is a Python dictionary, which preserves parameter names but loses the ordering. @@ -270,16 +272,6 @@ processed as dynamic types. This may be acceptable in some environments. -\section{Void} - -A SOAP void is a Python \code{None}. - -\begin{classdesc}{Void}{name\optional{, **keywords}} -A \code{Void} is an item without a value. -It is of marginal utility, mainly useful for interoperability tests, and -as an optional item within a \code{Struct}. -\end{classdesc} - \section{Strings} SOAP Strings are Python strings. This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <bov...@us...> - 2006-10-13 23:35:33
|
Revision: 1266 http://svn.sourceforge.net/pywebsvcs/?rev=1266&view=rev Author: boverhof Date: 2006-10-13 16:35:29 -0700 (Fri, 13 Oct 2006) Log Message: ----------- M test/test_t8.py M ZSI/TCnumbers.py M ZSI/TC.py M ZSI/TCcompound.py M doc/c06-tc.tex -- added some of the examples to unittest code -- some cleanup in code, remove outdated stuff, comments, use booleans. -- updates to Typecode chapter Modified Paths: -------------- trunk/zsi/ZSI/TC.py trunk/zsi/ZSI/TCcompound.py trunk/zsi/ZSI/TCnumbers.py trunk/zsi/doc/c06-tc.tex trunk/zsi/test/test_t8.py Modified: trunk/zsi/ZSI/TC.py =================================================================== --- trunk/zsi/ZSI/TC.py 2006-10-13 00:12:32 UTC (rev 1265) +++ trunk/zsi/ZSI/TC.py 2006-10-13 23:35:29 UTC (rev 1266) @@ -842,7 +842,7 @@ type = (SCHEMA.XSD3, 'string') logger = _GetLogger('ZSI.TC.String') - def __init__(self, pname=None, strip=1, **kw): + def __init__(self, pname=None, strip=True, **kw): TypeCode.__init__(self, pname, **kw) if kw.has_key('resolver'): self.resolver = kw['resolver'] self.strip = strip @@ -852,7 +852,7 @@ ''' if self.strip: text = text.strip() if self.pyclass is not None: - return self.pyclass(text) + return self.pyclass(text) return text def get_formatted_content(self, pyobj): @@ -1047,7 +1047,14 @@ ps.Backtrace(elt)) return val + def serialize(self, elt, sw, pyobj, name=None, orig=None, **kw): + if pyobj not in self.choices: + raise EvaluateException('Value not in enumeration list', + ps.Backtrace(elt)) + String.serialize(self, elt, sw, pyobj, name=name, orig=orig, **kw) + + # This is outside the Integer class purely for code esthetics. _ignored = [] Modified: trunk/zsi/ZSI/TCcompound.py =================================================================== --- trunk/zsi/ZSI/TCcompound.py 2006-10-13 00:12:32 UTC (rev 1265) +++ trunk/zsi/ZSI/TCcompound.py 2006-10-13 23:35:29 UTC (rev 1266) @@ -96,10 +96,9 @@ logger = _GetLogger('ZSI.TCcompound.ComplexType') def __init__(self, pyclass, ofwhat, pname=None, inorder=False, inline=False, - mutable=True, hasextras=0, mixed=False, mixed_aname='_text', **kw): + 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 - hasextras -- ignore extra input fields inorder -- fields must be in exact order or not inline -- don't href/id when serializing mutable -- object could change between multiple serializations @@ -117,7 +116,6 @@ self.mixed_aname = mixed_aname if self.mutable is True: self.inline = True - self.hasextras = hasextras self.type = kw.get('type') or _get_xsitype(self) t = type(ofwhat) if t not in _seqtypes: @@ -158,16 +156,6 @@ c = _child_elements(elt) count = len(c) if self.nilled(elt, ps): return Nilled -# repeatable_args = False -# for tc in self.ofwhat: -# if tc.maxOccurs > 1: -# repeatable_args = True -# break -# -# if not repeatable_args: -# if count > len(self.ofwhat) and not self.hasextras: -# raise EvaluateException('Too many sub-elements (%d>%d)' %( -# count,len(self.ofwhat)), ps.Backtrace(elt)) # Create the object. v = {} @@ -268,11 +256,7 @@ # type definition must be informed of element tag (nspname,pname), # element declaration is initialized with a tag. try: - if issubclass(self.pyclass, ElementDeclaration) is False and\ - issubclass(self.pyclass, TypeDefinition) is True: - pyobj = self.pyclass((self.nspname,self.pname)) - else: - pyobj = self.pyclass() + 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))) @@ -469,7 +453,7 @@ class Struct(ComplexType): '''Struct is a complex type for accessors identified by name. - Constraint: No element may be have the same name as any other, + Constraint: No element may have the same name as any other, nor may any element have a maxOccurs > 1. <xs:group name="Struct" > @@ -486,17 +470,16 @@ logger = _GetLogger('ZSI.TCcompound.Struct') def __init__(self, pyclass, ofwhat, pname=None, inorder=False, inline=False, - mutable=True, hasextras=0, **kw): + mutable=True, **kw): '''pyclass -- the Python class to hold the fields ofwhat -- a list of fields to be in the struct - hasextras -- ignore extra input fields 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, - hasextras=hasextras, **kw + **kw ) # Check Constraints @@ -533,7 +516,7 @@ raise TypeError("Only single-dimensioned arrays supported") self.fill = fill self.sparse = sparse - if self.sparse: ofwhat.optional = 1 + #if self.sparse: ofwhat.minOccurs = 0 self.mutable = mutable self.size = size self.nooffset = nooffset Modified: trunk/zsi/ZSI/TCnumbers.py =================================================================== --- trunk/zsi/ZSI/TCnumbers.py 2006-10-13 00:12:32 UTC (rev 1265) +++ trunk/zsi/ZSI/TCnumbers.py 2006-10-13 23:35:29 UTC (rev 1266) @@ -126,6 +126,13 @@ ps.Backtrace(elt)) return val + def serialize(self, elt, sw, pyobj, name=None, orig=None, **kw): + if pyobj not in self.choices: + raise EvaluateException('Value not in int enumeration list', + ps.Backtrace(elt)) + Integer.serialize(self, elt, sw, pyobj, name=name, orig=orig, **kw) + + class FPfloat(Decimal): '''IEEE 32bit floating point value. ''' @@ -166,5 +173,12 @@ '" not in enumeration list', ps.Backtrace(elt)) return val + + def serialize(self, elt, sw, pyobj, name=None, orig=None, **kw): + if pyobj not in self.choices: + raise EvaluateException('Value not in int enumeration list', + ps.Backtrace(elt)) + Decimal.serialize(self, elt, sw, pyobj, name=name, orig=orig, **kw) + if __name__ == '__main__': print _copyright Modified: trunk/zsi/doc/c06-tc.tex =================================================================== --- trunk/zsi/doc/c06-tc.tex 2006-10-13 00:12:32 UTC (rev 1265) +++ trunk/zsi/doc/c06-tc.tex 2006-10-13 23:35:29 UTC (rev 1266) @@ -35,9 +35,11 @@ The \code{nsdict} parameter to the \class{SoapWriter} construct can be used to specify prefix to namespace-URI mappings, these are otherwise handled automatically. +\section{\class{TC.TypeCode}} + +The \class{TypeCode} class is the parent class of all typecodes. + \begin{classdesc}{TypeCode}{**keywords} -The \code{pname} - The following keyword arguments may be used: \begin{tableiii}{l|c|p{30em}}{textrm}{Keyword}{Default}{Description} @@ -150,7 +152,8 @@ for the fourth. \subsection{compound data} -- Struct or Array -Compound data, such as a \code{struct}, may also be self-describing: +Compound data, such as a \code{struct}, may also be self-describing (namespace +are omitted for clarity): \begin{verbatim} <tns:foo> <tns:i xsi:type="SOAP-ENC:integer">12</tns:i> @@ -161,8 +164,11 @@ If this is parsed with a \class{TC.Any} typecode, either a Python \code{dict} is created or if \code{aslist} is True a \code{list}: \begin{verbatim} +ps = ParsedSoap(xml, envelope=False) +print ps.Parse(TC.Any()) { 'name': u'Hello world', 'i': 12 } +print ps.Parse(TC.Any(aslist=True)) [ 12, u'Hello world' ] \end{verbatim} Note that one preserves order, while the other preserves the element names. @@ -193,8 +199,18 @@ This class would know that the \code{i} element is an integer, so that the explicit typing becomes optional, rather than required. -The rest of this section describes how to add new -types to the \ZSI{} typecode engine. +\subsection{Adding new types} Most of the \class{TypeCodes} classes in +\module{TC} are registered with \class{Any}, making an instance of itself +available for dynamic typing. New \class{TypeCode} classes can be created and +registered with \class{Any} by using \function{RegisterType}. In order to +override an existing entry in the registry call \function{RegisterType} with +\code{clobber=True}. The serialization entries are mappings between builtin +Python types and a \class{TypeCode} instance, it is not possible to have one +Python type map to multiple typecodes. The parsing entries are mappings +between \code{(namespaceURI,name)} tuples, representing the \code{xsi:type} +attribute, and a \class{TypeCode} instance. Thus, only one instance of a +\class{TypeCode} class can represent a XML Schema type. So this mechanism is +not appropriate for representing XML Schema element information. \begin{classdesc}{\emph{NEWTYPECODE}(TypeCode)}{...} The new typecode should be derived from the \class{TC.TypeCode} class, and @@ -272,15 +288,21 @@ processed as dynamic types. This may be acceptable in some environments. +\section{\class{TC.SimpleType}} +Parent class of all simple types. + +\begin{memberdesc}{empty_content} +This is a class attribute. +Value returned when tag or node is present, is not nilled, and without text +content. +\end{memberdesc} + \section{Strings} -SOAP Strings are Python strings. -If the value to be serialized is a Python sequence, then an \code{href} -is generated, with the first element of the sequence used as the URI. -This can be used, for example, when generating SOAP with attachments. +SOAP/XMLSchema Strings are Python strings. \begin{classdesc}{String}{name\optional{, **keywords}} -The parent type of all SOAP strings. +The parent type of all strings. The following keyword arguments may be used: @@ -288,17 +310,14 @@ \lineiii{\code{resolver}}{\code{None}}{A function that can resolve an absolute URI and return its content as a string, as described in the \class{ParsedSoap} description.} -\lineiii{\code{strip}}{\code{1}}{If true, leading and trailing whitespace +\lineiii{\code{strip}}{\code{True}}{If true, leading and trailing whitespace are stripped from the content.} -\lineiii{\code{textprotect}}{\code{1}}{If true, less-than and ampersand -characters are replaced with \code{\<} and \code{\&}, respectively. -\versionadded{1.1}} \end{tableiii} \end{classdesc} \begin{classdesc}{Enumeration}{value_list, name\optional{, **keywords}} Like \class{TC.String}, but the value must be a member of -the \code{value_list} sequence of text strings +the \code{choices} sequence of text strings \end{classdesc} In addition to \class{TC.String}, @@ -374,9 +393,9 @@ \section{Integers} -SOAP integers are Python integers. +SOAP/XMLSchema integers are Python integers. -\begin{classdesc}{Integer}{name\optional{, **keywords}} +\begin{classdesc}{Integer}{\optional{**keywords}} The parent type of all integers. This class handles any of the several types (and ranges) of SOAP integers. @@ -388,66 +407,66 @@ \end{tableiii} \end{classdesc} -\begin{classdesc}{IEnumeration}{value_list, name\optional{, **keywords}} +\begin{classdesc}{IEnumeration}{choices\optional{, **keywords}} Like \class{TC.Integer}, but the value must be a member of -the \code{value_list} sequence. +the \code{choices} sequence. \end{classdesc} A number of sub-classes are defined to handle smaller-ranged numbers. -\begin{classdesc}{Ibyte}{name\optional{, **keywords}} +\begin{classdesc}{Ibyte}{\optional{**keywords}} A signed eight-bit value. \end{classdesc} -\begin{classdesc}{IunsignedByte}{name\optional{, **keywords}} +\begin{classdesc}{IunsignedByte}{\optional{**keywords}} An unsigned eight-bit value. \end{classdesc} -\begin{classdesc}{Ishort}{name\optional{, **keywords}} +\begin{classdesc}{Ishort}{\optional{**keywords}} A signed 16-bit value. \end{classdesc} -\begin{classdesc}{IunsignedShort}{name\optional{, **keywords}} +\begin{classdesc}{IunsignedShort}{\optional{**keywords}} An unsigned 16-bit value. \end{classdesc} -\begin{classdesc}{Iint}{name\optional{, **keywords}} +\begin{classdesc}{Iint}{\optional{**keywords}} A signed 32-bit value. \end{classdesc} -\begin{classdesc}{IunsignedInt}{name\optional{, **keywords}} +\begin{classdesc}{IunsignedInt}{\optional{**keywords}} An unsigned 32-bit value. \end{classdesc} -\begin{classdesc}{Ilong}{name\optional{, **keywords}} +\begin{classdesc}{Ilong}{\optional{**keywords}} An signed 64-bit value. \end{classdesc} -\begin{classdesc}{IunsignedLong}{name\optional{, **keywords}} +\begin{classdesc}{IunsignedLong}{\optional{**keywords}} An unsigned 64-bit value. \end{classdesc} -\begin{classdesc}{IpositiveInteger}{name\optional{, **keywords}} +\begin{classdesc}{IpositiveInteger}{\optional{**keywords}} A value greater than zero. \end{classdesc} -\begin{classdesc}{InegativeInteger}{name\optional{, **keywords}} +\begin{classdesc}{InegativeInteger}{\optional{**keywords}} A value less than zero. \end{classdesc} -\begin{classdesc}{InonPositiveInteger}{name\optional{, **keywords}} +\begin{classdesc}{InonPositiveInteger}{\optional{**keywords}} A value less than or equal to zero. \end{classdesc} -\begin{classdesc}{InonNegativeInteger}{name\optional{, **keywords}} +\begin{classdesc}{InonNegativeInteger}{\optional{**keywords}} A value greater than or equal to zero. \end{classdesc} \section{Floating-point Numbers} -SOAP floating point numbers are Python floats. +SOAP/XMLSchema floating point numbers are Python floats. -\begin{classdesc}{Decimal}{name\optional{, **keywords}} +\begin{classdesc}{Decimal}{\optional{**keywords}} The parent type of all floating point numbers. This class handles any of the several types (and ranges) of SOAP floating point numbers. @@ -515,43 +534,43 @@ When serializing, an integral or floating point number is taken as the number of seconds since the epoch, in UTC. -\begin{classdesc}{Duration}{name\optional{, **keywords}} +\begin{classdesc}{Duration}{\optional{**keywords}} A relative time period. Negative durations have all values less than zero; this makes it easy to add a duration to a Python time tuple. \end{classdesc} -\begin{classdesc}{Gregorian}{name\optional{, **keywords}} +\begin{classdesc}{Gregorian}{\optional{**keywords}} An absolute time period. This class should not be instantiated directly; use one of the \code{gXXX} classes instead. \end{classdesc} -\begin{classdesc}{gDateTime}{name\optional{, **keywords}} +\begin{classdesc}{gDateTime}{\optional{**keywords}} A date and time. \end{classdesc} -\begin{classdesc}{gDate}{name\optional{, **keywords}} +\begin{classdesc}{gDate}{\optional{**keywords}} A date. \end{classdesc} -\begin{classdesc}{gYearMonth}{name\optional{, **keywords}} +\begin{classdesc}{gYearMonth}{\optional{**keywords}} A year and month. \end{classdesc} -\begin{classdesc}{gYear}{name\optional{, **keywords}} +\begin{classdesc}{gYear}{\optional{**keywords}} A year. \end{classdesc} -\begin{classdesc}{gMonthDay}{name\optional{, **keywords}} +\begin{classdesc}{gMonthDay}{\optional{**keywords}} A month and day. \end{classdesc} -\begin{classdesc}{gDay}{name\optional{, **keywords}} +\begin{classdesc}{gDay}{\optional{**keywords}} A day. \end{classdesc} -\begin{classdesc}{gTime}{name\optional{, **keywords}} +\begin{classdesc}{gTime}{\optional{**keywords}} A time. \end{classdesc} @@ -559,7 +578,7 @@ SOAP Booleans are Python integers. -\begin{classdesc}{Boolean}{name\optional{, **keywords}} +\begin{classdesc}{Boolean}{\optional{**keywords}} When marshaling zero or the word ``false'' is returned as \code{0} and any non-zero value or the word ``true'' is returned as \code{1}. When serializing, the number \code{0} or \code{1} will be generated. @@ -583,7 +602,7 @@ Note that it is generally more efficient to keep the \class{ParsedSoap} object alive until the XML data is no longerneeded. -\begin{classdesc}{XML}{name\optional{, **keywords}} +\begin{classdesc}{XML}{\optional{**keywords}} This typecode represents a portion of an XML document embedded in a SOAP message. The value is the element node. @@ -616,37 +635,31 @@ identifying the namespace prefixes that should be output.} \end{tableiii} -\section{Struct} +\section{ComplexType} -SOAP structs are either Python dictionaries or -instances of application-specified classes. +Represents the XMLSchema ComplexType . +\versionadded{2.0} -\begin{classdesc}{Struct}{pyclass, typecode_seq, name\optional{, **keywords}} +\begin{classdesc}{ComplexType}{pyclass, ofwhat\optional{, **keywords}} This class defines a compound data structure. If \code{pyclass} is \code{None}, then the data will be marshaled -into a Python dictionary, and each item in the \code{typecode_seq} sequence +into a Python dictionary, and each item in the \code{ofwhat} sequence specifies a (possible) dictionary entry. -Otherwise, \code{pyclass} must be a Python class object whose constructor -takes a single parameter, which will be the value of the \code{name} -parameter given in the \class{TC.Struct} constructor. -(This allows a single \code{pyclass} to be used for different typecodes.) +Otherwise, \code{pyclass} must be a Python class object. The data is then marshaled into the object, and each item in the -\code{typecode_seq} +\code{ofwhat} sequence specifies an attribute of the instance to set. -Note that each typecode in \code{typecode_seq} must have a name. +Note that each typecode in \code{ofwhat} must have a name. The following keyword arguments may be used: \begin{tableiii}{l|c|p{30em}}{textrm}{Keyword}{Default}{Description} -\lineiii{\code{hasextras}}{\code{0}}{Ignore any extra elements that appear -in the in the structure. -If \code{inorder} is true, extras can only appear at the end.} -\lineiii{\code{inorder}}{\code{0}}{Items within the structure must appear -in the order specified in the \code{TCseq} sequence.} -\lineiii{\code{inline}}{\code{0}}{The structure is single-reference, +\lineiii{\code{inorder}}{\code{False}}{Items within the structure must appear +in the order specified in the \code{ofwhat} sequence.} +\lineiii{\code{inline}}{\code{False}}{The structure is single-reference, so ZSI does not have to use \code{href/id} encodings.} -\lineiii{\code{mutable}}{\code{0}}{If an object is going to be serialized +\lineiii{\code{mutable}}{\code{False}}{If an object is going to be serialized multiple times, and its state may be modified between serializations, then this keyword should be used, otherwise a single instance will be serialized, with multiple references to it. @@ -659,11 +672,15 @@ specified by this parameter. By default, type-checking is not done for structures; matching child element names is usually sufficient and senders rarely provide type information.} +\lineiii{\code{mixed}}{\code{False}}{using a mixed content model, allow text and +element content.} +\lineiii{\code{mixed_aname}}{\code{'_text'}}{if mixed is True, text +content is set in this attribute (key).} \end{tableiii} If the \code{typed} keyword is used, then its value is assigned to -all typecodes in the \code{typecode_seq} parameter. -If any of the typecodes in \code{typecode_seq} are repeatable, then the +all typecodes in the \code{ofwhat} parameter. +If any of the typecodes in \code{ofwhat} are repeatable, then the \code{inorder} keyword should not be used and the \code{hasextras} parameter \emph{must} be used. @@ -688,25 +705,12 @@ \end{verbatim} \end{classdesc} -\section{Choice} +\section{Struct} -A choice is a Python two-element \samp{(name, value)} tuple, representing -a union of different types. -The first item is a string identifying the type, and the second is the -actual data. +SOAP Struct is a complex type for accessors identified by name. No element may +have the same name as any other, nor may any element have a maxOccurs > 1. +SOAP Structs are either Python dictionaries or instances of application-specified classes. -\begin{classdesc}{Choice}{typecode_seq, name\optional{, **keywords}} -When parsing, ZSI will look at the element name in the SOAP message, and -determine which of the choices to create. - -When serializing Python objects to SOAP messages, \ZSI{} must be -explicitly told which of the choices define the data. -This is done by passing a two-element tuple. -The first item is a string identifying the name of a typecode -from the \code{typecode_seq} list of typecodes. -The second is the object to be serialized. -\end{classdesc} - \section{Arrays} SOAP arrays are Python lists; multi-dimensional arrays are @@ -718,9 +722,9 @@ \strong{Currently only singly-dimensioned arrays are supported.} -\begin{classdesc}{Array}{atype, ofwhat, name\optional{, **keywords}} -The \code{atype} parameter is a text string representing the SOAP array type. -the \code{ofwhat} parameter is a typecode describing the array elements. +\begin{classdesc}{Array}{atype, ofwhat\optional{, **keywords}} +The \code{atype} parameter is a \code{(URI,NCName)} tuple representing the SOAP +array type. The \code{ofwhat} parameter is a typecode describing the array elements. \end{classdesc} The following keyword arguments may be used: @@ -732,14 +736,16 @@ the array.} \lineiii{\code{fill}}{\code{None}}{The value to use when an array element is omitted.} -\lineiii{\code{mutable}}{\code{0}}{Same as \class{TC.Struct} -\versionadded{1.2}} +\lineiii{\code{mutable}}{\code{False}}{If an object is going to be serialized +multiple times, and its state may be modified between serializations, +then this keyword should be used, otherwise a single instance will be +serialized, with multiple references to it.} \lineiii{\code{nooffset}}{\code{0}}{Do not use the SOAP \code{offset} attribute so skip leading elements with the same value as \code{fill}.} -\lineiii{\code{sparse}}{\code{0}}{The array is sparse.} +\lineiii{\code{sparse}}{\code{False}}{The array is sparse.} \lineiii{\code{size}}{\code{None}}{An integer or list of integers that specifies the maximum array dimensions.} -\lineiii{\code{undeclared}}{\code{0}}{The SOAP \samp{arrayType} attribute +\lineiii{\code{undeclared}}{\code{False}}{The SOAP \samp{arrayType} attribute need not appear.} \end{tableiii} Modified: trunk/zsi/test/test_t8.py =================================================================== --- trunk/zsi/test/test_t8.py 2006-10-13 00:12:32 UTC (rev 1265) +++ trunk/zsi/test/test_t8.py 2006-10-13 23:35:29 UTC (rev 1266) @@ -1,9 +1,15 @@ #!/usr/bin/env python import unittest, sys from ZSI import * +from ZSI.wstools.Namespaces import SCHEMA, SOAP +NSDICT = {'tns':'xmlns:tns="urn:a"', + 'xsi':'xmlns:xsi="%s"' %SCHEMA.XSI3, + 'xsd':'xmlns:xsd="%s"' %SCHEMA.XSD3, + 'soap':'xmlns:SOAP-ENC="%s"' %SOAP.ENC, +} -class t8TestCase(unittest.TestCase): +class AnyTestCase(unittest.TestCase): "Test Any serialize and parse" def check_parse_empty_all(self): @@ -26,8 +32,6 @@ sw = SoapWriter() sw.serialize("", typecode=tc, typed=True) soap = str(sw) - print - print soap ps = ParsedSoap(soap) parsed = ps.Parse(Any()) self.assertEqual("", parsed) @@ -39,7 +43,6 @@ sw = SoapWriter() sw.serialize(orig, typecode=Any(pname="builtins", aslist=True)) - print >>sys.stdout, sw ps = ParsedSoap(str(sw)) parsed = ps.Parse(Any()) @@ -57,26 +60,87 @@ self.assertEqual(tuple, type(parsed[3])) self.assertEqual(type(myFloat), type(parsed[4])) - - def check_Any_nill(self): + def check_any_nill(self): result = ['23', {'a' : None, 'b': 5}] soap = str(SoapWriter().serialize(result, TC.Any(pname="NilRequest", nillable=True, aslist=True))) - print soap ps = ParsedSoap(soap) tc = TC.Any(nillable=True) pyobj = ps.Parse(tc) + def check_any_compound(self): + # from zsi developer's guide + xml = """ +<tns:foo %(tns)s %(xsi)s %(soap)s> + <tns:i xsi:type="SOAP-ENC:integer">12</tns:i> + <tns:name xsi:type="SOAP-ENC:string">Hello world</tns:name> +</tns:foo>""" %NSDICT -def makeTestSuite(): - suite = unittest.TestSuite() - suite.addTest(unittest.makeSuite(t8TestCase, "check")) - return suite + ps = ParsedSoap(xml, envelope=False) + self.failUnless(ps.Parse(TC.Any()) == {'i': 12, 'name': 'Hello world'}) + self.failUnless(ps.Parse(TC.Any(aslist=True)) == [12, 'Hello world']) + def check_any_typed_soap_integer(self): + # from zsi developer's guide + value = 12 + d = dict(value=value) + d.update(NSDICT) + xml = """<tns:i xsi:type="SOAP-ENC:integer" %(xsi)s %(soap)s %(tns)s>%(value)d</tns:i>""" %d + ps = ParsedSoap(xml, envelope=False) + self.failUnless(ps.Parse(TC.Any()) == value) + + def check_any_typed_xsd_int(self): + # from zsi developer's guide + value = 12 + d = dict(value=value) + d.update(NSDICT) + xml = """<tns:i xsi:type="xsd:int" %(xsi)s %(soap)s %(tns)s %(xsd)s>%(value)d</tns:i>""" %d + ps = ParsedSoap(xml, envelope=False) + self.failUnless(ps.Parse(TC.Any()) == value) + + def check_any_typed_nonNegativeInteger(self): + # from zsi developer's guide + value = 12 + d = dict(value=value) + d.update(NSDICT) + xml = """<tns:i xsi:type="xsd:nonNegativeInteger" %(xsi)s %(soap)s %(tns)s %(xsd)s>%(value)d</tns:i>""" %d + ps = ParsedSoap(xml, envelope=False) + self.failUnless(ps.Parse(TC.Any()) == value) + + def check_any_untyped_int(self): + # from zsi developer's guide + d = dict(value=12) + d.update(NSDICT) + xml = """<tns:i %(tns)s>12</tns:i>""" %NSDICT + ps = ParsedSoap(xml, envelope=False) + self.failUnlessRaises(EvaluateException, ps.Parse, TC.Any()) + + +# +# Creates permutation of test options: "check", "check_any", etc +# +_SEP = '_' +for t in [i[0].split(_SEP) for i in filter(lambda i: callable(i[1]), AnyTestCase.__dict__.items())]: + test = '' + for f in t: + test += f + if globals().has_key(test): test += _SEP; continue + def _closure(): + name = test + def _makeTestSuite(): + suite = unittest.TestSuite() + suite.addTest(unittest.makeSuite(AnyTestCase, name)) + return suite + return _makeTestSuite + + globals()[test] = _closure() + test += _SEP + +makeTestSuite = check + def main(): unittest.main(defaultTest="makeTestSuite") - if __name__ == "__main__" : main() This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <bov...@us...> - 2006-10-17 19:32:28
|
Revision: 1267 http://svn.sourceforge.net/pywebsvcs/?rev=1267&view=rev Author: boverhof Date: 2006-10-17 12:32:22 -0700 (Tue, 17 Oct 2006) Log Message: ----------- M ZSI/TC.py M ZSI/writer.py M doc/c06-tc.tex M doc/c07-writer.tex -- updates to doc, removed some comments and unused code. Modified Paths: -------------- trunk/zsi/ZSI/TC.py trunk/zsi/ZSI/writer.py trunk/zsi/doc/c06-tc.tex trunk/zsi/doc/c07-writer.tex Modified: trunk/zsi/ZSI/TC.py =================================================================== --- trunk/zsi/ZSI/TC.py 2006-10-13 23:35:29 UTC (rev 1266) +++ trunk/zsi/ZSI/TC.py 2006-10-17 19:32:22 UTC (rev 1267) @@ -615,8 +615,15 @@ def serialize(self, elt, sw, pyobj, name=None, orig=None, **kw): '''Handles the start and end tags, and attributes. callout to get_formatted_content to get the textNode value. - sw -- - pyobj -- processed content. + Parameters: + elt -- ElementProxy/DOM element + sw -- SoapWriter instance + pyobj -- processed content + + KeyWord Parameters: + name -- substitute name, (nspname,name) or name + orig -- + ''' objid = _get_idstr(pyobj) ns,n = self.get_name(name, objid) Modified: trunk/zsi/ZSI/writer.py =================================================================== --- trunk/zsi/ZSI/writer.py 2006-10-13 23:35:29 UTC (rev 1266) +++ trunk/zsi/ZSI/writer.py 2006-10-17 19:32:22 UTC (rev 1267) @@ -26,7 +26,7 @@ Instance Data: memo -- memory for id/href envelope -- add Envelope? - encoding -- + encodingStyle -- header -- add SOAP Header? outputclass -- ElementProxy class. ''' @@ -35,8 +35,7 @@ nsdict={}, outputclass=None, **kw): '''Initialize. ''' - if outputclass is None: - outputclass=ElementProxy + outputclass = outputclass or ElementProxy if not issubclass(outputclass, MessageInterface): raise TypeError, 'outputclass must subclass MessageInterface' @@ -54,13 +53,14 @@ return str(self.dom) def getSOAPHeader(self): - if self.header is True or self.header is False: + if self.header in (True, False): return None return self.header def serialize_header(self, pyobj, typecode=None, **kw): '''Serialize a Python object in SOAP-ENV:Header, make - sure everything in Header unique (no #href). + sure everything in Header unique (no #href). Must call + serialize first to create a document. Parameters: pyobjs -- instances to serialize in SOAP Header @@ -71,11 +71,13 @@ #header = self.dom.getElement(soap_env, 'Header') header = self._header if header is None: - header = self._header = self.dom.createAppendElement(soap_env, 'Header') + header = self._header = self.dom.createAppendElement(soap_env, + 'Header') typecode = getattr(pyobj, 'typecode', typecode) if typecode is None: - raise RuntimeError, 'typecode is required to serialize pyobj in header' + raise RuntimeError( + 'typecode is required to serialize pyobj in header') helt = typecode.serialize(header, self, pyobj, **kw) @@ -108,21 +110,18 @@ self.dom.createDocument(None,None) if typecode is None: typecode = pyobj.__class__.typecode - if TypeCode.typechecks and type(pyobj) == types.InstanceType and \ - not hasattr(typecode, 'pyclass'): - pass - # XXX XML ... - #raise TypeError('Serializing Python object with other than Struct.') kw = kw.copy() - - # TODO: FIX THIS... - #if root in [ 0, 1 ]: - # kw['attrtext'] = ' SOAP-ENC:root="%d"' % root if self.body is None: - typecode.serialize(self.dom, self, pyobj, **kw) + elt = typecode.serialize(self.dom, self, pyobj, **kw) else: - typecode.serialize(self.body, self, pyobj, **kw) + elt = typecode.serialize(self.body, self, pyobj, **kw) + + if root is not None: + if root not in [ 0, 1 ]: + raise ValueError, "SOAP-ENC root attribute not in [0,1]" + elt.setAttributeNS(SOAP.ENC, 'root', root) + return self def writeNSdict(self, nsdict): Modified: trunk/zsi/doc/c06-tc.tex =================================================================== --- trunk/zsi/doc/c06-tc.tex 2006-10-13 23:35:29 UTC (rev 1266) +++ trunk/zsi/doc/c06-tc.tex 2006-10-17 19:32:22 UTC (rev 1267) @@ -92,6 +92,14 @@ a \samp{(namespace, name)} tuple. \end{memberdesc} +\begin{memberdesc}{attribute_typecode_dict} +This is a class attribute. +This is a dict of \samp{(URI, NCName)} tuple keys, the values of each is a +typecode. This is how attribute declarations other than SOAP and XMLSchema +attribute declarations (eg. \code{xsi:type}, \code{id}, \code{href}, etc) are +represented. +\end{memberdesc} + \begin{memberdesc}{logger} This is a class attribute. logger instance for this class. Modified: trunk/zsi/doc/c07-writer.tex =================================================================== --- trunk/zsi/doc/c07-writer.tex 2006-10-13 23:35:29 UTC (rev 1266) +++ trunk/zsi/doc/c07-writer.tex 2006-10-17 19:32:22 UTC (rev 1267) @@ -14,36 +14,29 @@ \lineii{\code{xsi}}{\code{http://www.w3.org/2001/XMLSchema-instance}} \end{tableii} -\begin{classdesc}{SoapWriter}{out\optional{, **keywords}} -The \code{out} parameter is an object that has a \method{write()} -method for generating the output. - +\begin{classdesc}{SoapWriter}{optional{**keywords}} The following keyword arguments may be used: \begin{tableiii}{l|c|p{30em}}{textrm}{Keyword}{Default}{Description} -\lineiii{\code{encoding}}{\code{SOAP-ENC} value}{If not \code{None}, then +\lineiii{\code{encodingStyle}}{None}{If not \code{None}, then use the specified value as the value for the SOAP \code{encodingStyle} attribute. \versionadded{1.2}} -\lineiii{\code{envelope}}{\code{1}}{Write the SOAP envelope elements. +\lineiii{\code{envelope}}{\code{True}}{Create a SOAP Envelope \versionadded{1.2}} \lineiii{\code{nsdict}}{\code{\{\}}}{Dictionary of namespaces to declare -in the SOAP \code{Body}. -Note that earlier versions of ZSI put the declarations on the SOAP -\code{Envelope}; they have been moved to the \code{Body} for greater -interoperability.} -\lineiii{\code{header}}{\code{None}}{A sequence of elements to output in -the SOAP \code{Header}. -It may also be a text string, in which case it is output as-is, and should -therefore be XML text.} +in the SOAP \code{Envelope}} +\lineiii{\code{header}}{\code{True}}{create a SOAP \code{Header} element} +\lineiii{\code{outputclass}}{\code{ElementProxy}}{wrapper around DOM or other +XML library.} \end{tableiii} \end{classdesc} -Creating a \class{SoapWriter} object with a \class{StringIO} object for -the \code{out} parameter and \code{envelope} set to false results in an -object that can be used for serializing objects into a string. +Creating a \class{SoapWriter} object with \code{envelope} set to \code{False} +results in an object that can be used for serializing objects into a string. -\begin{methoddesc}{serialize}{pyobj\optional{, typecode\optional{, root=None\optional{, **keywords}}}} +\begin{methoddesc}{serialize}{pyobj\optional{, typecode=None\optional{, +root=None\optional{, header_pyobjs=None\optional{, **keywords}}}}} This method serializes the \code{pyobj} Python object as directed by the \code{typecode} typecode object. If \code{typecode} is omitted, then \code{pyobj} should be a Python @@ -58,16 +51,18 @@ method. \end{methoddesc} -\begin{methoddesc}{close}{\optional{trailer=None\optional{, nsdict=None}}} -Close off the SOAP message, finishing all the pending serializations. -If \code{trailer} is a string or list of elements, it is output after the -close-tag for the \code{Body}. -The \method{close()} method of the originally provided out object is NOT called. -(If it were, and the original \code{out} object were a \class{StringIO} -object, there would be no way to collect the data.) -This method will be invoked automatically if the object is deleted. +\begin{methoddesc}{close}{} +Invokes all the callbacks, if any. The \function{close} operations can only +happen once, if invoked a second time it will just return. This method will be +invoked automatically if the object is deleted. \end{methoddesc} + +\begin{methoddesc}{__str__}{} +Invokes the \function{close} method, and returns a string representation of the +serialized object. Assumes that \function{serialize} has been invoked. +\end{methoddesc} + The following methods are primarily useful for those writing new typecodes. \begin{methoddesc}{AddCallback}{func, arg} @@ -84,24 +79,15 @@ \end{methoddesc} \begin{methoddesc}{Known}{obj} -If \code{obj} has been seen before (based on its Python \code{id}), -return \code{1}. -Otherwise, remember \code{obj} and return \code{0}. +If \code{obj} has been seen before (based on its Python \code{id}), return +\code{1}. Otherwise, remember \code{obj} and return \code{0}. \end{methoddesc} \begin{methoddesc}{ReservedNS}{prefix, uri} -Returns true if the specified namespace \code{prefix} and -\code{uri} -collide with those used by the implementation. +Returns true if the specified namespace \code{prefix} and \code{uri} collide +with those used by the implementation. \end{methoddesc} -\begin{methoddesc}{write}{arg} -This is a convenience method that calls \method{self.out.write()} -on \code{arg}, with the addition that if \code{arg} is a sequence, -it iterates over the sequence, writing each item (that isn't \code{None}) -in turn. -\end{methoddesc} - \begin{methoddesc}{writeNSDict}{nsdict} Outputs \code{nsdict} as a namespace dictionary. It is assumed that an XML start-element is pending on the output This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <bov...@us...> - 2006-10-17 22:53:38
|
Revision: 1268 http://svn.sourceforge.net/pywebsvcs/?rev=1268&view=rev Author: boverhof Date: 2006-10-17 15:53:19 -0700 (Tue, 17 Oct 2006) Log Message: ----------- M test/test_t6.py M test/test_t4.py -- fixed a couple failure conditions M ZSI/dispatch.py M ZSI/fault.py M ZSI/client.py M doc/c10-dispatch.tex M doc/c08-fault.tex -- updates to docs, and moved a little code around and minor comment changes. Modified Paths: -------------- trunk/zsi/ZSI/client.py trunk/zsi/ZSI/dispatch.py trunk/zsi/ZSI/fault.py trunk/zsi/doc/c08-fault.tex trunk/zsi/doc/c10-dispatch.tex trunk/zsi/test/test_t4.py trunk/zsi/test/test_t6.py Modified: trunk/zsi/ZSI/client.py =================================================================== --- trunk/zsi/ZSI/client.py 2006-10-17 19:32:22 UTC (rev 1267) +++ trunk/zsi/ZSI/client.py 2006-10-17 22:53:19 UTC (rev 1268) @@ -67,8 +67,7 @@ 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, including a "name overloading" - style. + receiving SOAP messages are available. ''' defaultHttpTransport = httplib.HTTPConnection defaultHttpsTransport = httplib.HTTPSConnection @@ -444,7 +443,9 @@ 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. @@ -522,7 +523,7 @@ class NamedParamBinding(Binding): - '''Like binding, except the argument list for invocation is + '''Like Binding, except the argument list for invocation is named parameters. ''' logger = _GetLogger('ZSI.client.Binding') Modified: trunk/zsi/ZSI/dispatch.py =================================================================== --- trunk/zsi/ZSI/dispatch.py 2006-10-17 19:32:22 UTC (rev 1267) +++ trunk/zsi/ZSI/dispatch.py 2006-10-17 22:53:19 UTC (rev 1268) @@ -181,28 +181,7 @@ def _CGISendFault(f, **kw): _CGISendXML(f.AsSOAP(), 500, **kw) -def AsCGI(nsdict={}, typesmodule=None, rpc=None, modules=None): - '''Dispatch within a CGI script. - ''' - if os.environ.get('REQUEST_METHOD') != 'POST': - _CGISendFault(Fault(Fault.Client, 'Must use POST')) - return - ct = os.environ['CONTENT_TYPE'] - try: - if ct.startswith('multipart/'): - cid = resolvers.MIMEResolver(ct, sys.stdin) - xml = cid.GetSOAPPart() - ps = ParsedSoap(xml, resolver=cid.Resolve) - else: - length = int(os.environ['CONTENT_LENGTH']) - ps = ParsedSoap(sys.stdin.read(length)) - except ParseException, e: - _CGISendFault(FaultFromZSIException(e)) - return - _Dispatch(ps, modules, _CGISendXML, _CGISendFault, nsdict=nsdict, - typesmodule=typesmodule, rpc=rpc) - class SOAPRequestHandler(BaseHTTPRequestHandler): '''SOAP handler. ''' @@ -247,9 +226,9 @@ docstyle=self.server.docstyle, nsdict=self.server.nsdict, typesmodule=self.server.typesmodule, rpc=self.server.rpc) -def AsServer(port=80, modules=None, docstyle=0, nsdict={}, typesmodule=None, - rpc=None, **kw): - address = ('', port) +def AsServer(port=80, modules=None, docstyle=False, nsdict={}, typesmodule=None, + rpc=False, addr=''): + address = (addr, port) httpd = HTTPServer(address, SOAPRequestHandler) httpd.modules = modules httpd.docstyle = docstyle @@ -258,14 +237,34 @@ httpd.rpc = rpc httpd.serve_forever() -def AsHandler(request=None, modules=None, nsdict={}, rpc=None, **kw): +def AsCGI(nsdict={}, typesmodule=None, rpc=False, modules=None): + '''Dispatch within a CGI script. + ''' + if os.environ.get('REQUEST_METHOD') != 'POST': + _CGISendFault(Fault(Fault.Client, 'Must use POST')) + return + ct = os.environ['CONTENT_TYPE'] + try: + if ct.startswith('multipart/'): + cid = resolvers.MIMEResolver(ct, sys.stdin) + xml = cid.GetSOAPPart() + ps = ParsedSoap(xml, resolver=cid.Resolve) + else: + length = int(os.environ['CONTENT_LENGTH']) + ps = ParsedSoap(sys.stdin.read(length)) + except ParseException, e: + _CGISendFault(FaultFromZSIException(e)) + return + _Dispatch(ps, modules, _CGISendXML, _CGISendFault, nsdict=nsdict, + typesmodule=typesmodule, rpc=rpc) + +def AsHandler(request=None, modules=None, **kw): '''Dispatch from within ModPython.''' ps = ParsedSoap(request) kw['request'] = request - _Dispatch(ps, modules, _ModPythonSendXML, _ModPythonSendFault, - nsdict=nsdict, rpc=rpc, **kw) - -def AsJonPy(nsdict={}, typesmodule=None, rpc=None, modules=None, request=None, **kw): + _Dispatch(ps, modules, _ModPythonSendXML, _ModPythonSendFault, **kw) + +def AsJonPy(request=None, modules=None, **kw): '''Dispatch within a jonpy CGI/FastCGI script. ''' @@ -285,8 +284,7 @@ except ParseException, e: _JonPySendFault(FaultFromZSIException(e), **kw) return - _Dispatch(ps, modules, _JonPySendXML, _JonPySendFault, nsdict=nsdict, - typesmodule=typesmodule, rpc=rpc, **kw) + _Dispatch(ps, modules, _JonPySendXML, _JonPySendFault, **kw) if __name__ == '__main__': print _copyright Modified: trunk/zsi/ZSI/fault.py =================================================================== --- trunk/zsi/ZSI/fault.py 2006-10-17 19:32:22 UTC (rev 1267) +++ trunk/zsi/ZSI/fault.py 2006-10-17 22:53:19 UTC (rev 1268) @@ -47,7 +47,9 @@ self.any = detail ZSIHeaderDetail.typecode =\ - Struct(ZSIHeaderDetail, [AnyElement(aname='any')], pname=(ZSI_SCHEMA_URI, 'detail')) + Struct(ZSIHeaderDetail, + [AnyElement(aname='any', minOccurs=0, maxOccurs=UNBOUNDED)], + pname=(ZSI_SCHEMA_URI, 'detail')) class ZSIFaultDetailTypeCode(ElementDeclaration, Struct): @@ -132,8 +134,8 @@ actor=None, detail=None, headerdetail=None): if detail is not None and type(detail) not in _seqtypes: detail = (detail,) - #if headerdetail is not None and type(headerdetail) not in _seqtypes: - # headerdetail = (headerdetail,) + if headerdetail is not None and type(headerdetail) not in _seqtypes: + headerdetail = (headerdetail,) self.code, self.string, self.actor, self.detail, self.headerdetail = \ code, string, actor, detail, headerdetail ZSIException.__init__(self, code, string, actor, detail, headerdetail) Modified: trunk/zsi/doc/c08-fault.tex =================================================================== --- trunk/zsi/doc/c08-fault.tex 2006-10-17 19:32:22 UTC (rev 1267) +++ trunk/zsi/doc/c08-fault.tex 2006-10-17 22:53:19 UTC (rev 1268) @@ -62,13 +62,10 @@ A text string holding the value of the SOAP \code{faultstring} element. \end{memberdesc} -\begin{methoddesc}{AsSOAP}{\optional{output\optional{, **kw}}} +\begin{methoddesc}{AsSOAP}{\optional{, **kw}} This method serializes the \class{Fault} object into a SOAP message. -If the \var{output} parameter is not specified or \constant{None}, the -message is returned as a string. -Any other keyword arguments are passed to the \class{SoapWriter} constructor. -Otherwise \method{AsSOAP()} will call \code{\var{output}.write()} as needed -to output the message. +The message is returned as a string. +Any keyword arguments are passed to the \class{SoapWriter} constructor. \versionadded{1.1; the old \method{AsSoap()} method is still available} \end{methoddesc} @@ -83,8 +80,8 @@ \end{methoddesc} \begin{methoddesc}{serialize}{sw} -This method outputs the fault object onto the \var{sw} object, -which must support a \method{write()} method. +This method outputs the fault object onto the \var{sw} object, which is a +\class{SoapWriter} instance. \end{methoddesc} Some convenience functions are available to create a \class{Fault} Modified: trunk/zsi/doc/c10-dispatch.tex =================================================================== --- trunk/zsi/doc/c10-dispatch.tex 2006-10-17 19:32:22 UTC (rev 1267) +++ trunk/zsi/doc/c10-dispatch.tex 2006-10-17 22:53:19 UTC (rev 1268) @@ -33,29 +33,50 @@ \section{Dispatching} -The \module{ZSI.dispatch} module allows you to expose Python functions as a -web service. -The module provides the infrastructure to parse the request, dispatch -to the appropriate handler, and then serialize any return value -back to the client. -The value returned by the function will be serialized back to the client. -To return multiple values, return a list. +The \module{ZSI.dispatch} module allows you to expose Python functions as a web +service. The module provides the infrastructure to parse the request, dispatch +to the appropriate handler, and then serialize any return value back to the +client. The value returned by the function will be serialized back to the +client. If an exception occurs, a SOAP fault will be sent back to the client. -If an exception occurs, a SOAP fault will be sent back to the client. +\subsection{Dispatch Behaviors} By default the callback is invoked with the +pyobj representation of the body root element, and it is expected to return a +self-describing request (w/typecode). Parsing is done via a typecode from +typesmodule, or Any. Other keyword options are available in dispatch mechanisms +(see below) that result in different behavior. +\subsubsection{rpc} An rpc service will ignore the body root (RPC Wrapper) of +the request, and parse all "parts" of message via individual typecodes. The +callback function is expected to return the parts of the message in a dict or a +list. The dispatch mechanism will try to serialize it as a Struct but if this +is not possible it will be serialized as an Array. Parsing done via a typecode +from typesmodule, or Any. Not compatible with \var{docstyle}. + +\subsubsection{docstyle} Callback is invoked with a ParsedSoap instance +representing the request, and the return value is serialized with an XML +typecode (DOM). The result in wrapped as an rpc-style message, with +\emph{Response} appended to the request wrapper. Not compatible with \var{rpc}. + +\subsection{Special Modules} These are keyword options available to all +dispatch mechansism (see below). + +\subsubsection{modules}{Dispatch is based solely on the name of the root element in the +incoming SOAP request; the request URL is ignored. These modules will be search +for a matching function. If no modules are specified, only the +\module{__main__} module will be searched.} + +\subsubsection{typesmodule}{Used for parsing. This module should contain class +definitions with the \code{typecode} attribute set to a \class{TypeCode} +instance. By default, a class definition matching the root element name will be +retrieved or the Any typecode will be used. If using \emph{rpc}, each child of +the root element will be used to retrieve a class definition of the same name.} + +\subsection{Dispatch Mechanisms} Three dispatch mechanisms are provided: one supports standard CGI scripts, one runs a dedicated server based on the \module{BaseHTTPServer} module, and the third uses the JonPY package, \url{http://jonpy.sourceforge.net}, to support FastCGI. -\begin{methoddesc}{AsCGI}{\optional{module_list}} -This method parses the CGI input and invokes a function that has the -same name as the top-level SOAP request element. -The optional \code{module_list} parameter can specify a list of modules -(already imported) to search for functions. -If no modules are specified, only the \module{__main__} module will be searched. -\end{methoddesc} - \begin{methoddesc}{AsServer}{\optional{**keywords}} This creates a \class{HTTPServer} object with a request handler that only supports the ``POST'' method. @@ -66,28 +87,84 @@ The following keyword arguments may be used: \begin{tableiii}{l|c|p{30em}}{textrm}{Keyword}{Default}{Description} -\lineiii{\code{docstyle}}{\code{0}}{If true, then all methods are -invoked with a single argument, the unparsed body of the SOAP message.} +\lineiii{\code{port}}{\code{80}}{Port to listen on.} +\lineiii{\code{addr}}{\code{''}}{Address to listen on.} +\lineiii{\code{docstyle}}{\code{False}}{Exhibit the \emph{docstyle} behavior.} +\lineiii{\code{rpc}}{\code{False}}{Exhibit the \emph{rpc} behavior.} \lineiii{\code{modules}}{\code{(__main__,)}}{List of modules containing functions that can be invoked.} -\lineiii{\code{nsdict}}{\code{\{\}}}{Namespace dictionary to send in the - SOAP \code{Envelope}} -\lineiii{\code{port}}{\code{80}}{Port to listen on.} +\lineiii{\code{typesmodule}}{\code{(__main__,)}}{This module is used for +parsing, it contains class definitions that specify the \code{typecode} +attribute.} +\lineiii{\code{nsdict}}{\code{\{\}}}{Namespace dictionary to send in the SOAP +\code{Envelope}} \end{tableiii} \end{methoddesc} -\begin{methoddesc}{AsJonPy}{request=req\optional{, **keywords}} +\begin{methoddesc}{AsCGI}{\optional{**keywords}} +This method parses the CGI input and invokes a function that has the +same name as the top-level SOAP request element. + +The following keyword arguments may be used: + +\begin{tableiii}{l|c|p{30em}}{textrm}{Keyword}{Default}{Description} +\lineiii{\code{rpc}}{\code{False}}{Exhibit the \emph{rpc} behavior.} +\lineiii{\code{modules}}{\code{(__main__,)}}{List of modules containing +functions that can be invoked.} +\lineiii{\code{typesmodule}}{\code{(__main__,)}}{This module is used for +parsing, it contains class definitions that specify the \code{typecode} +attribute.} +\lineiii{\code{nsdict}}{\code{\{\}}}{Namespace dictionary to send in the SOAP +\code{Envelope}} +\end{tableiii} + +\end{methoddesc} + + + +\begin{methoddesc}{AsHandler}{request=None\optional{, **keywords}} + This method is used within a JonPY handler to do dispatch. The following keyword arguments may be used: \begin{tableiii}{l|c|p{30em}}{textrm}{Keyword}{Default}{Description} -\lineiii{\code{request}}{\code{(__main__,)}}{List of modules containing +\lineiii{\code{request}}{\code{None}}{modpython HTTPRequest instance.} +\lineiii{\code{modules}}{\code{(__main__,)}}{List of modules containing functions that can be invoked.} +\lineiii{\code{docstyle}}{\code{False}}{Exhibit the \emph{docstyle} behavior.} +\lineiii{\code{rpc}}{\code{False}}{Exhibit the \emph{rpc} behavior.} +\lineiii{\code{typesmodule}}{\code{(__main__,)}}{This module is used for +parsing, it contains class definitions that specify the \code{typecode} +attribute.} +\lineiii{\code{nsdict}}{\code{\{\}}}{Namespace dictionary to send in the SOAP +\code{Envelope}} \end{tableiii} +\end{methoddesc} + +\begin{methoddesc}{AsJonPy}{request=None\optional{, **keywords}} + +This method is used within a JonPY handler to do dispatch. + +The following keyword arguments may be used: + +\begin{tableiii}{l|c|p{30em}}{textrm}{Keyword}{Default}{Description} +\lineiii{\code{request}}{\code{None}}{jonpy Request instance.} +\lineiii{\code{modules}}{\code{(__main__,)}}{List of modules containing +functions that can be invoked.} +\lineiii{\code{docstyle}}{\code{False}}{Exhibit the \emph{docstyle} behavior.} +\lineiii{\code{rpc}}{\code{False}}{Exhibit the \emph{rpc} behavior.} +\lineiii{\code{typesmodule}}{\code{(__main__,)}}{This module is used for +parsing, it contains class definitions that specify the \code{typecode} +attribute.} +\lineiii{\code{nsdict}}{\code{\{\}}}{Namespace dictionary to send in the SOAP +\code{Envelope}} +\end{tableiii} + + The following code shows a sample use: \begin{verbatim} @@ -104,6 +181,8 @@ \end{methoddesc} +\subsection{Other Dispatch Stuff} + \begin{methoddesc}{GetClientBinding}{} More sophisticated scripts may want to use access the client binding object, which encapsulates all information about the client invoking the script. @@ -140,6 +219,7 @@ This is most useful when \method{AsCGI()} is used. \end{memberdesc} + \section{The \module{client} module --- sending SOAP messages} \ZSI{} includes a module to connect to a SOAP server over HTTP, send requests, @@ -149,7 +229,9 @@ It must be explicitly imported, as in \samp{from ZSI.client import AUTH,Binding}. -\begin{classdesc}{Binding}{\optional{**keywords}} +\subsection{_Binding} + +\begin{classdesc}{_Binding}{\optional{**keywords}} This class encapsulates a connection to a server, known as a \emph{binding}. A single binding may be used for multiple RPC calls. Between calls, modifiers may be used to change the URL being posted to, @@ -177,18 +259,20 @@ \lineiii{\code{transport}}{HTTPConnection/HTTPSConnection}{transport class} \lineiii{\code{transdict}}{\{\}}{keyword arguments for connection initialization} \lineiii{\code{url}}{n/a}{URL to post to.} +\lineiii{\code{wsAddressURI}}{None}{URI, identifies the WS-Address specification +to use. By default it's not used.} +\lineiii{\code{sig_handler}}{None}{XML Signature handler, must sign and verify.} \end{tableiii} If using SSL, the \code{cert_file} and \code{key_file} keyword parameters may -also be used. -For details see the documentation for the \module{httplib} module. +also be used. For details see the documentation for the \module{httplib} +module. \end{classdesc} -Once a \class{Binding} object has been created, the following modifiers are -available. -All of them return the binding object, so that multiple modifiers can -be chained together. +Once a \class{_Binding} object has been created, the following modifiers are +available. All of them return the binding object, so that multiple modifiers +can be chained together. \begin{methoddesc}{AddHeader}{header, value} Output the specified \code{header} and \code{value} with the HTTP @@ -317,15 +401,42 @@ A text string containing the HTTP reply text. \end{memberdesc} -Finally, if an attribute is fetched other than one of those described -above, it is taken to be the \code{opname} of a remote procedure, -and a callable object is returned. -This object dynamically parses its arguments, receives the reply, and -parses that. +\subsection{Binding} +If an attribute is fetched other than one of those described in +\class{_Binding}, it is taken to be the \code{opname} of a remote procedure, and +a callable object is returned. This object dynamically parses its arguments, +receives the reply, and parses that. -\begin{methoddesc}{opname}{args...} -Using this shortcut requires that the \method{SetURL()} was invoked first. -This method is then equivalent to: -\samp{RPC(None, opname, tuple(args), TC.Any())} +\begin{classdesc}{Binding}{\optional{**keywords}} +For other keyword arguments see \class{_Binding}. +\begin{tableiii}{l|c|p{20em}}{textrm}{Keyword}{Default}{Description} +\lineiii{\code{typesmodule}}{\code{None}}{See explanation in Dispatching} +\end{tableiii} +\end{classdesc} + +\begin{methoddesc}{opname}{*args} +Using this shortcut requires that the \var{url} attribute is set, either +throught the constructor or \method{SetURL()}. \end{methoddesc} + +\subsection{NamedParamBinding} +If an attribute is fetched other than one of those described +in \class{_Binding}, it is taken to be the \code{opname} of a remote procedure, and a callable +object is returned. This object dynamically parses its arguments, receives the +reply, and parses that. + +\begin{classdesc}{NamedParamBinding}{\optional{**keywords}} +For other keyword arguments see \class{_Binding}. +\begin{tableiii}{l|c|p{20em}}{textrm}{Keyword}{Default}{Description} +\lineiii{\code{typesmodule}}{\code{None}}{See explanation in Dispatching} +\end{tableiii} +\end{classdesc} + +\begin{methoddesc}{opname}{**kwargs} +Using this shortcut requires that the \var{url} attribute is set, either +throught the constructor or \method{SetURL()}. +\end{methoddesc} + + + Modified: trunk/zsi/test/test_t4.py =================================================================== --- trunk/zsi/test/test_t4.py 2006-10-17 19:32:22 UTC (rev 1267) +++ trunk/zsi/test/test_t4.py 2006-10-17 22:53:19 UTC (rev 1268) @@ -27,23 +27,23 @@ r = resolvers.NetworkResolver(['http:']) ps = ParsedSoap(IN, resolver=r.Resolve) except ParseException, e: - FaultFromZSIException(e).AsSOAP(OUT) + print >>OUT, FaultFromZSIException(e).AsSOAP() self.fail() except Exception, e: # Faulted while processing; assume it's in the header. - FaultFromException(e, 1, sys.exc_info()[2]).AsSOAP(OUT) + print >>OUT, FaultFromException(e, 1, sys.exc_info()[2]).AsSOAP() self.fail() print 'resolving' typecode = TC.Struct(None, [ TC.XML('xmltest'), TC.String('stringtest', resolver=r.Opaque), ]) try: dict = ps.Parse(typecode) - #except EvaluateException, e: - # FaultFromZSIException(e).AsSOAP(OUT) - # sys.exit(1) + except EvaluateException, e: + print >>OUT, FaultFromZSIException(e).AsSOAP() + self.fail() except Exception, e: # Faulted while processing; now it's the body - FaultFromException(e, 0, sys.exc_info()[2]).AsSOAP(OUT) + print >>OUT, FaultFromException(e, 0, sys.exc_info()[2]).AsSOAP() self.fail() PrettyPrint(dict['xmltest']) print '**', dict['stringtest'], '**' Modified: trunk/zsi/test/test_t6.py =================================================================== --- trunk/zsi/test/test_t6.py 2006-10-17 19:32:22 UTC (rev 1267) +++ trunk/zsi/test/test_t6.py 2006-10-17 22:53:19 UTC (rev 1268) @@ -19,19 +19,19 @@ cid = resolvers.MIMEResolver(m['content-type'], istr) xml = cid.GetSOAPPart() ps = ParsedSoap(xml, resolver=cid.Resolve) - #except ParseException, e: - # FaultFromZSIException(e).AsSOAP(OUT) - # self.fail() + except ParseException, e: + print >>OUT, FaultFromZSIException(e).AsSOAP() + self.fail() except Exception, e: # Faulted while processing; assume it's in the header. - FaultFromException(e, 1, sys.exc_info()[2]).AsSOAP(OUT) + print >>OUT, FaultFromException(e, 1, sys.exc_info()[2]).AsSOAP() self.fail() try: dict = ps.Parse(typecode) except Exception, e: # Faulted while processing; now it's the body - FaultFromException(e, 0, sys.exc_info()[2]).AsSOAP(OUT) + print >>OUT, FaultFromException(e, 0, sys.exc_info()[2]).AsSOAP() self.fail() self.failUnlessEqual(dict['stringtest'], strExtTest, This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <bov...@us...> - 2006-10-18 22:55:40
|
Revision: 1269 http://svn.sourceforge.net/pywebsvcs/?rev=1269&view=rev Author: boverhof Date: 2006-10-18 15:55:32 -0700 (Wed, 18 Oct 2006) Log Message: ----------- M test/test_t8.py M ZSI/TC.py fix for [ 1521700 ] Empty lists become None using TC.Any Modified Paths: -------------- trunk/zsi/ZSI/TC.py trunk/zsi/test/test_t8.py Modified: trunk/zsi/ZSI/TC.py =================================================================== --- trunk/zsi/ZSI/TC.py 2006-10-17 22:53:19 UTC (rev 1268) +++ trunk/zsi/ZSI/TC.py 2006-10-18 22:55:32 UTC (rev 1269) @@ -708,6 +708,9 @@ if _is_xsd_or_soap_ns(ns): parser = Any.parsemap.get((None,type)) if parser: return parser.parse(elt, ps) + if ((ns,type) == (SOAP.ENC,'Array') or + (_find_arraytype(elt) or '').endswith('[0]')): + return [] return None raise EvaluateException('Required Any missing', ps.Backtrace(elt)) Modified: trunk/zsi/test/test_t8.py =================================================================== --- trunk/zsi/test/test_t8.py 2006-10-17 22:53:19 UTC (rev 1268) +++ trunk/zsi/test/test_t8.py 2006-10-18 22:55:32 UTC (rev 1269) @@ -12,6 +12,23 @@ class AnyTestCase(unittest.TestCase): "Test Any serialize and parse" + def check_empty_array(self): + """Empty Array returned as list() + """ + data = [] + s = str(SoapWriter().serialize(data,TC.Any(aslist=True))) + p = ParsedSoap(s).Parse(TC.Any()) + self.failUnless(data==p, 'expecting "%s", got "%s"' %(data,p)) + + def check_empty_struct(self): + """Empty Struct is None, maybe dict() makes more sense, but this + is fairly hard to determine if not typed (which is the norm). + """ + data = {} + s = str(SoapWriter().serialize(data,TC.Any())) + p = ParsedSoap(s).Parse(TC.Any()) + self.failUnless(p==None, 'expecting "%s", got "%s"' %(None,p)) + def check_parse_empty_all(self): # None skip = [TC.FPEnumeration, TC.Enumeration, TC.IEnumeration, TC.List, TC.Integer] This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <bov...@us...> - 2006-10-19 22:31:20
|
Revision: 1270 http://svn.sourceforge.net/pywebsvcs/?rev=1270&view=rev Author: boverhof Date: 2006-10-19 15:31:07 -0700 (Thu, 19 Oct 2006) Log Message: ----------- M test/test_t8.py M ZSI/__init__.py A ZSI/schema.py M ZSI/generate/containers.py M ZSI/TC.py M ZSI/TCcompound.py M ZSI/writer.py M ZSI/address.py -- Moved all schema instance stuff into a new module "schema", Modified Paths: -------------- trunk/zsi/ZSI/TC.py trunk/zsi/ZSI/TCcompound.py trunk/zsi/ZSI/__init__.py trunk/zsi/ZSI/address.py trunk/zsi/ZSI/generate/containers.py trunk/zsi/ZSI/writer.py trunk/zsi/test/test_t8.py Added Paths: ----------- trunk/zsi/ZSI/schema.py Modified: trunk/zsi/ZSI/TC.py =================================================================== --- trunk/zsi/ZSI/TC.py 2006-10-18 22:55:32 UTC (rev 1269) +++ trunk/zsi/ZSI/TC.py 2006-10-19 22:31:07 UTC (rev 1270) @@ -10,7 +10,7 @@ _find_xmlns_prefix, _get_element_nsuri_name, _get_idstr, \ _Node, EvaluateException, \ _valid_encoding, ParseException - + from ZSI.wstools.Namespaces import SCHEMA, SOAP from ZSI.wstools.Utility import SplitQName from ZSI.wstools.c14n import Canonicalize @@ -22,13 +22,14 @@ from urllib import unquote as urldecode, quote as urlencode from binascii import unhexlify as hexdecode, hexlify as hexencode -UNBOUNDED = 'unbounded' _is_xsd_or_soap_ns = lambda ns: ns in [ SCHEMA.XSD3, SOAP.ENC, SCHEMA.XSD1, SCHEMA.XSD2, ] _find_nil = lambda E: _find_xsi_attr(E, "null") or _find_xsi_attr(E, "nil") def _get_xsitype(pyclass): + '''returns the xsi:type as a tuple, coupled with ZSI.schema + ''' if hasattr(pyclass,'type') and type(pyclass.type) in _seqtypes: return pyclass.type elif hasattr(pyclass,'type') and hasattr(pyclass, 'schema'): @@ -36,168 +37,12 @@ return (None,None) -def _get_type_definition(namespaceURI, name, **kw): - return SchemaInstanceType.getTypeDefinition(namespaceURI, name, **kw) -def _get_global_element_declaration(namespaceURI, name, **kw): - return SchemaInstanceType.getElementDeclaration(namespaceURI, name, **kw) +# value returned when xsi:nil="true" +Nilled = None +UNBOUNDED = 'unbounded' -def _get_substitute_element(elt, what): - raise NotImplementedError, 'Not implemented' -def _has_type_definition(namespaceURI, name): - return SchemaInstanceType.getTypeDefinition(namespaceURI, name) is not None - - -# -# functions for retrieving schema items from -# the global schema instance. -# -GED = _get_global_element_declaration -GTD = _get_type_definition - - -class SchemaInstanceType(type): - '''Register all types/elements, when hit already defined - class dont create a new one just give back reference. Thus - import order determines which class is loaded. - - class variables: - types -- dict of typecode classes definitions - representing global type definitions. - elements -- dict of typecode classes representing - global element declarations. - element_typecode_cache -- dict of typecode instances - representing global element declarations. - ''' - types = {} - elements = {} - element_typecode_cache = {} - - def __new__(cls,classname,bases,classdict): - '''If classdict has literal and schema register it as a - element declaration, else if has type and schema register - it as a type definition. - ''' - if classname in ['ElementDeclaration', 'TypeDefinition']: - return type.__new__(cls,classname,bases,classdict) - - if ElementDeclaration in bases: - if classdict.has_key('schema') is False or classdict.has_key('literal') is False: - raise AttributeError, 'ElementDeclaration must define schema and literal attributes' - - key = (classdict['schema'],classdict['literal']) - if SchemaInstanceType.elements.has_key(key) is False: - SchemaInstanceType.elements[key] = type.__new__(cls,classname,bases,classdict) - return SchemaInstanceType.elements[key] - - if TypeDefinition in bases: - if classdict.has_key('type') is None: - raise AttributeError, 'TypeDefinition must define type attribute' - - key = classdict['type'] - if SchemaInstanceType.types.has_key(key) is False: - SchemaInstanceType.types[key] = type.__new__(cls,classname,bases,classdict) - return SchemaInstanceType.types[key] - - raise TypeError, 'SchemaInstanceType must be an ElementDeclaration or TypeDefinition ' - - def getTypeDefinition(cls, namespaceURI, name, lazy=False): - '''Grab a type definition, returns a typecode class definition - because the facets (name, minOccurs, maxOccurs) must be provided. - - Parameters: - namespaceURI -- - name -- - ''' - klass = cls.types.get((namespaceURI, name), None) - if lazy and klass is not None: - return _Mirage(klass) - return klass - getTypeDefinition = classmethod(getTypeDefinition) - - def getElementDeclaration(cls, namespaceURI, name, isref=False, lazy=False): - '''Grab an element declaration, returns a typecode instance - representation or a typecode class definition. An element - reference has its own facets, and is local so it will not be - cached. - - Parameters: - namespaceURI -- - name -- - isref -- if element reference, return class definition. - ''' - key = (namespaceURI, name) - if isref: - klass = cls.elements.get(key,None) - if klass is not None and lazy is True: - return _Mirage(klass) - return klass - - typecode = cls.element_typecode_cache.get(key, None) - if typecode is None: - tcls = cls.elements.get(key,None) - if tcls is not None: - typecode = cls.element_typecode_cache[key] = tcls() - typecode.typed = False - - return typecode - getElementDeclaration = classmethod(getElementDeclaration) - - -class ElementDeclaration: - '''Typecodes subclass to represent a Global Element Declaration by - setting class variables schema and literal. - - schema = namespaceURI - literal = NCName - ''' - __metaclass__ = SchemaInstanceType - - -class TypeDefinition: - '''Typecodes subclass to represent a Global Type Definition by - setting class variable type. - - type = (namespaceURI, NCName) - ''' - __metaclass__ = SchemaInstanceType - - def getSubstituteType(self, elt, ps): - '''if xsi:type does not match the instance type attr, - check to see if it is a derived type substitution. - - DONT Return the element's type. - - Parameters: - elt -- the DOM element being parsed - ps -- the ParsedSoap object. - ''' - pyclass = SchemaInstanceType.getTypeDefinition(*self.type) - if pyclass is None: - raise EvaluateException( - 'No Type registed for xsi:type=(%s, %s)' % - (self.type[0], self.type[1]), ps.Backtrace(elt)) - - typeName = _find_type(elt) - prefix,typeName = SplitQName(typeName) - uri = ps.GetElementNSdict(elt).get(prefix) - subclass = SchemaInstanceType.getTypeDefinition(uri, typeName) - if subclass is None: - raise EvaluateException( - 'No registered xsi:type=(%s, %s), substitute for xsi:type=(%s, %s)' % - (uri, typeName, self.type[0], self.type[1]), ps.Backtrace(elt)) - - if not issubclass(subclass, pyclass) and subclass(None) and not issubclass(subclass, pyclass): - raise TypeError( - 'Substitute Type (%s, %s) is not derived from %s' % - (self.type[0], self.type[1], pyclass), ps.Backtrace(elt)) - - return subclass((self.nspname, self.pname)) - - -Nilled = None - class TypeCode: '''The parent class for all parseable SOAP types. Class data: @@ -1482,14 +1327,6 @@ return # Namespace if element AnyType was namespaced. -# if self.nspname != what.nspname: -# what.nspname = self.nspname -# -# if self.pname != what.pname: -# raise EvaluateException, \ -# 'element name of typecode(%s) must match element name of AnyType(%s)' \ -# %(what.pname,self.pname) - what.serialize(elt, sw, pyobj, name=(self.nspname or what.nspname, self.pname or what.pname), **kw) @@ -1503,7 +1340,7 @@ #locate xsi:type prefix, typeName = SplitQName(_find_type(elt)) namespaceURI = _resolve_prefix(elt, prefix) - pyclass = _get_type_definition(namespaceURI, typeName) + pyclass = GTD(namespaceURI, typeName) if not pyclass: if _is_xsd_or_soap_ns(namespaceURI): pyclass = _AnyStrict @@ -1577,14 +1414,14 @@ ''' skip = self.processContents == 'skip' nspname,pname = _get_element_nsuri_name(elt) - what = _get_global_element_declaration(nspname, pname) + what = GED(nspname, pname) if not skip and what is not None: pyobj = what.parse(elt, ps) try: pyobj.typecode = what except AttributeError, ex: # Assume this means builtin type. - pyobj = _GetPyobjWrapper.Wrap(pyobj, what) + pyobj = WrapImmutable(pyobj, what) return pyobj # Allow use of "<any>" element declarations w/ local @@ -1594,14 +1431,14 @@ namespaceURI = _resolve_prefix(elt, prefix or 'xmlns') # First look thru user defined namespaces, if don't find # look for 'primitives'. - pyclass = _get_type_definition(namespaceURI, typeName) or Any + pyclass = GTD(namespaceURI, typeName) or Any what = pyclass(pname=(nspname,pname)) pyobj = what.parse(elt, ps) try: pyobj.typecode = what except AttributeError, ex: # Assume this means builtin type. - pyobj = Wrap(pyobj, what) + pyobj = WrapImmutable(pyobj, what) what.typed = True return pyobj @@ -1619,7 +1456,7 @@ self.logger.error("Give up, parse (%s,%s) as a String", what.nspname, what.pname) what = String(pname=(nspname,pname), typed=False) - pyobj = Wrap(what.parse(elt, ps), what) + pyobj = WrapImmutable(what.parse(elt, ps), what) return pyobj @@ -1643,7 +1480,7 @@ if self.__class__.memberTypes is None: raise EvaluateException, 'uninitialized class variable memberTypes [(namespace,name),]' for nsuri,name in self.__class__.memberTypes: - tcclass = _get_type_definition(nsuri,name) + tcclass = GTD(nsuri,name) if tcclass is None: tc = Any.parsemap.get((nsuri,name)) typecode = tc.__class__(pname=(self.nspname,self.pname)) @@ -1734,7 +1571,7 @@ if type(self.itemTypeCode) in _seqtypes: namespaceURI,name = self.itemTypeCode try: - itemTypeCode = _get_type_definition(*self.itemType)(None) + itemTypeCode = GTD(*self.itemType)(None) except: if _is_xsd_or_soap_ns(namespaceURI) is False: raise @@ -1926,150 +1763,6 @@ return self.checktype(elt, ps) -class _Mirage: - '''Used with SchemaInstanceType for lazy evaluation, eval during serialize or - parse as needed. Mirage is callable, TypeCodes are not. When called it returns the - typecode. Tightly coupled with generated code. - - NOTE: **Must Use ClassType** for intended MRO of __call__ since setting it in - an instance attribute rather than a class attribute (will not work for object). - ''' - def __init__(self, klass): - self.klass = klass - self.__reveal = False - self.__cache = None - if issubclass(klass, ElementDeclaration): - self.__call__ = self._hide_element - - def __str__(self): - msg = "<Mirage id=%s, Local Element %s>" - if issubclass(self.klass, ElementDeclaration): - msg = "<Mirage id=%s, GED %s>" - return msg %(id(self), self.klass) - - def _hide_type(self, pname, aname, minOccurs=0, maxOccurs=1, nillable=False, - **kw): - self.__call__ = self._reveal_type - self.__reveal = True - - # store all attributes, make some visable for pyclass_type - self.__kw = kw - self.minOccurs,self.maxOccurs,self.nillable = minOccurs,maxOccurs,nillable - self.nspname,self.pname,self.aname = None,pname,aname - if type(self.pname) in (tuple,list): - self.nspname,self.pname = pname - - return self - - def _hide_element(self, minOccurs=0, maxOccurs=1, nillable=False, **kw): - self.__call__ = self._reveal_element - self.__reveal = True - - # store all attributes, make some visable for pyclass_type - self.__kw = kw - self.nspname = self.klass.schema - self.pname = self.klass.literal - #TODO: Fix hack - #self.aname = '_%s' %self.pname - self.minOccurs,self.maxOccurs,self.nillable = minOccurs,maxOccurs,nillable - - return self - - def _reveal_type(self): - if self.__cache is None: - self.__cache = self.klass(pname=self.pname, - aname=self.aname, minOccurs=self.minOccurs, - maxOccurs=self.maxOccurs, nillable=self.nillable, - **self.__kw) - return self.__cache - - def _reveal_element(self): - if self.__cache is None: - self.__cache = self.klass(minOccurs=self.minOccurs, - maxOccurs=self.maxOccurs, nillable=self.nillable, - **self.__kw) - return self.__cache - - __call__ = _hide_type - - -class _GetPyobjWrapper: - '''Get a python object that wraps data and typecode. Used by - <any> parse routine, so that typecode information discovered - during parsing is retained in the pyobj representation - and thus can be serialized. - ''' - types_dict = {} - - def RegisterBuiltin(cls, arg): - '''register a builtin, create a new wrapper. - ''' - if arg in cls.types_dict: - raise RuntimeError, '%s already registered' %arg - class _Wrapper(arg): - 'Wrapper for builtin %s\n%s' %(arg, cls.__doc__) - _Wrapper.__name__ = '_%sWrapper' %arg - cls.types_dict[arg] = _Wrapper - RegisterBuiltin = classmethod(RegisterBuiltin) - - def RegisterAnyElement(cls): - '''clobber all existing entries in Any serialmap, - replace with Wrapper classes. - ''' - for k,v in cls.types_dict.items(): - what = Any.serialmap.get(k) - if what is None: continue - if v in what.__class__.seriallist: continue - what.__class__.seriallist.append(v) - RegisterType(what.__class__, clobber=1) - RegisterAnyElement = classmethod(RegisterAnyElement) - - def Wrap(cls, pyobj, what): - '''return a wrapper for pyobj, with typecode attribute set. - Parameters: - pyobj -- instance of builtin type (immutable) - what -- typecode describing the data - ''' - d = cls.types_dict - if type(pyobj) is bool: - pyclass = d[int] - elif d.has_key(type(pyobj)) is True: - pyclass = d[type(pyobj)] - else: - raise TypeError,\ - 'Expecting a built-in type in %s (got %s).' %( - d.keys(),type(pyobj)) - - newobj = pyclass(pyobj) - newobj.typecode = what - return newobj - Wrap = classmethod(Wrap) - - -def Wrap(pyobj, what): - '''Wrap immutable instance so a typecode can be - set, making it self-describing ie. serializable. - ''' - return _GetPyobjWrapper.Wrap(pyobj, what) - - -def RegisterBuiltin(arg): - '''Add a builtin to be registered, and register it - with the Any typecode. - ''' - _GetPyobjWrapper.RegisterBuiltin(arg) - _GetPyobjWrapper.RegisterAnyElement() - - -def RegisterAnyElement(): - '''register all Wrapper classes with the Any typecode. - This allows instances returned by Any to be self-describing. - ie. serializable. AnyElement falls back on Any to parse - anything it doesn't understand. - ''' - return _GetPyobjWrapper.RegisterAnyElement() - - def RegisterType(C, clobber=0, *args, **keywords): instance = apply(C, args, keywords) for t in C.__dict__.get('parselist', []): @@ -2097,19 +1790,18 @@ Any.serialmap[key] = instance -# Load up Wrappers for builtin types -for i in [int,float,str,tuple,list,unicode]: - _GetPyobjWrapper.RegisterBuiltin(i) - - from TCnumbers import * from TCtimes import * +from schema import GTD, GED, WrapImmutable from TCcompound import * from TCapache import * - +# aliases backwards compatiblity +_get_type_definition, _get_global_element_declaration, Wrap = GTD, GED, WrapImmutable + f = lambda x: type(x) == types.ClassType and issubclass(x, TypeCode) and getattr(x, 'type', None) is not None TYPES = filter(f, map(lambda y:eval(y),dir())) + if __name__ == '__main__': print _copyright Modified: trunk/zsi/ZSI/TCcompound.py =================================================================== --- trunk/zsi/ZSI/TCcompound.py 2006-10-18 22:55:32 UTC (rev 1269) +++ trunk/zsi/ZSI/TCcompound.py 2006-10-19 22:31:07 UTC (rev 1270) @@ -7,10 +7,14 @@ _inttypes, _stringtypes, _seqtypes, _find_arraytype, _find_href, \ _find_type, _find_xmlns_prefix, _get_idstr, EvaluateException, \ ParseException -from ZSI.TC import _get_element_nsuri_name, \ - _get_substitute_element, _get_type_definition, _get_xsitype, \ - TypeCode, Any, AnyElement, AnyType, ElementDeclaration, TypeDefinition, \ - Nilled + +from TC import _get_element_nsuri_name, \ + _get_xsitype, TypeCode, Any, AnyElement, AnyType, \ + Nilled, UNBOUNDED + +from schema import ElementDeclaration, TypeDefinition, \ + _get_substitute_element, _get_type_definition + from ZSI.wstools.Namespaces import SCHEMA, SOAP from ZSI.wstools.Utility import SplitQName from ZSI.wstools.logging import getLogger as _GetLogger @@ -236,7 +240,7 @@ 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: + if any.maxOccurs == UNBOUNDED or any.maxOccurs > 1: v[any.aname].append(value) else: v[any.aname] = value @@ -246,7 +250,7 @@ # 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): + 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)) @@ -667,5 +671,4 @@ position += 1 - if __name__ == '__main__': print _copyright Modified: trunk/zsi/ZSI/__init__.py =================================================================== --- trunk/zsi/ZSI/__init__.py 2006-10-18 22:55:32 UTC (rev 1269) +++ trunk/zsi/ZSI/__init__.py 2006-10-19 22:31:07 UTC (rev 1270) @@ -412,11 +412,22 @@ TC.RegisterType(TC.gDay, minOccurs=0, nillable=False) TC.RegisterType(TC.gTime, minOccurs=0, nillable=False) TC.RegisterType(TC.Apache.Map, minOccurs=0, nillable=False) -TC.RegisterAnyElement() -try: - from ServiceProxy import * -except: - pass +## +## Register Wrappers for builtin types. +## TC.AnyElement wraps builtins so element name information can be saved +## +import schema +for i in [int,float,str,tuple,list,unicode]: + schema._GetPyobjWrapper.RegisterBuiltin(i) +## Load up Wrappers for builtin types +schema.RegisterAnyElement() + + +#try: +# from ServiceProxy import * +#except: +# pass + if __name__ == '__main__': print _copyright Modified: trunk/zsi/ZSI/address.py =================================================================== --- trunk/zsi/ZSI/address.py 2006-10-18 22:55:32 UTC (rev 1269) +++ trunk/zsi/ZSI/address.py 2006-10-19 22:31:07 UTC (rev 1270) @@ -5,8 +5,8 @@ import time, urlparse, socket from ZSI import _seqtypes, EvaluateException, WSActionException -from ZSI.TC import _get_global_element_declaration as GED, _get_type_definition as GTD, \ - _has_type_definition, AnyElement, AnyType, TypeCode +from TC import AnyElement, AnyType, TypeCode +from schema import GED, GTD, _has_type_definition from ZSI.TCcompound import ComplexType from ZSI.wstools.Namespaces import WSA_LIST Modified: trunk/zsi/ZSI/generate/containers.py =================================================================== --- trunk/zsi/ZSI/generate/containers.py 2006-10-18 22:55:32 UTC (rev 1269) +++ trunk/zsi/ZSI/generate/containers.py 2006-10-19 22:31:07 UTC (rev 1270) @@ -1047,8 +1047,7 @@ imports = [ 'import ZSI', 'import ZSI.TCcompound', - 'from ZSI.TC import ElementDeclaration,TypeDefinition', - 'from ZSI.TC import _get_type_definition as GTD, _get_global_element_declaration as GED', + 'from ZSI.schema import LocalElementDeclaration, ElementDeclaration, TypeDefinition, GTD, GED', ] logger = _GetLogger("TypesHeaderContainer") Added: trunk/zsi/ZSI/schema.py =================================================================== --- trunk/zsi/ZSI/schema.py (rev 0) +++ trunk/zsi/ZSI/schema.py 2006-10-19 22:31:07 UTC (rev 1270) @@ -0,0 +1,327 @@ +#! /usr/bin/env python +# $Header$ +'''XML Schema support +''' + +from ZSI import _copyright, _seqtypes, _find_type, EvaluateException +from ZSI.wstools.Namespaces import SCHEMA, SOAP +from ZSI.wstools.Utility import SplitQName + + +def _get_type_definition(namespaceURI, name, **kw): + return SchemaInstanceType.getTypeDefinition(namespaceURI, name, **kw) + +def _get_global_element_declaration(namespaceURI, name, **kw): + return SchemaInstanceType.getElementDeclaration(namespaceURI, name, **kw) + +def _get_substitute_element(elt, what): + raise NotImplementedError, 'Not implemented' + +def _has_type_definition(namespaceURI, name): + return SchemaInstanceType.getTypeDefinition(namespaceURI, name) is not None + + +# +# functions for retrieving schema items from +# the global schema instance. +# +GED = _get_global_element_declaration +GTD = _get_type_definition + + +def WrapImmutable(pyobj, what): + '''Wrap immutable instance so a typecode can be + set, making it self-describing ie. serializable. + ''' + return _GetPyobjWrapper.WrapImmutable(pyobj, what) + +def RegisterBuiltin(arg): + '''Add a builtin to be registered, and register it + with the Any typecode. + ''' + _GetPyobjWrapper.RegisterBuiltin(arg) + _GetPyobjWrapper.RegisterAnyElement() + +def RegisterAnyElement(): + '''register all Wrapper classes with the Any typecode. + This allows instances returned by Any to be self-describing. + ie. serializable. AnyElement falls back on Any to parse + anything it doesn't understand. + ''' + return _GetPyobjWrapper.RegisterAnyElement() + + +class SchemaInstanceType(type): + '''Register all types/elements, when hit already defined + class dont create a new one just give back reference. Thus + import order determines which class is loaded. + + class variables: + types -- dict of typecode classes definitions + representing global type definitions. + elements -- dict of typecode classes representing + global element declarations. + element_typecode_cache -- dict of typecode instances + representing global element declarations. + ''' + types = {} + elements = {} + element_typecode_cache = {} + + def __new__(cls,classname,bases,classdict): + '''If classdict has literal and schema register it as a + element declaration, else if has type and schema register + it as a type definition. + ''' + if classname in ['ElementDeclaration', 'TypeDefinition', 'LocalElementDeclaration',]: + return type.__new__(cls,classname,bases,classdict) + + if ElementDeclaration in bases: + if classdict.has_key('schema') is False or classdict.has_key('literal') is False: + raise AttributeError, 'ElementDeclaration must define schema and literal attributes' + + key = (classdict['schema'],classdict['literal']) + if SchemaInstanceType.elements.has_key(key) is False: + SchemaInstanceType.elements[key] = type.__new__(cls,classname,bases,classdict) + return SchemaInstanceType.elements[key] + + if TypeDefinition in bases: + if classdict.has_key('type') is None: + raise AttributeError, 'TypeDefinition must define type attribute' + + key = classdict['type'] + if SchemaInstanceType.types.has_key(key) is False: + SchemaInstanceType.types[key] = type.__new__(cls,classname,bases,classdict) + return SchemaInstanceType.types[key] + + if LocalElementDeclaration in bases: + return type.__new__(cls,classname,bases,classdict) + + raise TypeError, 'SchemaInstanceType must be an ElementDeclaration or TypeDefinition ' + + def getTypeDefinition(cls, namespaceURI, name, lazy=False): + '''Grab a type definition, returns a typecode class definition + because the facets (name, minOccurs, maxOccurs) must be provided. + + Parameters: + namespaceURI -- + name -- + ''' + klass = cls.types.get((namespaceURI, name), None) + if lazy and klass is not None: + return _Mirage(klass) + return klass + getTypeDefinition = classmethod(getTypeDefinition) + + def getElementDeclaration(cls, namespaceURI, name, isref=False, lazy=False): + '''Grab an element declaration, returns a typecode instance + representation or a typecode class definition. An element + reference has its own facets, and is local so it will not be + cached. + + Parameters: + namespaceURI -- + name -- + isref -- if element reference, return class definition. + ''' + key = (namespaceURI, name) + if isref: + klass = cls.elements.get(key,None) + if klass is not None and lazy is True: + return _Mirage(klass) + return klass + + typecode = cls.element_typecode_cache.get(key, None) + if typecode is None: + tcls = cls.elements.get(key,None) + if tcls is not None: + typecode = cls.element_typecode_cache[key] = tcls() + typecode.typed = False + + return typecode + getElementDeclaration = classmethod(getElementDeclaration) + + +class ElementDeclaration: + '''Typecodes subclass to represent a Global Element Declaration by + setting class variables schema and literal. + + schema = namespaceURI + literal = NCName + ''' + __metaclass__ = SchemaInstanceType + + +class LocalElementDeclaration: + '''Typecodes subclass to represent a Local Element Declaration. + ''' + __metaclass__ = SchemaInstanceType + + +class TypeDefinition: + '''Typecodes subclass to represent a Global Type Definition by + setting class variable type. + + type = (namespaceURI, NCName) + ''' + __metaclass__ = SchemaInstanceType + + def getSubstituteType(self, elt, ps): + '''if xsi:type does not match the instance type attr, + check to see if it is a derived type substitution. + + DONT Return the element's type. + + Parameters: + elt -- the DOM element being parsed + ps -- the ParsedSoap object. + ''' + pyclass = SchemaInstanceType.getTypeDefinition(*self.type) + if pyclass is None: + raise EvaluateException( + 'No Type registed for xsi:type=(%s, %s)' % + (self.type[0], self.type[1]), ps.Backtrace(elt)) + + typeName = _find_type(elt) + prefix,typeName = SplitQName(typeName) + uri = ps.GetElementNSdict(elt).get(prefix) + subclass = SchemaInstanceType.getTypeDefinition(uri, typeName) + if subclass is None: + raise EvaluateException( + 'No registered xsi:type=(%s, %s), substitute for xsi:type=(%s, %s)' % + (uri, typeName, self.type[0], self.type[1]), ps.Backtrace(elt)) + + if not issubclass(subclass, pyclass) and subclass(None) and not issubclass(subclass, pyclass): + raise TypeError( + 'Substitute Type (%s, %s) is not derived from %s' % + (self.type[0], self.type[1], pyclass), ps.Backtrace(elt)) + + return subclass((self.nspname, self.pname)) + + + +class _Mirage: + '''Used with SchemaInstanceType for lazy evaluation, eval during serialize or + parse as needed. Mirage is callable, TypeCodes are not. When called it returns the + typecode. Tightly coupled with generated code. + + NOTE: **Must Use ClassType** for intended MRO of __call__ since setting it in + an instance attribute rather than a class attribute (will not work for object). + ''' + def __init__(self, klass): + self.klass = klass + self.__reveal = False + self.__cache = None + if issubclass(klass, ElementDeclaration): + self.__call__ = self._hide_element + + def __str__(self): + msg = "<Mirage id=%s, Local Element %s>" + if issubclass(self.klass, ElementDeclaration): + msg = "<Mirage id=%s, GED %s>" + return msg %(id(self), self.klass) + + def _hide_type(self, pname, aname, minOccurs=0, maxOccurs=1, nillable=False, + **kw): + self.__call__ = self._reveal_type + self.__reveal = True + + # store all attributes, make some visable for pyclass_type + self.__kw = kw + self.minOccurs,self.maxOccurs,self.nillable = minOccurs,maxOccurs,nillable + self.nspname,self.pname,self.aname = None,pname,aname + if type(self.pname) in (tuple,list): + self.nspname,self.pname = pname + + return self + + def _hide_element(self, minOccurs=0, maxOccurs=1, nillable=False, **kw): + self.__call__ = self._reveal_element + self.__reveal = True + + # store all attributes, make some visable for pyclass_type + self.__kw = kw + self.nspname = self.klass.schema + self.pname = self.klass.literal + #TODO: Fix hack + #self.aname = '_%s' %self.pname + self.minOccurs,self.maxOccurs,self.nillable = minOccurs,maxOccurs,nillable + + return self + + def _reveal_type(self): + if self.__cache is None: + self.__cache = self.klass(pname=self.pname, + aname=self.aname, minOccurs=self.minOccurs, + maxOccurs=self.maxOccurs, nillable=self.nillable, + **self.__kw) + return self.__cache + + def _reveal_element(self): + if self.__cache is None: + self.__cache = self.klass(minOccurs=self.minOccurs, + maxOccurs=self.maxOccurs, nillable=self.nillable, + **self.__kw) + return self.__cache + + __call__ = _hide_type + + +class _GetPyobjWrapper: + '''Get a python object that wraps data and typecode. Used by + <any> parse routine, so that typecode information discovered + during parsing is retained in the pyobj representation + and thus can be serialized. + ''' + types_dict = {} + + def RegisterBuiltin(cls, arg): + '''register a builtin, create a new wrapper. + ''' + if arg in cls.types_dict: + raise RuntimeError, '%s already registered' %arg + class _Wrapper(arg): + 'Wrapper for builtin %s\n%s' %(arg, cls.__doc__) + _Wrapper.__name__ = '_%sWrapper' %arg.__name__ + cls.types_dict[arg] = _Wrapper + RegisterBuiltin = classmethod(RegisterBuiltin) + + def RegisterAnyElement(cls): + '''If find registered TypeCode instance, add Wrapper class + to TypeCode class serialmap and Re-RegisterType. Provides + Any serialzation of any instances of the Wrapper. + ''' + for k,v in cls.types_dict.items(): + what = Any.serialmap.get(k) + if what is None: continue + if v in what.__class__.seriallist: continue + what.__class__.seriallist.append(v) + RegisterType(what.__class__, clobber=1, **what.__dict__) + RegisterAnyElement = classmethod(RegisterAnyElement) + + def WrapImmutable(cls, pyobj, what): + '''return a wrapper for pyobj, with typecode attribute set. + Parameters: + pyobj -- instance of builtin type (immutable) + what -- typecode describing the data + ''' + d = cls.types_dict + if type(pyobj) is bool: + pyclass = d[int] + elif d.has_key(type(pyobj)) is True: + pyclass = d[type(pyobj)] + else: + raise TypeError,\ + 'Expecting a built-in type in %s (got %s).' %( + d.keys(),type(pyobj)) + + newobj = pyclass(pyobj) + newobj.typecode = what + return newobj + WrapImmutable = classmethod(WrapImmutable) + + +from TC import Any, RegisterType + +if __name__ == '__main__': print _copyright + Modified: trunk/zsi/ZSI/writer.py =================================================================== --- trunk/zsi/ZSI/writer.py 2006-10-18 22:55:32 UTC (rev 1269) +++ trunk/zsi/ZSI/writer.py 2006-10-19 22:31:07 UTC (rev 1270) @@ -5,7 +5,6 @@ from ZSI import _copyright, _get_idstr, ZSI_SCHEMA_URI from ZSI import _backtrace, _stringtypes, _seqtypes -from ZSI.TC import AnyElement, TypeCode from ZSI.wstools.Utility import MessageInterface, ElementProxy from ZSI.wstools.Namespaces import XMLNS, SOAP, SCHEMA from ZSI.wstools.c14n import Canonicalize Modified: trunk/zsi/test/test_t8.py =================================================================== --- trunk/zsi/test/test_t8.py 2006-10-18 22:55:32 UTC (rev 1269) +++ trunk/zsi/test/test_t8.py 2006-10-19 22:31:07 UTC (rev 1270) @@ -1,6 +1,6 @@ #!/usr/bin/env python -import unittest, sys -from ZSI import * +import unittest, sys, types, time +from ZSI import TC, SoapWriter, ParsedSoap, EvaluateException from ZSI.wstools.Namespaces import SCHEMA, SOAP NSDICT = {'tns':'xmlns:tns="urn:a"', @@ -39,7 +39,7 @@ sw.serialize(None, typecode=tc, typed=True) soap = str(sw) ps = ParsedSoap(soap) - parsed = ps.Parse(Any()) + parsed = ps.Parse(TC.Any()) self.assertEqual(None, parsed) def check_parse_empty_string(self): @@ -50,7 +50,7 @@ sw.serialize("", typecode=tc, typed=True) soap = str(sw) ps = ParsedSoap(soap) - parsed = ps.Parse(Any()) + parsed = ps.Parse(TC.Any()) self.assertEqual("", parsed) def check_builtins(self): @@ -59,10 +59,10 @@ orig = [myInt,myLong,myStr,myDate,myFloat] sw = SoapWriter() - sw.serialize(orig, typecode=Any(pname="builtins", aslist=True)) + sw.serialize(orig, typecode=TC.Any(pname="builtins", aslist=True)) ps = ParsedSoap(str(sw)) - parsed = ps.Parse(Any()) + parsed = ps.Parse(TC.Any()) self.assertEqual(len(orig), len(parsed)) self.assertEqual(myInt, parsed[0]) This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <bov...@us...> - 2006-10-20 23:26:58
|
Revision: 1271 http://svn.sourceforge.net/pywebsvcs/?rev=1271&view=rev Author: boverhof Date: 2006-10-20 16:26:53 -0700 (Fri, 20 Oct 2006) Log Message: ----------- M test/wsdl2py/test_AWSECommerceService.py M test/wsdl2py/config.txt M ZSI/generate/containers.py M CHANGES [ 1525567 ] Amazon ECommerce Issues Now wsdl2py layer looks to see if element is local, if is marks as "LocalElementDeclaration". Modified Paths: -------------- trunk/zsi/CHANGES trunk/zsi/ZSI/generate/containers.py trunk/zsi/test/wsdl2py/config.txt trunk/zsi/test/wsdl2py/test_AWSECommerceService.py Modified: trunk/zsi/CHANGES =================================================================== --- trunk/zsi/CHANGES 2006-10-19 22:31:07 UTC (rev 1270) +++ trunk/zsi/CHANGES 2006-10-20 23:26:53 UTC (rev 1271) @@ -6,9 +6,12 @@ - Record facets (restrictions) in XMLSchema.py <vc...@da...> - Remove Send()'s kwargs out of _args list <ef...@bo...> -Change for 2.0.0 released xxx: +Change for 2.0.0rc3 released xxx: - Removed "requestclass" keyword argument to Binding.Send - simplified and retooled Binding/NamedParamBinding and dispatch. + - BUG [ 1525567 ] Amazon ECommerce Issues: local element declarations + overriding global element declarations with the same name within the + same namespace. Change for 2.0.0rc2 released 28-March-2006: - Replace many/most id() with _get_idstr() to hide negative numbers Modified: trunk/zsi/ZSI/generate/containers.py =================================================================== --- trunk/zsi/ZSI/generate/containers.py 2006-10-19 22:31:07 UTC (rev 1270) +++ trunk/zsi/ZSI/generate/containers.py 2006-10-20 23:26:53 UTC (rev 1271) @@ -1888,8 +1888,49 @@ type = DEC logger = _GetLogger("ElementSimpleTypeContainer") + def _setContent(self): + aname = self.getAttributeName(self.name) + pyclass = self.pyclass + + # bool cannot be subclassed + if pyclass == 'bool': pyclass = 'int' + kw = KW.copy() + kw.update(dict(aname=aname, ns=self.ns, name=self.name, + subclass=self.sKlass,literal=self.literalTag(), + schema=self.schemaTag(), init=self.simpleConstructor(), + klass=self.getClassName(), element="ElementDeclaration")) + + if self.local: + kw['element'] = 'LocalElementDeclaration' + + element = map(lambda i: i %kw, [ + '%(ID1)sclass %(klass)s(%(subclass)s, %(element)s):', + '%(ID2)s%(literal)s', + '%(ID2)s%(schema)s', + '%(ID2)s%(init)s', + '%(ID3)skw["pname"] = ("%(ns)s","%(name)s")', + '%(ID3)skw["aname"] = "%(aname)s"', + ] + ) + + # TODO: What about getPyClass and getPyClassDefinition? + # I want to add pyclass metaclass here but this needs to be + # corrected first. + # + # anyType (?others) has no pyclass. + app = element.append + if pyclass is not None: + app('%sclass IHolder(%s): typecode=self' % (ID3, pyclass),) + app('%skw["pyclass"] = IHolder' %(ID3),) + app('%sIHolder.__name__ = "%s_immutable_holder"' %(ID3, aname),) + + app('%s%s' % (ID3, self.simpleConstructor(self.sKlass)),) + + self.writeArray(element) + def setUp(self, tp): self._item = tp + self.local = tp.isLocal() try: self.name = tp.getAttribute('name') self.ns = tp.getTargetNamespace() @@ -1912,39 +1953,7 @@ raise Wsdl2PythonError('Error occured processing element: %s' %( tp.getItemTrace()), *ex.args) - def _setContent(self): - aname = self.getAttributeName(self.name) - pyclass = self.pyclass - # bool cannot be subclassed - if pyclass == 'bool': pyclass = 'int' - - element = [ - '%sclass %s(%s, ElementDeclaration):'\ - % (ID1, self.getClassName(), self.sKlass), - '%s%s' % (ID2, self.literalTag()), - '%s%s' % (ID2, self.schemaTag()), - '%s%s' % (ID2, self.simpleConstructor()), - '%skw["pname"] = ("%s","%s")' % (ID3, self.ns, self.name), - '%skw["aname"] = "%s"' % (ID3, aname), - ] - - # TODO: What about getPyClass and getPyClassDefinition? - # I want to add pyclass metaclass here but this needs to be - # corrected first. - # - # anyType (?others) has no pyclass. - app = element.append - if pyclass is not None: - app('%sclass IHolder(%s): typecode=self' % (ID3, pyclass),) - app('%skw["pyclass"] = IHolder' %(ID3),) - app('%sIHolder.__name__ = "%s_immutable_holder"' %(ID3, aname),) - - app('%s%s' % (ID3, self.simpleConstructor(self.sKlass)),) - - self.writeArray(element) - - class ElementLocalSimpleTypeContainer(TypecodeContainerBase): '''local simpleType container ''' @@ -1952,18 +1961,26 @@ logger = _GetLogger("ElementLocalSimpleTypeContainer") def _setContent(self): + kw = KW.copy() + kw.update(dict(aname=self.getAttributeName(self.name), ns=self.ns, name=self.name, + subclass=self.sKlass,literal=self.literalTag(), + schema=self.schemaTag(), init=self.simpleConstructor(), + klass=self.getClassName(), element="ElementDeclaration", + baseinit=self.simpleConstructor(self.sKlass))) - element = [ - '%sclass %s(%s, ElementDeclaration):' % (ID1, self.getClassName(), - self.sKlass), - '%s%s' % (ID2, self.literalTag()), - '%s%s' % (ID2, self.schemaTag()), - '%s%s' % (ID2, self.simpleConstructor()), - '%skw["pname"] = ("%s","%s")' % (ID3, self.ns, self.name), - '%skw["aname"] = "%s"' % (ID3, self.getAttributeName(self.name)), - '%s%s' % (ID3, self.simpleConstructor(self.sKlass)), + if self.local: + kw['element'] = 'LocalElementDeclaration' + + element = map(lambda i: i %kw, [ + '%(ID1)sclass %(klass)s(%(subclass)s, %(element)s):', + '%(ID2)s%(literal)s', + '%(ID2)s%(schema)s', + '%(ID2)s%(init)s', + '%(ID3)skw["pname"] = ("%(ns)s","%(name)s")', + '%(ID3)skw["aname"] = "%(aname)s"', + '%(ID3)s%(baseinit)s', ] - + ) self.writeArray(element) def setUp(self, tp): @@ -1972,6 +1989,7 @@ tp.content.isLocal() is True and tp.content.isSimple() is True ,\ 'expecting local simple type: %s' %tp.getItemTrace() + self.local = tp.isLocal() self.name = tp.getAttribute('name') self.ns = tp.getTargetNamespace() content = tp.content.content @@ -2012,16 +2030,62 @@ class ElementLocalComplexTypeContainer(TypecodeContainerBase, AttributeMixIn): - type = DEC logger = _GetLogger("ElementLocalComplexTypeContainer") + def _setContent(self): + kw = KW.copy() + try: + kw.update(dict(klass=self.getClassName(), + subclass='ZSI.TCcompound.ComplexType', + element='ElementDeclaration', + literal=self.literalTag(), + schema=self.schemaTag(), + init=self.simpleConstructor(), + ns=self.ns, name=self.name, + aname=self.getAttributeName(self.name), + nsurilogic=self.nsuriLogic(), + ofwhat=self.getTypecodeList(), + atypecode=self.attribute_typecode, + pyclass=self.getPyClass(), + )) + except Exception, ex: + args = ['Failure processing an element w/local complexType: %s' %( + self._item.getItemTrace())] + args += ex.args + ex.args = tuple(args) + raise + + if self.local: + kw['element'] = 'LocalElementDeclaration' + + element = [ + '%(ID1)sclass %(klass)s(%(subclass)s, %(element)s):', + '%(ID2)s%(literal)s', + '%(ID2)s%(schema)s', + '%(ID2)s%(init)s', + '%(ID3)s%(nsurilogic)s', + '%(ID3)sTClist = [%(ofwhat)s]', + '%(ID3)skw["pname"] = ("%(ns)s","%(name)s")', + '%(ID3)skw["aname"] = "%(aname)s"', + '%(ID3)s%(atypecode)s = {}', + '%(ID3)sZSI.TCcompound.ComplexType.__init__(self,None,TClist,inorder=0,**kw)', + ] + for l in self.attrComponents: element.append('%(ID3)s'+str(l)) + element += self.getPyClassDefinition() + element.append('%(ID3)sself.pyclass = %(pyclass)s' %kw) + self.writeArray(map(lambda l: l %kw, element)) + def setUp(self, tp): ''' {'xsd':['annotation', 'simpleContent', 'complexContent',\ 'group', 'all', 'choice', 'sequence', 'attribute', 'attributeGroup',\ 'anyAttribute', 'any']} ''' + # + # TODO: Need a Recursive solution, this is incomplete will ignore many + # extensions, restrictions, etc. + # self._item = tp # JRB HACK SUPPORTING element/no content. assert tp.isElement() is True and \ @@ -2030,6 +2094,7 @@ self.name = tp.getAttribute('name') self.ns = tp.getTargetNamespace() + self.local = tp.isLocal() complex = tp.content # JRB HACK SUPPORTING element/no content. @@ -2037,124 +2102,130 @@ self.mgContent = () return - attributeContent = complex.getAttributeContent() - - self.mgContent = None + #attributeContent = complex.getAttributeContent() + #self.mgContent = None if complex.content is None: self.mgContent = () - elif complex.content.isSimple(): - if complex.content.content.isExtension(): - # TODO: Not really supported just passing thru - pass - elif complex.content.content.isRestriction(): - # TODO: Not really supported just passing thru - pass - else: - raise ContainerError,\ - 'not implemented local complexType/simpleContent: %s'\ - %tp.getItemTrace() - elif complex.content.isComplex() is True: - if complex.content.content is None: - self.mgContent = () - elif complex.content.content.isExtension() is True and\ - complex.content.content.content is not None and\ - complex.content.content.content.isModelGroup() is True: - self.mgContent = complex.content.content.content.content - attributeContent = \ + self.attrComponents = self._setAttributes(complex.getAttributeContent()) + return + + is_simple = complex.content.isSimple() + if is_simple and complex.content.content.isExtension(): + # TODO: Not really supported just passing thru + self.mgContent = () + self.attrComponents = self._setAttributes(complex.getAttributeContent()) + return + + if is_simple and complex.content.content.isRestriction(): + # TODO: Not really supported just passing thru + self.mgContent = () + self.attrComponents = self._setAttributes(complex.getAttributeContent()) + return + + if is_simple: + raise ContainerError, 'not implemented local complexType/simpleContent: %s'\ + %tp.getItemTrace() + + is_complex = complex.content.isComplex() + if is_complex and complex.content.content is None: + # TODO: Recursion... + self.mgContent = () + self.attrComponents = self._setAttributes(complex.getAttributeContent()) + return + + if (is_complex and complex.content.content.isExtension() and + complex.content.content.content is not None and + complex.content.content.content.isModelGroup()): + + self.mgContent = complex.content.content.content.content + self.attrComponents = self._setAttributes( complex.content.content.getAttributeContent() - elif complex.content.content.isRestriction() is True and\ - complex.content.content.content is not None and\ - complex.content.content.content.isModelGroup() is True: - self.mgContent = complex.content.content.content.content - attributeContent = \ + ) + return + + if (is_complex and complex.content.content.isRestriction() and + complex.content.content.content is not None and + complex.content.content.content.isModelGroup()): + + self.mgContent = complex.content.content.content.content + self.attrComponents = self._setAttributes( complex.content.content.getAttributeContent() - elif complex.content.isModelGroup() is True: - self.mgContent = complex.content.content + ) + return - if self.mgContent is None: + if is_complex: self.mgContent = () - assert type(self.mgContent) is tuple, 'XXX: %s' %self.mgContent.getItemTrace() + self.attrComponents = self._setAttributes(complex.getAttributeContent()) + return - self.attrComponents = self._setAttributes(attributeContent) + if complex.content.isModelGroup(): + self.mgContent = complex.content.content + self.attrComponents = self._setAttributes(complex.getAttributeContent()) + return + + # TODO: Scary Fallthru + self.mgContent = () + self.attrComponents = self._setAttributes(complex.getAttributeContent()) + +class ElementGlobalDefContainer(TypecodeContainerBase): + type = DEC + logger = _GetLogger("ElementGlobalDefContainer") + def _setContent(self): + '''GED defines element name, so also define typecode aname + ''' + kw = KW.copy() try: - element = [ - '%sclass %s(ZSI.TCcompound.ComplexType, ElementDeclaration):' \ - % (ID1,self.getClassName()), - '%s%s' % (ID2, self.schemaTag()), - '%s%s' % (ID2, self.literalTag()), - '%s%s' % (ID2, self.simpleConstructor()), - #'%s' % self.getElements(), - '%s%s' % (ID3, self.nsuriLogic()), - '%sTClist = [%s]' % (ID3, self.getTypecodeList()), - '%skw["pname"] = ("%s","%s")' % (ID3, self.ns, self.name), - '%skw["aname"] = "%s"' % (ID3, self.getAttributeName(self.name)), - ] + kw.update(dict(klass=self.getClassName(), + element='ElementDeclaration', + literal=self.literalTag(), + schema=self.schemaTag(), + init=self.simpleConstructor(), + ns=self.ns, name=self.name, + aname=self.getAttributeName(self.name), + baseslogic=self.getBasesLogic(ID3), + #ofwhat=self.getTypecodeList(), + #atypecode=self.attribute_typecode, + #pyclass=self.getPyClass(), + alias=NAD.getAlias(self.sKlassNS), + subclass=type_class_name(self.sKlass), + )) except Exception, ex: - args = ['Failure processing an element w/local complexType: %s' %self._item.getItemTrace()] + args = ['Failure processing an element w/local complexType: %s' %( + self._item.getItemTrace())] args += ex.args ex.args = tuple(args) raise - element.append('%s%s = {}'%(ID3, self.attribute_typecode)) - element.append(\ - '%(ID3)sZSI.TCcompound.ComplexType.__init__(self, None, TClist, inorder=0, **kw)' %KW - ) - for l in self.attrComponents: element.append('%s%s'%(ID3, l)) - - # pyclass class definition - element += self.getPyClassDefinition() - - # set pyclass - kw = KW.copy() - kw['pyclass'] = self.getPyClass() - element.append('%(ID3)sself.pyclass = %(pyclass)s' %kw) - - self.writeArray(element) + if self.local: + kw['element'] = 'LocalElementDeclaration' - -class ElementGlobalDefContainer(TypecodeContainerBase): + element = [ + '%(ID1)sclass %(klass)s(%(element)s):', + '%(ID2)s%(literal)s', + '%(ID2)s%(schema)s', + '%(ID2)s%(init)s', + '%(ID3)skw["pname"] = ("%(ns)s","%(name)s")', + '%(ID3)skw["aname"] = "%(aname)s"', + '%(baseslogic)s', + '%(ID3)s%(alias)s.%(subclass)s.__init__(self, **kw)', + '%(ID3)sif self.pyclass is not None: self.pyclass.__name__ = "%(klass)s_Holder"', + ] - type = DEC - logger = _GetLogger("ElementGlobalDefContainer") + self.writeArray(map(lambda l: l %kw, element)) def setUp(self, element): # Save for debugging self._item = element - + self.local = element.isLocal() self.name = element.getAttribute('name') self.ns = element.getTargetNamespace() - tp = element.getTypeDefinition('type') self.sKlass = tp.getAttribute('name') self.sKlassNS = tp.getTargetNamespace() - def _setContent(self): - '''GED defines element name, so also define typecode aname - ''' - try: - element = [ - '%sclass %s(ElementDeclaration):' % (ID1, self.getClassName()), - '%s%s' % (ID2, self.literalTag()), - '%s%s' % (ID2, self.schemaTag()), - '%s%s' % (ID2, self.simpleConstructor()), - '%skw["pname"] = ("%s","%s")' % (ID3, self.ns, self.name), - '%skw["aname"] = "%s"' % (ID3, self.getAttributeName(self.name)), - '%s' % self.getBasesLogic(ID3), - '%s%s.%s.__init__(self, **kw)' \ - % (ID3, NAD.getAlias(self.sKlassNS), type_class_name(self.sKlass) ), - '%sif self.pyclass is not None: self.pyclass.__name__ = "%s_Holder"' %(ID3, self.getClassName()), - ] - except Exception, ex: - args = ['Failure processing an element w/global definition: %s' %self._item.getItemTrace()] - args += ex.args - ex.args = tuple(args) - raise - - self.writeArray(element) - class ComplexTypeComplexContentContainer(TypecodeContainerBase, AttributeMixIn): '''Represents ComplexType with ComplexContent. ''' Modified: trunk/zsi/test/wsdl2py/config.txt =================================================================== --- trunk/zsi/test/wsdl2py/config.txt 2006-10-19 22:31:07 UTC (rev 1270) +++ trunk/zsi/test/wsdl2py/config.txt 2006-10-20 23:26:53 UTC (rev 1271) @@ -114,13 +114,13 @@ document = True literal = True broke = False -tests = test_MapPoint test_OpcDaGateway test_Sabre test_Echo +tests = test_MapPoint test_OpcDaGateway test_Sabre test_Echo test_AWSECommerceService [doc_literal_broke] document = True literal = True broke = True -tests = test_AWSECommerceService +tests = [doc_literal_broke_interop] document = True Modified: trunk/zsi/test/wsdl2py/test_AWSECommerceService.py =================================================================== --- trunk/zsi/test/wsdl2py/test_AWSECommerceService.py 2006-10-19 22:31:07 UTC (rev 1270) +++ trunk/zsi/test/wsdl2py/test_AWSECommerceService.py 2006-10-20 23:26:53 UTC (rev 1271) @@ -6,6 +6,8 @@ ########################################################################### import sys, unittest from ServiceTest import main, ServiceTestCase, ServiceTestSuite, TestException +from ZSI.schema import ElementDeclaration, GED +from ZSI import ParsedSoap """ Unittest for contacting the Amazon ECommerce Service @@ -51,7 +53,45 @@ ServiceTestCase.__init__(self, methodName) self.wsdl2py_args.append('-b') self.wsdl2py_args.append('--lazy') + + def test_local_bug_1525567(self): + element = GED("http://webservices.amazon.com/AWSECommerceService/2006-09-18", 'Items') + # Make sure this is a GED + self.failUnless(isinstance(element, ElementDeclaration), '"%s" not a GED' %element) + def test_local_parse_ItemSearch(self): + msg = self.client_module.ItemSearchResponseMsg() + ps = ParsedSoap(ItemSearchResponseMsg) + response = ps.Parse(msg.typecode) + response.OperationRequest.Arguments + for i in response.OperationRequest.Arguments.Argument: + i.get_attribute_Name() + i.get_attribute_Value() + + for i in response.OperationRequest.HTTPHeaders.Header or []: + i.get_attribute_Name() + i.get_attribute_Value() + + response.OperationRequest.RequestId + response.OperationRequest.RequestProcessingTime + for its in response.Items: + self.failUnless(its.TotalResults == 55, '') + self.failUnless(its.TotalPages == 6, '') + for it in its.Item: + it.ASIN; + it.Accessories; + #it.AlternateVersions; + it.BrowseNodes + #it.Collections; + it.CustomerReviews ;it.DetailPageURL + it.EditorialReviews; it.Errors; it.ImageSets; it.ItemAttributes + it.LargeImage; it.ListmaniaLists; it.MediumImage; it.MerchantItemAttributes + it.OfferSummary; it.Offers; + #it.ParentASIN; + it.SalesRank; it.SearchInside + it.SimilarProducts; it.SmallImage; it.Subjects; it.Tracks; + + def test_net_ItemSearch(self): loc = self.client_module.AWSECommerceServiceLocator() port = loc.getAWSECommerceServicePortType(**self.getPortKWArgs()) @@ -87,15 +127,24 @@ for it in its.Item: it.ASIN; it.Accessories; - it.AlternateVersions; + #it.AlternateVersions; it.BrowseNodes - it.Collections; it.CustomerReviews ;it.DetailPageURL + #it.Collections; + it.CustomerReviews ;it.DetailPageURL it.EditorialReviews; it.Errors; it.ImageSets; it.ItemAttributes it.LargeImage; it.ListmaniaLists; it.MediumImage; it.MerchantItemAttributes - it.OfferSummary; it.Offers; it.ParentASIN; it.SalesRank; it.SearchInside + it.OfferSummary; it.Offers; + #it.ParentASIN; + it.SalesRank; it.SearchInside it.SimilarProducts; it.SmallImage; it.Subjects; it.Tracks; it.VariationSummary; it.Variations -if __name__ == "__main__" : +ItemSearchResponseMsg="""<?xml version="1.0" encoding="UTF-8"?> +<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" +xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/" +xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" +xmlns:xsd="http://www.w3.org/2001/XMLSchema"><SOAP-ENV:Body><ItemSearchResponse xmlns="http://webservices.amazon.com/AWSECommerceService/2006-09-18"><OperationRequest><HTTPHeaders><Header Name="UserAgent"></Header></HTTPHeaders><RequestId>1C167XDF9BX253MEYAF2</RequestId><Arguments><Argument Name="Service" Value="AWSECommerceService"></Argument></Arguments><RequestProcessingTime>0.987805128097534</RequestProcessingTime></OperationRequest><Items><Request><IsValid>True</IsValid><ItemSearchRequest><ItemPage>1</ItemPage><Keywords>Tamerlane</Keywords><ResponseGroup>Medium</ResponseGroup><SearchIndex>Books</SearchIndex></ItemSearchRequest></Request><TotalResults>55</TotalResults><TotalPages>6</TotalPages><Item><ASIN>030681465X</ASIN><DetailPageURL>http://www.amazon.com/gp/redirect.html%3FASIN=030681465X%26tag=ws%26lcode=sp1%26cID=2025%26ccmID=165953%26location=/o/ASIN/030681465X%253FSubscriptionId=0HP1WHME000749APYWR2</DetailPageURL><SalesRank>135340</SalesRank><SmallImage><URL>http://images.amazon.com/images/P/030681465X.01._SCTHUMBZZZ_V66860320_.jpg</URL><Height Units="pixels">75</Height><Width Units="pixels">50</Width></SmallImage><MediumImage><URL>http://images.amazon.com/images/P/030681465X.01._SCMZZZZZZZ_V66860320_.jpg</URL><Height Units="pixels">160</Height><Width Units="pixels">108</Width></MediumImage><LargeImage><URL>http://images.amazon.com/images/P/030681465X.01._SCLZZZZZZZ_V66860320_.jpg</URL><Height Units="pixels">500</Height><Width Units="pixels">337</Width></LargeImage><ImageSets><ImageSet Category="primary"><SmallImage><URL>http://images.amazon.com/images/P/030681465X.01._SCTHUMBZZZ_V66860320_.jpg</URL><Height Units="pixels">75</Height><Width Units="pixels">50</Width></SmallImage><MediumImage><URL>http://images.amazon.com/images/P/030681465X.01._SCMZZZZZZZ_V66860320_.jpg</URL><Height Units="pixels">160</Height><Width Units="pixels">108</Width></MediumImage><LargeImage><URL>http://images.amazon.com/images/P/030681465X.01._SCLZZZZZZZ_V66860320_.jpg</URL><Height Units="pixels">500</Height><Width Units="pixels">337</Width></LargeImage></ImageSet></ImageSets><ItemAttributes><Author>Justin Marozzi</Author><Binding>Hardcover</Binding><DeweyDecimalNumber>920</DeweyDecimalNumber><EAN>9780306814655</EAN><Edition>New Ed</Edition><ISBN>030681465X</ISBN><Label>Da Capo Press</Label><ListPrice><Amount>2695</Amount><CurrencyCode>USD</CurrencyCode><FormattedPrice>$26.95</FormattedPrice></ListPrice><Manufacturer>Da Capo Press</Manufacturer><NumberOfItems>1</NumberOfItems><NumberOfPages>368</NumberOfPages><PackageDimensions><Height Units="hundredths-inches">150</Height><Length Units="hundredths-inches">904</Length><Weight Units="hundredths-pounds">174</Weight><Width Units="hundredths-inches">640</Width></PackageDimensions><ProductGroup>Book</ProductGroup><PublicationDate>2006-02-22</PublicationDate><Publisher>Da Capo Press</Publisher><Studio>Da Capo Press</Studio><Title>Tamerlane: Sword of Islam, Conqueror of the World</Title></ItemAttributes><OfferSummary><LowestNewPrice><Amount>831</Amount><CurrencyCode>USD</CurrencyCode><FormattedPrice>$8.31</FormattedPrice></LowestNewPrice><LowestUsedPrice><Amount>832</Amount><CurrencyCode>USD</CurrencyCode><FormattedPrice>$8.32</FormattedPrice></LowestUsedPrice><TotalNew>43</TotalNew><TotalUsed>26</TotalUsed><TotalCollectible>0</TotalCollectible><TotalRefurbished>0</TotalRefurbished></OfferSummary><EditorialReviews><EditorialReview><Source>Book Description</Source><Content>A powerful account of the life of Tamerlane the Great (1336-1405), the last great Mongol conqueror of Central Asia, ruler of a vast empire, and one of history's most brutal tyrants <P> Tamerlane, aka Temur-the Mongol successor to Genghis Khan-ranks with Alexander the Great as one of the world's great conquerors, yet the details of his life are scarcely known in the West. Born in obscurity and poverty, he rose to become a fierce tribal leader, and with that his dominion and power grew with astonishing speed. He blazed through Asia, razing cities to the ground. He tortured conquered inhabitants without mercy, sometimes ordering them buried alive, at other times decapitating them. Over the ruins of conquered Baghdad, Tamerlane had his soldiers erect a pyramid of 90,000 enemy heads. As he and his armies swept through Central Asia, sacking, and then rebuilding cities, Tamerlane gradually imposed an iron rule and a refined culture over a vast territory-from the steppes of Asia to the Syrian coastline. <P> Justin Marozzi traveled in the footsteps of this fearsome emperor of Samarkand (modern-day Uzbekistan) to write this book, which is part history, part travelogue. He carefully follows the path of this infamous and enigmatic conqueror, recounting the history and the story of this cruel, cultivated, and indomitable warrior.</Content></EditorialReview></EditorialReviews></Item><Item><ASIN>1853141046</ASIN><DetailPageURL>http://www.amazon.com/gp/redirect.html%3FASIN=1853141046%26tag=ws%26lcode=sp1%26cID=2025%26ccmID=165953%26location=/o/ASIN/1853141046%253FSubscriptionId=0HP1WHME000749APYWR2</DetailPageURL><SalesRank>366445</SalesRank><ItemAttributes><Author>David Nicolle</Author><Author>Richard Hook</Author><Binding>Hardcover</Binding><DeweyDecimalNumber>950.20922</DeweyDecimalNumber><EAN>9781853141041</EAN><ISBN>1853141046</ISBN><Label>Firebird</Label><ListPrice><Amount>2495</Amount><CurrencyCode>USD</CurrencyCode><FormattedPrice>$24.95</FormattedPrice></ListPrice><Manufacturer>Firebird</Manufacturer><NumberOfItems>1</NumberOfItems><NumberOfPages>208</NumberOfPages><PackageDimensions><Height Units="hundredths-inches">1000</Height><Length Units="hundredths-inches">75</Length><Weight Units="hundredths-pounds">160</Weight><Width Units="hundredths-inches">775</Width></PackageDimensions><ProductGroup>Book</ProductGroup><PublicationDate>1990-09</PublicationDate><Publisher>Firebird</Publisher><Studio>Firebird</Studio><Title>The Mongol Warlords: Ghengis Khan, Kublai Khan, Hulegu, Tamerlane (Heroes & Warriors)</Title></ItemAttributes><OfferSummary><LowestUsedPrice><Amount>1095</Amount><CurrencyCode>USD</CurrencyCode><FormattedPrice>$10.95</FormattedPrice></LowestUsedPrice><TotalNew>0</TotalNew><TotalUsed>3</TotalUsed><TotalCollectible>0</TotalCollectible><TotalRefurbished>0</TotalRefurbished></OfferSummary></Item><Item><ASIN>0521633842</ASIN><DetailPageURL>http://www.amazon.com/gp/redirect.html%3FASIN=0521633842%26tag=ws%26lcode=sp1%26cID=2025%26ccmID=165953%26location=/o/ASIN/0521633842%253FSubscriptionId=0HP1WHME000749APYWR2</DetailPageURL><SalesRank>429712</SalesRank><SmallImage><URL>http://images.amazon.com/images/P/0521633842.01._SCTHUMBZZZ_V1114821525_.jpg</URL><Height Units="pixels">60</Height><Width Units="pixels">39</Width></SmallImage><MediumImage><URL>http://images.amazon.com/images/P/0521633842.01._SCMZZZZZZZ_V1114821525_.jpg</URL><Height Units="pixels">140</Height><Width Units="pixels">90</Width></MediumImage><LargeImage><URL>http://images.amazon.com/images/P/0521633842.01._SCLZZZZZZZ_V1114821525_.jpg</URL><Height Units="pixels">475</Height><Width Units="pixels">306</Width></LargeImage><ImageSets><ImageSet Category="primary"><SmallImage><URL>http://images.amazon.com/images/P/0521633842.01._SCTHUMBZZZ_V1114821525_.jpg</URL><Height Units="pixels">60</Height><Width Units="pixels">39</Width></SmallImage><MediumImage><URL>http://images.amazon.com/images/P/0521633842.01._SCMZZZZZZZ_V1114821525_.jpg</URL><Height Units="pixels">140</Height><Width Units="pixels">90</Width></MediumImage><LargeImage><URL>http://images.amazon.com/images/P/0521633842.01._SCLZZZZZZZ_V1114821525_.jpg</URL><Height Units="pixels">475</Height><Width Units="pixels">306</Width></LargeImage></ImageSet></ImageSets><ItemAttributes><Author>Beatrice Forbes Manz</Author><Binding>Paperback</Binding><DeweyDecimalNumber>950.2</DeweyDecimalNumber><EAN>9780521633840</EAN><Edition>Reprint</Edition><ISBN>0521633842</ISBN><Label>Cambridge University Press</Label><ListPrice><Amount>2299</Amount><CurrencyCode>USD</CurrencyCode><FormattedPrice>$22.99</FormattedPrice></ListPrice><Manufacturer>Cambridge University Press</Manufacturer><NumberOfItems>1</NumberOfItems><NumberOfPages>246</NumberOfPages><PackageDimensions><Height Units="hundredths-inches">67</Height><Length Units="hundredths-inches">850</Length><Weight Units="hundredths-pounds">74</Weight><Width Units="hundredths-inches">562</Width></PackageDimensions><ProductGroup>Book</ProductGroup><PublicationDate>1999-03-28</PublicationDate><Publisher>Cambridge University Press</Publisher><Studio>Cambridge University Press</Studio><Title>The Rise and Rule of Tamerlane (Canto original series)</Title></ItemAttributes><OfferSummary><LowestNewPrice><Amount>1298</Amount><CurrencyCode>USD</CurrencyCode><FormattedPrice>$12.98</FormattedPrice></LowestNewPrice><LowestUsedPrice><Amount>1054</Amount><CurrencyCode>USD</CurrencyCode><FormattedPrice>$10.54</FormattedPrice></LowestUsedPrice><LowestCollectiblePrice><Amount>2299</Amount><CurrencyCode>USD</CurrencyCode><FormattedPrice>$22.99</FormattedPrice></LowestCollectiblePrice><TotalNew>25</TotalNew><TotalUsed>21</TotalUsed><TotalCollectible>1</TotalCollectible><TotalRefurbished>0</TotalRefurbished></OfferSummary><EditorialReviews><EditorialReview><Source>Book Description</Source><Content>This is the first serious study of Tamerlane, the great nomad conqueror who rose to power in 1370 on the ruins of the Mongol Empire and led his armies on campaigns of unprecedented scope, ranging from Moscow to Delhi. As the last nomad ruler to unite the steppe regions of Eurasia, Tamerlane marks the transition from the era of nomad conquest and rule to the modern ascendency of the settled world.</Content></EditorialReview></EditorialReviews></Item><Item><ASIN>1885221770</ASIN><DetailPageURL>http://www.amazon.com/gp/redirect.html%3FASIN=1885221770%26tag=ws%26lcode=sp1%26cID=2025%26ccmID=165953%26location=/o/ASIN/1885221770%253FSubscriptionId=0HP1WHME000749APYWR2</DetailPageURL><SalesRank>474520</SalesRank><SmallImage><URL>http://images.amazon.com/images/P/1885221770.01._SCTHUMBZZZ_V1056534986_.jpg</URL><Height Units="pixels">60</Height><Width Units="pixels">40</Width></SmallImage><MediumImage><URL>http://images.amazon.com/images/P/1885221770.01._SCMZZZZZZZ_V1056534986_.jpg</URL><Height Units="pixels">140</Height><Width Units="pixels">93</Width></MediumImage><LargeImage><URL>http://images.amazon.com/images/P/1885221770.01._SCLZZZZZZZ_V1056534986_.jpg</URL><Height Units="pixels">475</Height><Width Units="pixels">317</Width></LargeImage><ImageSets><ImageSet Category="primary"><SmallImage><URL>http://images.amazon.com/images/P/1885221770.01._SCTHUMBZZZ_V1056534986_.jpg</URL><Height Units="pixels">60</Height><Width Units="pixels">40</Width></SmallImage><MediumImage><URL>http://images.amazon.com/images/P/1885221770.01._SCMZZZZZZZ_V1056534986_.jpg</URL><Height Units="pixels">140</Height><Width Units="pixels">93</Width></MediumImage><LargeImage><URL>http://images.amazon.com/images/P/1885221770.01._SCLZZZZZZZ_V1056534986_.jpg</URL><Height Units="pixels">475</Height><Width Units="pixels">317</Width></LargeImage></ImageSet></ImageSets><ItemAttributes><Author>Roy Stier</Author><Binding>Paperback</Binding><EAN>9781885221773</EAN><ISBN>1885221770</ISBN><Label>Bookpartners</Label><ListPrice><Amount>1695</Amount><CurrencyCode>USD</CurrencyCode><FormattedPrice>$16.95</FormattedPrice></ListPrice><Manufacturer>Bookpartners</Manufacturer><NumberOfItems>1</NumberOfItems><NumberOfPages>304</NumberOfPages><PackageDimensions><Height Units="hundredths-inches">79</Height><Length Units="hundredths-inches">900</Length><Weight Units="hundredths-pounds">92</Weight><Width Units="hundredths-inches">606</Width></PackageDimensions><ProductGroup>Book</ProductGroup><PublicationDate>1998-09</PublicationDate><Publisher>Bookpartners</Publisher><Studio>Bookpartners</Studio><Title>Tamerlane: The Ultimate Warrior</Title></ItemAttributes><OfferSummary><LowestUsedPrice><Amount>975</Amount><CurrencyCode>USD</CurrencyCode><FormattedPrice>$9.75</FormattedPrice></LowestUsedPrice><LowestCollectiblePrice><Amount>2295</Amount><CurrencyCode>USD</CurrencyCode><FormattedPrice>$22.95</FormattedPrice></LowestCollectiblePrice><TotalNew>0</TotalNew><TotalUsed>3</TotalUsed><TotalCollectible>1</TotalCollectible><TotalRefurbished>0</TotalRefurbished></OfferSummary><EditorialReviews><EditorialReview><Source>Book Description</Source><Content>From humble beginnings, Tamerlane, the ancient Turki-Mongol conqueror, rose to become the scourge of his time and changed the course of history. <P>The name Tamerlane runs the gamut of human emotions, evoking in many a revulsion for the devil incarnate, in others, an appreciation for the benefactor of millions. <P>By using accounts from Tamerlane's detractors and his admirers, Roy Stier has captured an amazing story that gives credence to the old adage, "truth is stranger than fiction." <P>Tamerlane, the Ultimate Warrior is presented as a fascinating series of events and captures the reader in the first comprehensive view of this historical figure who dominated Asia and made Europe tremble.</Content></EditorialReview></EditorialReviews></Item><Item><ASIN>0850459494</ASIN><DetailPageURL>http://www.amazon.com/gp/redirect.html%3FASIN=0850459494%26tag=ws%26lcode=sp1%26cID=2025%26ccmID=165953%26location=/o/ASIN/0850459494%253FSubscriptionId=0HP1WHME000749APYWR2</DetailPageURL><SalesRank>480359</SalesRank><SmallImage><URL>http://images.amazon.com/images/P/0850459494.01._SCTHUMBZZZ_V1128022797_.jpg</URL><Height Units="pixels">75</Height><Width Units="pixels">56</Width></SmallImage><MediumImage><URL>http://images.amazon.com/images/P/0850459494.01._SCMZZZZZZZ_V1128022797_.jpg</URL><Height Units="pixels">160</Height><Width Units="pixels">119</Width></MediumImage><LargeImage><URL>http://images.amazon.com/images/P/0850459494.01._SCLZZZZZZZ_V1128022797_.jpg</URL><Height Units="pixels">500</Height><Width Units="pixels">372</Width></LargeImage><ImageSets><ImageSet Category="primary"><SmallImage><URL>http://images.amazon.com/images/P/0850459494.01._SCTHUMBZZZ_V1128022797_.jpg</URL><Height Units="pixels">75</Height><Width Units="pixels">56</Width></SmallImage><MediumImage><URL>http://images.amazon.com/images/P/0850459494.01._SCMZZZZZZZ_V1128022797_.jpg</URL><Height Units="pixels">160</Height><Width Units="pixels">119</Width></MediumImage><LargeImage><URL>http://images.amazon.com/images/P/0850459494.01._SCLZZZZZZZ_V1128022797_.jpg</URL><Height Units="pixels">500</Height><Width Units="pixels">372</Width></LargeImage></ImageSet></ImageSets><ItemAttributes><Author>David Nicolle</Author><Binding>Paperback</Binding><Creator Role="Illustrator">Angus Mcbride</Creator><EAN>9780850459494</EAN><ISBN>0850459494</ISBN><Label>Osprey Publishing</Label><ListPrice><Amount>1595</Amount><CurrencyCode>USD</CurrencyCode><FormattedPrice>$15.95</FormattedPrice></ListPrice><Manufacturer>Osprey Publishing</Manufacturer><NumberOfItems>1</NumberOfItems><NumberOfPages>48</NumberOfPages><PackageDimensions><Height Units="hundredths-inches">15</Height><Length Units="hundredths-inches">978</Length><Weight Units="hundredths-pounds">36</Weight><Width Units="hundredths-inches">722</Width></PackageDimensions><ProductGroup>Book</ProductGroup><PublicationDate>1990-07-26</PublicationDate><Publisher>Osprey Publishing</Publisher><ReleaseDate>1990-07-26</ReleaseDate><Studio>Osprey Publishing</Studio><Title>The Age of Tamerlane (Men-at-Arms)</Title></ItemAttributes><OfferSummary><LowestNewPrice><Amount>920</Amount><CurrencyCode>USD</CurrencyCode><FormattedPrice>$9.20</FormattedPrice></LowestNewPrice><LowestUsedPrice><Amount>815</Amount><CurrencyCode>USD</CurrencyCode><FormattedPrice>$8.15</FormattedPrice></LowestUsedPrice><TotalNew>12</TotalNew><TotalUsed>9</TotalUsed><TotalCollectible>0</TotalCollectible><TotalRefurbished>0</TotalRefurbished></OfferSummary><EditorialReviews><EditorialReview><Source>Book Description</Source><Content>Tamerlane or Timur-i-Lenk ('Timur the Lame') is one of the most extraordinary conquerors in history. In the late 14th century his armies seized huge territories from the borders of Mongolia to Palestine and Anatolia. His passage was marked by massacres that outdid even those of the Mongols for sheer savagery. Timur's career was unequalled since Alexander the Great in terms of constant battlefield success. Only in his youth, while recovering his family estates south of Samarqand, did he face occasional defeat. This title tells the remarkable story of Timur and details the organisation, tactics, arms and armour of his all-conquering army.</Content></EditorialReview></EditorialReviews></Item><Item><ASIN>1851684573</ASIN><DetailPageURL>http://www.amazon.com/gp/redirect.html%3FASIN=1851684573%26tag=ws%26lcode=sp1%26cID=2025%26ccmID=165953%26location=/o/ASIN/1851684573%253FSubscriptionId=0HP1WHME000749APYWR2</DetailPageURL><SalesRank>600493</SalesRank><SmallImage><URL>http://images.amazon.com/images/P/1851684573.01._SCTHUMBZZZ_V63318467_.jpg</URL><Height Units="pixels">75</Height><Width Units="pixels">49</Width></SmallImage><MediumImage><URL>http://images.amazon.com/images/P/1851684573.01._SCMZZZZZZZ_V63318467_.jpg</URL><Height Units="pixels">160</Height><Width Units="pixels">104</Width></MediumImage><LargeImage><URL>http://images.amazon.com/images/P/1851684573.01._SCLZZZZZZZ_V63318467_.jpg</URL><Height Units="pixels">500</Height><Width Units="pixels">324</Width></LargeImage><ImageSets><ImageSet Category="primary"><SmallImage><URL>http://images.amazon.com/images/P/1851684573.01._SCTHUMBZZZ_V63318467_.jpg</URL><Height Units="pixels">75</Height><Width Units="pixels">49</Width></SmallImage><MediumImage><URL>http://images.amazon.com/images/P/1851684573.01._SCMZZZZZZZ_V63318467_.jpg</URL><Height Units="pixels">160</Height><Width Units="pixels">104</Width></MediumImage><LargeImage><URL>http://images.amazon.com/images/P/1851684573.01._SCLZZZZZZZ_V63318467_.jpg</URL><Height Units="pixels">500</Height><Width Units="pixels">324</Width></LargeImage></ImageSet></ImageSets><ItemAttributes><Author>Robert Rand</Author><Binding>Paperback</Binding><DeweyDecimalNumber>320</DeweyDecimalNumber><EAN>9781851684571</EAN><ISBN>1851684573</ISBN><Label>Oneworld Publications</Label><ListPrice><Amount>1495</Amount><CurrencyCode>USD</CurrencyCode><FormattedPrice>$14.95</FormattedPrice></ListPrice><Manufacturer>Oneworld Publications</Manufacturer><NumberOfItems>1</NumberOfItems><NumberOfPages>224</NumberOfPages><PackageDimensions><Height Units="hundredths-inches">66</Height><Length Units="hundredths-inches">784</Length><Weight Units="hundredths-pounds">54</Weight><Width Units="hundredths-inches">512</Width></PackageDimensions><ProductGroup>Book</ProductGroup><PublicationDate>2006-09-11</PublicationDate><Publisher>Oneworld Publications</Publisher><Studio>Oneworld Publications</Studio><Title>Tamerlane's Children: Dispatches from Contemporary Uzbekistan</Title></ItemAttributes><OfferSummary><LowestNewPrice><Amount>915</Amount><CurrencyCode>USD</CurrencyCode><FormattedPrice>$9.15</FormattedPrice></LowestNewPrice><LowestUsedPrice><Amount>950</Amount><CurrencyCode>USD</CurrencyCode><FormattedPrice>$9.50</FormattedPrice></LowestUsedPrice><TotalNew>31</TotalNew><TotalUsed>6</TotalUsed><TotalCollectible>0</TotalCollectible><TotalRefurbished>0</TotalRefurbished></OfferSummary><EditorialReviews><EditorialReview><Source>Book Description</Source><Content>In the central park of Tashkent, in a place the Uzbeks call the square, a magnificent statue of a mounted warrior dominates the surroundings - Tamerlane - national hero of post-Soviet Uzbekistan. And yet how does this 14th century conqueror reflect one of the world's most diverse and politically intriguing countries?Having spent three years in the region, renowned journalist Robert Rand seeks to answer this question, covering an assortment of fascinating topics, ranging from the effect of 9/11 to the clash of culture in Uzbek pop music. Overflowing with charming anecdotes and loveable personalities, Rand gives the reader a real sense of the country's confused identity and the challenges which it and its people will face in generations to come.</Content></EditorialReview></EditorialReviews></Item><Item><ASIN>B000GKT9AQ</ASIN><DetailPageURL>http://www.amazon.com/gp/redirect.html%3FASIN=B000GKT9AQ%26tag=ws%26lcode=sp1%26cID=2025%26ccmID=165953%26location=/o/ASIN/B000GKT9AQ%253FSubscriptionId=0HP1WHME000749APYWR2</DetailPageURL><SalesRank>619234</SalesRank><ItemAttributes><Author>Harold Lamb</Author><Binding>Hardcover</Binding><Label>Garden City, N.Y., U.S.A.: Doubleday & Company, Inc.</Label><Manufacturer>Garden City, N.Y., U.S.A.: Doubleday & Company, Inc.</Manufacturer><ProductGroup>Book</ProductGroup><ProductTypeName>BOOKS_1973_AND_LATER</ProductTypeName><PublicationDate>1941</PublicationDate><Publisher>Garden City, N.Y., U.S.A.: Doubleday & Company, Inc.</Publisher><Studio>Garden City, N.Y., U.S.A.: Doubleday & Company, Inc.</Studio><Title>Earth Shakers: The: The March of the Barbarians and Tamerlane</Title></ItemAttributes><OfferSummary><LowestUsedPrice><Amount>850</Amount><CurrencyCode>USD</CurrencyCode><FormattedPrice>$8.50</FormattedPrice></LowestUsedPrice><TotalNew>0</TotalNew><TotalUsed>2</TotalUsed><TotalCollectible>0</TotalCollectible><TotalRefurbished>0</TotalRefurbished></OfferSummary></Item><Item><ASIN>B00087SKA2</ASIN><DetailPageURL>http://www.amazon.com/gp/redirect.html%3FASIN=B00087SKA2%26tag=ws%26lcode=sp1%26cID=2025%26ccmID=165953%26location=/o/ASIN/B00087SKA2%253FSubscriptionId=0HP1WHME000749APYWR2</DetailPageURL><SalesRank>855185</SalesRank><ItemAttributes><Author>Harold Lamb</Author><Binding>Unknown Binding</Binding><Label>Bantam Books</Label><Manufacturer>Bantam Books</Manufacturer><NumberOfPages>216</NumberOfPages><ProductGroup>Book</ProductGroup><PublicationDate>1955</PublicationDate><Publisher>Bantam Books</Publisher><Studio>Bantam Books</Studio><Title>Tamerlane: Conqueror of the earth</Title></ItemAttributes><OfferSummary><LowestUsedPrice><Amount>650</Amount><CurrencyCode>USD</CurrencyCode><FormattedPrice>$6.50</FormattedPrice></LowestUsedPrice><TotalNew>0</TotalNew><TotalUsed>5</TotalUsed><TotalCollectible>0</TotalCollectible><TotalRefurbished>0</TotalRefurbished></OfferSummary></Item><Item><ASIN>0689304463</ASIN><DetailPageURL>http://www.amazon.com/gp/redirect.html%3FASIN=0689304463%26tag=ws%26lcode=sp1%26cID=2025%26ccmID=165953%26location=/o/ASIN/0689304463%253FSubscriptionId=0HP1WHME000749APYWR2</DetailPageURL><SalesRank>1028876</SalesRank><ItemAttributes><Author>Barbara Corcoran</Author><Binding>Hardcover</Binding><Creator Role="Illustrator">Charles Robinson</Creator><EAN>9780689304460</EAN><Edition>[1st ed.]</Edition><ISBN>0689304463</ISBN><Label>Macmillan Pub Co</Label><ListPrice><Amount>695</Amount><CurrencyCode>USD</CurrencyCode><FormattedPrice>$6.95</FormattedPrice></ListPrice><Manufacturer>Macmillan Pub Co</Manufacturer><NumberOfItems>1</NumberOfItems><NumberOfPages>152</NumberOfPages><ProductGroup>Book</ProductGroup><PublicationDate>1975-02</PublicationDate><Publisher>Macmillan Pub Co</Publisher><ReadingLevel>Young Adult</ReadingLevel><Studio>Macmillan Pub Co</Studio><Title>Meet Me at Tamerlane's Tomb</Title></ItemAttributes><OfferSummary><LowestUsedPrice><Amount>30</Amount><CurrencyCode>USD</CurrencyCode><FormattedPrice>$0.30</FormattedPrice></LowestUsedPrice><LowestCollectiblePrice><Amount>1000</Amount><CurrencyCode>USD</CurrencyCode><FormattedPrice>$10.00</FormattedPrice></LowestCollectiblePrice><TotalNew>0</TotalNew><TotalUsed>20</TotalUsed><TotalCollectible>2</TotalCollectible><TotalRefurbished>0</TotalRefurbished></OfferSummary></Item></Items></ItemSearchResponse></SOAP-ENV:Body></SOAP-ENV:Envelope>""" + +if __name__ == '__main__': main() This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <bov...@us...> - 2006-10-23 21:15:58
|
Revision: 1274 http://svn.sourceforge.net/pywebsvcs/?rev=1274&view=rev Author: boverhof Date: 2006-10-23 14:15:52 -0700 (Mon, 23 Oct 2006) Log Message: ----------- A test/test_TCtimes.py M ZSI/TCtimes.py M CHANGES -- [ 1558078 ] Problem receiving date/time values with time zones added patch with several modifications, and created a new unittest Modified Paths: -------------- trunk/zsi/CHANGES trunk/zsi/ZSI/TCtimes.py Added Paths: ----------- trunk/zsi/test/test_TCtimes.py Modified: trunk/zsi/CHANGES =================================================================== --- trunk/zsi/CHANGES 2006-10-21 00:09:11 UTC (rev 1273) +++ trunk/zsi/CHANGES 2006-10-23 21:15:52 UTC (rev 1274) @@ -7,11 +7,19 @@ - Remove Send()'s kwargs out of _args list <ef...@bo...> Change for 2.0.0rc3 released xxx: + - Updated ZSI developers guide + - Added ZSI wsdl2py users guide + - Added support for setuptools in setup script. If setuptools is installed + use it, else revert to distutils. - Removed "requestclass" keyword argument to Binding.Send - - simplified and retooled Binding/NamedParamBinding and dispatch. + - simplified and retooled Binding/NamedParamBinding and dispatch, added + "typesmodule" back into Binding. Now it's mirror image of dispatch. + - Microseconds to TCtime - BUG [ 1525567 ] Amazon ECommerce Issues: local element declarations overriding global element declarations with the same name within the same namespace. + - new module "schema", contains "all" the code for dealing with global + Schema instance. Change for 2.0.0rc2 released 28-March-2006: - Replace many/most id() with _get_idstr() to hide negative numbers Modified: trunk/zsi/ZSI/TCtimes.py =================================================================== --- trunk/zsi/ZSI/TCtimes.py 2006-10-21 00:09:11 UTC (rev 1273) +++ trunk/zsi/ZSI/TCtimes.py 2006-10-23 21:15:52 UTC (rev 1274) @@ -6,7 +6,11 @@ from ZSI import _copyright, _floattypes, _inttypes, _get_idstr, EvaluateException from ZSI.TC import TypeCode, SimpleType from ZSI.wstools.Namespaces import SCHEMA -import operator, re, time +import operator, re, time as _time +from time import mktime as _mktime, localtime as _localtime, gmtime as _gmtime +from datetime import tzinfo as _tzinfo, timedelta as _timedelta,\ + datetime as _datetime +from math import modf as _modf _niltime = [ 0, 0, 0, # year month day @@ -14,36 +18,119 @@ 0, 0, 0 # weekday, julian day, dst flag ] +#### Code added to check current timezone offset +_zero = _timedelta(0) +_dstoffset = _stdoffset = _timedelta(seconds=-_time.timezone) +if _time.daylight: _dstoffset = _timedelta(seconds=-_time.altzone) +_dstdiff = _dstoffset - _stdoffset + + +class _localtimezone(_tzinfo): + """ """ + def dst(self, dt): + """datetime -> DST offset in minutes east of UTC.""" + tt = _localtime(_mktime((dt.year, dt.month, dt.day, + dt.hour, dt.minute, dt.second, dt.weekday(), 0, -1))) + if tt.tm_isdst > 0: return _dstdiff + return _zero + + #def fromutc(...) + #datetime in UTC -> datetime in local time. + + def tzname(self, dt): + """datetime -> string name of time zone.""" + tt = _localtime(_mktime((dt.year, dt.month, dt.day, + dt.hour, dt.minute, dt.second, dt.weekday(), 0, -1))) + return _time.tzname[tt.tm_isdst > 0] + + def utcoffset(self, dt): + """datetime -> minutes east of UTC (negative for west of UTC).""" + tt = _localtime(_mktime((dt.year, dt.month, dt.day, + dt.hour, dt.minute, dt.second, dt.weekday(), 0, -1))) + if tt.tm_isdst > 0: return _dstoffset + return _stdoffset + +class _fixedoffset(_tzinfo): + """Fixed offset in minutes east from UTC. + + A class building tzinfo objects for fixed-offset time zones. + Note that _fixedoffset(0, "UTC") is a different way to build a + UTC tzinfo object. + """ + #def __init__(self, offset, name): + def __init__(self, offset): + self.__offset = _timedelta(minutes=offset) + #self.__name = name + + def dst(self, dt): + """datetime -> DST offset in minutes east of UTC.""" + return _zero + + def tzname(self, dt): + """datetime -> string name of time zone.""" + #return self.__name + return "server" + + def utcoffset(self, dt): + """datetime -> minutes east of UTC (negative for west of UTC).""" + return self.__offset + + def _dict_to_tuple(d): '''Convert a dictionary to a time tuple. Depends on key values in the regexp pattern! - ''' + ''' retval = _niltime[:] for k,i in ( ('Y', 0), ('M', 1), ('D', 2), ('h', 3), ('m', 4), ): v = d.get(k) if v: retval[i] = int(v) + v = d.get('s') - if v: retval[5] = int(float(v)) + if v: + msec,sec = _modf(float(v)) + retval[6],retval[5] = int(round(msec*1000)), int(sec) + v = d.get('tz') if v and v != 'Z': h,m = map(int, v.split(':')) - if h < 0: - retval[3] += abs(h) - retval[4] += m - else: - retval[3] -= abs(h) - retval[4] -= m + # check for time zone offset, if within the same timezone, + # ignore offset specific calculations + offset=_localtimezone().utcoffset(_datetime.now()) + local_offset_hour = offset.seconds/3600 + local_offset_min = (offset.seconds%3600)%60 + if local_offset_hour > 12: + local_offset_hour -= 24 + + if local_offset_hour != h or local_offset_min != m: + if h<0: + #TODO: why is this set to server + #foff = _fixedoffset(-((abs(h)*60+m)),"server") + foff = _fixedoffset(-((abs(h)*60+m))) + else: + #TODO: why is this set to server + #foff = _fixedoffset((abs(h)*60+m),"server") + foff = _fixedoffset((abs(h)*60+m)) + + dt = _datetime(retval[0],retval[1],retval[2],retval[3],retval[4], + retval[5],0,foff) + + # update dict with calculated timezone + localdt=dt.astimezone(_localtimezone()) + retval[0] = localdt.year + retval[1] = localdt.month + retval[2] = localdt.day + retval[3] = localdt.hour + retval[4] = localdt.minute + retval[5] = localdt.second + if d.get('neg', 0): retval[0:5] = map(operator.__neg__, retval[0:5]) return tuple(retval) - class Duration(SimpleType): '''Time duration. - TODO: NOT FIXED YET... ''' - parselist = [ (None,'duration') ] lex_pattern = re.compile('^' r'(?P<neg>-?)P' \ r'((?P<Y>\d+)Y)?' r'((?P<M>\d+)M)?' r'((?P<D>\d+)D)?' \ @@ -74,7 +161,7 @@ def get_formatted_content(self, pyobj): if type(pyobj) in _floattypes or type(pyobj) in _inttypes: - pyobj = time.gmtime(pyobj) + pyobj = _gmtime(pyobj) d = {} pyobj = tuple(pyobj) @@ -107,23 +194,16 @@ try: retval = _dict_to_tuple(m.groupdict()) except ValueError, e: - raise EvaluateException(str(e)) + #raise EvaluateException(str(e)) + raise if self.pyclass is not None: return self.pyclass(retval) return retval -# def parse(self, elt, ps): -# self.checkname(elt, ps) -# elt = self.SimpleHREF(elt, ps, 'Gregorian') -# if not elt: return None -# if self.nilled(elt, ps): return Nilled -# v = self.simple_value(elt, ps) -# return self.text_to_data(text) - def get_formatted_content(self, pyobj): if type(pyobj) in _floattypes or type(pyobj) in _inttypes: - pyobj = time.gmtime(pyobj) + pyobj = _gmtime(pyobj) d = {} pyobj = tuple(pyobj) @@ -133,12 +213,20 @@ else: d['neg'] = '' + ms = pyobj[6] + if not ms: + d = { 'Y': pyobj[0], 'M': pyobj[1], 'D': pyobj[2], + 'h': pyobj[3], 'm': pyobj[4], 's': pyobj[5], } + return self.format % d + + if ms > 999: + raise ValueError, 'milliseconds must be a integer between 0 and 999' + d = { 'Y': pyobj[0], 'M': pyobj[1], 'D': pyobj[2], - 'h': pyobj[3], 'm': pyobj[4], 's': pyobj[5], } - val = self.format % d - return val + 'h': pyobj[3], 'm': pyobj[4], 's': pyobj[5], 'ms':ms, } + return self.format_ms % d + - class gDateTime(Gregorian): '''A date and time. ''' @@ -148,6 +236,7 @@ r'(?P<h>\d\d):' r'(?P<m>\d\d):' r'(?P<s>\d*(\.\d+)?)' \ r'(?P<tz>(Z|([-+]\d\d:\d\d))?)' '$') tag, format = 'dateTime', '%(Y)04d-%(M)02d-%(D)02dT%(h)02d:%(m)02d:%(s)02dZ' + format_ms = format[:-1] + '.%(ms)03dZ' type = (SCHEMA.XSD3, 'dateTime') class gDate(Gregorian): @@ -219,6 +308,7 @@ r'(?P<h>\d\d):' r'(?P<m>\d\d):' r'(?P<s>\d*(\.\d+)?)' \ r'(?P<tz>Z|([-+]\d\d:\d\d))?' '$') tag, format = 'time', '%(h)02d:%(m)02d:%(s)02dZ' + format_ms = format[:-1] + '.%(ms)03dZ' type = (SCHEMA.XSD3, 'time') if __name__ == '__main__': print _copyright Added: trunk/zsi/test/test_TCtimes.py =================================================================== --- trunk/zsi/test/test_TCtimes.py (rev 0) +++ trunk/zsi/test/test_TCtimes.py 2006-10-23 21:15:52 UTC (rev 1274) @@ -0,0 +1,143 @@ +#!/usr/bin/env python +import unittest, sys, tests_good, tests_bad, time +from ZSI import * +try: + import cStringIO as StringIO +except ImportError: + import StringIO + + +class TestCase(unittest.TestCase): + '''Examples from "Definitive XML Schema, Priscilla Walmsley, p237-246 + ''' + def check_dateTime_local_offset(self): + # UTC with local timezone offset + # + typecode = TC.gDateTime() + off_hour = time.altzone/60/60 + off_min = time.altzone%60 + stamp_offset = '1968-04-02T13:20:00+%02d:%02d' %(off_hour,off_min) + data = typecode.text_to_data(stamp_offset, None, None) + stamp = typecode.get_formatted_content(data) + + correct = "1968-04-01T22:20:00Z" + self.failUnless(stamp == correct, + 'dateTime with local offset(%s), expecting "%s" got "%s"' %( + stamp_offset, correct, stamp)) + + def check_valid_dateTime(self): + typecode = TC.gDateTime() + for i in ('1968-04-02T13:20:00', '1968-04-02T13:20:15.5', + '1968-04-02T13:20:00-05:00', '1968-04-02T13:20:00Z'): + data = typecode.text_to_data(i, None, None) + text = typecode.get_formatted_content(data) + + def check_parse_microseconds(self): + good = (1968, 4, 2, 13, 20, 15, 511, 0, 0) + typecode = TC.gDateTime() + data = typecode.text_to_data('1968-04-02T13:20:15.511', None, None) + self.failUnless(data == good, + 'did not parse something %s, not equal %s' %(data,good)) + + def check_serialize_microseconds(self): + dateTime = '1968-04-02T13:20:15.511Z' + typecode = TC.gDateTime() + text = typecode.get_formatted_content((1968, 4, 2, 13, 20, 15, 511, 0, 0)) + self.failUnless(text == dateTime, + 'did not serialze correctly %s, not equal %s' %(text, dateTime)) + + def check_serialize_microseconds_1000(self): + bad = (1968, 4, 2, 13, 20, 15, 1000, 0) + typecode = TC.gDateTime() + self.failUnlessRaises(ValueError, typecode.get_formatted_content, bad) + + def check_serialize_microseconds_lessZero(self): + '''ignore negative microseconds + ''' + bad = (1968, 4, 2, 13, 20, 15, -1, 0) + typecode = TC.gDateTime() + text = typecode.get_formatted_content(bad) + typecode.get_formatted_content(bad) + + def check_parse_microseconds2(self): + good = (1968, 4, 2, 13, 20, 15, 500, 0, 0) + typecode = TC.gDateTime() + data = typecode.text_to_data('1968-04-02T13:20:15.5Z', None,None) + self.failUnless(data == good, + 'did not serialze correctly %s, not equal %s' %(data, good)) + + #text = typecode.get_formatted_content((1968, 4, 2, 13, 20, 15, 5, 0, 500)) + #self.failUnless(text == dateTime, + # 'did not serialze correctly %s, not equal %s' %(text, dateTime)) + + def check_invalid_dateTime(self): + typecode = TC.gDateTime() + + def check_valid_time(self): + typecode = TC.gTime() + for i in ('13:20:00', '13:20:30.5555', '13:20:00Z'): + data = typecode.text_to_data(i, None, None) + text = typecode.get_formatted_content(data) + + def broke_valid_time(self): + typecode = TC.gTime() + data = typecode.text_to_data('13:20:00-05:00', None, None) + + def check_invalid_time(self): + typecode = TC.gTime() + for i in ('5:20:00', '13:20.5:00',): + self.failUnlessRaises(Exception, typecode.text_to_data, i, None, None), + + def broke_invalid_time_no_seconds(self): + typecode = TC.gTime() + i = '13:20:' + self.failUnlessRaises(Exception, typecode.text_to_data, i, None, None) + + def broke_invalid_time_bad_timeofday(self): + typecode = TC.gTime() + i = '13:65:00' + self.failUnlessRaises(Exception, typecode.text_to_data, i, None, None) + + def check_valid_date(self): + typecode = TC.gDate() + for i in ('1968-04-02', '-0045-01-01', '11968-04-02', '1968-04-02+05:00', '1968-04-02Z'): + data = typecode.text_to_data(i, None, None) + text = typecode.get_formatted_content(data) + + def check_invalid_date(self): + typecode = TC.gDate() + for i in ('68-04-02', '1968-4-2', '1968/04/02', '04-02-1968',): + self.failUnlessRaises(Exception, typecode.text_to_data, i, None, None), + + def broke_invalid_date_april31(self): + # No checks for valid date April 30 days + typecode = TC.gDate() + self.failUnlessRaises(Exception, typecode.text_to_data, '1968-04-31', None, None), + +# +# Creates permutation of test options: "check", "check_any", etc +# +_SEP = '_' +for t in [i[0].split(_SEP) for i in filter(lambda i: callable(i[1]), TestCase.__dict__.items())]: + test = '' + for f in t: + test += f + if globals().has_key(test): test += _SEP; continue + def _closure(): + name = test + def _makeTestSuite(): + suite = unittest.TestSuite() + suite.addTest(unittest.makeSuite(TestCase, name)) + return suite + return _makeTestSuite + + globals()[test] = _closure() + test += _SEP + + +makeTestSuite = check +def main(): + unittest.main(defaultTest="makeTestSuite") +if __name__ == "__main__" : main() + + This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <bov...@us...> - 2006-10-23 21:50:49
|
Revision: 1275 http://svn.sourceforge.net/pywebsvcs/?rev=1275&view=rev Author: boverhof Date: 2006-10-23 14:50:42 -0700 (Mon, 23 Oct 2006) Log Message: ----------- M test/wsdl2py/test_WhiteMesa.py M ZSI/generate/commands.py -- [ 1520095 ] wsdl2py -b, error w/no schema w/rpc bindings added fix Modified Paths: -------------- trunk/zsi/ZSI/generate/commands.py trunk/zsi/test/wsdl2py/test_WhiteMesa.py Modified: trunk/zsi/ZSI/generate/commands.py =================================================================== --- trunk/zsi/ZSI/generate/commands.py 2006-10-23 21:15:52 UTC (rev 1274) +++ trunk/zsi/ZSI/generate/commands.py 2006-10-23 21:50:42 UTC (rev 1275) @@ -25,11 +25,14 @@ def SetPyclassMetaclass(option, opt, value, parser, *args, **kwargs): """set up pyclass metaclass for complexTypes""" - from ZSI.generate.containers import TypecodeContainerBase, TypesHeaderContainer + from ZSI.generate.containers import ServiceHeaderContainer, TypecodeContainerBase, TypesHeaderContainer TypecodeContainerBase.metaclass = kwargs['metaclass'] TypesHeaderContainer.imports.append(\ 'from %(module)s import %(metaclass)s' %kwargs ) + ServiceHeaderContainer.imports.append(\ + 'from %(module)s import %(metaclass)s' %kwargs + ) def SetUpTwistedClient(option, opt, value, parser, *args, **kwargs): from ZSI.generate.containers import ServiceHeaderContainer Modified: trunk/zsi/test/wsdl2py/test_WhiteMesa.py =================================================================== --- trunk/zsi/test/wsdl2py/test_WhiteMesa.py 2006-10-23 21:15:52 UTC (rev 1274) +++ trunk/zsi/test/wsdl2py/test_WhiteMesa.py 2006-10-23 21:50:42 UTC (rev 1275) @@ -46,6 +46,10 @@ client_file_name = "RPC_Literal_TestDefinitions_services.py" types_file_name = "RPC_Literal_TestDefinitions_services_types.py" server_file_name = "RPC_Literal_TestDefinitions_services_server.py" + + def __init__(self, methodName): + ServiceTestCase.__init__(self, methodName) + self.wsdl2py_args.append('-b') def test_local_EchoBoolean(self): from ZSI.writer import SoapWriter This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <bov...@us...> - 2006-11-01 22:31:34
|
Revision: 1290 http://svn.sourceforge.net/pywebsvcs/?rev=1290&view=rev Author: boverhof Date: 2006-11-01 14:31:30 -0800 (Wed, 01 Nov 2006) Log Message: ----------- couple changes to get unittest to work on windows, the test/wsdlpy dispatch tests still fail because windows doesn't understand #!/usr/bin/env python Modified Paths: -------------- trunk/zsi/ZSI/generate/commands.py trunk/zsi/test/wsdl2py/ServiceTest.py Modified: trunk/zsi/ZSI/generate/commands.py =================================================================== --- trunk/zsi/ZSI/generate/commands.py 2006-10-30 23:49:33 UTC (rev 1289) +++ trunk/zsi/ZSI/generate/commands.py 2006-11-01 22:31:30 UTC (rev 1290) @@ -171,8 +171,9 @@ except Exception, e: print "Error loading %s: \n\t%s" % (location, e) # exit code UNIX specific, Windows? - sys.exit(os.EX_NOINPUT) - + if hasattr(os, 'EX_NOINPUT'): sys.exit(os.EX_NOINPUT) + sys.exit("error loading %s" %location) + if options.simple_naming: # Use a different client suffix WriteServiceModule.client_module_suffix = "_client" Modified: trunk/zsi/test/wsdl2py/ServiceTest.py =================================================================== --- trunk/zsi/test/wsdl2py/ServiceTest.py 2006-10-30 23:49:33 UTC (rev 1289) +++ trunk/zsi/test/wsdl2py/ServiceTest.py 2006-11-01 22:31:30 UTC (rev 1290) @@ -77,7 +77,11 @@ ''' host = CONFIG_PARSER.get(SECTION_DISPATCH, 'host') port = CONFIG_PARSER.get(SECTION_DISPATCH, 'port') - process = subprocess.Popen([cmd, port], env=ENVIRON) + try: + process = subprocess.Popen(['python %s' %cmd, port], env=ENVIRON) + except: + print >>sys.stderr, 'error executing: %s' %cmd + raise time.sleep(1) return process @@ -281,7 +285,8 @@ exit = -1 #TODO: returncode WINDOWS? - self.failUnless(os.WIFEXITED(exit), + WIF = hasattr(os, 'WIFEXITED') + if WIF: self.failUnless(os.WIFEXITED(exit), '"%s" exited with signal#: %d' %(wsdl2py, exit)) self.failUnless(exit == 0, '"%s" exited with exit status: %d' %(wsdl2py, exit)) @@ -296,7 +301,7 @@ warnings.warn("TODO: Not sure what is going on here?") #TODO: returncode WINDOWS? - self.failUnless(os.WIFEXITED(exit), + if WIF: self.failUnless(os.WIFEXITED(exit), '"%s" exited with signal#: %d' %(wsdl2dispatch, exit)) self.failUnless(exit == 0, '"%s" exited with exit status: %d' %(wsdl2dispatch, exit)) @@ -372,8 +377,11 @@ ServiceTestCase.CleanUp() ServiceTestCase._lastToDispatch = expath - ServiceTestCase._process = _LaunchContainer(TOPDIR + '/' + expath) - + ServiceTestCase._process = \ + _LaunchContainer(os.path.join(os.path.abspath(TOPDIR), + *expath.split('/'))) + + def CleanUp(cls): """call this when dispatch server is no longer needed, maybe another needs to be started. Assumption that This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <bov...@us...> - 2006-12-19 21:30:31
|
Revision: 1309 http://svn.sourceforge.net/pywebsvcs/?rev=1309&view=rev Author: boverhof Date: 2006-12-19 13:30:26 -0800 (Tue, 19 Dec 2006) Log Message: ----------- M test/test_zsi.py A test/test_list.py M test/test_zsi_net.py M ZSI/TC.py M ZSI/TCtimes.py -- patch for [ 1615921 ] StringIO used but not imported in TC.py -- added unittest for List -- noticed in TCtimes there is problematic support of miliseconds, I think this was added before last rc. Cant stuff ms in time_struct, need to use datetime for this. Modified Paths: -------------- trunk/zsi/ZSI/TC.py trunk/zsi/ZSI/TCtimes.py trunk/zsi/test/test_zsi.py trunk/zsi/test/test_zsi_net.py Added Paths: ----------- trunk/zsi/test/test_list.py Modified: trunk/zsi/ZSI/TC.py =================================================================== --- trunk/zsi/ZSI/TC.py 2006-12-19 01:24:09 UTC (rev 1308) +++ trunk/zsi/ZSI/TC.py 2006-12-19 21:30:26 UTC (rev 1309) @@ -22,9 +22,9 @@ from urllib import unquote as urldecode, quote as urlencode from binascii import unhexlify as hexdecode, hexlify as hexencode try: - import cStringIO as StringIO + from cStringIO import StringIO except ImportError: - import StringIO + from StringIO import StringIO _is_xsd_or_soap_ns = lambda ns: ns in [ @@ -1587,7 +1587,7 @@ itemTypeCode = pyclass(None) if itemTypeCode is None: - raise EvaluateException('Filed to locate %s' %self.itemTypeCode) + raise EvaluateException('Failed to locate %s' %str(self.itemTypeCode)) if hasattr(itemTypeCode, 'text_to_data') is False: raise EvaluateException('TypeCode class %s missing text_to_data method' %itemTypeCode) @@ -1600,7 +1600,8 @@ list are space separated. ''' v = [] - for item in text.split(' '): + items = text.split() + for item in items: v.append(self.itemTypeCode.text_to_data(item, elt, ps)) if self.pyclass is not None: @@ -1616,9 +1617,7 @@ href = _find_href(elt) if not href: if self.nilled(elt, ps) is False: - # No content, no HREF, not NIL: empty string - return "" - # No content, no HREF, and is NIL... + return [] if self.nillable is True: return Nilled raise EvaluateException('Required string missing', @@ -1629,18 +1628,19 @@ self.checktype(elt, ps) if self.nilled(elt, ps): return Nilled - if len(_children(elt)) == 0: return '' + if len(_children(elt)) == 0: return [] v = self.simple_value(elt, ps) return self.text_to_data(v, elt, ps) + def serialize(self, elt, sw, pyobj, name=None, orig=None, **kw): '''elt -- the current DOMWrapper element sw -- soapWriter object pyobj -- python object to serialize ''' - if type(pyobj) not in _seqtypes: - raise EvaluateException, 'expecting a list' + if pyobj is not None and type(pyobj) not in _seqtypes: + raise EvaluateException, 'expecting a list or None' objid = _get_idstr(pyobj) ns,n = self.get_name(name, objid) @@ -1650,12 +1650,12 @@ return None tc = self.itemTypeCode - s = StringIO() + s = StringIO(); sep = ' ' for item in pyobj: s.write(tc.get_formatted_content(item)) - s.write(' ') + s.write(sep) - el.createAppendTextNode(textNode) + el.createAppendTextNode(s.getvalue()) class _AnyStrict(Any): Modified: trunk/zsi/ZSI/TCtimes.py =================================================================== --- trunk/zsi/ZSI/TCtimes.py 2006-12-19 01:24:09 UTC (rev 1308) +++ trunk/zsi/ZSI/TCtimes.py 2006-12-19 21:30:26 UTC (rev 1309) @@ -80,6 +80,13 @@ '''Convert a dictionary to a time tuple. Depends on key values in the regexp pattern! ''' + # TODO: Adding a ms field to struct_time tuples is problematic + # since they don't have this field. Should use datetime + # which has a microseconds field, else no ms.. When mapping struct_time + # to gDateTime the last 3 fields are irrelevant, here using dummy values to make + # everything happy. + # + retval = _niltime[:] for k,i in ( ('Y', 0), ('M', 1), ('D', 2), ('h', 3), ('m', 4), ): v = d.get(k) Added: trunk/zsi/test/test_list.py =================================================================== --- trunk/zsi/test/test_list.py (rev 0) +++ trunk/zsi/test/test_list.py 2006-12-19 21:30:26 UTC (rev 1309) @@ -0,0 +1,71 @@ +#!/usr/bin/env python +import unittest, time, datetime +import ZSI +from ZSI.writer import SoapWriter +from ZSI import _get_element_nsuri_name +from ZSI.schema import GED, TypeDefinition, ElementDeclaration +from ZSI.parse import ParsedSoap +from cStringIO import StringIO + + +class TestList1_Def(ZSI.TC.List, TypeDefinition): + itemType = (u'http://www.w3.org/2001/XMLSchema', u'dateTime') + schema = "urn:test" + type = (schema, "tUsage") + def __init__(self, pname, **kw): + ZSI.TC.List.__init__(self, pname, **kw) + + +class TestList2_Def(ZSI.TC.List, TypeDefinition): + itemType = ZSI.TC.gDateTime() + schema = "urn:test" + type = (schema, "tUsage") + def __init__(self, pname, **kw): + ZSI.TC.List.__init__(self, pname, **kw) + + +class ListTestCase(unittest.TestCase): + "test List TypeCode" + + def setUp(self): + pass + + def tearDown(self): + pass + + def check_list_defs(self): + gl = globals() + for klass in map(lambda h: gl[h], filter(lambda g: (g.startswith('TestList') and + issubclass(gl[g],ZSI.TC.List)), gl)): + + typecode = klass('whatever', nillable=True) + data = None + for i in range(10): + sw = SoapWriter() + sw.serialize(data, typecode) + s = str(sw) + print s + ps = ParsedSoap(s); pyobj = ps.Parse(typecode) + assert pyobj == data, 'Data corruption expected "%s", got "%s"' %(str(data),str(pyobj)) + if data is None: + data = []; continue; + + # + # cut last 3 fields off: weekday (0-6, Monday is 0), Julian day (day in the year, 1-366), + # DST (Daylight Savings Time) flag (-1, 0 or 1) + # + utc = list(time.gmtime(i)[:-3]) + [999,0,0] + data.append(tuple(utc)) + + +def makeTestSuite(): + suite = unittest.TestSuite() + suite.addTest(unittest.makeSuite(ListTestCase, "check")) + return suite + +def main(): + unittest.main(defaultTest="makeTestSuite") + +if __name__ == '__main__': + main() + Modified: trunk/zsi/test/test_zsi.py =================================================================== --- trunk/zsi/test/test_zsi.py 2006-12-19 01:24:09 UTC (rev 1308) +++ trunk/zsi/test/test_zsi.py 2006-12-19 21:30:26 UTC (rev 1309) @@ -9,6 +9,7 @@ import test_t8 import test_t9 import test_union +import test_list import test_TCtimes def makeTestSuite(): Modified: trunk/zsi/test/test_zsi_net.py =================================================================== --- trunk/zsi/test/test_zsi_net.py 2006-12-19 01:24:09 UTC (rev 1308) +++ trunk/zsi/test/test_zsi_net.py 2006-12-19 21:30:26 UTC (rev 1309) @@ -11,6 +11,7 @@ import test_t9 import test_union import test_TCtimes +import test_list def makeTestSuite(): return unittest.TestSuite( This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <bov...@us...> - 2007-01-03 23:43:04
|
Revision: 1314 http://svn.sourceforge.net/pywebsvcs/?rev=1314&view=rev Author: boverhof Date: 2007-01-03 15:43:01 -0800 (Wed, 03 Jan 2007) Log Message: ----------- M test/wsdl2py/test_Choice.py M test/wsdl2py/test_AmazonS3.py M test/wsdl2py/test_AWSECommerceService.py M test/wsdl2py/test_Sabre.py M test/wsdl2py/config.txt M test/wsdl2py/test_DateService.py M test/wsdl2py/ServiceTest.py M test/wsdl2py/servers/DateService.py M test/wsdl2py/servers/SquareService.py M test/wsdl2py/servers/EchoServer.py M test/wsdl2py/servers/FinancialService.py M test/wsdl2py/servers/WhiteMesa.py M test/wsdl2py/test_FinancialService.py M test/wsdl2py/test_DerivedTypes.py M test/wsdl2py/test_ThreatService.py M test/wsdl2py/test_OpcDaGateway.py M test/wsdl2py/test_Echo.py M test/wsdl2py/test_ZipCodeResolver.py M test/wsdl2py/test_XMethodsQuery.py M test/wsdl2py/test_SquareService.py M test/wsdl2py/test_InfoBil.py M test/wsdl2py/test_WhiteMesa.py M test/wsdl2py/test_Attributes.py M test/wsdl2py/test_MapPoint.py M setup.py M doc/guide02-wsdl2py.tex M CHANGES -- update wsdl2py test code, simplified generated module names Modified Paths: -------------- trunk/zsi/CHANGES trunk/zsi/doc/guide02-wsdl2py.tex trunk/zsi/setup.py trunk/zsi/test/wsdl2py/ServiceTest.py trunk/zsi/test/wsdl2py/config.txt trunk/zsi/test/wsdl2py/servers/DateService.py trunk/zsi/test/wsdl2py/servers/EchoServer.py trunk/zsi/test/wsdl2py/servers/FinancialService.py trunk/zsi/test/wsdl2py/servers/SquareService.py trunk/zsi/test/wsdl2py/servers/WhiteMesa.py trunk/zsi/test/wsdl2py/test_AWSECommerceService.py trunk/zsi/test/wsdl2py/test_AmazonS3.py trunk/zsi/test/wsdl2py/test_Attributes.py trunk/zsi/test/wsdl2py/test_Choice.py trunk/zsi/test/wsdl2py/test_DateService.py trunk/zsi/test/wsdl2py/test_DerivedTypes.py trunk/zsi/test/wsdl2py/test_Echo.py trunk/zsi/test/wsdl2py/test_FinancialService.py trunk/zsi/test/wsdl2py/test_InfoBil.py trunk/zsi/test/wsdl2py/test_MapPoint.py trunk/zsi/test/wsdl2py/test_OpcDaGateway.py trunk/zsi/test/wsdl2py/test_Sabre.py trunk/zsi/test/wsdl2py/test_SquareService.py trunk/zsi/test/wsdl2py/test_ThreatService.py trunk/zsi/test/wsdl2py/test_WhiteMesa.py trunk/zsi/test/wsdl2py/test_XMethodsQuery.py trunk/zsi/test/wsdl2py/test_ZipCodeResolver.py Modified: trunk/zsi/CHANGES =================================================================== --- trunk/zsi/CHANGES 2007-01-03 23:41:45 UTC (rev 1313) +++ trunk/zsi/CHANGES 2007-01-03 23:43:01 UTC (rev 1314) @@ -6,6 +6,11 @@ - Record facets (restrictions) in XMLSchema.py <vc...@da...> - Remove Send()'s kwargs out of _args list <ef...@bo...> +Change for 2.0.0 released xxx: + - no more wsdl2dispatch, wsdl2py does it all + - simplified and consolidated various wsdl2py script options + - wsdl2py added some soapheader support to client code. + Change for 2.0.0rc3 released xxx: - Updated ZSI developers guide - Added ZSI wsdl2py users guide Modified: trunk/zsi/doc/guide02-wsdl2py.tex =================================================================== --- trunk/zsi/doc/guide02-wsdl2py.tex 2007-01-03 23:41:45 UTC (rev 1313) +++ trunk/zsi/doc/guide02-wsdl2py.tex 2007-01-03 23:43:01 UTC (rev 1314) @@ -1,27 +1,38 @@ \chapter{WSDL to Python Code} -The \WPY script is the most used tool. It will generate all the -code needed to access a Web Service through an exposed WSDL document, usually -this description is available at a URL which is provided to the script. +The \WPY script is used to generate all the code needed to access a Web Service +through an exposed WSDL document, usually this description is available at a URL +which is provided to the script. -\WPY generates a "stub" module from the WSDL SOAP Bindings. It contains various -classes, including a \it{Locator} which represents the bindings to the actual -Web Service, and several \it{port} classes that are used to remotely invoke -operations on the \WS, as well as various \it{Message} classes that -represent the SOAP and XML Schema data types. A \it{Message} instance is -serialized as a XML instance. A \it{Message} passed as an argument to a -\it{port} method is then serialized into a SOAP Envelope and transported to the -\WS, the client will then wait for an expected response, and finally the SOAP -response is marshalled back into the \it{Message} returned to the user. +\section{Generated Modules} +\WPY will generate a client, types, and service module. From the the WSDL +SOAP Bindings, the client and service modules are created. The types module +contains typecodes for the schema defined by the WSDL. -A second module the "types", contains typecodes representing all the components -of each schema specified by the target WSDL Document (not including built-in -types). Each schema component declared at the top-level, the immediate children -of the \it{schema} tag, are global in scope and by importing the "types" module -an application has access to the GEDs and global type definitions either -directly by reference or through the convenience functions \code{GED} and -\code{GTD}, respectively. For more information on these functions please see .. +\subsection{CLIENT: locator, port} +various classes, including a \it{Locator} which represents the +SOAP binding to the actual Web Service, and several \it{port} classes that are +used to remotely invoke operations on the \WS, as well as various \it{Message} +classes that represent the SOAP and XML Schema data types. A \it{Message} +instance is serialized as a XML instance. A \it{Message} passed as an argument +to a \it{port} method is then serialized into a SOAP Envelope and transported to +the \WS, the client will then wait for an expected response, and finally the +SOAP response is marshalled back into the \it{Message} returned to the user. +\subsection{TYPES: typecodes/schema} +typecodes representing all the components of each schema specified by the target +WSDL Document (not including built-in types). Each schema component declared at +the top-level, the immediate children of the \it{schema} tag, are global in +scope and by importing the "types" module an application has access to the GEDs +and global type definitions either directly by reference or through the +convenience functions \code{GED} and \code{GTD}, respectively. For more +information on these functions please see .. + +\subsection{SERVICE: service interface/bindings} +skeleton class, normally subclassed and invoked by implementation code. The +skeleton defines a callback method for each operation defined in the SOAP +\it{Binding}. These methods marshal/unmarshall XML into python types. + \section{wsdl2py} \subsection{Basics of Code Generation} Modified: trunk/zsi/setup.py =================================================================== --- trunk/zsi/setup.py 2007-01-03 23:41:45 UTC (rev 1313) +++ trunk/zsi/setup.py 2007-01-03 23:43:01 UTC (rev 1314) @@ -41,7 +41,6 @@ additional_params['entry_points'] = { 'console_scripts': [ 'wsdl2py = ZSI.generate.commands:wsdl2py', - 'wsdl2dispatch = ZSI.generate.commands:wsdl2dispatch', ], } additional_params['install_requires'] = [ "PyXML >= 0.8.3", ] @@ -50,7 +49,7 @@ "http://sourceforge.net/project/showfiles.php?group_id=6473&package_id=6541&release_id=286213", ] else: - additional_params['scripts'] = ["scripts/wsdl2py", "scripts/wsdl2dispatch"] + additional_params['scripts'] = ["scripts/wsdl2py",] setup( name="ZSI", Modified: trunk/zsi/test/wsdl2py/ServiceTest.py =================================================================== --- trunk/zsi/test/wsdl2py/ServiceTest.py 2007-01-03 23:41:45 UTC (rev 1313) +++ trunk/zsi/test/wsdl2py/ServiceTest.py 2007-01-03 23:43:01 UTC (rev 1314) @@ -262,9 +262,9 @@ args = [] ServiceTestCase._wsdl[url] = False if os.path.isfile(url): - args += ['-f', os.path.abspath(url)] + args.append(os.path.abspath(url)) else: - args += ['-u', url] + args.append(url) try: os.mkdir(MODULEDIR) @@ -277,7 +277,7 @@ try: # Client Stubs - wsdl2py = ['wsdl2py'] + args + self.wsdl2py_args + wsdl2py = ['wsdl2py'] + self.wsdl2py_args + args try: exit = subprocess.call(wsdl2py) except OSError, ex: @@ -292,19 +292,19 @@ '"%s" exited with exit status: %d' %(wsdl2py, exit)) # Service Stubs - if '-x' not in self.wsdl2py_args: - wsdl2dispatch = (['wsdl2dispatch'] + args + - self.wsdl2dispatch_args) - try: - exit = subprocess.call(wsdl2dispatch) - except OSError, ex: - warnings.warn("TODO: Not sure what is going on here?") + #if '-x' not in self.wsdl2py_args: + # wsdl2dispatch = (['wsdl2dispatch'] + args + + # self.wsdl2dispatch_args) + # try: + # exit = subprocess.call(wsdl2dispatch) + # except OSError, ex: + # warnings.warn("TODO: Not sure what is going on here?") - #TODO: returncode WINDOWS? - if WIF: self.failUnless(os.WIFEXITED(exit), - '"%s" exited with signal#: %d' %(wsdl2dispatch, exit)) - self.failUnless(exit == 0, - '"%s" exited with exit status: %d' %(wsdl2dispatch, exit)) + # #TODO: returncode WINDOWS? + # if WIF: self.failUnless(os.WIFEXITED(exit), + # '"%s" exited with signal#: %d' %(wsdl2dispatch, exit)) + # self.failUnless(exit == 0, + # '"%s" exited with exit status: %d' %(wsdl2dispatch, exit)) ServiceTestCase._wsdl[url] = True Modified: trunk/zsi/test/wsdl2py/config.txt =================================================================== --- trunk/zsi/test/wsdl2py/config.txt 2007-01-03 23:41:45 UTC (rev 1313) +++ trunk/zsi/test/wsdl2py/config.txt 2007-01-03 23:43:01 UTC (rev 1314) @@ -19,7 +19,7 @@ # ########################################################################## [configuration] -tracefile = False +tracefile = 1 debug = False skip = False twisted = False @@ -117,7 +117,7 @@ document = True literal = True broke = False -tests = test_MapPoint test_OpcDaGateway test_Sabre test_Echo test_AWSECommerceService test_FinancialService +tests = test_MapPoint test_OpcDaGateway test_Echo test_AWSECommerceService test_FinancialService [doc_literal_broke] document = True @@ -162,3 +162,6 @@ test_ThreatService = http://www.boyzoid.com/threat.cfc?wsdl test_TerraService = http://terraservice.net/TerraService.asmx?WSDL test_InfoBil = http://javatest2.infodata.se/webservices/services/Infobil?wsdl + +# Google AdWords +test_GoogleAdWords_TES = https://sandbox.google.com/api/adwords/v8/TrafficEstimatorService?wsdl Modified: trunk/zsi/test/wsdl2py/servers/DateService.py =================================================================== --- trunk/zsi/test/wsdl2py/servers/DateService.py 2007-01-03 23:41:45 UTC (rev 1313) +++ trunk/zsi/test/wsdl2py/servers/DateService.py 2007-01-03 23:43:01 UTC (rev 1314) @@ -5,7 +5,7 @@ ########################################################################### import sys, time from ZSI.ServiceContainer import AsServer -from DateService_services_server import simple_Date_Service as _DateService +from DateService_server import simple_Date_Service as _DateService class Service(_DateService): def soap_getCurrentDate(self, ps): Modified: trunk/zsi/test/wsdl2py/servers/EchoServer.py =================================================================== --- trunk/zsi/test/wsdl2py/servers/EchoServer.py 2007-01-03 23:41:45 UTC (rev 1313) +++ trunk/zsi/test/wsdl2py/servers/EchoServer.py 2007-01-03 23:43:01 UTC (rev 1314) @@ -5,7 +5,7 @@ ########################################################################### import sys from ZSI.ServiceContainer import AsServer -from EchoServer_services_server import EchoServer +from EchoServer_server import EchoServer """ EchoServer example service Modified: trunk/zsi/test/wsdl2py/servers/FinancialService.py =================================================================== --- trunk/zsi/test/wsdl2py/servers/FinancialService.py 2007-01-03 23:41:45 UTC (rev 1313) +++ trunk/zsi/test/wsdl2py/servers/FinancialService.py 2007-01-03 23:43:01 UTC (rev 1314) @@ -4,7 +4,7 @@ # See LBNLCopyright for copyright notice! ########################################################################### import sys -from FinancialService_services_server import * +from FinancialService_server import * from ZSI.ServiceContainer import AsServer class Service(FinancialService): Modified: trunk/zsi/test/wsdl2py/servers/SquareService.py =================================================================== --- trunk/zsi/test/wsdl2py/servers/SquareService.py 2007-01-03 23:41:45 UTC (rev 1313) +++ trunk/zsi/test/wsdl2py/servers/SquareService.py 2007-01-03 23:43:01 UTC (rev 1314) @@ -4,7 +4,7 @@ # See LBNLCopyright for copyright notice! ########################################################################### import sys -import SquareService_services_server as Square +import SquareService_server as Square from ZSI.ServiceContainer import AsServer class Service(Square.SquareService): Modified: trunk/zsi/test/wsdl2py/servers/WhiteMesa.py =================================================================== --- trunk/zsi/test/wsdl2py/servers/WhiteMesa.py 2007-01-03 23:41:45 UTC (rev 1313) +++ trunk/zsi/test/wsdl2py/servers/WhiteMesa.py 2007-01-03 23:43:01 UTC (rev 1314) @@ -5,7 +5,7 @@ ########################################################################### import sys from ZSI.ServiceContainer import AsServer -from RPC_Literal_TestDefinitions_services_server import WhiteMesaSoapRpcLitTestSvc as WhiteMesa +from RPC_Literal_TestDefinitions_server import WhiteMesaSoapRpcLitTestSvc as WhiteMesa """ WhiteMesa web service for rpc/literal tests. Modified: trunk/zsi/test/wsdl2py/test_AWSECommerceService.py =================================================================== --- trunk/zsi/test/wsdl2py/test_AWSECommerceService.py 2007-01-03 23:41:45 UTC (rev 1313) +++ trunk/zsi/test/wsdl2py/test_AWSECommerceService.py 2007-01-03 23:43:01 UTC (rev 1314) @@ -47,9 +47,9 @@ """Test case for Amazon ECommerce Web service """ name = "test_AWSECommerceService" - client_file_name = "AWSECommerceService_services.py" - types_file_name = "AWSECommerceService_services_types.py" - server_file_name = "AWSECommerceService_services_server.py" + client_file_name = "AWSECommerceService_client.py" + types_file_name = "AWSECommerceService_types.py" + server_file_name = "AWSECommerceService_server.py" def __init__(self, methodName): ServiceTestCase.__init__(self, methodName) Modified: trunk/zsi/test/wsdl2py/test_AmazonS3.py =================================================================== --- trunk/zsi/test/wsdl2py/test_AmazonS3.py 2007-01-03 23:41:45 UTC (rev 1313) +++ trunk/zsi/test/wsdl2py/test_AmazonS3.py 2007-01-03 23:43:01 UTC (rev 1314) @@ -45,9 +45,9 @@ """Test case for AmazonS3 web service """ name = "test_AmazonS3" - client_file_name = "AmazonS3_services.py" - types_file_name = "AmazonS3_services_types.py" - server_file_name = "AmazonS3_services_server.py" + client_file_name = "AmazonS3_client.py" + types_file_name = "AmazonS3_types.py" + server_file_name = "AmazonS3_server.py" def __init__(self, methodName): ServiceTestCase.__init__(self, methodName) Modified: trunk/zsi/test/wsdl2py/test_Attributes.py =================================================================== --- trunk/zsi/test/wsdl2py/test_Attributes.py 2007-01-03 23:41:45 UTC (rev 1313) +++ trunk/zsi/test/wsdl2py/test_Attributes.py 2007-01-03 23:43:01 UTC (rev 1314) @@ -45,7 +45,7 @@ class AttributeTestCase(ServiceTestCase): name = "test_Attributes" - types_file_name = "test_Attributes_xsd_services_types.py" + types_file_name = "test_Attributes_xsd_types.py" def __init__(self, methodName): ServiceTestCase.__init__(self, methodName) Modified: trunk/zsi/test/wsdl2py/test_Choice.py =================================================================== --- trunk/zsi/test/wsdl2py/test_Choice.py 2007-01-03 23:41:45 UTC (rev 1313) +++ trunk/zsi/test/wsdl2py/test_Choice.py 2007-01-03 23:43:01 UTC (rev 1314) @@ -44,7 +44,7 @@ class ChoiceTestCase(ServiceTestCase): name = "test_Choice" - types_file_name = "test_Choice_xsd_services_types.py" + types_file_name = "test_Choice_xsd_types.py" def __init__(self, methodName): ServiceTestCase.__init__(self, methodName) Modified: trunk/zsi/test/wsdl2py/test_DateService.py =================================================================== --- trunk/zsi/test/wsdl2py/test_DateService.py 2007-01-03 23:41:45 UTC (rev 1313) +++ trunk/zsi/test/wsdl2py/test_DateService.py 2007-01-03 23:43:01 UTC (rev 1314) @@ -46,9 +46,9 @@ """Test case for Holger's DateService """ name = "test_DateService" - client_file_name = "DateService_services.py" - types_file_name = "DateService_services_types.py" - server_file_name = "DateService_services_server.py" + client_file_name = "DateService_client.py" + types_file_name = "DateService_types.py" + server_file_name = "DateService_server.py" def __init__(self, methodName): ServiceTestCase.__init__(self, methodName) Modified: trunk/zsi/test/wsdl2py/test_DerivedTypes.py =================================================================== --- trunk/zsi/test/wsdl2py/test_DerivedTypes.py 2007-01-03 23:41:45 UTC (rev 1313) +++ trunk/zsi/test/wsdl2py/test_DerivedTypes.py 2007-01-03 23:43:01 UTC (rev 1314) @@ -46,7 +46,7 @@ class DTTestCase(ServiceTestCase): name = "test_DerivedTypes" client_file_name = None - types_file_name = "test_DerivedTypes_xsd_services_types.py" + types_file_name = "test_DerivedTypes_xsd_types.py" server_file_name = None def __init__(self, methodName): Modified: trunk/zsi/test/wsdl2py/test_Echo.py =================================================================== --- trunk/zsi/test/wsdl2py/test_Echo.py 2007-01-03 23:41:45 UTC (rev 1313) +++ trunk/zsi/test/wsdl2py/test_Echo.py 2007-01-03 23:43:01 UTC (rev 1314) @@ -40,9 +40,9 @@ class EchoTestCase(ServiceTestCase): name = "test_Echo" - client_file_name = "EchoServer_services.py" - types_file_name = "EchoServer_services_types.py" - server_file_name = "EchoServer_services_server.py" + client_file_name = "EchoServer_client.py" + types_file_name = "EchoServer_types.py" + server_file_name = "EchoServer_server.py" def __init__(self, methodName): ServiceTestCase.__init__(self, methodName) Modified: trunk/zsi/test/wsdl2py/test_FinancialService.py =================================================================== --- trunk/zsi/test/wsdl2py/test_FinancialService.py 2007-01-03 23:41:45 UTC (rev 1313) +++ trunk/zsi/test/wsdl2py/test_FinancialService.py 2007-01-03 23:43:01 UTC (rev 1314) @@ -48,9 +48,9 @@ """Test case for Holger's SquareService """ name = "test_FinancialService" - client_file_name = "FinancialService_services.py" - types_file_name = "FinancialService_services_types.py" - server_file_name = "FinancialService_services_server.py" + client_file_name = "FinancialService_client.py" + types_file_name = "FinancialService_types.py" + server_file_name = "FinancialService_server.py" def __init__(self, methodName): ServiceTestCase.__init__(self, methodName) Modified: trunk/zsi/test/wsdl2py/test_InfoBil.py =================================================================== --- trunk/zsi/test/wsdl2py/test_InfoBil.py 2007-01-03 23:41:45 UTC (rev 1313) +++ trunk/zsi/test/wsdl2py/test_InfoBil.py 2007-01-03 23:43:01 UTC (rev 1314) @@ -40,9 +40,9 @@ class TestCase(ServiceTestCase): name = "test_InfoBil" - client_file_name = "InfoBilServiceService_services.py" - types_file_name = "InfoBilServiceService_services_types.py" - server_file_name = "InfoBilServiceService_services_server.py" + client_file_name = "InfoBilServiceService_client.py" + types_file_name = "InfoBilServiceService_types.py" + server_file_name = "InfoBilServiceService_server.py" def __init__(self, methodName): ServiceTestCase.__init__(self, methodName) Modified: trunk/zsi/test/wsdl2py/test_MapPoint.py =================================================================== --- trunk/zsi/test/wsdl2py/test_MapPoint.py 2007-01-03 23:41:45 UTC (rev 1313) +++ trunk/zsi/test/wsdl2py/test_MapPoint.py 2007-01-03 23:43:01 UTC (rev 1314) @@ -42,9 +42,9 @@ """ name = "test_MapPoint" - client_file_name = "CommonService_services.py" - types_file_name = "CommonService_services_types.py" - server_file_name = "CommonService_services_server.py" + client_file_name = "CommonService_client.py" + types_file_name = "CommonService_types.py" + server_file_name = "CommonService_server.py" def test_net_GetVersionInfo(self): """expect this to fail cause i'm not doing http authentication. Modified: trunk/zsi/test/wsdl2py/test_OpcDaGateway.py =================================================================== --- trunk/zsi/test/wsdl2py/test_OpcDaGateway.py 2007-01-03 23:41:45 UTC (rev 1313) +++ trunk/zsi/test/wsdl2py/test_OpcDaGateway.py 2007-01-03 23:43:01 UTC (rev 1314) @@ -52,9 +52,9 @@ def Write(self, request): """ name = "test_OpcDaGateway" - client_file_name = "OpcXmlDaSrv_services.py" - types_file_name = "OpcXmlDaSrv_services_types.py" - server_file_name = "OpcXmlDaSrv_services_server.py" + client_file_name = "OpcXmlDaSrv_client.py" + types_file_name = "OpcXmlDaSrv_types.py" + server_file_name = "OpcXmlDaSrv_server.py" def __init__(self, methodName): ServiceTestCase.__init__(self, methodName) Modified: trunk/zsi/test/wsdl2py/test_Sabre.py =================================================================== --- trunk/zsi/test/wsdl2py/test_Sabre.py 2007-01-03 23:41:45 UTC (rev 1313) +++ trunk/zsi/test/wsdl2py/test_Sabre.py 2007-01-03 23:43:01 UTC (rev 1314) @@ -44,9 +44,9 @@ """ name = "test_Sabre" - client_file_name = "SessionCreateRQService_services.py" - types_file_name = "SessionCreateRQService_services_types.py" - server_file_name = "SessionCreateRQService_services_server.py" + client_file_name = "SessionCreateRQService_client.py" + types_file_name = "SessionCreateRQService_types.py" + server_file_name = "SessionCreateRQService_server.py" def __init__(self, methodName): ServiceTestCase.__init__(self, methodName) Modified: trunk/zsi/test/wsdl2py/test_SquareService.py =================================================================== --- trunk/zsi/test/wsdl2py/test_SquareService.py 2007-01-03 23:41:45 UTC (rev 1313) +++ trunk/zsi/test/wsdl2py/test_SquareService.py 2007-01-03 23:43:01 UTC (rev 1314) @@ -48,9 +48,9 @@ """Test case for Holger's SquareService """ name = "test_SquareService" - client_file_name = "SquareService_services.py" - types_file_name = "SquareService_services_types.py" - server_file_name = "SquareService_services_server.py" + client_file_name = "SquareService_client.py" + types_file_name = "SquareService_types.py" + server_file_name = "SquareService_server.py" def __init__(self, methodName): ServiceTestCase.__init__(self, methodName) Modified: trunk/zsi/test/wsdl2py/test_ThreatService.py =================================================================== --- trunk/zsi/test/wsdl2py/test_ThreatService.py 2007-01-03 23:41:45 UTC (rev 1313) +++ trunk/zsi/test/wsdl2py/test_ThreatService.py 2007-01-03 23:43:01 UTC (rev 1314) @@ -44,8 +44,8 @@ """Test case for ZipCodeResolver Web service """ name = "test_ThreatService" - client_file_name = "Current_Homeland_Security_Threat_Level_services.py" - types_file_name = "Current_Homeland_Security_Threat_Level_services_types.py" + client_file_name = "Current_Homeland_Security_Threat_Level_client.py" + types_file_name = "Current_Homeland_Security_Threat_Level_types.py" server_file_name = None def __init__(self, methodName): Modified: trunk/zsi/test/wsdl2py/test_WhiteMesa.py =================================================================== --- trunk/zsi/test/wsdl2py/test_WhiteMesa.py 2007-01-03 23:41:45 UTC (rev 1313) +++ trunk/zsi/test/wsdl2py/test_WhiteMesa.py 2007-01-03 23:43:01 UTC (rev 1314) @@ -43,9 +43,9 @@ """Test case for ZipCodeResolver Web service """ name = "test_WhiteMesa" - client_file_name = "RPC_Literal_TestDefinitions_services.py" - types_file_name = "RPC_Literal_TestDefinitions_services_types.py" - server_file_name = "RPC_Literal_TestDefinitions_services_server.py" + client_file_name = "RPC_Literal_TestDefinitions_client.py" + types_file_name = "RPC_Literal_TestDefinitions_types.py" + server_file_name = "RPC_Literal_TestDefinitions_server.py" def __init__(self, methodName): ServiceTestCase.__init__(self, methodName) Modified: trunk/zsi/test/wsdl2py/test_XMethodsQuery.py =================================================================== --- trunk/zsi/test/wsdl2py/test_XMethodsQuery.py 2007-01-03 23:41:45 UTC (rev 1313) +++ trunk/zsi/test/wsdl2py/test_XMethodsQuery.py 2007-01-03 23:43:01 UTC (rev 1314) @@ -43,9 +43,9 @@ """Test case for XMethodsQuery Web service """ name = "test_XMethodsQuery" - client_file_name = "XMethodsQuery_services.py" - types_file_name = "XMethodsQuery_services_types.py" - server_file_name = "XMethodsQuery_services_server.py" + client_file_name = "XMethodsQuery_client.py" + types_file_name = "XMethodsQuery_types.py" + server_file_name = "XMethodsQuery_server.py" def __init__(self, methodName): ServiceTestCase.__init__(self, methodName) Modified: trunk/zsi/test/wsdl2py/test_ZipCodeResolver.py =================================================================== --- trunk/zsi/test/wsdl2py/test_ZipCodeResolver.py 2007-01-03 23:41:45 UTC (rev 1313) +++ trunk/zsi/test/wsdl2py/test_ZipCodeResolver.py 2007-01-03 23:43:01 UTC (rev 1314) @@ -44,9 +44,9 @@ """Test case for ZipCodeResolver Web service """ name = "test_ZipCodeResolver" - client_file_name = "ZipCodeResolver_services.py" - types_file_name = "ZipCodeResolver_services_types.py" - #server_file_name = "ZipCodeResolver_services_server.py" + client_file_name = "ZipCodeResolver.py" + types_file_name = "ZipCodeResolver_types.py" + #server_file_name = "ZipCodeResolver_server.py" def test_net_CorrectedAddressHtml(self): loc = self.client_module.ZipCodeResolverLocator() This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <bov...@us...> - 2007-01-11 21:53:53
|
Revision: 1317 http://svn.sourceforge.net/pywebsvcs/?rev=1317&view=rev Author: boverhof Date: 2007-01-11 13:53:49 -0800 (Thu, 11 Jan 2007) Log Message: ----------- A test/wsdl2py/test_GoogleAdWords.py -- added unittest for google adwords, good soap:header access example M test/wsdl2py/config.txt M test/wsdl2py/test_DateService.py A test/wsdl2py/test_GoogleAdWords.py M test/wsdl2py/test_ThreatService.py M test/wsdl2py/test_XMethodsQuery.py M test/wsdl2py/test_MapPoint.py M test/wsdl2py/test_AWSECommerceService.py M test/wsdl2py/test_FinancialService.py M test/wsdl2py/test_SquareService.py M test/wsdl2py/test_WhiteMesa.py -- modified tests to work with changes M ZSI/generate/wsdl2python.py M ZSI/generate/commands.py M ZSI/generate/containers.py -- changed locator access method from "portType.name" to "port.name", because this is correct. This could be problematic for services that declare multiple port's of the same portType. -- changed name of "SOAP" classes. Name after "binding.name", which is correct, not "port.name". Now if multiple ports w/same binding create 1 class and all of the "getPort" accessors use the 1 class. M ZSI/TC.py -- fixed _AnyLax and _AnyStrict constructors.. M CHANGES Modified Paths: -------------- trunk/zsi/CHANGES trunk/zsi/ZSI/TC.py trunk/zsi/ZSI/generate/commands.py trunk/zsi/ZSI/generate/containers.py trunk/zsi/ZSI/generate/wsdl2python.py trunk/zsi/test/wsdl2py/config.txt trunk/zsi/test/wsdl2py/test_AWSECommerceService.py trunk/zsi/test/wsdl2py/test_DateService.py trunk/zsi/test/wsdl2py/test_FinancialService.py trunk/zsi/test/wsdl2py/test_MapPoint.py trunk/zsi/test/wsdl2py/test_SquareService.py trunk/zsi/test/wsdl2py/test_ThreatService.py trunk/zsi/test/wsdl2py/test_WhiteMesa.py trunk/zsi/test/wsdl2py/test_XMethodsQuery.py Added Paths: ----------- trunk/zsi/test/wsdl2py/test_GoogleAdWords.py Modified: trunk/zsi/CHANGES =================================================================== --- trunk/zsi/CHANGES 2007-01-11 17:27:28 UTC (rev 1316) +++ trunk/zsi/CHANGES 2007-01-11 21:53:49 UTC (rev 1317) @@ -10,6 +10,10 @@ - no more wsdl2dispatch, wsdl2py does it all - simplified and consolidated various wsdl2py script options - wsdl2py added some soapheader support to client code. + - wsdl2py changed Locator accessors names to match the "port.name" + rather than the "portType.name" + - wsdl2py changed generated Binding class names to match the "binding.name" + rather than the "portType.name" Change for 2.0.0rc3 released xxx: - Updated ZSI developers guide Modified: trunk/zsi/ZSI/TC.py =================================================================== --- trunk/zsi/ZSI/TC.py 2007-01-11 17:27:28 UTC (rev 1316) +++ trunk/zsi/ZSI/TC.py 2007-01-11 21:53:49 UTC (rev 1317) @@ -1666,8 +1666,7 @@ logger = _GetLogger('ZSI.TC._AnyStrict') def __init__(self, pname=None, aslist=False, **kw): - TypeCode.__init__(self, pname=pname, **kw) - self.aslist = aslist + Any.__init__(self, pname=pname, aslist=aslist, **kw) self.unique = True def serialize(self, elt, sw, pyobj, name=None, **kw): @@ -1687,8 +1686,7 @@ logger = _GetLogger('ZSI.TC._AnyLax') def __init__(self, pname=None, aslist=False, **kw): - TypeCode.__init__(self, pname=pname, **kw) - self.aslist = aslist + Any.__init__(self, pname=pname, aslist=aslist, **kw) self.unique = True def parse_into_dict_or_list(self, elt, ps): Modified: trunk/zsi/ZSI/generate/commands.py =================================================================== --- trunk/zsi/ZSI/generate/commands.py 2007-01-11 17:27:28 UTC (rev 1316) +++ trunk/zsi/ZSI/generate/commands.py 2007-01-11 21:53:49 UTC (rev 1317) @@ -67,17 +67,13 @@ return f def wsdl2py(args=None): + """Utility for automatically generating client/service interface code from a wsdl +definition, and a set of classes representing element declarations and +type definitions. By default invoking this script produces three files, each +named after the wsdl definition name, in the current working directory. +These files will end with '_client.py', '_types.py', '_server.py' +respectively. """ - A utility for automatically generating client interface code from a wsdl - definition, and a set of classes representing element declarations and - type definitions. This will produce two files in the current working - directory named after the wsdl definition name. - - eg. <definition name='SampleService'> - SampleService_client.py - SampleService_types.py - SampleService_server.py - """ op = optparse.OptionParser(usage="USAGE: %wsdl2py [options] WSDL", description=wsdl2py.__doc__) @@ -120,7 +116,7 @@ action="callback", callback=SetUpTwistedClient, callback_kwargs={'module':'ZSI.generate.pyclass', 'metaclass':'pyclass_type'}, - help="generate a twisted.web client, dependencies python>=2.4, Twisted>=2.0.0, TwistedWeb>=0.5.0") + help="generate a twisted.web client/server, dependencies python>=2.4, Twisted>=2.0.0, TwistedWeb>=0.5.0") # Extended generation options #op.add_option("-e", "--extended", @@ -134,7 +130,7 @@ # help="file to load types from") op.add_option("-o", "--output-dir", action="store", dest="output_dir", default=".", type="string", - help="Directory to place generated files in (default current directory)") + help="save files in directory") op.add_option("-s", "--simple-naming", action="store_true", dest="simple_naming", default=False, help="map element names directly to python attributes") @@ -190,7 +186,7 @@ # Use a different client suffix # WriteServiceModule.client_module_suffix = "_client" # Write messages definitions to a separate file. - wsdl2pyServiceDescription.separate_messages = True + #wsdl2pyServiceDescription.separate_messages = True # Use more simple type and element class names containers.SetTypeNameFunc( lambda n: '%s_' %(NC_to_CN(n)) ) containers.SetElementNameFunc( lambda n: '%s' %(NC_to_CN(n)) ) Modified: trunk/zsi/ZSI/generate/containers.py =================================================================== --- trunk/zsi/ZSI/generate/containers.py 2007-01-11 17:27:28 UTC (rev 1316) +++ trunk/zsi/ZSI/generate/containers.py 2007-01-11 21:53:49 UTC (rev 1317) @@ -371,8 +371,11 @@ self.logger.warning('Skip port(%s), not a SOAP-1.1 address binding' %p.name) continue - info = (p.getBinding().getPortType().name, p.getBinding().name, ab.location) - self.portInfo.append(info) + #info = (p.getBinding().getPortType().name, p.getBinding().name, ab.location) + self.portInfo.append( (NC_to_CN(p.name), + NC_to_CN(p.getBinding().name), + ab.location) + ) def getLocatorName(self): '''return class name of generated locator. @@ -392,23 +395,22 @@ self.locatorName = '%sLocator' %self.serviceName locator = ['# Locator', 'class %s:' %self.locatorName, ] self.portMethods = [] - for p in self.portInfo: - ptName = NC_to_CN(p[0]) - bName = NC_to_CN(p[1]) - sAdd = p[2] - method = 'get%s' %ptName - - pI = [ - '%s%s_address = "%s"' % (ID1, ptName, sAdd), - '%sdef get%sAddress(self):' % (ID1, ptName), - '%sreturn %sLocator.%s_address' % (ID2, - self.serviceName,ptName), - '%sdef %s(self, url=None, **kw):' %(ID1, method), - '%sreturn %s%s(url or %sLocator.%s_address, **kw)' \ - % (ID2, bName, self.clientClassSuffix, self.serviceName, ptName), + kwargs = KW.copy() + for port,bind,addr in self.portInfo: + # access method each port + method = 'get%s' %port + kwargs.update(dict(port=port, bind=bind, addr=addr, + service=self.serviceName, suffix=self.clientClassSuffix, method=method)) + + locator += [ + '%(ID1)s%(port)s_address = "%(addr)s"' %kwargs, + '%(ID1)sdef get%(port)sAddress(self):' %kwargs, + '%(ID2)sreturn %(service)sLocator.%(port)s_address' %kwargs, + '%(ID1)sdef %(method)s(self, url=None, **kw):' %kwargs, + '%(ID2)sreturn %(bind)s%(suffix)s(url or %(service)sLocator.%(port)s_address, **kw)' %kwargs, ] + self.portMethods.append(method) - locator += pI self.writeArray(locator) @@ -509,6 +511,7 @@ self.inputSimpleType = \ FromMessageGetSimpleElementDeclaration(op.getInputMessage()) self.inputAction = op.getInputAction() + self.soap_input_headers = bop.input.findBindings(WSDLTools.SoapHeaderBinding) if bop.output is not None: sbody = bop.output.findBinding(WSDLTools.SoapBodyBinding) @@ -519,10 +522,7 @@ self.outputSimpleType = \ FromMessageGetSimpleElementDeclaration(op.getOutputMessage()) self.outputAction = op.getOutputAction() - - - self.soap_input_headers = bop.input.findBindings(WSDLTools.SoapHeaderBinding) - self.soap_output_headers = bop.output.findBindings(WSDLTools.SoapHeaderBinding) + self.soap_output_headers = bop.output.findBindings(WSDLTools.SoapHeaderBinding) def _setContent(self): '''create string representation of operation. @@ -687,8 +687,9 @@ self.writeArray(method) -class ServiceOperationsClassContainer(ServiceContainerBase): - ''' +class BindingDescription(ServiceContainerBase): + '''writes out SOAP Binding class + class variables: readerclass -- writerclass -- @@ -697,7 +698,7 @@ readerclass = None writerclass = None operationclass = ServiceOperationContainer - logger = _GetLogger("ServiceOperationsClassContainer") + logger = _GetLogger("BindingDescription") def __init__(self, useWSA=False, do_extended=False, wsdl=None): '''Parameters: @@ -709,7 +710,7 @@ ServiceContainerBase.__init__(self) self.useWSA = useWSA self.rProp = None - self.bName = None + #self.bName = None self.operations = None self.do_extended = do_extended self._wsdl = wsdl # None unless do_extended == True @@ -734,43 +735,44 @@ cls.operationclass = className setOperationClass = classmethod(setOperationClass) - def setUp(self, port): + def setUp(self, item): '''This method finds all SOAP Binding Operations, it will skip all bindings that are not SOAP. - port -- WSDL.Port instance + item -- WSDL.Binding instance ''' - assert isinstance(port, WSDLTools.Port), \ - 'expecting WSDLTools Port instance' + assert isinstance(item, WSDLTools.Binding), \ + 'expecting WSDLTools Binding instance' + portType = item.getPortType() + self._kwargs = KW.copy() + self._kwargs['bind'] = NC_to_CN(item.name) self.operations = [] - self.bName = port.getBinding().name - self.rProp = port.getBinding().getPortType().getResourceProperties() - soap_binding = port.getBinding().findBinding(WSDLTools.SoapBinding) + self.rProp = portType.getResourceProperties() + soap_binding = item.findBinding(WSDLTools.SoapBinding) if soap_binding is None: raise Wsdl2PythonError,\ - 'port(%s) missing WSDLTools.SoapBinding' %port.name + 'Binding(%s) missing WSDLTools.SoapBinding' %item.name - for bop in port.getBinding().operations: + for bop in item.operations: soap_bop = bop.findBinding(WSDLTools.SoapOperationBinding) if soap_bop is None: self.logger.warning(\ - 'Skip port(%s) operation(%s) no SOAP Binding Operation'\ - %(port.name, bop.name), + 'Skip Binding(%s) operation(%s) no SOAP Binding Operation'\ + %(item.name, bop.name), ) continue - #soapAction = soap_bop.soapAction if bop.input is not None: soapBodyBind = bop.input.findBinding(WSDLTools.SoapBodyBinding) if soapBodyBind is None: self.logger.warning(\ - 'Skip port(%s) operation(%s) Bindings(%s) not supported'\ - %(port.name, bop.name, bop.extensions) + 'Skip Binding(%s) operation(%s) Bindings(%s) not supported'\ + %(item.name, bop.name, bop.extensions) ) continue - op = port.getBinding().getPortType().operations.get(bop.name) + op = portType.operations.get(bop.name) if op is None: raise Wsdl2PythonError,\ 'no matching portType/Binding operation(%s)' % bop.name @@ -782,27 +784,32 @@ def _setContent(self): if self.useWSA is True: - ctorArgs = 'endPointReference=None, **kw' - epr = 'self.endPointReference = endPointReference' + args = 'endPointReference=None, **kw' + epr = 'self.endPointReference = endPointReference' else: - ctorArgs = '**kw' + args = '**kw' epr = '# no ws-addressing' if self.rProp: - rprop = 'kw.setdefault("ResourceProperties", ("%s","%s"))'\ + rp = 'kw.setdefault("ResourceProperties", ("%s","%s"))'\ %(self.rProp[0], self.rProp[1]) else: - rprop = '# no resource properties' + rp = '# no resource properties' + kwargs = self._kwargs + kwargs.update(dict(suffix=self.clientClassSuffix, + args=args, epr=epr, rp=rp, readerclass=self.readerclass, + writerclass=self.writerclass,)) + methods = [ '# Methods', - 'class %s%s:' % (NC_to_CN(self.bName), self.clientClassSuffix), - '%sdef __init__(self, url, %s):' % (ID1, ctorArgs), - '%skw.setdefault("readerclass", %s)' % (ID2, self.readerclass), - '%skw.setdefault("writerclass", %s)' % (ID2, self.writerclass), - '%s%s' % (ID2, rprop), - '%sself.binding = client.Binding(url=url, **kw)' %ID2, - '%s%s' % (ID2,epr), + 'class %(bind)s%(suffix)s:' %kwargs, + '%(ID1)sdef __init__(self, url, %(args)s):' %kwargs, + '%(ID2)skw.setdefault("readerclass", %(readerclass)s)' %kwargs, + '%(ID2)skw.setdefault("writerclass", %(writerclass)s)' %kwargs, + '%(ID2)s%(rp)s' % kwargs, + '%(ID2)sself.binding = client.Binding(url=url, **kw)' %kwargs, + '%(ID2)s%(epr)s' % kwargs, ] for op in self.operations: @@ -810,6 +817,7 @@ self.writeArray(methods) +ServiceOperationsClassContainer = BindingDescription class MessageContainerInterface: Modified: trunk/zsi/ZSI/generate/wsdl2python.py =================================================================== --- trunk/zsi/ZSI/generate/wsdl2python.py 2007-01-11 17:27:28 UTC (rev 1316) +++ trunk/zsi/ZSI/generate/wsdl2python.py 2007-01-11 21:53:49 UTC (rev 1317) @@ -7,7 +7,7 @@ # $Id$ -import os +import os, warnings from ZSI import _get_idstr from ZSI.wstools.logging import getLogger as _GetLogger from ZSI.wstools import WSDLTools @@ -239,7 +239,7 @@ self.imports = ServiceHeaderContainer() self.messagesImports = ServiceHeaderContainer() self.locator = ServiceLocatorContainer() - self.methods = [] + self.bindings = [] self.messages = [] self.do_extended=do_extended self._wsdl = wsdl # None unless do_extended == True @@ -272,30 +272,42 @@ self.locator.setUp(service) + try: + bindings = map(lambda p: p.binding, service.ports) + except: + warnings.warn('not all ports have binding declared,') + bindings = () + for port in service.ports: - sop_container = ServiceOperationsClassContainer(useWSA=self.wsAddressing, do_extended=self.do_extended, wsdl=self._wsdl) + 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: - sop_container.setUp(port) + desc.setUp(port.getBinding()) 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: + 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=True) + mw.setUp(soc, port, input=False) 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) - self.methods.append(sop_container) - def write(self, fd, msg_fd=None): """write out module to file descriptor. @@ -309,7 +321,7 @@ print >>fd, self.imports print >>fd, self.locator - for m in self.methods: + for m in self.bindings: print >>fd, m if msg_fd != None: Modified: trunk/zsi/test/wsdl2py/config.txt =================================================================== --- trunk/zsi/test/wsdl2py/config.txt 2007-01-11 17:27:28 UTC (rev 1316) +++ trunk/zsi/test/wsdl2py/config.txt 2007-01-11 21:53:49 UTC (rev 1317) @@ -164,4 +164,10 @@ test_InfoBil = http://javatest2.infodata.se/webservices/services/Infobil?wsdl # Google AdWords -test_GoogleAdWords_TES = https://sandbox.google.com/api/adwords/v8/TrafficEstimatorService?wsdl +test_GoogleAdWords = https://sandbox.google.com/api/adwords/v8/TrafficEstimatorService?wsdl + +# TODO: These aren't finished +test_GoogleAdWords_CS = https://sandbox.google.com/api/adwords/v8/CampaignService?wsdl +test_Manufacturer = /Users/boverhof/Desktop/Workspace/Python/zsi/test/wsdl2py/wsdl/ManufacturerImpl.wsdl + + Modified: trunk/zsi/test/wsdl2py/test_AWSECommerceService.py =================================================================== --- trunk/zsi/test/wsdl2py/test_AWSECommerceService.py 2007-01-11 17:27:28 UTC (rev 1316) +++ trunk/zsi/test/wsdl2py/test_AWSECommerceService.py 2007-01-11 21:53:49 UTC (rev 1317) @@ -96,7 +96,7 @@ def test_net_ItemSearch(self): loc = self.client_module.AWSECommerceServiceLocator() - port = loc.getAWSECommerceServicePortType(**self.getPortKWArgs()) + port = loc.getAWSECommerceServicePort(**self.getPortKWArgs()) msg = self.client_module.ItemSearchRequestMsg() msg.SubscriptionId = '0HP1WHME000749APYWR2' Modified: trunk/zsi/test/wsdl2py/test_DateService.py =================================================================== --- trunk/zsi/test/wsdl2py/test_DateService.py 2007-01-11 17:27:28 UTC (rev 1316) +++ trunk/zsi/test/wsdl2py/test_DateService.py 2007-01-11 21:53:49 UTC (rev 1317) @@ -60,7 +60,7 @@ def test_dispatch_getCurrentDate_getDate(self): offset = 9 loc = self.client_module.simple_Date_ServiceLocator() - port = loc.getDateService_PortType(**self.getPortKWArgs()) + port = loc.getDateService_Port(**self.getPortKWArgs()) print "START" msg = self.client_module.getCurrentDateRequest() msg.Input = "Test" Modified: trunk/zsi/test/wsdl2py/test_FinancialService.py =================================================================== --- trunk/zsi/test/wsdl2py/test_FinancialService.py 2007-01-11 17:27:28 UTC (rev 1316) +++ trunk/zsi/test/wsdl2py/test_FinancialService.py 2007-01-11 21:53:49 UTC (rev 1317) @@ -58,7 +58,7 @@ def test_dispatch_getPV(self): loc = self.client_module.FinancialServiceLocator() - port = loc.getFinancialService_PortType(**self.getPortKWArgs()) + port = loc.getFinancialService_Port(**self.getPortKWArgs()) msg = self.client_module.getPVRequest() msg.Irate = 4 Added: trunk/zsi/test/wsdl2py/test_GoogleAdWords.py =================================================================== --- trunk/zsi/test/wsdl2py/test_GoogleAdWords.py (rev 0) +++ trunk/zsi/test/wsdl2py/test_GoogleAdWords.py 2007-01-11 21:53:49 UTC (rev 1317) @@ -0,0 +1,97 @@ +#!/usr/bin/env python +############################################################################ +# Joshua R. Boverhof, LBNL +# See LBNLCopyright for copyright notice! +########################################################################### +import os, sys, unittest +from ServiceTest import main, ServiceTestCase, ServiceTestSuite +from ZSI import FaultException +""" +Unittest for contacting google adwords + +WSDL: +""" + +# General targets +def dispatch(): + """Run all dispatch tests""" + suite = ServiceTestSuite() + suite.addTest(unittest.makeSuite(ServiceTest, 'test_dispatch')) + return suite + +def local(): + """Run all local tests""" + suite = ServiceTestSuite() + suite.addTest(unittest.makeSuite(ServiceTest, 'test_local')) + return suite + +def net(): + """Run all network tests""" + suite = ServiceTestSuite() + suite.addTest(unittest.makeSuite(ServiceTest, 'test_net')) + return suite + +def all(): + """Run all tests""" + suite = ServiceTestSuite() + suite.addTest(unittest.makeSuite(ServiceTest, 'test_')) + return suite + + +class TrafficEstimatorServiceTest(ServiceTestCase): + """Test case for Google AdWords, sandbox v8 + Reads header information from a file "adwords.properties", need to format this for ConfigParser + +[test_GoogleAdWords_TES] +email = +password = +useragent = +applicationtoken = + + """ + name = "test_GoogleAdWords_TES" + client_file_name = "TrafficEstimatorService_client.py" + types_file_name = "TrafficEstimatorService_types.py" + server_file_name = "TrafficEstimatorService_server.py" + + header_info = os.path.join(os.getenv('HOME'), 'adwords.properties') + + def __init__(self, methodName): + ServiceTestCase.__init__(self, methodName) + self.wsdl2py_args.append('-b') + + def _get_soap_headers(self): + from ConfigParser import ConfigParser + cp = ConfigParser(); cp.read(self.header_info) + p,e,a,u = map(lambda var: cp.get(self.__class__.name, var), 'password email applicationtoken useragent'.split()) + tns,GED = "https://adwords.google.com/api/adwords/v8", self.client_module.GED + + password = GED(tns, "password").pyclass(p) + email = GED(tns, "email").pyclass(e) + atoken = GED(tns, "applicationToken").pyclass(a) + useragent = GED(tns, "useragent").pyclass(u) + + # google sandbox uses these conventions... + dtoken = GED(tns, "developerToken").pyclass('%s++USD' %e) + cemail = GED(tns, "clientEmail").pyclass('client_1+'+e) + + return (email, password, useragent, dtoken, atoken, cemail) + + def test_net_KeywordEstimate(self): + loc = self.client_module.TrafficEstimatorServiceLocator() + port = loc.getTrafficEstimatorService(**self.getPortKWArgs()) + msg = self.client_module.estimateKeywordListRequest() + + kwd = msg.new_keywordRequests() + kwd.Text = "flowers" + kwd.MaxCpc = 50000L + kwd.Type = "Broad" + msg.KeywordRequests = [ kwd ] + + rsp = port.estimateKeywordList(msg, soapheaders=self._get_soap_headers()) + +ServiceTest = TrafficEstimatorServiceTest + +if __name__ == "__main__" : + main() + Modified: trunk/zsi/test/wsdl2py/test_MapPoint.py =================================================================== --- trunk/zsi/test/wsdl2py/test_MapPoint.py 2007-01-11 17:27:28 UTC (rev 1316) +++ trunk/zsi/test/wsdl2py/test_MapPoint.py 2007-01-11 21:53:49 UTC (rev 1317) @@ -5,6 +5,7 @@ ########################################################################### import sys, unittest from ServiceTest import main, ServiceTestCase, ServiceTestSuite +from ZSI.auth import AUTH """ Unittest for contacting the Map Point Service. @@ -46,11 +47,17 @@ types_file_name = "CommonService_types.py" server_file_name = "CommonService_server.py" + def __init__(self, methodName): + ServiceTestCase.__init__(self, methodName) + self.wsdl2py_args.append('-b') + def test_net_GetVersionInfo(self): """expect this to fail cause i'm not doing http authentication. """ loc = self.client_module.CommonServiceLocator() - port = loc.getCommonServiceSoap(**self.getPortKWArgs()) + kw = self.getPortKWArgs() + #port = loc.getCommonServiceSoap(auth=(AUTH.httpdigest, "USERNAME", "PASSWORD"), **kw) + port = loc.getCommonServiceSoap(**kw) msg = self.client_module.GetVersionInfoSoapIn() try: @@ -58,6 +65,13 @@ except RuntimeError: # RuntimeError: HTTP Digest Authorization Failed pass + + port.binding.SetAuth(AUTH.httpdigest, user="USERNAME", password="PASSWORD") + print ">> DIGEST AUTH" + try: + rsp = port.GetVersionInfo(msg) + except RuntimeError: + pass if __name__ == "__main__" : Modified: trunk/zsi/test/wsdl2py/test_SquareService.py =================================================================== --- trunk/zsi/test/wsdl2py/test_SquareService.py 2007-01-11 17:27:28 UTC (rev 1316) +++ trunk/zsi/test/wsdl2py/test_SquareService.py 2007-01-11 21:53:49 UTC (rev 1317) @@ -61,7 +61,7 @@ def test_dispatch_getSquare(self): loc = self.client_module.SquareServiceLocator() - port = loc.getSquarePortType(**self.getPortKWArgs()) + port = loc.getSquarePort(**self.getPortKWArgs()) msg = self.client_module.getSquareRequest() msg.X = 4.0 Modified: trunk/zsi/test/wsdl2py/test_ThreatService.py =================================================================== --- trunk/zsi/test/wsdl2py/test_ThreatService.py 2007-01-11 17:27:28 UTC (rev 1316) +++ trunk/zsi/test/wsdl2py/test_ThreatService.py 2007-01-11 21:53:49 UTC (rev 1317) @@ -54,7 +54,7 @@ def test_net_threatLevel(self): loc = self.client_module.Current_Homeland_Security_Threat_LevelLocator() - port = loc.getthreat(**self.getPortKWArgs()) + port = loc.getthreat_cfc(**self.getPortKWArgs()) msg = self.client_module.threatLevelRequest() rsp = port.threatLevel(msg) Modified: trunk/zsi/test/wsdl2py/test_WhiteMesa.py =================================================================== --- trunk/zsi/test/wsdl2py/test_WhiteMesa.py 2007-01-11 17:27:28 UTC (rev 1316) +++ trunk/zsi/test/wsdl2py/test_WhiteMesa.py 2007-01-11 21:53:49 UTC (rev 1317) @@ -63,7 +63,7 @@ msg._inputBoolean = True loc = self.client_module.WhiteMesaSoapRpcLitTestSvcLocator() - port = loc.getSoapTestPortTypeRpc(**self.getPortKWArgs()) + port = loc.getSoap11TestRpcLitPort(**self.getPortKWArgs()) rsp = port.echoBoolean(msg) self.failUnless(msg._inputBoolean == rsp._return, Modified: trunk/zsi/test/wsdl2py/test_XMethodsQuery.py =================================================================== --- trunk/zsi/test/wsdl2py/test_XMethodsQuery.py 2007-01-11 17:27:28 UTC (rev 1316) +++ trunk/zsi/test/wsdl2py/test_XMethodsQuery.py 2007-01-11 21:53:49 UTC (rev 1317) @@ -53,7 +53,7 @@ def test_net_getAllServiceNames(self): loc = self.client_module.XMethodsQueryLocator() - port = loc.getXMethodsQuerySoapPortType(**self.getPortKWArgs()) + port = loc.getXMethodsQuerySoap(**self.getPortKWArgs()) msg = self.client_module.getAllServiceNames2SoapIn() rsp = port.getAllServiceNames(msg) @@ -61,7 +61,7 @@ def test_net_getAllServiceSummaries(self): loc = self.client_module.XMethodsQueryLocator() - port = loc.getXMethodsQuerySoapPortType(**self.getPortKWArgs()) + port = loc.getXMethodsQuerySoap(**self.getPortKWArgs()) msg = self.client_module.getAllServiceSummaries1SoapIn() rsp = port.getAllServiceSummaries(msg) @@ -69,7 +69,7 @@ def test_net_getServiceDetail(self): loc = self.client_module.XMethodsQueryLocator() - port = loc.getXMethodsQuerySoapPortType(**self.getPortKWArgs()) + port = loc.getXMethodsQuerySoap(**self.getPortKWArgs()) msg = self.client_module.getServiceDetail4SoapIn() msg._id = 'uuid:A29C0D6C-5529-0D27-A91A-8E02D343532B' @@ -78,7 +78,7 @@ def test_net_getServiceNamesByPublisher(self): loc = self.client_module.XMethodsQueryLocator() - port = loc.getXMethodsQuerySoapPortType(**self.getPortKWArgs()) + port = loc.getXMethodsQuerySoap(**self.getPortKWArgs()) msg = self.client_module.getServiceNamesByPublisher3SoapIn() msg._publisherID = 'xmethods.net' @@ -87,7 +87,7 @@ def test_net_getServiceSummariesByPublisher(self): loc = self.client_module.XMethodsQueryLocator() - port = loc.getXMethodsQuerySoapPortType(**self.getPortKWArgs()) + port = loc.getXMethodsQuerySoap(**self.getPortKWArgs()) msg = self.client_module.getServiceSummariesByPublisher0SoapIn() msg._publisherID = 'xmethods.net' This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <bov...@us...> - 2007-01-25 23:09:16
|
Revision: 1336 http://svn.sourceforge.net/pywebsvcs/?rev=1336&view=rev Author: boverhof Date: 2007-01-25 15:09:17 -0800 (Thu, 25 Jan 2007) Log Message: ----------- A test/test_rfc2617.py M test/test_zsi.py M test/test_zsi_net.py M test/wsdl2py/test_AWSECommerceService.py M ZSI/digest_auth.py M ZSI/client.py -- merge over changes Report [ 1593310 ] Http Digest authentication fails Modification of Patch [ 1593314 ] HttpDigest authentication patch Modified Paths: -------------- trunk/zsi/ZSI/client.py trunk/zsi/ZSI/digest_auth.py trunk/zsi/test/test_zsi.py trunk/zsi/test/test_zsi_net.py trunk/zsi/test/wsdl2py/test_AWSECommerceService.py Added Paths: ----------- trunk/zsi/test/test_rfc2617.py Modified: trunk/zsi/ZSI/client.py =================================================================== --- trunk/zsi/ZSI/client.py 2007-01-25 22:39:50 UTC (rev 1335) +++ trunk/zsi/ZSI/client.py 2007-01-25 23:09:17 UTC (rev 1336) @@ -277,9 +277,9 @@ print >>self.trace, "_" * 33, time.ctime(time.time()), "REQUEST:" print >>self.trace, soapdata - #scheme,netloc,path,nil,nil,nil = urlparse.urlparse(url) - path = _get_postvalue_from_absoluteURI(url) - self.h.putrequest("POST", path) + 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=utf-8') self.__addcookies() @@ -296,7 +296,7 @@ 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, soapaction, **kw) + self.SendSOAPDataHTTPDigestAuth(response, soapdata, url, request_uri, soapaction, **kw) self.http_callbacks[401] = None self.http_callbacks[401] = digest_auth_cb @@ -308,7 +308,7 @@ # Clear prior receive state. self.data, self.ps = None, None - def SendSOAPDataHTTPDigestAuth(self, response, soapdata, url, soapaction, **kw): + 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. @@ -333,7 +333,7 @@ dict_fetch(chaldict,'realm',None) and \ dict_fetch(chaldict,'qop',None): authdict = generate_response(chaldict, - url, self.auth_user, self.auth_pass, method='POST') + request_uri, self.auth_user, self.auth_pass, method='POST') headers = {\ 'Authorization':build_authorization_arg(authdict), 'Expect':'100-continue', Modified: trunk/zsi/ZSI/digest_auth.py =================================================================== --- trunk/zsi/ZSI/digest_auth.py 2007-01-25 22:39:50 UTC (rev 1335) +++ trunk/zsi/ZSI/digest_auth.py 2007-01-25 23:09:17 UTC (rev 1336) @@ -2,7 +2,7 @@ # $Header$ '''Utilities for HTTP Digest Authentication ''' - +import re from md5 import md5 import random import time @@ -75,24 +75,31 @@ def fetch_challenge(http_header): + """ apparently keywords Basic and Digest are not being checked + anywhere and decisions are being made based on authorization + configuration of client, so I guess you better know what you are + doing. Here I am requiring one or the other be specified. + + challenge Basic auth_param + challenge Digest auth_param """ - Create a challenge dictionary from a HTTPResponse objects getheaders() method. - """ - chaldict = {} - vals = http_header.split(' ') - chaldict['challenge'] = vals[0] - for val in vals[1:]: - try: - a,b = val.split('=') - b=b.replace('"','') - b=b.replace("'",'') - b=b.replace(",",'') - chaldict[a.lower()] = b - except: - pass - return chaldict + m = fetch_challenge.wwwauth_header_re.match(http_header) + if m is None: + raise RuntimeError, 'expecting "WWW-Authenticate header [Basic,Digest]"' + d = dict(challenge=m.groups()[0]) + m = fetch_challenge.auth_param_re.search(http_header) + while m is not None: + k,v = http_header[m.start():m.end()].split('=') + d[k.lower()] = v[1:-1] + m = fetch_challenge.auth_param_re.search(http_header, m.end()) + + return d +fetch_challenge.wwwauth_header_re = re.compile(r'\s*([bB]asic|[dD]igest)\s+(?:[\w]+="[^"]+",?\s*)?') +fetch_challenge.auth_param_re = re.compile(r'[\w]+="[^"]+"') + + def build_authorization_arg(authdict): """ Create an "Authorization" header value from an authdict (created by generate_response()). Added: trunk/zsi/test/test_rfc2617.py =================================================================== --- trunk/zsi/test/test_rfc2617.py (rev 0) +++ trunk/zsi/test/test_rfc2617.py 2007-01-25 23:09:17 UTC (rev 1336) @@ -0,0 +1,52 @@ +#!/usr/bin/env python +""" +RFC2617 + +HTTP Authentication: Basic and Digest Access Authentication +""" +import unittest +from ZSI import digest_auth +from ZSI.wstools.logging import setBasicLoggerDEBUG +setBasicLoggerDEBUG() + +class DATestCase(unittest.TestCase): + "test Union TypeCode" + + def check_challenge_single_www_authenticate_header(self): + challenge='Basic realm="WallyWorld"' + print "=="*30 + print challenge + print "=="*30 + cd = digest_auth.fetch_challenge(challenge) + expect = {'challenge': 'Basic', 'realm': 'WallyWorld'} + self.failUnless(cd == expect, 'Expected equivalent') + + def check_challenge_single_www_authenticate_header2(self): + challenge='Basic realm="Wally World"' + cd = digest_auth.fetch_challenge(challenge) + expect = {'challenge': 'Basic', 'realm': 'Wally World'} + self.failUnless(cd == expect, 'Expected equivalent') + + def check_challenge_single_www_authenticate_header3(self): + challenge = '''Digest + realm="tes...@ho...", + qop="auth,auth-int", + nonce="dcd98b7102dd2f0e8b11d0f600bfb0c093", + opaque="5ccc069c403ebaf9f0171e9517f40e41"''' + cd = digest_auth.fetch_challenge(challenge) + expect = {'nonce': 'dcd98b7102dd2f0e8b11d0f600bfb0c093', 'challenge': 'Digest', 'opaque': '5ccc069c403ebaf9f0171e9517f40e41', 'realm': 'tes...@ho...', 'qop': 'auth,auth-int'} + self.failUnless(cd == expect, 'Expected equivalent') + + + +def makeTestSuite(): + suite = unittest.TestSuite() + suite.addTest(unittest.makeSuite(DATestCase, "check")) + return suite + +def main(): + unittest.main(defaultTest="makeTestSuite") + +if __name__ == '__main__': + main() + Modified: trunk/zsi/test/test_zsi.py =================================================================== --- trunk/zsi/test/test_zsi.py 2007-01-25 22:39:50 UTC (rev 1335) +++ trunk/zsi/test/test_zsi.py 2007-01-25 23:09:17 UTC (rev 1336) @@ -11,6 +11,7 @@ import test_union import test_list import test_TCtimes +import test_rfc2617 def makeTestSuite(): return unittest.TestSuite( Modified: trunk/zsi/test/test_zsi_net.py =================================================================== --- trunk/zsi/test/test_zsi_net.py 2007-01-25 22:39:50 UTC (rev 1335) +++ trunk/zsi/test/test_zsi_net.py 2007-01-25 23:09:17 UTC (rev 1336) @@ -12,6 +12,7 @@ import test_union import test_TCtimes import test_list +import test_rfc2617 def makeTestSuite(): return unittest.TestSuite( Modified: trunk/zsi/test/wsdl2py/test_AWSECommerceService.py =================================================================== --- trunk/zsi/test/wsdl2py/test_AWSECommerceService.py 2007-01-25 22:39:50 UTC (rev 1335) +++ trunk/zsi/test/wsdl2py/test_AWSECommerceService.py 2007-01-25 23:09:17 UTC (rev 1336) @@ -47,9 +47,9 @@ """Test case for Amazon ECommerce Web service """ name = "test_AWSECommerceService" - client_file_name = "AWSECommerceService_services.py" - types_file_name = "AWSECommerceService_services_types.py" - server_file_name = "AWSECommerceService_services_server.py" + client_file_name = "AWSECommerceService_client.py" + types_file_name = "AWSECommerceService_types.py" + server_file_name = "AWSECommerceService_server.py" def __init__(self, methodName): ServiceTestCase.__init__(self, methodName) @@ -96,7 +96,7 @@ def test_net_ItemSearch(self): loc = self.client_module.AWSECommerceServiceLocator() - port = loc.getAWSECommerceServicePortType(**self.getPortKWArgs()) + port = loc.getAWSECommerceServicePort(**self.getPortKWArgs()) msg = self.client_module.ItemSearchRequestMsg() msg.SubscriptionId = '0HP1WHME000749APYWR2' This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <bov...@us...> - 2007-01-26 18:45:58
|
Revision: 1341 http://svn.sourceforge.net/pywebsvcs/?rev=1341&view=rev Author: boverhof Date: 2007-01-26 10:30:24 -0800 (Fri, 26 Jan 2007) Log Message: ----------- M test/wsdl2py/config.txt A test/wsdl2py/test_BasicComm.py A test/wsdl2py/servers/BasicServer.py A test/wsdl2py/BasicComm.wsdl M ZSI/dispatch.py M ZSI/ServiceContainer.py merge trunk w/previous commit Modified Paths: -------------- trunk/zsi/ZSI/ServiceContainer.py trunk/zsi/ZSI/dispatch.py trunk/zsi/test/wsdl2py/config.txt Added Paths: ----------- trunk/zsi/test/wsdl2py/BasicComm.wsdl trunk/zsi/test/wsdl2py/servers/BasicServer.py trunk/zsi/test/wsdl2py/test_BasicComm.py Modified: trunk/zsi/ZSI/ServiceContainer.py =================================================================== --- trunk/zsi/ZSI/ServiceContainer.py 2007-01-26 18:07:53 UTC (rev 1340) +++ trunk/zsi/ZSI/ServiceContainer.py 2007-01-26 18:30:24 UTC (rev 1341) @@ -113,7 +113,7 @@ # If No response just return. if result is None: - return + return SendResponse('', **kw) sw = SoapWriter(nsdict=nsdict) try: Modified: trunk/zsi/ZSI/dispatch.py =================================================================== --- trunk/zsi/ZSI/dispatch.py 2007-01-26 18:07:53 UTC (rev 1340) +++ trunk/zsi/ZSI/dispatch.py 2007-01-26 18:30:24 UTC (rev 1341) @@ -191,10 +191,16 @@ '''Send some XML. ''' self.send_response(code) - self.send_header('Content-type', 'text/xml; charset="utf-8"') - self.send_header('Content-Length', str(len(text))) + + if text: + self.send_header('Content-type', 'text/xml; charset="utf-8"') + self.send_header('Content-Length', str(len(text))) + self.end_headers() - self.wfile.write(text) + + if text: + self.wfile.write(text) + self.wfile.flush() def send_fault(self, f, code=500): Added: trunk/zsi/test/wsdl2py/BasicComm.wsdl =================================================================== --- trunk/zsi/test/wsdl2py/BasicComm.wsdl (rev 0) +++ trunk/zsi/test/wsdl2py/BasicComm.wsdl 2007-01-26 18:30:24 UTC (rev 1341) @@ -0,0 +1,82 @@ +<?xml version="1.0" encoding="UTF-8"?> +<definitions + xmlns="http://schemas.xmlsoap.org/wsdl/" + xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" + xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/" + xmlns:http="http://schemas.xmlsoap.org/wsdl/http/" + xmlns:xsd="http://www.w3.org/2001/XMLSchema" + xmlns:tns="urn:ZSI:examples" + targetNamespace="urn:ZSI:examples" > + <types> + <xsd:schema elementFormDefault="qualified" targetNamespace="urn:ZSI:examples"> + <xsd:element name="Basic"> + <xsd:complexType> + <xsd:sequence> + <xsd:element minOccurs="0" maxOccurs="1" name="BasicIn" type="xsd:string" /> + </xsd:sequence> + </xsd:complexType> + </xsd:element> + <xsd:element name="BasicResponse"> + <xsd:complexType> + <xsd:sequence> + <xsd:element minOccurs="0" maxOccurs="1" name="BasicResult" type="xsd:string" /> + </xsd:sequence> + </xsd:complexType> + </xsd:element> + <xsd:element name="BasicOneWay"> + <xsd:complexType> + <xsd:sequence> + <xsd:element minOccurs="0" maxOccurs="1" name="BasicIn" type="xsd:string" /> + </xsd:sequence> + </xsd:complexType> + </xsd:element> + </xsd:schema> + </types> + + <message name="BasicRequest"> + <part name="parameters" element="tns:Basic" /> + </message> + <message name="BasicResponse"> + <part name="parameters" element="tns:BasicResponse"/> + </message> + <message name="BasicOneWayRequest"> + <part name="parameters" element="tns:BasicOneWay" /> + </message> + + <portType name="BasicServer"> + <operation name="Basic"> + <input message="tns:BasicRequest"/> + <output message="tns:BasicResponse"/> + </operation> + <operation name="BasicOneWay"> + <input message="tns:BasicOneWayRequest"/> + </operation> + </portType> + + <binding name="BasicServer" type="tns:BasicServer"> + <soap:binding style="document" + transport="http://schemas.xmlsoap.org/soap/http"/> + <operation name="Basic"> + <soap:operation soapAction="Basic"/> + <input> + <soap:body use="literal"/> + </input> + <output> + <soap:body use="literal"/> + </output> + </operation> + <operation name="BasicOneWay"> + <soap:operation soapAction="BasicOneWay"/> + <input> + <soap:body use="literal"/> + </input> + </operation> + </binding> + + <service name="BasicServer"> + <port name="BasicServer" binding="tns:BasicServer"> + <soap:address location="http://localhost:7000"/> + </port> + </service> + +</definitions> Modified: trunk/zsi/test/wsdl2py/config.txt =================================================================== --- trunk/zsi/test/wsdl2py/config.txt 2007-01-26 18:07:53 UTC (rev 1340) +++ trunk/zsi/test/wsdl2py/config.txt 2007-01-26 18:30:24 UTC (rev 1341) @@ -33,6 +33,7 @@ twisted = False test_WhiteMesa = servers/WhiteMesa.py test_Echo = servers/EchoServer.py +test_BasicComm = servers/BasicServer.py test_SquareService = servers/SquareService.py test_DateService = servers/DateService.py test_FinancialService = servers/FinancialService.py @@ -117,7 +118,7 @@ document = True literal = True broke = False -tests = test_MapPoint test_OpcDaGateway test_Echo test_AWSECommerceService test_FinancialService +tests = test_MapPoint test_Echo test_AWSECommerceService test_FinancialService test_BasicComm test_Manufacturer test_Racing [doc_literal_broke] document = True @@ -151,6 +152,7 @@ test_Sabre = http://webservices.sabre.com/wsdl/sabreXML1.0.00/res/SessionCreateRQ.wsdl test_Echo = ../../samples/Echo/Echo.wsdl +test_BasicComm = BasicComm.wsdl test_Choice = test_Choice.xsd test_Attributes = test_Attributes.xsd test_DerivedTypes = test_DerivedTypes.xsd Added: trunk/zsi/test/wsdl2py/servers/BasicServer.py =================================================================== --- trunk/zsi/test/wsdl2py/servers/BasicServer.py (rev 0) +++ trunk/zsi/test/wsdl2py/servers/BasicServer.py 2007-01-26 18:30:24 UTC (rev 1341) @@ -0,0 +1,27 @@ +#!/usr/bin/env python + +import sys +from ZSI.ServiceContainer import AsServer +from BasicServer_server import BasicServer + +""" +BasicServer example service + +WSDL: BasicComm.wsdl + +""" + + +class Service(BasicServer): + def soap_Basic(self, ps): + response = BasicServer.soap_Basic(self, ps) + response._BasicResult = self.request._BasicIn + return response + + def soap_BasicOneWay(self, ps): + return BasicServer.soap_BasicOneWay(self, ps) + + +if __name__ == "__main__" : + port = int(sys.argv[1]) + AsServer(port, (Service('test'),)) Added: trunk/zsi/test/wsdl2py/test_BasicComm.py =================================================================== --- trunk/zsi/test/wsdl2py/test_BasicComm.py (rev 0) +++ trunk/zsi/test/wsdl2py/test_BasicComm.py 2007-01-26 18:30:24 UTC (rev 1341) @@ -0,0 +1,105 @@ +#!/usr/bin/env python + +import os, sys, unittest +from ServiceTest import main, ServiceTestCase, ServiceTestSuite +from ZSI import FaultException +from ConfigParser import ConfigParser, NoSectionError, NoOptionError +""" +Unittest + +WSDL: BasicComm.wsdl +""" +CONFIG_FILE = 'config.txt' +CONFIG_PARSER = ConfigParser() +SECTION_DISPATCH = 'dispatch' + +CONFIG_PARSER.read(CONFIG_FILE) + +# General targets +def dispatch(): + """Run all dispatch tests""" + suite = ServiceTestSuite() + suite.addTest(unittest.makeSuite(BasicCommTestCase, 'test_dispatch')) + return suite + +def local(): + """Run all local tests""" + suite = ServiceTestSuite() + suite.addTest(unittest.makeSuite(BasicCommTestCase, 'test_local')) + return suite + +def net(): + """Run all network tests""" + suite = ServiceTestSuite() + suite.addTest(unittest.makeSuite(BasicCommTestCase, 'test_net')) + return suite + +def all(): + """Run all tests""" + suite = ServiceTestSuite() + suite.addTest(unittest.makeSuite(BasicCommTestCase, 'test_')) + return suite + + +class BasicCommTestCase(ServiceTestCase): + name = "test_BasicComm" + client_file_name = "BasicServer_client.py" + types_file_name = "BasicServer_types.py" + server_file_name = "BasicServer_server.py" + + def __init__(self, methodName): + ServiceTestCase.__init__(self, methodName) + self.wsdl2py_args.append('-b') + + def test_local_Basic(self): + msg = self.client_module.BasicRequest() + rsp = self.client_module.BasicResponse() + + def test_dispatch_Basic(self): + loc = self.client_module.BasicServerLocator() + port = loc.getBasicServer(**self.getPortKWArgs()) + + msg = self.client_module.BasicRequest() + msg._BasicIn = 'bla bla bla' + rsp = port.Basic(msg) + self.failUnless(rsp._BasicResult == msg._BasicIn, "Bad Echo") + + # test whether we get an HTTP response on a message with + # no soap response. + import httplib + msg = u""" + <SOAP-ENV:Envelope + xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/" + xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" + xmlns:ZSI="http://www.zolera.com/schemas/ZSI/" + xmlns:xsd="http://www.w3.org/2001/XMLSchema" + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> + <SOAP-ENV:Header></SOAP-ENV:Header> + <SOAP-ENV:Body xmlns:ns1="urn:ZSI:examples"> + <ns1:BasicOneWay> + <ns1:BasicIn>bla bla bla</ns1:BasicIn> + </ns1:BasicOneWay> + </SOAP-ENV:Body> + </SOAP-ENV:Envelope>""".encode('utf-8') + headers = {"Content-type": 'text/xml; charset="utf-8"', 'Content-Length': str(len(msg))} + + host = CONFIG_PARSER.get(SECTION_DISPATCH, 'host') + port = CONFIG_PARSER.get(SECTION_DISPATCH, 'port') + path = CONFIG_PARSER.get(SECTION_DISPATCH, 'path') + + conn = httplib.HTTPConnection("%s:%s" % (host, port)) + conn.request('POST', '/' + path, msg, headers) + try: + response = conn.getresponse() + except httplib.BadStatusLine: + conn.close() + self.fail('No HTTP Response') + + conn.close() + self.failUnless(response.status == 200, 'Wrong HTTP Result') + + + +if __name__ == "__main__" : + main() + This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <bov...@us...> - 2007-01-26 19:17:20
|
Revision: 1343 http://svn.sourceforge.net/pywebsvcs/?rev=1343&view=rev Author: boverhof Date: 2007-01-26 11:17:13 -0800 (Fri, 26 Jan 2007) Log Message: ----------- M test/wsdl2py/test_Choice.py M test/wsdl2py/config.txt M test/wsdl2py/test_GoogleAdWords.py M ZSI/generate/commands.py M ZSI/TCtimes.py -- found little problem with formatting TCtimes typecodes, added Choice/DerivedTypes/Attributes into default test suite Modified Paths: -------------- trunk/zsi/ZSI/TCtimes.py trunk/zsi/ZSI/generate/commands.py trunk/zsi/test/wsdl2py/config.txt trunk/zsi/test/wsdl2py/test_Choice.py trunk/zsi/test/wsdl2py/test_GoogleAdWords.py Modified: trunk/zsi/ZSI/TCtimes.py =================================================================== --- trunk/zsi/ZSI/TCtimes.py 2007-01-26 18:40:46 UTC (rev 1342) +++ trunk/zsi/ZSI/TCtimes.py 2007-01-26 19:17:13 UTC (rev 1343) @@ -221,7 +221,7 @@ d['neg'] = '' ms = pyobj[6] - if not ms: + if not ms or not hasattr(self, 'format_ms'): d = { 'Y': pyobj[0], 'M': pyobj[1], 'D': pyobj[2], 'h': pyobj[3], 'm': pyobj[4], 's': pyobj[5], } return self.format % d Modified: trunk/zsi/ZSI/generate/commands.py =================================================================== --- trunk/zsi/ZSI/generate/commands.py 2007-01-26 18:40:46 UTC (rev 1342) +++ trunk/zsi/ZSI/generate/commands.py 2007-01-26 19:17:13 UTC (rev 1343) @@ -175,7 +175,12 @@ # exit code UNIX specific, Windows? if hasattr(os, 'EX_NOINPUT'): sys.exit(os.EX_NOINPUT) sys.exit("error loading %s" %location) - + + if isinstance(wsdl, XMLSchema.XMLSchema): + wsdl.location = location + _wsdl2py(options, wsdl) + return + _wsdl2py(options, wsdl) _wsdl2dispatch(options, wsdl) Modified: trunk/zsi/test/wsdl2py/config.txt =================================================================== --- trunk/zsi/test/wsdl2py/config.txt 2007-01-26 18:40:46 UTC (rev 1342) +++ trunk/zsi/test/wsdl2py/config.txt 2007-01-26 19:17:13 UTC (rev 1343) @@ -118,7 +118,7 @@ document = True literal = True broke = False -tests = test_MapPoint test_Echo test_AWSECommerceService test_FinancialService test_BasicComm test_Manufacturer test_Racing +tests = test_MapPoint test_Echo test_AWSECommerceService test_FinancialService test_BasicComm test_Manufacturer test_Racing test_Attributes test_Choice test_DerivedTypes [doc_literal_broke] document = True Modified: trunk/zsi/test/wsdl2py/test_Choice.py =================================================================== --- trunk/zsi/test/wsdl2py/test_Choice.py 2007-01-26 18:40:46 UTC (rev 1342) +++ trunk/zsi/test/wsdl2py/test_Choice.py 2007-01-26 19:17:13 UTC (rev 1343) @@ -64,12 +64,9 @@ """<choice minOccurs=1 maxOccurs=unbounded> """ pyobj = GED("urn:example", "Hard").pyclass() - pyobj.Name = "steve" - pyobj.Name.append("mark") - pyobj.Any = "whatever" - pyobj.Rank = 2 - pyobj.Rank.append(3) - pyobj.Rank.append(4) + pyobj.Name = ["steve", "mark"] + pyobj.Any = ["whatever"] + pyobj.Rank = [2,3,4] sw = SoapWriter() sw.serialize(pyobj) print str(sw) Modified: trunk/zsi/test/wsdl2py/test_GoogleAdWords.py =================================================================== --- trunk/zsi/test/wsdl2py/test_GoogleAdWords.py 2007-01-26 18:40:46 UTC (rev 1342) +++ trunk/zsi/test/wsdl2py/test_GoogleAdWords.py 2007-01-26 19:17:13 UTC (rev 1343) @@ -42,14 +42,14 @@ """Test case for Google AdWords, sandbox v8 Reads header information from a file "adwords.properties", need to format this for ConfigParser -[test_GoogleAdWords_TES] +[test_GoogleAdWords] email = password = useragent = applicationtoken = """ - name = "test_GoogleAdWords_TES" + name = "test_GoogleAdWords" client_file_name = "TrafficEstimatorService_client.py" types_file_name = "TrafficEstimatorService_types.py" server_file_name = "TrafficEstimatorService_server.py" This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <bov...@us...> - 2007-01-30 17:32:29
|
Revision: 1346 http://svn.sourceforge.net/pywebsvcs/?rev=1346&view=rev Author: boverhof Date: 2007-01-30 09:32:19 -0800 (Tue, 30 Jan 2007) Log Message: ----------- A test/wsdl2py/test_EchoWSAddr200403.py M test/wsdl2py/config.txt AM test/wsdl2py/servers/EchoWSAddr200403Server.py M ZSI/generate/wsdl2dispatch.py M ZSI/ServiceContainer.py M ZSI/address.py Merged ZSI_v2_0_0 fix for ws-addressing via ServiceContainer [ 1615228 ] "Unexpected keyword" error when using wsdl2dispatch with -a Modified Paths: -------------- trunk/zsi/ZSI/ServiceContainer.py trunk/zsi/ZSI/address.py trunk/zsi/ZSI/generate/wsdl2dispatch.py trunk/zsi/test/wsdl2py/config.txt Added Paths: ----------- trunk/zsi/test/wsdl2py/servers/EchoWSAddr200403Server.py trunk/zsi/test/wsdl2py/test_EchoWSAddr200403.py Modified: trunk/zsi/ZSI/ServiceContainer.py =================================================================== --- trunk/zsi/ZSI/ServiceContainer.py 2007-01-27 01:03:50 UTC (rev 1345) +++ trunk/zsi/ZSI/ServiceContainer.py 2007-01-30 17:32:19 UTC (rev 1346) @@ -26,6 +26,7 @@ PostNotSpecified SOAPActionNotSpecified ServiceSOAPBinding + WSAResource SimpleWSResource SOAPRequestHandler ServiceContainer @@ -69,7 +70,7 @@ address = action service = server.getNode(post) isWSResource = False - if isinstance(service, SimpleWSResource): + if isinstance(service, WSAResource): isWSResource = True service.setServiceURL(localURL) address = Address() @@ -122,7 +123,7 @@ return SendFault(FaultFromException(e, 0, sys.exc_info()[2]), **kw) if isWSResource is True: - action = service.getResponseAction(action) + action = service.getResponseAction(ps, action) addressRsp = Address(action=action) try: addressRsp.setResponseFromWSAddress(address, localURL) @@ -220,7 +221,7 @@ return self.getOperation(ps, action)(ps) -class SimpleWSResource(ServiceSOAPBinding): +class WSAResource(ServiceSOAPBinding): '''Simple WSRF service, performs method resolutions based on WS-Action values rather than SOAP Action. @@ -452,7 +453,8 @@ address -- Address instance representing WS-Address ''' method = self.getCallBack(ps, post, action) - if isinstance(method.im_self, SimpleWSResource): + if (isinstance(method.im_self, WSAResource) or + isinstance(method.im_self, SimpleWSResource)): return method(ps, address) return method(ps) Modified: trunk/zsi/ZSI/address.py =================================================================== --- trunk/zsi/ZSI/address.py 2007-01-27 01:03:50 UTC (rev 1345) +++ trunk/zsi/ZSI/address.py 2007-01-30 17:32:19 UTC (rev 1346) @@ -52,7 +52,7 @@ value -- Action value server returned. ''' if action is None: - raise WSActionException, 'User did not specify WSAddress Action value to expect' + raise WSActionException, 'Response missing WSAddress Action' if not value: raise WSActionException, 'missing WSAddress Action, expecting %s' %action if value != action: @@ -72,8 +72,8 @@ if scheme==schemeF and path==pathF and query==queryF and fragment==fragmentF: netloc = netloc.split(':') + ['80'] netlocF = netlocF.split(':') + ['80'] - if netloc[1]==netlocF[1] and \ - socket.gethostbyname(netloc[0])==socket.gethostbyname(netlocF[0]): + if netloc[1]==netlocF[1] and (socket.gethostbyname(netlocF[0]) in + ('127.0.0.1', socket.gethostbyname(netloc[0]))): return raise WSActionException, 'wrong WS-Address From(%s), expecting %s'%(value,self._addressTo) Modified: trunk/zsi/ZSI/generate/wsdl2dispatch.py =================================================================== --- trunk/zsi/ZSI/generate/wsdl2dispatch.py 2007-01-27 01:03:50 UTC (rev 1345) +++ trunk/zsi/ZSI/generate/wsdl2dispatch.py 2007-01-30 17:32:19 UTC (rev 1346) @@ -3,7 +3,7 @@ import ZSI, string, sys, getopt, urlparse, types, warnings from ZSI.wstools import WSDLTools from ZSI.generate.wsdl2python import WriteServiceModule, MessageTypecodeContainer -from ZSI.ServiceContainer import ServiceSOAPBinding, SimpleWSResource +from ZSI.ServiceContainer import ServiceSOAPBinding, SimpleWSResource, WSAResource from ZSI.generate.utility import TextProtect, GetModuleBaseNameFromWSDL, NCName_to_ClassName, GetPartsSubNames, TextProtectAttributeName from ZSI.generate import WsdlGeneratorError, Wsdl2PythonError from ZSI.generate.wsdl2python import SchemaDescription @@ -364,7 +364,7 @@ class WSAServiceModuleWriter(ServiceModuleWriter): '''Creates a skeleton for a WS-Address service instance. ''' - def __init__(self, base=SimpleWSResource, prefix='wsa', service_class=SOAPService, strict=True): + def __init__(self, base=WSAResource, prefix='wsa', service_class=SOAPService, strict=True): ''' Parameters: strict -- check that soapAction and input ws-action do not collide. @@ -430,6 +430,7 @@ for ext in bop.extensions: if isinstance(ext, WSDLTools.SoapOperationBinding) is False: continue soap_action = ext.soapAction + if not soap_action: break if wsaction_in is None: break if wsaction_in == soap_action: break if self.strict is False: Modified: trunk/zsi/test/wsdl2py/config.txt =================================================================== --- trunk/zsi/test/wsdl2py/config.txt 2007-01-27 01:03:50 UTC (rev 1345) +++ trunk/zsi/test/wsdl2py/config.txt 2007-01-30 17:32:19 UTC (rev 1346) @@ -19,7 +19,7 @@ # ########################################################################## [configuration] -tracefile = 1 +tracefile = False debug = False skip = False twisted = False @@ -37,6 +37,7 @@ test_SquareService = servers/SquareService.py test_DateService = servers/DateService.py test_FinancialService = servers/FinancialService.py +test_EchoWSAddr200403 = servers/EchoWSAddr200403Server.py ########################################################################## @@ -118,7 +119,7 @@ document = True literal = True broke = False -tests = test_MapPoint test_Echo test_AWSECommerceService test_FinancialService test_BasicComm test_Manufacturer test_Racing test_Attributes test_Choice test_DerivedTypes +tests = test_MapPoint test_Echo test_AWSECommerceService test_FinancialService test_BasicComm test_Manufacturer test_Racing test_Attributes test_Choice test_DerivedTypes test_EchoWSAddr200403 [doc_literal_broke] document = True @@ -165,6 +166,8 @@ test_TerraService = http://terraservice.net/TerraService.asmx?WSDL test_InfoBil = http://javatest2.infodata.se/webservices/services/Infobil?wsdl +test_EchoWSAddr200403 = EchoWSAddr200403.wsdl + # Google AdWords test_GoogleAdWords = https://sandbox.google.com/api/adwords/v8/TrafficEstimatorService?wsdl @@ -172,4 +175,3 @@ test_GoogleAdWords_CS = https://sandbox.google.com/api/adwords/v8/CampaignService?wsdl test_Manufacturer = ManufacturerImpl.wsdl test_Racing = Racing.wsdl - Added: trunk/zsi/test/wsdl2py/servers/EchoWSAddr200403Server.py =================================================================== --- trunk/zsi/test/wsdl2py/servers/EchoWSAddr200403Server.py (rev 0) +++ trunk/zsi/test/wsdl2py/servers/EchoWSAddr200403Server.py 2007-01-30 17:32:19 UTC (rev 1346) @@ -0,0 +1,26 @@ +#!/usr/bin/env python +############################################################################ +# Joshua R. Boverhof, LBNL +# See LBNLCopyright for copyright notice! +########################################################################### +import sys +from ZSI.ServiceContainer import AsServer +from EchoWSAddr200403Server_server import EchoWSAddr200403Server as EchoServer + +""" +EchoServer example service + +WSDL: ../../samples/Echo/Echo.wsdl + +""" + +class WSAService(EchoServer): + def wsa_Echo(self, ps, addr): + response = EchoServer.wsa_Echo(self, ps, addr) + response.EchoResult = self.request.EchoIn + return response + + +if __name__ == "__main__" : + port = int(sys.argv[1]) + AsServer(port, (WSAService('test'),)) Property changes on: trunk/zsi/test/wsdl2py/servers/EchoWSAddr200403Server.py ___________________________________________________________________ Name: svn:executable + * Added: trunk/zsi/test/wsdl2py/test_EchoWSAddr200403.py =================================================================== --- trunk/zsi/test/wsdl2py/test_EchoWSAddr200403.py (rev 0) +++ trunk/zsi/test/wsdl2py/test_EchoWSAddr200403.py 2007-01-30 17:32:19 UTC (rev 1346) @@ -0,0 +1,74 @@ +#!/usr/bin/env python +############################################################################ +# Joshua R. Boverhof, LBNL +# See LBNLCopyright for copyright notice! +########################################################################### +import os, sys, unittest +from ServiceTest import main, ServiceTestCase, ServiceTestSuite +from ZSI import FaultException +""" +Unittest + +WSDL: ../../samples/Echo/Echo.wsdl +""" + +# General targets +def dispatch(): + """Run all dispatch tests""" + suite = ServiceTestSuite() + suite.addTest(unittest.makeSuite(EchoTestCase, 'test_dispatch')) + return suite + +def local(): + """Run all local tests""" + suite = ServiceTestSuite() + suite.addTest(unittest.makeSuite(EchoTestCase, 'test_local')) + return suite + +def net(): + """Run all network tests""" + suite = ServiceTestSuite() + suite.addTest(unittest.makeSuite(EchoTestCase, 'test_net')) + return suite + +def all(): + """Run all tests""" + suite = ServiceTestSuite() + suite.addTest(unittest.makeSuite(EchoTestCase, 'test_')) + return suite + + +class EchoTestCase(ServiceTestCase): + name = "test_EchoWSAddr200403" + client_file_name = "EchoWSAddr200403Server_client.py" + types_file_name = "EchoWSAddr200403Server_types.py" + server_file_name = "EchoWSAddr200403Server_server.py" + + def __init__(self, methodName): + ServiceTestCase.__init__(self, methodName) + self.wsdl2py_args.append('-a') + self.wsdl2py_args.append('-b') + self.wsdl2dispatch_args.append('-a') + + def getPortKWArgs(self): + kw = ServiceTestCase.getPortKWArgs(self) + kw['wsAddressURI'] = 'http://schemas.xmlsoap.org/ws/2004/03/addressing' + return kw + + def test_local_Echo(self): + msg = self.client_module.EchoRequest() + rsp = self.client_module.EchoResponse() + + def test_dispatch_Echo(self): + loc = self.client_module.EchoWSAddr200403ServerLocator() + port = loc.getport(**self.getPortKWArgs()) + + msg = self.client_module.EchoRequest() + msg.EchoIn = 'bla bla bla' + rsp = port.Echo(msg) + self.failUnless(rsp.EchoResult == msg.EchoIn, "Bad Echo") + + +if __name__ == "__main__" : + main() + This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <bov...@us...> - 2007-01-30 18:57:53
|
Revision: 1347 http://svn.sourceforge.net/pywebsvcs/?rev=1347&view=rev Author: boverhof Date: 2007-01-30 10:57:47 -0800 (Tue, 30 Jan 2007) Log Message: ----------- A test/test_URI.py M test/test_zsi.py M test/test_zsi_net.py M ZSI/TC.py [ 1520092 ] URI Bug: urllib.quote escaping reserved chars added "safe" keyword arg to urlencode, and "reserved" attribute to URI. Modified Paths: -------------- trunk/zsi/ZSI/TC.py trunk/zsi/test/test_zsi.py trunk/zsi/test/test_zsi_net.py Added Paths: ----------- trunk/zsi/test/test_URI.py Modified: trunk/zsi/ZSI/TC.py =================================================================== --- trunk/zsi/ZSI/TC.py 2007-01-30 17:32:19 UTC (rev 1346) +++ trunk/zsi/ZSI/TC.py 2007-01-30 18:57:47 UTC (rev 1347) @@ -724,10 +724,15 @@ class URI(String): '''A URI. + Class data: + reserved -- urllib.quote will escape all reserved characters + regardless of whether they are used for the reserved purpose. + ''' parselist = [ (None,'anyURI'),(SCHEMA.XSD3, 'anyURI')] type = (SCHEMA.XSD3, 'anyURI') logger = _GetLogger('ZSI.TC.URI') + reserved = ";/?:@&=+$," def text_to_data(self, text, elt, ps): '''text --> typecode specific data. @@ -739,10 +744,9 @@ '''typecode data --> text ''' pyobj = String.get_formatted_content(self, pyobj) - return urlencode(pyobj) + return urlencode(pyobj, safe=self.reserved) - class QName(String): '''A QName type ''' Added: trunk/zsi/test/test_URI.py =================================================================== --- trunk/zsi/test/test_URI.py (rev 0) +++ trunk/zsi/test/test_URI.py 2007-01-30 18:57:47 UTC (rev 1347) @@ -0,0 +1,86 @@ +#!/usr/bin/env python +import unittest, sys, tests_good, tests_bad, time +from ZSI import * +try: + import cStringIO as StringIO +except ImportError: + import StringIO + + +"""Bug [ 1520092 ] URI Bug: urllib.quote escaping reserved chars + +From rfc2396: + +"If the data for a URI component would conflict with the reserved +purpose, then the conflicting data must be escaped before forming the +URI." + +reserved = ";" | "/" | "?" | ":" | "@" | "&" | "=" | "+" | +"$" | "," + + + +This implies that if ":" is used for a reserved purpose, + +if scheme is defined then +append scheme to result +append ":" to result + +, then it should not be escaped. +""" + + +class TestCase(unittest.TestCase): + def check_uri_quoting(self): + """ all reserved characters used for reserved purpose. + """ + sw1 = SoapWriter(envelope=False) + tc1= TC.URI('sourceforge') + orig = 'https://sourceforge.net/tracker/index.php?func=detail&aid=1520092&group_id=26590&atid=387667' + sw1.serialize(orig, typecode=tc1, typed=False) + s1 = str(sw1) + + sw2 = SoapWriter(envelope=False) + tc2= TC.String('sourceforge') + sw2.serialize(orig, typecode=tc2, typed=False) + s2 = str(sw2) + + print s1 + print s2 + self.failUnless(s1 == s2, + 'reserved characters used for reserved purpose should not be escaped.') + + ps = ParsedSoap(s2, envelope=False) + pyobj = ps.Parse(tc2) + + self.failUnless(pyobj == orig, 'parsed object should be equivalent to original') + + + +# +# Creates permutation of test options: "check", "check_any", etc +# +_SEP = '_' +for t in [i[0].split(_SEP) for i in filter(lambda i: callable(i[1]), TestCase.__dict__.items())]: + test = '' + for f in t: + test += f + if globals().has_key(test): test += _SEP; continue + def _closure(): + name = test + def _makeTestSuite(): + suite = unittest.TestSuite() + suite.addTest(unittest.makeSuite(TestCase, name)) + return suite + return _makeTestSuite + + globals()[test] = _closure() + test += _SEP + + +makeTestSuite = check +def main(): + unittest.main(defaultTest="makeTestSuite") +if __name__ == "__main__" : main() + + Modified: trunk/zsi/test/test_zsi.py =================================================================== --- trunk/zsi/test/test_zsi.py 2007-01-30 17:32:19 UTC (rev 1346) +++ trunk/zsi/test/test_zsi.py 2007-01-30 18:57:47 UTC (rev 1347) @@ -11,6 +11,7 @@ import test_union import test_list import test_TCtimes +import test_URI import test_rfc2617 def makeTestSuite(): Modified: trunk/zsi/test/test_zsi_net.py =================================================================== --- trunk/zsi/test/test_zsi_net.py 2007-01-30 17:32:19 UTC (rev 1346) +++ trunk/zsi/test/test_zsi_net.py 2007-01-30 18:57:47 UTC (rev 1347) @@ -11,6 +11,7 @@ import test_t9 import test_union import test_TCtimes +import test_URI import test_list import test_rfc2617 This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <bov...@us...> - 2007-01-30 19:56:00
|
Revision: 1350 http://svn.sourceforge.net/pywebsvcs/?rev=1350&view=rev Author: boverhof Date: 2007-01-30 11:55:44 -0800 (Tue, 30 Jan 2007) Log Message: ----------- M test/wsdl2py/test_BasicComm.py M test/wsdl2py/servers/BasicServer.py M ZSI/generate/containers.py [ 1596575 ] clients created with wsdl2py do not propagate errors for one-way operations: grab response, if it's not empty it should be a soap:fault. Modified Paths: -------------- trunk/zsi/ZSI/generate/containers.py trunk/zsi/test/wsdl2py/servers/BasicServer.py trunk/zsi/test/wsdl2py/test_BasicComm.py Modified: trunk/zsi/ZSI/generate/containers.py =================================================================== --- trunk/zsi/ZSI/generate/containers.py 2007-01-30 19:04:28 UTC (rev 1349) +++ trunk/zsi/ZSI/generate/containers.py 2007-01-30 19:55:44 UTC (rev 1350) @@ -621,69 +621,74 @@ # not significant. However, a convention is to name it after the method name # with the string "Response" appended. # - if self.outputName: - response = ['%s%s' % (ID2, wsactionOut),] - if self.isRPC() and not self.isLiteral(): - # rpc/encoded Replace wrapper name with None - response.append(\ - '%stypecode = Struct(pname=None, ofwhat=%s.typecode.ofwhat, pyclass=%s.typecode.pyclass)' %( - ID2, self.outputName, self.outputName) + if not self.outputName: + method.append('%s#check for soap, assume soap:fault' %(ID2,)) + method.append('%sif self.binding.IsSOAP(): self.binding.Receive(None, **kw)' % (ID2,)) + self.writeArray(method) + return + + response = ['%s%s' % (ID2, wsactionOut),] + if self.isRPC() and not self.isLiteral(): + # rpc/encoded Replace wrapper name with None + response.append(\ + '%stypecode = Struct(pname=None, ofwhat=%s.typecode.ofwhat, pyclass=%s.typecode.pyclass)' %( + ID2, self.outputName, self.outputName) + ) + response.append(\ + '%sresponse = self.binding.Receive(typecode%s)' %( + ID2, responseArgs) + ) + else: + response.append(\ + '%sresponse = self.binding.Receive(%s.typecode%s)' %( + ID2, self.outputName, responseArgs) + ) + + # only support lit + if self.soap_output_headers: + sh = '[' + for shb in self.soap_output_headers: + #shb.encodingStyle, shb.use, shb.namespace + shb.message + shb.part + try: + msg = self._wsdl.messages[shb.message] + part = msg.parts[shb.part] + if part.element is not None: + sh += 'GED%s,' %str(part.element) + else: + warnings.warn('skipping soap output header in Message "%s"' %str(msg)) + except: + raise WSDLFormatError( + 'failure processing output header typecodes, ' + + 'could not find message "%s" or its part "%s"' %( + shb.message, shb.part) ) + + sh += ']' + if len(sh) > 2: response.append(\ - '%sresponse = self.binding.Receive(typecode%s)' %( - ID2, responseArgs) - ) - else: - response.append(\ - '%sresponse = self.binding.Receive(%s.typecode%s)' %( - ID2, self.outputName, responseArgs) - ) + '%sself.soapheaders = self.binding.ps.ParseHeaderElements(%s)' %(ID2, sh) + ) - # only support lit - if self.soap_output_headers: - sh = '[' - for shb in self.soap_output_headers: - #shb.encodingStyle, shb.use, shb.namespace - shb.message - shb.part - try: - msg = self._wsdl.messages[shb.message] - part = msg.parts[shb.part] - if part.element is not None: - sh += 'GED%s,' %str(part.element) - else: - warnings.warn('skipping soap output header in Message "%s"' %str(msg)) - except: - raise WSDLFormatError( - 'failure processing output header typecodes, ' + - 'could not find message "%s" or its part "%s"' %( - shb.message, shb.part) - ) - - sh += ']' - if len(sh) > 2: - response.append(\ - '%sself.soapheaders = self.binding.ps.ParseHeaderElements(%s)' %(ID2, sh) - ) + if self.outputSimpleType: + response.append('%sreturn %s(response)' %(ID2, self.outputName)) + else: + if self.do_extended: + partsList = self.getOperation().getOutputMessage().parts.values() + subNames = GetPartsSubNames(partsList, self._wsdl) + args = [] + for pa in subNames: + args += pa - if self.outputSimpleType: - response.append('%sreturn %s(response)' %(ID2, self.outputName)) - else: - if self.do_extended: - partsList = self.getOperation().getOutputMessage().parts.values() - subNames = GetPartsSubNames(partsList, self._wsdl) - args = [] - for pa in subNames: - args += pa + for arg in args: + response.append('%s%s = response.%s' % (ID2, self.mangle(arg), self.getAttributeName(arg)) ) + margs = ",".join(args) + response.append("%sreturn %s" % (ID2, margs) ) + else: + response.append('%sreturn response' %ID2) + method += response - for arg in args: - response.append('%s%s = response.%s' % (ID2, self.mangle(arg), self.getAttributeName(arg)) ) - margs = ",".join(args) - response.append("%sreturn %s" % (ID2, margs) ) - else: - response.append('%sreturn response' %ID2) - method += response - self.writeArray(method) Modified: trunk/zsi/test/wsdl2py/servers/BasicServer.py =================================================================== --- trunk/zsi/test/wsdl2py/servers/BasicServer.py 2007-01-30 19:04:28 UTC (rev 1349) +++ trunk/zsi/test/wsdl2py/servers/BasicServer.py 2007-01-30 19:55:44 UTC (rev 1350) @@ -19,9 +19,14 @@ return response def soap_BasicOneWay(self, ps): - return BasicServer.soap_BasicOneWay(self, ps) + response = BasicServer.soap_BasicOneWay(self, ps) + if self.request._BasicIn == 'fault': + # return a soap:fault + raise RuntimeError, 'you wanted a fault?' + return response + if __name__ == "__main__" : port = int(sys.argv[1]) AsServer(port, (Service('test'),)) Modified: trunk/zsi/test/wsdl2py/test_BasicComm.py =================================================================== --- trunk/zsi/test/wsdl2py/test_BasicComm.py 2007-01-30 19:04:28 UTC (rev 1349) +++ trunk/zsi/test/wsdl2py/test_BasicComm.py 2007-01-30 19:55:44 UTC (rev 1350) @@ -2,7 +2,7 @@ import os, sys, unittest from ServiceTest import main, ServiceTestCase, ServiceTestSuite -from ZSI import FaultException +from ZSI import FaultException, Fault from ConfigParser import ConfigParser, NoSectionError, NoOptionError """ Unittest @@ -98,8 +98,26 @@ conn.close() self.failUnless(response.status == 200, 'Wrong HTTP Result') + def test_dispatch_BasicOneWay(self): + loc = self.client_module.BasicServerLocator() + port = loc.getBasicServer(**self.getPortKWArgs()) + + msg = self.client_module.BasicOneWayRequest() + msg.BasicIn = 'bla bla bla' + rsp = port.BasicOneWay(msg) + self.failUnless(rsp == None, "Bad One-Way") + def test_dispatch_BasicOneWay_fault(self): + """server will send back a soap:fault + """ + loc = self.client_module.BasicServerLocator() + port = loc.getBasicServer(**self.getPortKWArgs()) + + msg = self.client_module.BasicOneWayRequest() + msg.BasicIn = 'fault' + self.failUnlessRaises(FaultException, port.BasicOneWay, msg) + if __name__ == "__main__" : main() This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <bov...@us...> - 2007-02-01 06:15:25
|
Revision: 1352 http://svn.sourceforge.net/pywebsvcs/?rev=1352&view=rev Author: boverhof Date: 2007-01-31 22:15:24 -0800 (Wed, 31 Jan 2007) Log Message: ----------- M test/wsdl2py/test_EchoWSAddr200403.py M test/wsdl2py/config.txt M test/wsdl2py/ServiceTest.py M test/wsdl2py/servers/EchoWSAddr200403Server.py M ZSI/TC.py M ZSI/fault.py M ZSI/address.py [ 1618810 ] address.py assumes reference parameters, which are optional TC -- Fixed a pyclass problem with ZSI.TC.URI TC -- Simplified Any, AnyElement fault -- Made all faults "lax" processing Modified Paths: -------------- trunk/zsi/ZSI/TC.py trunk/zsi/ZSI/address.py trunk/zsi/ZSI/fault.py trunk/zsi/test/wsdl2py/ServiceTest.py trunk/zsi/test/wsdl2py/config.txt trunk/zsi/test/wsdl2py/servers/EchoWSAddr200403Server.py trunk/zsi/test/wsdl2py/test_EchoWSAddr200403.py Modified: trunk/zsi/ZSI/TC.py =================================================================== --- trunk/zsi/ZSI/TC.py 2007-01-30 20:03:06 UTC (rev 1351) +++ trunk/zsi/ZSI/TC.py 2007-02-01 06:15:24 UTC (rev 1352) @@ -516,12 +516,11 @@ logger = _GetLogger('ZSI.TC.Any') parsemap, serialmap = {}, {} - def __init__(self, pname=None, aslist=False, minOccurs=0, **kw): - TypeCode.__init__(self, pname, minOccurs=minOccurs, **kw) + def __init__(self, pname=None, aslist=False, minOccurs=0, unique=False, **kw): + TypeCode.__init__(self, pname, minOccurs=minOccurs, unique=unique, **kw) self.aslist = aslist - self.kwargs = {'aslist':aslist} + self.kwargs = dict(aslist=aslist, unique=unique) self.kwargs.update(kw) - self.unique = False # input arg v should be a list of tuples (name, value). def listify(self, v): @@ -623,13 +622,13 @@ "xsd:anyType[" + str(len(pyobj)) + "]" ) for o in pyobj: #TODO maybe this should take **self.kwargs... - serializer = getattr(o, 'typecode', self.__class__()) # also used by _AnyLax() + serializer = getattr(o, 'typecode', Any()) serializer.serialize(array, sw, o, name='element', **kw) else: struct = elt.createAppendElement(ns, n) for o in pyobj: #TODO maybe this should take **self.kwargs... - serializer = getattr(o, 'typecode', self.__class__()) # also used by _AnyLax() + serializer = getattr(o, 'typecode', Any()) serializer.serialize(struct, sw, o, **kw) return @@ -737,14 +736,13 @@ def text_to_data(self, text, elt, ps): '''text --> typecode specific data. ''' - val = String.text_to_data(self, text, elt, ps) - return urldecode(val) + return String.text_to_data(self, urldecode(text), elt, ps) def get_formatted_content(self, pyobj): '''typecode data --> text ''' - pyobj = String.get_formatted_content(self, pyobj) - return urlencode(pyobj, safe=self.reserved) + return String.get_formatted_content(self, + urlencode(pyobj, safe=self.reserved)) class QName(String): @@ -1352,7 +1350,7 @@ pyclass = GTD(namespaceURI, typeName) if not pyclass: if _is_xsd_or_soap_ns(namespaceURI): - pyclass = _AnyStrict + pyclass = Any elif (str(namespaceURI).lower()==str(Apache.Map.type[0]).lower())\ and (str(typeName).lower() ==str(Apache.Map.type[1]).lower()): pyclass = Apache.Map @@ -1402,13 +1400,13 @@ tc = (types.ClassType, pyobj.__class__.__name__) what = Any.serialmap.get(tc) + self.logger.debug('processContents: %s', self.processContents) + # failed to find a registered type for class if what is None: #TODO: seems incomplete. what about facets. - if self.processContents == 'strict': - what = _AnyStrict(pname=(self.nspname,self.pname)) - else: - what = _AnyLax(pname=(self.nspname,self.pname)) + #if self.processContents == 'strict': + what = Any(pname=(self.nspname,self.pname)) self.logger.debug('serialize with %s', what.__class__.__name__) what.serialize(elt, sw, pyobj, **kw) @@ -1455,25 +1453,36 @@ if skip: what = XML(pname=(nspname,pname), wrapped=False) elif self.processContents == 'lax': - what = _AnyLax(pname=(nspname,pname)) + what = Any(pname=(nspname,pname), unique=True) else: - what = _AnyStrict(pname=(nspname,pname)) + what = Any(pname=(nspname,pname), unique=True) try: - return what.parse(elt, ps) + pyobj = what.parse(elt, ps) except EvaluateException, ex: self.logger.debug("error parsing: %s" %str(ex)) - if len(_children(elt)) == 0: + if len(_children(elt)) != 0: + self.logger.debug('parse <any>, return as dict') + return Any(aslist=False).parse_into_dict_or_list(elt, ps) + self.logger.debug("Give up, parse (%s,%s) as a String", what.nspname, what.pname) what = String(pname=(nspname,pname), typed=False) return WrapImmutable(what.parse(elt, ps), what) - self.logger.debug('parse <any>, return as dict') - return Any(aslist=False).parse_into_dict_or_list(elt, ps) + if pyobj is None: + return + try: + pyobj.typecode = what + except AttributeError: + pyobj = WrapImmutable(pyobj, what) + return pyobj + + + class Union(SimpleType): '''simpleType Union @@ -1667,113 +1676,6 @@ el.createAppendTextNode(s.getvalue()) -class _AnyStrict(Any): - ''' Handles an unspecified types when using a concrete schemas and - processContents = "strict". - ''' - #WARNING: unstable - logger = _GetLogger('ZSI.TC._AnyStrict') - - def __init__(self, pname=None, aslist=False, **kw): - Any.__init__(self, pname=pname, aslist=aslist, **kw) - self.unique = True - - def serialize(self, elt, sw, pyobj, name=None, **kw): - if not (type(pyobj) is dict and not self.aslist): - Any.serialize(self, elt=elt,sw=sw,pyobj=pyobj,name=name, **kw) - - raise EvaluateException( - 'Serializing dictionaries not implemented when processContents=\"strict\".' + - 'Try as a list or use processContents=\"lax\".' - ) - - -class _AnyLax(Any): - ''' Handles unspecified types when using a concrete schemas and - processContents = "lax". - ''' - logger = _GetLogger('ZSI.TC._AnyLax') - - def __init__(self, pname=None, aslist=False, **kw): - Any.__init__(self, pname=pname, aslist=aslist, **kw) - self.unique = True - - def parse_into_dict_or_list(self, elt, ps): - c = _child_elements(elt) - count = len(c) - v = [] - if count == 0: - href = _find_href(elt) - if not href: return {} - elt = ps.FindLocalHREF(href, elt) - self.checktype(elt, ps) - c = _child_elements(elt) - count = len(c) - if count == 0: return self.listify([]) - if self.nilled(elt, ps): return Nilled - - # group consecutive elements with the same name together - # We treat consecutive elements with the same name as lists. - groupedElements = [] # tuples of (name, elementList) - previousName = "" - currentElementList = None - for ce in _child_elements(elt): - name = ce.localName - if (name != previousName): # new name, so new group - if currentElementList != None: # store previous group if there is one - groupedElements.append( (previousName, currentElementList) ) - currentElementList = list() - currentElementList.append(ce) # append to list - previousName = name - # add the last group if necessary - if currentElementList != None: # store previous group if there is one - groupedElements.append( (previousName, currentElementList) ) - - # parse the groups of names - if len(groupedElements) < 1: # should return earlier - return None - # return a list if there is one name and multiple data - elif (len(groupedElements) == 1) and (len(groupedElements[0][0]) > 1): - self.aslist = False - # else return a dictionary - - for name,eltList in groupedElements: - lst = [] - for elt in eltList: - #aslist = self.aslist - lst.append( self.parse(elt, ps) ) - #self.aslist = aslist # restore the aslist setting - if len(lst) > 1: # consecutive elements with the same name means a list - v.append( (name, lst) ) - elif len(lst) == 1: - v.append( (name, lst[0]) ) - - return self.listify(v) - - def checkname(self, elt, ps): - '''See if the name and type of the "elt" element is what we're - looking for. Return the element's type. - Since this is _AnyLax, it's ok if names don't resolve. - ''' - - parselist,errorlist = self.get_parse_and_errorlist() - ns, name = _get_element_nsuri_name(elt) - if ns == SOAP.ENC: - if parselist and \ - (None, name) not in parselist and (ns, name) not in parselist: - raise EvaluateException( - 'Element mismatch (got %s wanted %s) (SOAP encoding namespace)' % \ - (name, errorlist), ps.Backtrace(elt)) - return (ns, name) - - # Not a type, check name matches. - if self.nspname and ns != self.nspname: - raise EvaluateException('Element NS mismatch (got %s wanted %s)' % \ - (ns, self.nspname), ps.Backtrace(elt)) - - return self.checktype(elt, ps) - - def RegisterType(C, clobber=0, *args, **keywords): instance = apply(C, args, keywords) for t in C.__dict__.get('parselist', []): @@ -1800,6 +1702,7 @@ str(C) + ' duplicating serial registration for ' + str(t)) Any.serialmap[key] = instance + def _DynamicImport(moduleName, className): ''' Utility function for RegisterTypeWithSchemaAndClass Modified: trunk/zsi/ZSI/address.py =================================================================== --- trunk/zsi/ZSI/address.py 2007-01-30 20:03:06 UTC (rev 1351) +++ trunk/zsi/ZSI/address.py 2007-02-01 06:15:24 UTC (rev 1352) @@ -183,19 +183,14 @@ raise EvaluateException, 'endPointReference must be of type %s' \ %GTD(namespaceURI ,'EndpointReferenceType') - ReferenceProperties = endPointReference._ReferenceProperties - any = ReferenceProperties._any or [] - #if not (what.maxOccurs=='unbounded' and type(any) in _seqtypes): - # raise EvaluateException, 'ReferenceProperties <any> assumed maxOccurs unbounded' + ReferenceProperties = getattr(endPointReference, '_ReferenceProperties', None) + if ReferenceProperties is not None: + for v in getattr(ReferenceProperties, '_any', ()): + if not hasattr(v,'typecode'): + raise EvaluateException, '<any> element, instance missing typecode attribute' - for v in any: - if not hasattr(v,'typecode'): - raise EvaluateException, '<any> element, instance missing typecode attribute' + pyobjs.append(v) - pyobjs.append(v) - - #pyobjs.append(v) - self.header_pyobjs = tuple(pyobjs) def setResponseFromWSAddress(self, address, localURL): @@ -249,83 +244,6 @@ self._from = pyobjs[(namespaceURI,elements[3])] self._relatesTo = pyobjs[(namespaceURI,elements[4])] -# TODO: Remove MessageContainer. Hopefully the new <any> functionality -# makes this irrelevant. But could create an Interop problem. -""" -class MessageContainer: - '''Automatically wraps all primitive types so attributes - can be specified. - ''' - class IntHolder(int): pass - class StrHolder(str): pass - class UnicodeHolder(unicode): pass - class LongHolder(long): pass - class FloatHolder(float): pass - class BoolHolder(int): pass - #class TupleHolder(tuple): pass - #class ListHolder(list): pass - typecode = None - pyclass_list = [IntHolder,StrHolder,UnicodeHolder,LongHolder, - FloatHolder,BoolHolder,] - def __setattr__(self, key, value): - '''wrap all primitives with Holders if present. - ''' - if type(value) in _seqtypes: - value = list(value) - for indx in range(len(value)): - try: - item = self._wrap(value[indx]) - except TypeError, ex: - pass - else: - value[indx] = item - elif type(value) is bool: - value = BoolHolder(value) - else: - try: - value = self._wrap(value) - except TypeError, ex: - pass - self.__dict__[key] = value - def _wrap(self, value): - '''wrap primitive, return None - ''' - if value is None: - return value - for pyclass in self.pyclass_list: - if issubclass(value.__class__, pyclass): break - else: - raise TypeError, 'MessageContainer does not know about type %s' %(type(value)) - return pyclass(value) - - def setUp(self, typecode=None, pyclass=None): - '''set up all attribute names (aname) in this python instance. - If what is a ComplexType or a simpleType w/attributes instantiate - a new MessageContainer, else set attribute aname to None. - ''' - if typecode is None: - typecode = self.typecode - else: - self.typecode = typecode - - if not isinstance(typecode, TypeCode): - raise TypeError, 'typecode must be a TypeCode class instance' - - if isinstance(typecode, ComplexType): - if typecode.has_attributes() is True: - setattr(self, typecode.attrs_aname, {}) - if typecode.mixed is True: - setattr(self, typecode.mixed_aname, None) - for what in typecode.ofwhat: - setattr(self, what.aname, None) - if isinstance(what, ComplexType): - setattr(self, what.aname, MessageContainer()) - getattr(self, what.aname).setUp(typecode=what) - else: - raise TypeError, 'Primitive type' -""" - - if __name__ == '__main__': print _copyright Modified: trunk/zsi/ZSI/fault.py =================================================================== --- trunk/zsi/ZSI/fault.py 2007-01-30 20:03:06 UTC (rev 1351) +++ trunk/zsi/ZSI/fault.py 2007-02-01 06:15:24 UTC (rev 1352) @@ -35,7 +35,7 @@ String(pname='faultstring'), URI(pname=(SOAP.ENV,'faultactor'), minOccurs=0), Detail.typecode, - AnyElement(aname='any',minOccurs=0, maxOccurs=UNBOUNDED), + AnyElement(aname='any',minOccurs=0, maxOccurs=UNBOUNDED, processContents="lax"), ], pname=(SOAP.ENV,'Fault'), inline=True, @@ -48,7 +48,7 @@ ZSIHeaderDetail.typecode =\ Struct(ZSIHeaderDetail, - [AnyElement(aname='any', minOccurs=0, maxOccurs=UNBOUNDED)], + [AnyElement(aname='any', minOccurs=0, maxOccurs=UNBOUNDED, processContents="lax")], pname=(ZSI_SCHEMA_URI, 'detail')) Modified: trunk/zsi/test/wsdl2py/ServiceTest.py =================================================================== --- trunk/zsi/test/wsdl2py/ServiceTest.py 2007-01-30 20:03:06 UTC (rev 1351) +++ trunk/zsi/test/wsdl2py/ServiceTest.py 2007-02-01 06:15:24 UTC (rev 1352) @@ -34,7 +34,7 @@ SECTION_DISPATCH = 'dispatch' TRACEFILE = sys.stdout TOPDIR = os.getcwd() -MODULEDIR = TOPDIR + '/stubs' +MODULEDIR = os.path.join(TOPDIR, 'stubs') SECTION_SERVERS = 'servers' CONFIG_PARSER.read(CONFIG_FILE) Modified: trunk/zsi/test/wsdl2py/config.txt =================================================================== --- trunk/zsi/test/wsdl2py/config.txt 2007-01-30 20:03:06 UTC (rev 1351) +++ trunk/zsi/test/wsdl2py/config.txt 2007-02-01 06:15:24 UTC (rev 1352) @@ -19,7 +19,7 @@ # ########################################################################## [configuration] -tracefile = False +tracefile = 1 debug = False skip = False twisted = False Modified: trunk/zsi/test/wsdl2py/servers/EchoWSAddr200403Server.py =================================================================== --- trunk/zsi/test/wsdl2py/servers/EchoWSAddr200403Server.py 2007-01-30 20:03:06 UTC (rev 1351) +++ trunk/zsi/test/wsdl2py/servers/EchoWSAddr200403Server.py 2007-02-01 06:15:24 UTC (rev 1352) @@ -6,6 +6,7 @@ import sys from ZSI.ServiceContainer import AsServer from EchoWSAddr200403Server_server import EchoWSAddr200403Server as EchoServer +from ZSI.schema import GTD """ EchoServer example service @@ -14,10 +15,20 @@ """ +EndpointReferenceType = GTD('http://schemas.xmlsoap.org/ws/2004/03/addressing','EndpointReferenceType') + + class WSAService(EchoServer): def wsa_Echo(self, ps, addr): response = EchoServer.wsa_Echo(self, ps, addr) response.EchoResult = self.request.EchoIn + + if isinstance(response.EchoResult, EndpointReferenceType): + addr1 = response.EchoResult + for a in addr.Any: + if a not in addr1.ReferenceProperties.Any: + raise RuntimeError, 'EPRs dont match' + return response Modified: trunk/zsi/test/wsdl2py/test_EchoWSAddr200403.py =================================================================== --- trunk/zsi/test/wsdl2py/test_EchoWSAddr200403.py 2007-01-30 20:03:06 UTC (rev 1351) +++ trunk/zsi/test/wsdl2py/test_EchoWSAddr200403.py 2007-02-01 06:15:24 UTC (rev 1352) @@ -5,7 +5,9 @@ ########################################################################### import os, sys, unittest from ServiceTest import main, ServiceTestCase, ServiceTestSuite -from ZSI import FaultException +from ZSI import FaultException, TC +from ZSI.schema import GED, GTD + """ Unittest @@ -46,9 +48,7 @@ def __init__(self, methodName): ServiceTestCase.__init__(self, methodName) - self.wsdl2py_args.append('-a') - self.wsdl2py_args.append('-b') - self.wsdl2dispatch_args.append('-a') + self.wsdl2py_args.append('-ab') def getPortKWArgs(self): kw = ServiceTestCase.getPortKWArgs(self) @@ -68,7 +68,73 @@ rsp = port.Echo(msg) self.failUnless(rsp.EchoResult == msg.EchoIn, "Bad Echo") + def test_dispatch_Echo_MIH_EPR(self): + epr = GED('http://schemas.xmlsoap.org/ws/2004/03/addressing','EndpointReference').pyclass() + epr.Address = 'urn:whatever' + loc = self.client_module.EchoWSAddr200403ServerLocator() + port = loc.getport(endPointReference=epr, **self.getPortKWArgs()) + + msg = self.client_module.EchoRequest() + msg.EchoIn = 1 + rsp = port.Echo(msg) + self.failUnless(rsp.EchoResult == msg.EchoIn, "Bad Echo") + + def test_dispatch_Echo_MIH_EPR2(self): + epr = GED('http://schemas.xmlsoap.org/ws/2004/03/addressing','EndpointReference').pyclass() + epr.Address = 'urn:whatever' + epr.ReferenceProperties = epr.new_ReferenceProperties() + + loc = self.client_module.EchoWSAddr200403ServerLocator() + port = loc.getport(endPointReference=epr, **self.getPortKWArgs()) + + msg = self.client_module.EchoRequest() + msg.EchoIn = 1 + rsp = port.Echo(msg) + self.failUnless(rsp.EchoResult == msg.EchoIn, "Bad Echo") + + def test_dispatch_Echo_MIH_EPR3_BadHeader(self): + """Unqualified element "mystr" in Header + """ + epr = GED('http://schemas.xmlsoap.org/ws/2004/03/addressing','EndpointReference').pyclass() + epr.Address = 'urn:whatever' + epr.ReferenceProperties = epr.new_ReferenceProperties() + class Xstr(str): + typecode = TC.String('mystr') + + epr.ReferenceProperties.Any = [Xstr('whatever'),] + + loc = self.client_module.EchoWSAddr200403ServerLocator() + self._setUpDispatch() + port = loc.getport(endPointReference=epr, **self.getPortKWArgs()) + + msg = self.client_module.EchoRequest() + self.failUnlessRaises(FaultException, port.Echo,msg) + + def test_dispatch_Echo_MIH_EPR3(self): + epr = GED('http://schemas.xmlsoap.org/ws/2004/03/addressing','EndpointReference').pyclass() + epr.Address = 'urn:whatever' + epr.ReferenceProperties = epr.new_ReferenceProperties() + class Xstr(str): + typecode = TC.String(('urn:josh','mystr')) + + epr.ReferenceProperties.Any = [Xstr('whatever'),] + + loc = self.client_module.EchoWSAddr200403ServerLocator() + self._setUpDispatch() + port = loc.getport(endPointReference=epr, **self.getPortKWArgs()) + + msg = self.client_module.EchoRequest() + epr2 = GTD('http://schemas.xmlsoap.org/ws/2004/03/addressing','EndpointReferenceType')(None).pyclass() + epr2.Address = epr.Address + epr2.ReferenceProperties = epr.ReferenceProperties + + msg.EchoIn = epr2 + rsp = port.Echo(msg) + self.failUnless(rsp.EchoResult.Address == msg.EchoIn.Address, "Bad Echo") + self.failUnless(rsp.EchoResult.ReferenceProperties.Any == msg.EchoIn.ReferenceProperties.Any, "Bad Echo") + + if __name__ == "__main__" : main() This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <bov...@us...> - 2007-02-01 23:20:06
|
Revision: 1356 http://svn.sourceforge.net/pywebsvcs/?rev=1356&view=rev Author: boverhof Date: 2007-02-01 15:20:06 -0800 (Thu, 01 Feb 2007) Log Message: ----------- M setup.cfg M doc/guide02-wsdl2py.tex M ZSI/version.py -- update version of trunk Modified Paths: -------------- trunk/zsi/ZSI/version.py trunk/zsi/doc/guide02-wsdl2py.tex trunk/zsi/setup.cfg Modified: trunk/zsi/ZSI/version.py =================================================================== --- trunk/zsi/ZSI/version.py 2007-02-01 22:36:26 UTC (rev 1355) +++ trunk/zsi/ZSI/version.py 2007-02-01 23:20:06 UTC (rev 1356) @@ -1,2 +1,2 @@ # Auto-generated file; do not edit -Version = (2, 0, 0) +Version = (2, 1, 0) Modified: trunk/zsi/doc/guide02-wsdl2py.tex =================================================================== --- trunk/zsi/doc/guide02-wsdl2py.tex 2007-02-01 22:36:26 UTC (rev 1355) +++ trunk/zsi/doc/guide02-wsdl2py.tex 2007-02-01 23:20:06 UTC (rev 1356) @@ -347,7 +347,7 @@ # assign values using the properties or methods opts.Query = 'Newton' -opts.set_element__Limit(10) +opts.set_element_Limit(10) # don't forget the attribute opts.set_attribute_timeout(1.0) Modified: trunk/zsi/setup.cfg =================================================================== --- trunk/zsi/setup.cfg 2007-02-01 22:36:26 UTC (rev 1355) +++ trunk/zsi/setup.cfg 2007-02-01 23:20:06 UTC (rev 1356) @@ -5,7 +5,7 @@ [version] major = 2 -minor = 0 +minor = 1 patchlevel = 0 #candidate = 3 candidate = 0 This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <bov...@us...> - 2007-02-21 00:50:38
|
Revision: 1360 http://svn.sourceforge.net/pywebsvcs/?rev=1360&view=rev Author: boverhof Date: 2007-02-20 16:50:31 -0800 (Tue, 20 Feb 2007) Log Message: ----------- A test/wsdl2py/test_SubstitutionGroup.py M test/wsdl2py/config.txt A test/wsdl2py/test_SubstitutionGroup.xsd M test/wsdl2py/test_Racing.py -- added unittests M ZSI/schema.py M ZSI/generate/containers.py M ZSI/TC.py M ZSI/TCcompound.py [ 1664772 ] substitutionGroups unsupported -- added substitutionGroup support Modified Paths: -------------- trunk/zsi/ZSI/TC.py trunk/zsi/ZSI/TCcompound.py trunk/zsi/ZSI/generate/containers.py trunk/zsi/ZSI/schema.py trunk/zsi/test/wsdl2py/config.txt trunk/zsi/test/wsdl2py/test_Racing.py Added Paths: ----------- trunk/zsi/test/wsdl2py/test_SubstitutionGroup.py trunk/zsi/test/wsdl2py/test_SubstitutionGroup.xsd Modified: trunk/zsi/ZSI/TC.py =================================================================== --- trunk/zsi/ZSI/TC.py 2007-02-13 17:19:11 UTC (rev 1359) +++ trunk/zsi/ZSI/TC.py 2007-02-21 00:50:31 UTC (rev 1360) @@ -1474,6 +1474,10 @@ if pyobj is None: return + # dict is elementName:value pairs + if type(pyobj) is dict: + return pyobj + try: pyobj.typecode = what except AttributeError: Modified: trunk/zsi/ZSI/TCcompound.py =================================================================== --- trunk/zsi/ZSI/TCcompound.py 2007-02-13 17:19:11 UTC (rev 1359) +++ trunk/zsi/ZSI/TCcompound.py 2007-02-21 00:50:31 UTC (rev 1360) @@ -12,8 +12,8 @@ _get_xsitype, TypeCode, Any, AnyElement, AnyType, \ Nilled, UNBOUNDED -from schema import ElementDeclaration, TypeDefinition, \ - _get_substitute_element, _get_type_definition +from schema import GED, ElementDeclaration, TypeDefinition, \ + _get_substitute_element, _get_type_definition, _is_substitute_element from ZSI.wstools.Namespaces import SCHEMA, SOAP from ZSI.wstools.Utility import SplitQName @@ -59,6 +59,10 @@ 'bad usage, failed to serialize element reference (%s, %s), in: %s' % (typecode.nspname, typecode.pname, sw.Backtrace(elt),)) + # check substitutionGroup + if _is_substitute_element(typecode, sub): + return sub + raise TypeError(\ 'failed to serialize (%s, %s) illegal sub GED (%s,%s): %s' % (typecode.nspname, typecode.pname, sub.nspname, sub.pname, @@ -70,6 +74,7 @@ 'failed to serialize substitute %s for %s, not derivation: %s' % (sub, typecode, sw.Backtrace(elt),)) + # Make our substitution type match the elements facets sub.nspname = typecode.nspname sub.pname = typecode.pname sub.aname = typecode.aname @@ -78,21 +83,7 @@ return sub -def _get_any_instances(ofwhat, d): - '''Run thru list ofwhat.anames and find unmatched keys in value - dictionary d. Assume these are element wildcard instances. - ''' - any_keys = [] - anames = map(lambda what: what.aname, ofwhat) - for aname,pyobj in d.items(): - if isinstance(pyobj, AnyType) or aname in anames or pyobj is None: - continue - any_keys.append(aname) - return any_keys - - - class ComplexType(TypeCode): '''Represents an element of complexType, potentially containing other elements. @@ -192,17 +183,26 @@ 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] ]: + # Parse value, and mark this one done. if debug: - self.logger.debug("child node: (%s,%s)", c_elt.namespaceURI, - c_elt.tagName) + self.logger.debug("child node: (%s,%s)", c_elt.namespaceURI, c_elt.tagName) + + match = False 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 + match = True + value = what.parse(c_elt, ps) + else: + # substitutionGroup head must be a global element declaration + # if successful delegate to matching GED + subwhat = _get_substitute_element(what, c_elt, ps) + if subwhat: + match = True + value = subwhat.parse(c_elt, ps) + + if debug: + self.logger.debug("substitutionGroup: %s", subwhat) + + if match: if what.maxOccurs > 1: if v.has_key(what.aname): v[what.aname].append(value) @@ -214,11 +214,10 @@ v[what.aname] = value c[j] = None break - else: - if debug: - self.logger.debug("no element (%s,%s)", - what.nspname, what.pname) + 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', Modified: trunk/zsi/ZSI/generate/containers.py =================================================================== --- trunk/zsi/ZSI/generate/containers.py 2007-02-13 17:19:11 UTC (rev 1359) +++ trunk/zsi/ZSI/generate/containers.py 2007-02-21 00:50:31 UTC (rev 1360) @@ -1942,12 +1942,20 @@ raise RuntimeError('Must set style(%s) for typecode list generation' % self.style) - + class ElementSimpleTypeContainer(TypecodeContainerBase): type = DEC logger = _GetLogger("ElementSimpleTypeContainer") + def _substitutionGroupTag(self): + value = self.substitutionGroup + if not value: + return 'substitutionGroup = None' + + nsuri,ncname = value + return 'substitutionGroup = ("%s","%s")' %(nsuri, ncname) + def _setContent(self): aname = self.getAttributeName(self.name) pyclass = self.pyclass @@ -1956,6 +1964,7 @@ if pyclass == 'bool': pyclass = 'int' kw = KW.copy() kw.update(dict(aname=aname, ns=self.ns, name=self.name, + substitutionGroup=self._substitutionGroupTag(), subclass=self.sKlass,literal=self.literalTag(), schema=self.schemaTag(), init=self.simpleConstructor(), klass=self.getClassName(), element="ElementDeclaration")) @@ -1993,6 +2002,7 @@ self.local = tp.isLocal() try: self.name = tp.getAttribute('name') + self.substitutionGroup = tp.getAttribute('substitutionGroup') self.ns = tp.getTargetNamespace() qName = tp.getAttribute('type') except Exception, ex: @@ -2253,6 +2263,14 @@ type = DEC logger = _GetLogger("ElementGlobalDefContainer") + def _substitutionGroupTag(self): + value = self.substitutionGroup + if not value: + return 'substitutionGroup = None' + + nsuri,ncname = value + return 'substitutionGroup = ("%s","%s")' %(nsuri, ncname) + def _setContent(self): '''GED defines element name, so also define typecode aname ''' @@ -2261,6 +2279,7 @@ kw.update(dict(klass=self.getClassName(), element='ElementDeclaration', literal=self.literalTag(), + substitutionGroup=self._substitutionGroupTag(), schema=self.schemaTag(), init=self.simpleConstructor(), ns=self.ns, name=self.name, @@ -2286,6 +2305,7 @@ '%(ID1)sclass %(klass)s(%(element)s):', '%(ID2)s%(literal)s', '%(ID2)s%(schema)s', + '%(ID2)s%(substitutionGroup)s', '%(ID2)s%(init)s', '%(ID3)skw["pname"] = ("%(ns)s","%(name)s")', '%(ID3)skw["aname"] = "%(aname)s"', @@ -2301,6 +2321,7 @@ self._item = element self.local = element.isLocal() self.name = element.getAttribute('name') + self.substitutionGroup = element.getAttribute('substitutionGroup') self.ns = element.getTargetNamespace() tp = element.getTypeDefinition('type') self.sKlass = tp.getAttribute('name') Modified: trunk/zsi/ZSI/schema.py =================================================================== --- trunk/zsi/ZSI/schema.py 2007-02-13 17:19:11 UTC (rev 1359) +++ trunk/zsi/ZSI/schema.py 2007-02-21 00:50:31 UTC (rev 1360) @@ -3,7 +3,7 @@ '''XML Schema support ''' -from ZSI import _copyright, _seqtypes, _find_type, EvaluateException +from ZSI import _copyright, _seqtypes, _find_type, _get_element_nsuri_name, EvaluateException from ZSI.wstools.Namespaces import SCHEMA, SOAP from ZSI.wstools.Utility import SplitQName @@ -14,13 +14,47 @@ def _get_global_element_declaration(namespaceURI, name, **kw): return SchemaInstanceType.getElementDeclaration(namespaceURI, name, **kw) -def _get_substitute_element(elt, what): - raise NotImplementedError, 'Not implemented' +def _get_substitute_element(head, elt, ps): + '''if elt matches a member of the head substitutionGroup, return + the GED typecode. + head -- ElementDeclaration typecode, + elt -- the DOM element being parsed + ps -- ParsedSoap Instance + ''' + if not isinstance(head, ElementDeclaration): + return None + + return ElementDeclaration.getSubstitutionElement(head, elt, ps) + def _has_type_definition(namespaceURI, name): return SchemaInstanceType.getTypeDefinition(namespaceURI, name) is not None +def _is_substitute_element(head, sub): + '''if head and sub are both GEDs, and sub declares + head as its substitutionGroup then return True. + head -- Typecode instance + sub -- Typecode instance + ''' + if not isinstance(head, ElementDeclaration) or not isinstance(sub, ElementDeclaration): + return False + + try: + group = sub.substitutionGroup + except AttributeError: + return False + + ged = GED(*group) + + # TODO: better way of representing element references. Wrap them with + # facets, and dereference when needed and delegate to.. + print (head.nspname == ged.nspname and head.pname == ged.pname) + if head is ged or not (head.nspname == ged.nspname and head.pname == ged.pname): + return False + + return True + # # functions for retrieving schema items from # the global schema instance. @@ -67,6 +101,7 @@ types = {} elements = {} element_typecode_cache = {} + #substitution_registry = {} def __new__(cls,classname,bases,classdict): '''If classdict has literal and schema register it as a @@ -81,10 +116,23 @@ raise AttributeError, 'ElementDeclaration must define schema and literal attributes' key = (classdict['schema'],classdict['literal']) - if SchemaInstanceType.elements.has_key(key) is False: - SchemaInstanceType.elements[key] = type.__new__(cls,classname,bases,classdict) - return SchemaInstanceType.elements[key] + if SchemaInstanceType.elements.has_key(key): + return SchemaInstanceType.elements[key] + # create global element declaration + ged = SchemaInstanceType.elements[key] = type.__new__(cls,classname,bases,classdict) + + # TODO: Maybe I want access to all registrants?? + # + #if classdict.has_key('substitutionGroup'): + # sub = classdict.has_key('substitutionGroup') + # if not SchemaInstanceType.substitution_registry.has_key(sub): + # SchemaInstanceType.substitution_registry[sub] = [ged] + # else: + # SchemaInstanceType.substitution_registry[sub].append(ged) + + return ged + if TypeDefinition in bases: if classdict.has_key('type') is None: raise AttributeError, 'TypeDefinition must define type attribute' @@ -148,10 +196,60 @@ schema = namespaceURI literal = NCName + substitutionGroup -- GED reference of form, (namespaceURI,NCName) ''' __metaclass__ = SchemaInstanceType - + def checkSubstitute(self, typecode): + '''If this is True, allow typecode to be substituted + for "self" typecode. + ''' + if not isinstance(typecode, ElementDeclaration): + return False + + try: + nsuri,ncname = typecode.substitutionGroup + except AttributeError: + return False + + if (nsuri,ncname) != (self.schema,self.literal): + # allow slop with the empty namespace + if not nsuri and not self.schema and ncname == self.literal: + return True + + return False + + sub = GED(self.schema, self.literal) + if sub is None or sub is not typecode: + return False + + return True + + def getSubstitutionElement(self, elt, ps): + '''if elt matches a member of the head substitutionGroup, return + the GED typecode representation of the member. + + head -- ElementDeclaration typecode, + elt -- the DOM element being parsed + ps -- ParsedSoap instance + ''' + nsuri,ncname = _get_element_nsuri_name(elt) + typecode = GED(nsuri,ncname) + if typecode is None: + return + + try: + nsuri,ncname = typecode.substitutionGroup + except AttributeError: + return + + if (ncname == self.pname) and (nsuri == self.nspname or + (not nsuri and not self.nspname)): + return typecode + + return + + class LocalElementDeclaration: '''Typecodes subclass to represent a Local Element Declaration. ''' @@ -273,8 +371,8 @@ during parsing is retained in the pyobj representation and thus can be serialized. ''' - types_dict = {} - + types_dict = dict() + def RegisterBuiltin(cls, arg): '''register a builtin, create a new wrapper. ''' Modified: trunk/zsi/test/wsdl2py/config.txt =================================================================== --- trunk/zsi/test/wsdl2py/config.txt 2007-02-13 17:19:11 UTC (rev 1359) +++ trunk/zsi/test/wsdl2py/config.txt 2007-02-21 00:50:31 UTC (rev 1360) @@ -19,7 +19,7 @@ # ########################################################################## [configuration] -tracefile = 1 +tracefile = False debug = False skip = False twisted = False @@ -119,7 +119,7 @@ document = True literal = True broke = False -tests = test_MapPoint test_Echo test_AWSECommerceService test_FinancialService test_BasicComm test_Manufacturer test_Racing test_Attributes test_Choice test_DerivedTypes test_EchoWSAddr200403 +tests = test_MapPoint test_Echo test_AWSECommerceService test_FinancialService test_BasicComm test_Manufacturer test_Racing test_Attributes test_Choice test_DerivedTypes test_EchoWSAddr200403 test_SubstitutionGroup [doc_literal_broke] document = True @@ -157,6 +157,7 @@ test_Choice = test_Choice.xsd test_Attributes = test_Attributes.xsd test_DerivedTypes = test_DerivedTypes.xsd +test_SubstitutionGroup = test_SubstitutionGroup.xsd test_SquareService = SquareService.wsdl test_DateService = DateService.wsdl Modified: trunk/zsi/test/wsdl2py/test_Racing.py =================================================================== --- trunk/zsi/test/wsdl2py/test_Racing.py 2007-02-13 17:19:11 UTC (rev 1359) +++ trunk/zsi/test/wsdl2py/test_Racing.py 2007-02-21 00:50:31 UTC (rev 1360) @@ -5,7 +5,7 @@ ########################################################################### import os, sys, unittest from ServiceTest import main, ServiceTestCase, ServiceTestSuite -from ZSI import FaultException, ParsedSoap +from ZSI import FaultException, ParsedSoap, SoapWriter """ Unittest @@ -61,6 +61,21 @@ pyobj.EventApproximatesResult.Any, any)) + pyobj.EventApproximatesResult.Any = dict(pyobj.EventApproximatesResult.Any) + sw = SoapWriter() + sw.serialize(pyobj) + print str(sw) + ps2 = ParsedSoap(str(sw)) + pyobj2 = ps.Parse(self.client_module.EventApproximatesSoapOut.typecode) + print "EAR: ", pyobj2.EventApproximatesResult + print "Any: ", pyobj2.EventApproximatesResult.Any + + + self.failUnless(pyobj.EventApproximatesResult.Any == pyobj2.EventApproximatesResult.Any, + 'Failed match:\n %s\n\n%s' %(pyobj.EventApproximatesResult.Any, pyobj2.EventApproximatesResult.Any)) + + + MSG="""<?xml version="1.0" encoding="utf-8"?> <soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema"> <soap:Body> Added: trunk/zsi/test/wsdl2py/test_SubstitutionGroup.py =================================================================== --- trunk/zsi/test/wsdl2py/test_SubstitutionGroup.py (rev 0) +++ trunk/zsi/test/wsdl2py/test_SubstitutionGroup.py 2007-02-21 00:50:31 UTC (rev 1360) @@ -0,0 +1,87 @@ +#!/usr/bin/env python +############################################################################ +# Joshua R. Boverhof, LBNL +# See LBNLCopyright for copyright notice! +########################################################################### +import os, sys, unittest, time +from ServiceTest import main, ServiceTestCase, ServiceTestSuite +from ZSI import FaultException +from ZSI.TC import _get_global_element_declaration as GED +from ZSI.writer import SoapWriter +from ZSI.parse import ParsedSoap + +""" +Unittest for substitutionGroup +[ ] + +XSD: +""" + +# General targets +def dispatch(): + """Run all dispatch tests""" + suite = ServiceTestSuite() + suite.addTest(unittest.makeSuite(SubstitutionGroupTestCase, 'test_dispatch')) + return suite + +def local(): + """Run all local tests""" + suite = ServiceTestSuite() + suite.addTest(unittest.makeSuite(SubstitutionGroupTestCase, 'test_local')) + return suite + +def net(): + """Run all network tests""" + suite = ServiceTestSuite() + suite.addTest(unittest.makeSuite(SubstitutionGroupTestCase, 'test_net')) + return suite + +def all(): + """Run all tests""" + suite = ServiceTestSuite() + suite.addTest(unittest.makeSuite(SubstitutionGroupTestCase, 'test_')) + return suite + + +class SubstitutionGroupTestCase(ServiceTestCase): + name = "test_SubstitutionGroup" + types_file_name = "test_SubstitutionGroup_xsd_types.py" + + def __init__(self, methodName): + ServiceTestCase.__init__(self, methodName) + self.wsdl2py_args.append('-b') + self.wsdl2py_args.append('-x') + + def test_local_attribute1(self): + """ + """ + self.types_module + + xml = """<?xml version="1.0" encoding="UTF-8"?> + <holder xmlns='urn:subGroup:types'> + <baseElt><base>from base</base></baseElt> + <childElt><base>from base</base><child>from child</child></childElt></holder>""" + + ps = ParsedSoap(xml, envelope=False) + p1 = ps.Parse(GED("urn:subGroup:types", "holder")) + + b1 = p1.BaseElt[0] + c1 = p1.BaseElt[1] + + sw = SoapWriter(envelope=False) + sw.serialize(p1) + + ps = ParsedSoap(str(sw), envelope=False) + p2 = ps.Parse(GED("urn:subGroup:types", "holder")) + b2 = p2.BaseElt[0] + c2 = p2.BaseElt[1] + + self.failUnlessEqual(b1.Base, b2.Base) + self.failUnlessEqual(c1.Base, c2.Base) + self.failUnlessEqual(c1.Child, c2.Child) + + + +if __name__ == "__main__" : + main() + Added: trunk/zsi/test/wsdl2py/test_SubstitutionGroup.xsd =================================================================== --- trunk/zsi/test/wsdl2py/test_SubstitutionGroup.xsd (rev 0) +++ trunk/zsi/test/wsdl2py/test_SubstitutionGroup.xsd 2007-02-21 00:50:31 UTC (rev 1360) @@ -0,0 +1,38 @@ +<?xml version="1.0" encoding="UTF-8"?> + +<xsd:schema + xmlns:xsd="http://www.w3.org/2001/XMLSchema" + xmlns:tns="urn:subGroup:types" + targetNamespace="urn:subGroup:types" + elementFormDefault='qualified'> + + <xsd:complexType name='baseType'> + <xsd:sequence> + <xsd:element name="base" type='xsd:string'/> + <xsd:any namespace="##other" minOccurs="0" maxOccurs="unbounded" processContents="lax"/> + </xsd:sequence> + </xsd:complexType> + + <xsd:complexType name='childType'> + <xsd:complexContent> + <xsd:extension base="tns:baseType"> + <xsd:sequence> + <xsd:element name="child" type='xsd:string'/> + </xsd:sequence> + </xsd:extension> + </xsd:complexContent> + </xsd:complexType> + + <xsd:element name="baseElt" type="tns:baseType"/> + <xsd:element name="childElt" type="tns:childType" substitutionGroup='tns:baseElt'/> + + <!-- Holder type --> + <xsd:complexType name='holderType'> + <xsd:sequence> + <xsd:element ref="tns:baseElt" maxOccurs='unbounded'/> + </xsd:sequence> + </xsd:complexType> + + <xsd:element name='holder' type='tns:holderType'/> + +</xsd:schema> This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |