Gaudi Framework, version v21r8

Home   Generated: 17 Mar 2010

genconfuser.py

Go to the documentation of this file.
00001 #!/usr/bin/env python
00002 """
00003 Generate _confDb.py files for ConfigurableUser classes.
00004 """
00005 
00006 import os, sys, time, logging
00007 from pprint import pformat
00008 from GaudiKernel.ConfigurableDb import loadConfigurableDb, cfgDb
00009 
00010 logging.VERBOSE = (logging.INFO + logging.DEBUG) / 2 
00011 logging.addLevelName(logging.VERBOSE, "VERBOSE")
00012 logging.verbose = lambda msg, *args, **kwargs: \
00013     apply(logging.log, (logging.VERBOSE, msg) + args, kwargs)
00014 
00015 def _inheritsfrom(derived, basename):
00016     """
00017     Check if the class name 'basename' is anywhere in the base classes of the
00018     class 'derived'.
00019     If 'derived' _is_ 'basename', returns False.  
00020     """
00021     for b in derived.__bases__:
00022         if b.__name__ == basename:
00023             return True
00024         else:
00025             if _inheritsfrom(b, basename):
00026                 return True
00027     return False
00028 
00029 def getConfigurableUsers(modulename, root, mayNotExist = False):
00030     """
00031     Find in the module 'modulename' all the classes that derive from ConfigurableUser.
00032     Return the list of the names.
00033     The flag mayNotExist is used to choose the level of the logging message in case
00034     the requested module does not exist.
00035     """
00036     # remember the old system path
00037     oldpath = list(sys.path)
00038     # we need to hack the sys.path to add the first part of the module name after root
00039     moduleelements = modulename.split('.')
00040     if len(moduleelements) > 1:
00041         moddir = os.sep.join([root] + moduleelements[:-1])
00042     else:
00043         moddir = root
00044     # this is the name of the submodule to import
00045     shortmodname = moduleelements[-1]
00046     # check if the module file actually exists
00047     if not os.path.exists(os.path.join(moddir, shortmodname) + ".py"):
00048         msg = "Module %s does not exist" % modulename
00049         if mayNotExist:
00050             logging.verbose(msg)
00051         else:
00052             logging.error(msg)
00053         # no file -> do not try to import
00054         return []
00055     # prepend moddir to the path
00056     sys.path.insert(0, moddir)
00057     logging.verbose("sys.path prepended with %r", sys.path[0])
00058     
00059     logging.info("Looking for ConfigurableUser in %r", modulename)
00060     g, l = {}, {}
00061     try:
00062         logging.verbose("importing %s", shortmodname)
00063         exec "import %s as mod" % shortmodname in g, l
00064     finally:
00065         # restore old sys.path
00066         logging.verbose("restoring old sys.path")
00067         sys.path = oldpath
00068     mod = l["mod"]
00069     if "__all__" in dir(mod) and mod.__all__:
00070         all = mod.__all__
00071     else:
00072         all = [ n for n in dir(mod) if not n.startswith("_")]
00073     result = []
00074     for name in all:
00075         cfg = cfgDb.get(name)
00076         if cfg and cfg["module"] != modulename:
00077             # This name comes from another module
00078             logging.verbose("Object %r already found in module %r", name, cfg["module"])
00079             continue
00080         t = getattr(mod, name)
00081         if isinstance(t, type) and  _inheritsfrom(t, "ConfigurableUser"):
00082             result.append(name)
00083     logging.verbose("Found %r", result)
00084     return result
00085 
00086 def main():
00087     from optparse import OptionParser
00088     parser = OptionParser(prog = os.path.basename(sys.argv[0]),
00089                           usage = "%prog [options] <PackageName> [<Module1> ...]")
00090     parser.add_option("-o", "--output", action="store", type="string",
00091                       help="output file for confDb data [default = '../genConf/<PackageName>_user_confDb.py'].")
00092     parser.add_option("-r", "--root", action="store", type="string",
00093                       help="root directory of the python modules [default = '../python'].")
00094     parser.add_option("-v", "--verbose", action="store_true",
00095                       help="print some debugging information")
00096     parser.add_option("--lockerpath", action="store",
00097                       metavar = "DIRNAME",
00098                       help="directory where to find the module 'locker'")
00099     parser.set_defaults(root = os.path.join("..","python"))
00100     
00101     opts, args = parser.parse_args()
00102     
00103     if opts.verbose:
00104         log_level = logging.VERBOSE
00105     else:
00106         log_level = logging.INFO
00107     logging.basicConfig(format = "%(levelname)s: %(message)s",
00108                         stream = sys.stdout,
00109                         level = log_level)
00110 
00111     if len(args) < 1:
00112         parser.error("PackageName is required")
00113     
00114     package_name = args.pop(0)
00115 
00116     usingConvention = False
00117     if not args:
00118         # use the conventional module name <package>.Configuration
00119         args = [package_name + ".Configuration"]
00120         usingConvention = True
00121     
00122     if not opts.output:
00123         outputfile = os.path.join("..", "genConf", package_name + '_user_confDb.py')
00124     else:
00125         outputfile = opts.output
00126     
00127     # The locking ensures that nobody tries to modify the python.zip file while
00128     # we read it.
00129     dbLock = None
00130     if "GAUDI_BUILD_LOCK" in os.environ:
00131         if opts.lockerpath:
00132             sys.path.append(opts.lockerpath)
00133         # Get the LockFile class from the locker module in GaudiPolicy or use a fake
00134         # factory.
00135         try:
00136             from locker import LockFile
00137         except ImportError:
00138             def LockFile(*args, **kwargs):
00139                 return None
00140         # obtain the lock
00141         dbLock = LockFile(os.environ["GAUDI_BUILD_LOCK"], temporary =  True) 
00142     
00143     # We can disable the error on missing configurables only if we can import Gaudi.Configurables
00144     # It must be done at this point because it may conflict with logging.basicConfig
00145     try:
00146         import Gaudi.Configurables
00147         Gaudi.Configurables.ignoreMissingConfigurables = True
00148     except:
00149         pass
00150     # load configurables database to avoid fake duplicates
00151     loadConfigurableDb()
00152     # ensure that local configurables are in the database
00153     try:
00154         # Add the local python directories to the python path to be able to import the local
00155         # configurables
00156         sys.path.insert(0, os.path.join("..", "genConf"))
00157         sys.path.insert(0, os.path.join("..", "python"))
00158         localConfDb = os.path.join("..", "genConf", package_name, package_name + '_confDb.py')
00159         if os.path.exists(localConfDb):
00160             execfile(localConfDb, {}, {})
00161     except:
00162         pass # ignore failures (not important)
00163     del dbLock # Now we can let the others operate on the install area python directory
00164     
00165     # Collecting ConfigurableUser specializations
00166     cus = {}
00167     for mod in args:
00168         lst = None
00169         try:
00170             lst = getConfigurableUsers(mod, root = opts.root, mayNotExist = usingConvention)
00171         except ImportError:
00172             import traceback
00173             logging.error("Cannot import module %r:\n%s", mod,
00174                           traceback.format_exc().rstrip()) # I remove the trailing '\n'
00175             return 2
00176         if lst:
00177             cus[mod] = lst
00178             # Add the configurables to the database as fake entries to avoid duplicates
00179             for m in lst:
00180                 cfgDb.add(configurable = m,
00181                           package = 'None',
00182                           module  = 'None',
00183                           lib     = 'None')
00184         elif not usingConvention:
00185             logging.warning("Specified module %r does not contain ConfigurableUser specializations", mod)
00186     
00187     if cus:
00188         logging.info("ConfigurableUser found:\n%s", pformat(cus))
00189         # header
00190         output = """##  -*- python -*-
00191 # db file automatically generated by %s on: %s
00192 ## insulates outside world against anything bad that could happen
00193 ## also prevents global scope pollution
00194 def _fillCfgDb():
00195     from GaudiKernel.Proxy.ConfigurableDb import CfgDb
00196 
00197     # get a handle on the repository of Configurables
00198     cfgDb = CfgDb()
00199 
00200     # populate the repository with informations on Configurables 
00201 """ % (parser.prog, time.asctime())
00202         
00203         for mod in cus:
00204             for cu in cus[mod]:
00205                 output += """
00206     cfgDb.add( configurable = '%s',
00207                package = '%s',
00208                module  = '%s',
00209                lib     = 'None' )""" % (cu, package_name, mod)
00210 
00211         # trailer
00212         output += """
00213 
00214     return #_fillCfgDb
00215 
00216 # fill cfgDb at module import...
00217 try:
00218     _fillCfgDb()
00219     #house cleaning...
00220     del _fillCfgDb
00221 except Exception,err:
00222     print "Py:ConfigurableDb   ERROR Problem with [%%s] content!" %% __name__
00223     print "Py:ConfigurableDb   ERROR",err
00224     print "Py:ConfigurableDb   ERROR   ==> culprit is package [%s] !"
00225 """ % package_name
00226     elif usingConvention:
00227         logging.info("No ConfigurableUser found")
00228         output = "# No ConfigurableUser specialization\n"
00229     else:
00230         logging.error("No ConfigurableUser specialization found")
00231         return 1
00232 
00233     # create the destination directory if not there
00234     output_dir = os.path.dirname(outputfile)
00235     if not os.path.exists(output_dir):
00236         logging.info("Creating directory %r", output_dir)
00237         os.makedirs(output_dir, 0755)
00238     
00239     # write output to file
00240     logging.verbose("Writing confDb data to %r", outputfile)
00241     open(outputfile, "w").write(output)
00242     return 0
00243 
00244 if __name__ == '__main__':
00245     retcode = main()
00246     sys.exit(retcode)

Generated at Wed Mar 17 18:06:32 2010 for Gaudi Framework, version v21r8 by Doxygen version 1.5.6 written by Dimitri van Heesch, © 1997-2004