• Main Page
  • Related Pages
  • Modules
  • Namespaces
  • Data Structures
  • Files
  • File List
  • Globals

contrib/opal/ZSI/ZSI/generate/commands.py

00001 ############################################################################
00002 # Joshua Boverhof<JRBoverhof@lbl.gov>, LBNL
00003 # Monte Goode <MMGoode@lbl.gov>, LBNL
00004 # See Copyright for copyright notice!
00005 ############################################################################
00006 
00007 import exceptions, sys, optparse, os, warnings, traceback
00008 from os.path import isfile, join, split
00009 
00010 #from operator import xor
00011 import ZSI
00012 from ConfigParser import ConfigParser
00013 from ZSI.generate.wsdl2python import WriteServiceModule, ServiceDescription as wsdl2pyServiceDescription
00014 from ZSI.wstools import WSDLTools, XMLSchema
00015 from ZSI.wstools.logging import setBasicLoggerDEBUG
00016 from ZSI.generate import containers, utility
00017 from ZSI.generate.utility import NCName_to_ClassName as NC_to_CN, TextProtect
00018 from ZSI.generate.wsdl2dispatch import ServiceModuleWriter as ServiceDescription
00019 from ZSI.generate.wsdl2dispatch import WSAServiceModuleWriter as ServiceDescriptionWSA
00020 
00021 
00022 warnings.filterwarnings('ignore', '', exceptions.UserWarning)
00023 def SetDebugCallback(option, opt, value, parser, *args, **kwargs):
00024     setBasicLoggerDEBUG()
00025     warnings.resetwarnings()
00026 
00027 def SetPyclassMetaclass(option, opt, value, parser, *args, **kwargs):
00028     """set up pyclass metaclass for complexTypes"""
00029     from ZSI.generate.containers import ServiceHeaderContainer,\
00030         TypecodeContainerBase, TypesHeaderContainer
00031         
00032     TypecodeContainerBase.metaclass = kwargs['metaclass']
00033     TypesHeaderContainer.imports.append(\
00034             'from %(module)s import %(metaclass)s' %kwargs
00035             )
00036     ServiceHeaderContainer.imports.append(\
00037             'from %(module)s import %(metaclass)s' %kwargs
00038             )
00039 
00040 def SetUpLazyEvaluation(option, opt, value, parser, *args, **kwargs):
00041     from ZSI.generate.containers import TypecodeContainerBase
00042     TypecodeContainerBase.lazy = True
00043     
00044 
00045 
00046 def wsdl2py(args=None):
00047     """Utility for automatically generating client/service interface code from
00048     a wsdl definition, and a set of classes representing element declarations 
00049     and type definitions.  By default invoking this script produces three files, 
00050     each named after the wsdl definition name, in the current working directory.
00051     
00052     Generated Modules Suffix:
00053         _client.py -- client locator, rpc proxy port, messages
00054         _types.py  -- typecodes representing 
00055         _server.py -- server-side bindings
00056         
00057     Parameters:
00058         args -- optional can provide arguments, rather than parsing 
00059             command-line.
00060             
00061     return:
00062         Default behavior is to return None, if args are provided then
00063         return names of the generated files.
00064                                                     
00065     """
00066     op = optparse.OptionParser(usage="USAGE: %wsdl2py [options] WSDL",
00067                  description=wsdl2py.__doc__)
00068     
00069     # Basic options
00070     op.add_option("-x", "--schema",
00071                   action="store_true", dest="schema", default=False,
00072                   help="process just the schema from an xsd file [no services]")
00073 
00074     op.add_option("-d", "--debug",
00075                   action="callback", callback=SetDebugCallback,
00076                   help="debug output")
00077                   
00078     # WS Options
00079     op.add_option("-a", "--address",
00080                   action="store_true", dest="address", default=False,
00081                   help="ws-addressing support, must include WS-Addressing schema.")
00082                   
00083     # pyclass Metaclass 
00084     op.add_option("-b", "--complexType",
00085                   action="callback", callback=SetPyclassMetaclass, 
00086                   callback_kwargs={'module':'ZSI.generate.pyclass', 
00087                       'metaclass':'pyclass_type'},
00088                   help="add convenience functions for complexTypes, including Getters, Setters, factory methods, and properties (via metaclass). *** DONT USE WITH --simple-naming ***")
00089     
00090     # Lazy Evaluation of Typecodes (done at serialization/parsing when needed).
00091     op.add_option("-l", "--lazy",
00092                   action="callback", callback=SetUpLazyEvaluation, 
00093                   callback_kwargs={},
00094                   help="EXPERIMENTAL: recursion error solution, lazy evalution of typecodes")
00095     
00096     # Use Twisted
00097     op.add_option("-w", "--twisted",
00098                   action="store_true", dest='twisted', default=False,
00099                   help="generate a twisted.web client/server, dependencies python>=2.4, Twisted>=2.0.0, TwistedWeb>=0.5.0")
00100     
00101     op.add_option("-o", "--output-dir",
00102                   action="store", dest="output_dir", default=".", type="string",
00103                   help="save files in directory")
00104     
00105     op.add_option("-s", "--simple-naming",
00106                   action="store_true", dest="simple_naming", default=False,
00107                   help="map element names directly to python attributes")
00108     
00109     op.add_option("-p", "--pydoc",
00110                   action="store_true", dest="pydoc", default=False,
00111                   help="top-level directory for pydoc documentation.")
00112     
00113     
00114     is_cmdline = args is None
00115     if is_cmdline:
00116         (options, args) = op.parse_args()
00117     else:
00118         (options, args) = op.parse_args(args)
00119 
00120     if len(args) != 1:
00121         print>>sys.stderr, 'Expecting a file/url as argument (WSDL).'
00122         sys.exit(os.EX_USAGE)
00123         
00124     location = args[0]
00125     if options.schema is True:
00126         reader = XMLSchema.SchemaReader(base_url=location)
00127     else:
00128         reader = WSDLTools.WSDLReader()
00129 
00130     load = reader.loadFromFile
00131     if not isfile(location):
00132         load = reader.loadFromURL
00133 
00134     try:
00135         wsdl = load(location)
00136     except Exception, e:
00137         print >> sys.stderr, "Error loading %s: \n\t%s" % (location, e)
00138         traceback.print_exc(sys.stderr)
00139         # exit code UNIX specific, Windows?
00140         if hasattr(os, 'EX_NOINPUT'): sys.exit(os.EX_NOINPUT)
00141         sys.exit("error loading %s" %location)
00142   
00143     if isinstance(wsdl, XMLSchema.XMLSchema): 
00144         wsdl.location = location
00145         files = _wsdl2py(options, wsdl)
00146     else:
00147         files = _wsdl2py(options, wsdl)
00148         files.append(_wsdl2dispatch(options, wsdl))
00149     
00150     if getattr(options, 'pydoc', False):
00151         _writepydoc(os.path.join('docs', 'API'), *files)
00152         
00153     if is_cmdline:
00154         return
00155     
00156     return files
00157     
00158 
00159 #def wsdl2dispatch(args=None):
00160 #    """Deprecated: wsdl2py now generates everything
00161 #    A utility for automatically generating service skeleton code from a wsdl
00162 #    definition.
00163 #    """
00164 #    op = optparse.OptionParser()
00165 #    op.add_option("-a", "--address",
00166 #                  action="store_true", dest="address", default=False,
00167 #                  help="ws-addressing support, must include WS-Addressing schema.")
00168 #    op.add_option("-d", "--debug",
00169 #                  action="callback", callback=SetDebugCallback,
00170 #                  help="debug output")
00171 #    op.add_option("-t", "--types",
00172 #                  action="store", dest="types", default=None, type="string",
00173 #                  help="Write generated files to OUTPUT_DIR")
00174 #    op.add_option("-o", "--output-dir",
00175 #                  action="store", dest="output_dir", default=".", type="string",
00176 #                  help="file to load types from")
00177 #    op.add_option("-s", "--simple-naming",
00178 #                  action="store_true", dest="simple_naming", default=False,
00179 #                  help="Simplify generated naming.")
00180 #    
00181 #    if args is None:
00182 #        (options, args) = op.parse_args()
00183 #    else:
00184 #        (options, args) = op.parse_args(args)
00185 #        
00186 #    if len(args) != 1:
00187 #        print>>sys.stderr, 'Expecting a file/url as argument (WSDL).'
00188 #        sys.exit(os.EX_USAGE)
00189 #        
00190 #    reader = WSDLTools.WSDLReader()
00191 #    if isfile(args[0]):
00192 #        _wsdl2dispatch(options, reader.loadFromFile(args[0]))
00193 #        return
00194 #
00195 #    _wsdl2dispatch(options, reader.loadFromURL(args[0]))
00196 
00197 
00198 def _wsdl2py(options, wsdl):
00199 
00200     if options.twisted:
00201         from ZSI.generate.containers import ServiceHeaderContainer
00202         try:
00203             ServiceHeaderContainer.imports.remove('from ZSI import client')
00204         except ValueError:
00205             pass
00206         ServiceHeaderContainer.imports.append('from ZSI.twisted import client')
00207 
00208 
00209     if options.simple_naming:
00210         # Use a different client suffix
00211         # WriteServiceModule.client_module_suffix = "_client"
00212         # Write messages definitions to a separate file.
00213         #wsdl2pyServiceDescription.separate_messages = True
00214         # Use more simple type and element class names
00215         containers.SetTypeNameFunc( lambda n: '%s_' %(NC_to_CN(n)) )
00216         containers.SetElementNameFunc( lambda n: '%s' %(NC_to_CN(n)) )
00217         # Don't add "_" to the attribute name (remove when --aname works well)
00218         containers.ContainerBase.func_aname = lambda instnc,n: TextProtect(str(n))
00219         # write out the modules with their names rather than their number.
00220         utility.namespace_name = lambda cls, ns: utility.Namespace2ModuleName(ns)
00221 
00222     files = []
00223     append =  files.append
00224     if isinstance(wsdl, XMLSchema.XMLSchema):
00225         wsm = WriteServiceModule(_XMLSchemaAdapter(wsdl.location, wsdl),
00226                                  addressing=options.address)
00227     else:
00228         wsm = WriteServiceModule(wsdl, addressing=options.address)
00229         client_mod = wsm.getClientModuleName()
00230         client_file = join(options.output_dir, '%s.py' %client_mod)
00231         append(client_file)
00232         fd = open(client_file, 'w+')
00233         wsm.writeClient(fd)
00234         fd.close()
00235     
00236     types_mod = wsm.getTypesModuleName()
00237     types_file = join(options.output_dir, '%s.py' %types_mod)
00238     append(types_file)
00239     fd = open(types_file, 'w+' )
00240     wsm.writeTypes(fd)
00241     fd.close()
00242     
00243     return files
00244 
00245 
00246 def _wsdl2dispatch(options, wsdl):
00247     """TOOD: Remove ServiceContainer stuff, and replace with WSGI.
00248     """
00249     kw = dict()
00250     if options.twisted:
00251         from ZSI.twisted.WSresource import WSResource
00252         kw['base'] = WSResource
00253         ss = ServiceDescription(**kw)
00254         if options.address is True:
00255             raise RuntimeError, 'WS-Address w/twisted currently unsupported, edit the "factory" attribute by hand'
00256     else:
00257         # TODO: make all this handler arch
00258         if options.address is True:
00259             ss = ServiceDescriptionWSA()
00260         else:
00261             ss = ServiceDescription(**kw)
00262 
00263     ss.fromWSDL(wsdl)
00264     file_name = ss.getServiceModuleName()+'.py'
00265     fd = open( join(options.output_dir, file_name), 'w+')
00266     ss.write(fd)
00267     fd.close()
00268     
00269     return file_name
00270 
00271 
00272 class _XMLSchemaAdapter:
00273     """Adapts an obj XMLSchema.XMLSchema to look like a WSDLTools.WSDL,
00274     just setting a couple attributes code expects to see.
00275     """
00276     def __init__(self, location, schema):
00277         """Parameters:
00278         location -- base location, file path
00279         schema -- XMLSchema instance
00280         """
00281         self.name = '_'.join(split(location)[-1].split('.'))
00282         self.types = {schema.targetNamespace:schema}
00283         
00284         
00285         
00286         
00287 import os, pydoc, sys, warnings, inspect
00288 import  os.path
00289 
00290 from distutils import log
00291 from distutils.command.build_py import build_py
00292 from distutils.util import convert_path
00293 
00294 #from setuptools import find_packages
00295 #from setuptools import Command
00296 from ZSI.schema import ElementDeclaration, TypeDefinition
00297 #from pyGridWare.utility.generate.Modules import NR
00298 #from pyGridWare.utility.generate.Modules import CLIENT, TYPES
00299 
00300 #def find_packages_modules(where='.'):
00301 #    #pack,mod,mod_file 
00302 #    """Return a list all Python packages found within directory 'where'
00303 #    """
00304 #    out = []
00305 #    stack=[(convert_path(where), '')]
00306 #    while stack:
00307 #        where,prefix = stack.pop(0)
00308 #        for name in os.listdir(where):
00309 #            fn = os.path.join(where,name)
00310 #            #if (os.path.isdir(fn) and
00311 #            #    os.path.isfile(os.path.join(fn,'__init__.py'))
00312 #            #):
00313 #            #    out.append(prefix+name); stack.append((fn,prefix+name+'.'))
00314 #            if (os.path.isdir(fn) and
00315 #                os.path.isfile(os.path.join(fn,'__init__.py'))):
00316 #                stack.append((fn,prefix+name+'.'))
00317 #                continue
00318 #
00319 #            if name == '__init__.py' or not name.endswith('.py'): 
00320 #                continue
00321 #
00322 #            out.append((prefix, name.split('.py')[0])) 
00323 #            
00324 #    return out
00325 
00326 
00327 def _writedoc(doc, thing, forceload=0):
00328     """Write HTML documentation to a file in the current directory.
00329     """
00330     try:
00331         object, name = pydoc.resolve(thing, forceload)
00332         page = pydoc.html.page(pydoc.describe(object), pydoc.html.document(object, name))
00333         fname = os.path.join(doc, name + '.html')
00334         file = open(fname, 'w')
00335         file.write(page)
00336         file.close()
00337     except (ImportError, pydoc.ErrorDuringImport), value:
00338         traceback.print_exc(sys.stderr)
00339     else:
00340         return name + '.html'
00341         
00342 
00343 def _writeclientdoc(doc, thing, forceload=0):
00344     """Write HTML documentation to a file in the current directory.
00345     """
00346     docmodule = pydoc.HTMLDoc.docmodule
00347     def strongarm(self, object, name=None, mod=None, *ignored):
00348         result = docmodule(self, object, name, mod, *ignored)
00349 
00350         # Grab all the aliases to pyclasses and create links.
00351         nonmembers = []
00352         push = nonmembers.append
00353         for k,v in inspect.getmembers(object, inspect.isclass):
00354             if inspect.getmodule(v) is not object and getattr(v,'typecode',None) is not None:
00355                 push('<a href="%s.html">%s</a>: pyclass alias<br/>' %(v.__name__,k))
00356 
00357         result += self.bigsection('Aliases', '#ffffff', '#eeaa77', ''.join(nonmembers))
00358         return result
00359 
00360     pydoc.HTMLDoc.docmodule = strongarm
00361     try:
00362         object, name = pydoc.resolve(thing, forceload)
00363         page = pydoc.html.page(pydoc.describe(object), pydoc.html.document(object, name))
00364         name = os.path.join(doc, name + '.html')
00365         file = open(name, 'w')
00366         file.write(page)
00367         file.close()
00368     except (ImportError, pydoc.ErrorDuringImport), value:
00369         log.debug(str(value))
00370 
00371     pydoc.HTMLDoc.docmodule = docmodule
00372 
00373 def _writetypesdoc(doc, thing, forceload=0):
00374     """Write HTML documentation to a file in the current directory.
00375     """
00376     try:
00377         object, name = pydoc.resolve(thing, forceload)
00378         name = os.path.join(doc, name + '.html')
00379     except (ImportError, pydoc.ErrorDuringImport), value:
00380         log.debug(str(value))
00381         return
00382         
00383     # inner classes
00384     cdict = {}
00385     fdict = {}
00386     elements_dict = {}
00387     types_dict = {}
00388     for kname,klass in inspect.getmembers(thing, inspect.isclass):
00389         if thing is not inspect.getmodule(klass):
00390             continue
00391         
00392         cdict[kname] = inspect.getmembers(klass, inspect.isclass)
00393         for iname,iklass in cdict[kname]:
00394             key = (kname,iname)
00395             fdict[key] = _writedoc(doc, iklass)
00396             if issubclass(iklass, ElementDeclaration):
00397                 
00398                 try:
00399                     typecode = iklass()
00400                 except (AttributeError,RuntimeError), ex:
00401                     elements_dict[iname] = _writebrokedoc(doc, ex, iname)
00402                     continue
00403 
00404                 elements_dict[iname] = None
00405                 if typecode.pyclass is not None:                        
00406                     elements_dict[iname] = _writedoc(doc, typecode.pyclass)
00407 
00408                 continue
00409 
00410             if issubclass(iklass, TypeDefinition):
00411                 try:
00412                     typecode = iklass(None)
00413                 except (AttributeError,RuntimeError), ex:
00414                     types_dict[iname] = _writebrokedoc(doc, ex, iname)
00415                     continue
00416 
00417                 types_dict[iname] = None
00418                 if typecode.pyclass is not None:
00419                     types_dict[iname] = _writedoc(doc, typecode.pyclass)
00420 
00421                 continue
00422                         
00423                 
00424     def strongarm(self, object, name=None, mod=None, funcs={}, classes={}, *ignored):
00425         """Produce HTML documentation for a class object."""
00426         realname = object.__name__
00427         name = name or realname
00428         bases = object.__bases__
00429         object, name = pydoc.resolve(object, forceload)
00430         contents = []
00431         push = contents.append
00432         if name == realname:
00433             title = '<a name="%s">class <strong>%s</strong></a>' % (
00434                 name, realname)
00435         else:   
00436             title = '<strong>%s</strong> = <a name="%s">class %s</a>' % (
00437                 name, name, realname)
00438                 
00439         mdict = {}
00440         if bases:
00441             parents = []
00442             for base in bases:
00443                 parents.append(self.classlink(base, object.__module__))
00444             title = title + '(%s)' % pydoc.join(parents, ', ')
00445             
00446         doc = self.markup(pydoc.getdoc(object), self.preformat, funcs, classes, mdict)
00447         doc = doc and '<tt>%s<br>&nbsp;</tt>' % doc
00448         for iname,iclass in cdict[name]:
00449             fname = fdict[(name,iname)]
00450 
00451             if elements_dict.has_key(iname):
00452                 push('class <a href="%s">%s</a>: element declaration typecode<br/>'\
00453                     %(fname,iname))
00454                 pyclass = elements_dict[iname]
00455                 if pyclass is not None:
00456                     push('<ul>instance attributes:')
00457                     push('<li><a href="%s">pyclass</a>: instances serializable to XML<br/></li>'\
00458                         %elements_dict[iname])
00459                     push('</ul>')
00460             elif types_dict.has_key(iname):
00461                 push('class <a href="%s">%s</a>: type definition typecode<br/>' %(fname,iname))
00462                 pyclass = types_dict[iname]
00463                 if pyclass is not None:
00464                     push('<ul>instance attributes:')
00465                     push('<li><a href="%s">pyclass</a>: instances serializable to XML<br/></li>'\
00466                           %types_dict[iname])
00467                     push('</ul>')
00468             else:
00469                 push('class <a href="%s">%s</a>: TODO not sure what this is<br/>' %(fname,iname))
00470                 
00471         contents = ''.join(contents)
00472         return self.section(title, '#000000', '#ffc8d8', contents, 3, doc) 
00473     
00474     doclass = pydoc.HTMLDoc.docclass
00475     pydoc.HTMLDoc.docclass = strongarm
00476             
00477     try:
00478         page = pydoc.html.page(pydoc.describe(object), pydoc.html.document(object, name))
00479         file = open(name, 'w')
00480         file.write(page)
00481         file.close()
00482     except (ImportError, pydoc.ErrorDuringImport), value:
00483         log.debug(str(value))
00484         
00485     pydoc.HTMLDoc.docclass = doclass
00486     
00487 
00488         
00489 def _writebrokedoc(doc, ex, name, forceload=0):
00490     try:
00491         fname = os.path.join(doc, name + '.html')
00492         page = pydoc.html.page(pydoc.describe(ex), pydoc.html.document(str(ex), fname))
00493         file = open(fname, 'w')
00494         file.write(page)
00495         file.close()
00496     except (ImportError, pydoc.ErrorDuringImport), value:
00497         log.debug(str(value))
00498         
00499     return name + '.html'
00500 
00501 def _writepydoc(doc, *args):
00502     """create pydoc html pages
00503     doc -- destination directory for documents
00504     *args -- modules run thru pydoc
00505     """
00506     ok = True
00507     if not os.path.isdir(doc):
00508         os.makedirs(doc)
00509     
00510     if os.path.curdir not in sys.path:
00511         sys.path.append(os.path.curdir)
00512 
00513     for f in args:
00514         if f.startswith('./'): f = f[2:]
00515         name = os.path.sep.join(f.strip('.py').split(os.path.sep))
00516         try:
00517             e = __import__(name)
00518         except Exception,ex:
00519             raise
00520 #            _writebrokedoc(doc, ex, name)
00521 #            continue
00522    
00523         if name.endswith('_client'):
00524             _writeclientdoc(doc, e)
00525             continue
00526     
00527         if name.endswith('_types'):
00528             _writetypesdoc(doc, e)
00529             continue
00530   
00531         try: 
00532             _writedoc(doc, e)
00533         except IndexError,ex:
00534             _writebrokedoc(doc, ex, name)
00535             continue
00536 
00537 

Generated on Wed Oct 20 2010 11:12:15 for APBS by  doxygen 1.7.2