| The Gaudi Framework v28r2-patches (bc4ad17a)

- Main Page
- Related Pages
- Modules
- Namespaces
- Classes
- Files

- File List
- File Members

genconfuser.py
Go to the documentation of this file.
1 #!/usr/bin/env python
2 # -*- coding: utf-8 -*-
3 """
4 Generate _confDb.py files for ConfigurableUser classes.
5 """
6
7 import os
8 import sys
9 import time
10 import logging
11 import GaudiKernel.ConfigurableDb
12
13 from pprint import pformat
14 from glob import glob
15 from GaudiKernel.ConfigurableDb import cfgDb
16
17 logging.VERBOSE = (logging.INFO + logging.DEBUG) / 2
18 logging.addLevelName(logging.VERBOSE, "VERBOSE")
19 logging.verbose = lambda msg, *args, **kwargs: \
20 apply(logging.log, (logging.VERBOSE, msg) + args, kwargs)
21
22 def _inheritsfrom(derived, basenames):
23 """
24 Check if any of the class names in 'basenames' is anywhere in the base
25 classes of the class 'derived'.
26 If 'derived' _is_ one in 'basenames', returns False.
27
28 'basenames' can be a string or an iterable (of strings).
29 """
30 if isinstance(basenames, basestring):
31 basenames = (basenames,)
32 for b in derived.__bases__:
33 if b.__name__ in basenames:
34 return True
35 else:
36 if _inheritsfrom(b, basenames):
37 return True
38 return False
39
40 def loadConfigurableDb():
41 '''
42 Equivalent to GaudiKernel.ConfigurableDb.loadConfigurableDb(), but does a
43 deep search and executes the '*.confdb' files instead of importing them.
44 '''
45 log = GaudiKernel.ConfigurableDb.log
46 from os.path import join as path_join
47 # look for the confdb files in all the reasonable places
48 # - CMake builds
49 confDbFiles = []
50 for path in sys.path:
51 confDbFiles += [f for f in glob(path_join(path, '*', '*.confdb'))
52 if os.path.isfile(f)]
53 # - used projects and local merged file
54 pathlist = os.getenv("LD_LIBRARY_PATH", "").split(os.pathsep)
55 for path in filter(os.path.isdir, pathlist):
56 confDbFiles += [f for f in [path_join(path, f) for f in os.listdir(path)
57 if f.endswith('.confdb')]]
58 # - load the confdb files
59 for confDb in confDbFiles:
60 log.debug( "\t-loading [%s]..." % confDb )
61 try:
62 cfgDb._loadModule( confDb )
63 except Exception, err:
64 # It may happen that the file is found but not completely
65 # written, usually during parallel builds, but we do not care.
66 log.warning( "Could not load file [%s] !", confDb )
67 log.warning( "Reason: %s", err )
68 # top up with the regular merged confDb (for the used projects)
69 GaudiKernel.ConfigurableDb.loadConfigurableDb()
70
71 def getConfigurableUsers(modulename, root, mayNotExist = False):
72 """
73 Find in the module 'modulename' all the classes that derive from ConfigurableUser.
74 Return the list of the names.
75 The flag mayNotExist is used to choose the level of the logging message in case
76 the requested module does not exist.
77 """
78 # remember the old system path
79 oldpath = list(sys.path)
80 # we need to hack the sys.path to add the first part of the module name after root
81 moduleelements = modulename.split('.')
82 if len(moduleelements) > 1:
83 moddir = os.sep.join([root] + moduleelements[:-1])
84 else:
85 moddir = root
86 # this is the name of the submodule to import
87 shortmodname = moduleelements[-1]
88 # check if the module file actually exists
89 if not os.path.exists(os.path.join(moddir, shortmodname) + ".py"):
90 msg = "Module %s does not exist" % modulename
91 if mayNotExist:
92 logging.verbose(msg)
93 else:
94 logging.error(msg)
95 # no file -> do not try to import
96 return []
97 # prepend moddir to the path
98 sys.path.insert(0, moddir)
99 logging.verbose("sys.path prepended with %r", sys.path[0])
100
101 logging.info("Looking for ConfigurableUser in %r", modulename)
102 g, l = {}, {}
103 try:
104 logging.verbose("importing %s", shortmodname)
105 exec "import %s as mod" % shortmodname in g, l
106 finally:
107 # restore old sys.path
108 logging.verbose("restoring old sys.path")
109 sys.path = oldpath
110 mod = l["mod"]
111 if "__all__" in dir(mod) and mod.__all__:
112 all = mod.__all__
113 else:
114 all = [ n for n in dir(mod) if not n.startswith("_")]
115 result = []
116 for name in all:
117 cfg = cfgDb.get(name)
118 if cfg and cfg["module"] != modulename:
119 # This name comes from another module
120 logging.verbose("Object %r already found in module %r", name, cfg["module"])
121 continue
122 t = getattr(mod, name)
123 if isinstance(t, type) and _inheritsfrom(t, ('ConfigurableUser',
124 'SuperAlgorithm')):
125 result.append(name)
126 logging.verbose("Found %r", result)
127 return result
128
129 def main():
130 from optparse import OptionParser
131 parser = OptionParser(prog = os.path.basename(sys.argv[0]),
132 usage = "%prog [options] <PackageName> [<Module1> ...]")
133 parser.add_option("-o", "--output", action="store", type="string",
134 help="output file for confDb data [default = '../genConf/<PackageName>_user_confDb.py'].")
135 parser.add_option("-r", "--root", action="store", type="string",
136 help="root directory of the python modules [default = '../python'].")
137 parser.add_option("-v", "--verbose", action="store_true",
138 help="print some debugging information")
139 parser.add_option("--debug", action="store_true",
140 help="print more debugging information")
141 parser.set_defaults(root = os.path.join("..","python"))
142
143 opts, args = parser.parse_args()
144
145 if opts.debug:
146 log_level = logging.DEBUG
147 elif opts.verbose:
148 log_level = logging.VERBOSE
149 else:
150 log_level = logging.INFO if os.environ.get('VERBOSE') else logging.WARNING
151 logging.basicConfig(format = "%(levelname)s: %(message)s",
152 stream = sys.stdout,
153 level = log_level)
154
155 if len(args) < 1:
156 parser.error("PackageName is required")
157
158 package_name = args.pop(0)
159
160 usingConvention = False
161 if not args:
162 # use the conventional module name <package>.Configuration
163 args = [package_name + ".Configuration"]
164 usingConvention = True
165
166 genConfDir = os.path.join("..", os.environ.get("CMTCONFIG", ""), "genConf")
167 if not os.path.exists(genConfDir):
168 genConfDir = os.path.join("..", "genConf")
169
170 if not opts.output:
171 outputfile = os.path.join(genConfDir, package_name + '_user.confdb')
172 else:
173 outputfile = opts.output
174
175 # We can disable the error on missing configurables only if we can import Gaudi.Configurables
176 # It must be done at this point because it may conflict with logging.basicConfig
177 try:
178 import Gaudi.Configurables
179 Gaudi.Configurables.ignoreMissingConfigurables = True
180 except:
181 pass
182 # load configurables database to avoid fake duplicates
183 loadConfigurableDb()
184 # ensure that local configurables are in the database
185 try:
186 # Add the local python directories to the python path to be able to import the local
187 # configurables
188 sys.path.insert(0, genConfDir)
189 sys.path.insert(0, os.path.join("..", "python"))
190 localConfDb = os.path.join(genConfDir, package_name, package_name + '.confdb')
191 if os.path.exists(localConfDb):
192 cfgDb._loadModule(localConfDb)
193 # Extend the search path of the package module to find the configurables
194 package_module = __import__(package_name)
195 package_module.__path__.insert(0, os.path.join(genConfDir, package_name))
196 except:
197 pass # ignore failures (not important)
198
199 # Collecting ConfigurableUser specializations
200 cus = {}
201 for mod in args:
202 lst = None
203 try:
204 lst = getConfigurableUsers(mod, root = opts.root, mayNotExist = usingConvention)
205 except ImportError:
206 import traceback
207 logging.error("Cannot import module %r:\n%s", mod,
208 traceback.format_exc().rstrip()) # I remove the trailing '\n'
209 return 2
210 if lst:
211 cus[mod] = lst
212 # Add the configurables to the database as fake entries to avoid duplicates
213 for m in lst:
214 cfgDb.add(configurable = m,
215 package = 'None',
216 module = 'None',
217 lib = 'None')
218 elif not usingConvention:
219 logging.warning("Specified module %r does not contain ConfigurableUser specializations", mod)
220
221 if cus:
222 logging.info("ConfigurableUser found:\n%s", pformat(cus))
223 # header
224 output = """## -*- ascii -*-
225 # db file automatically generated by %s on: %s
226 """ % (parser.prog, time.asctime())
227
228 for mod in cus:
229 for cu in cus[mod]:
230 output += "%s %s %s\n" % (mod, 'None', cu)
231
232 # trailer
233 output += "## %s\n" % package_name
234 elif usingConvention:
235 logging.info("No ConfigurableUser found")
236 output = ("# db file automatically generated by %s on: %s\n"
237 "# No ConfigurableUser specialization in %s\n") % (parser.prog, time.asctime(), package_name)
238 else:
239 logging.error("No ConfigurableUser specialization found")
240 return 1
241
242 # create the destination directory if not there
243 output_dir = os.path.dirname(outputfile)
244 try:
245 logging.info("Creating directory %r", output_dir)
246 os.makedirs(output_dir, 0755)
247 except OSError, err:
248 import errno
249 if err.errno == errno.EEXIST:
250 # somebody already - perhaps concurrently - created that dir.
251 pass
252 else:
253 raise
254
255 # write output to file
256 logging.verbose("Writing confDb data to %r", outputfile)
257 open(outputfile, "w").write(output)
258 return 0
259
260 if __name__ == '__main__':
261 retcode = main()
262 sys.exit(retcode)
GaudiKernel.ConfigurableDb.loadConfigurableDb
def loadConfigurableDb()
Helper function to load all ConfigurableDb files holding informations.
Definition: ConfigurableDb.py:106
GaudiKernel.ConfigurableDb
Definition: ConfigurableDb.py:1
genconfuser.getConfigurableUsers
def getConfigurableUsers(modulename, root, mayNotExist=False)
Definition: genconfuser.py:71
genconfuser._inheritsfrom
def _inheritsfrom(derived, basenames)
Definition: genconfuser.py:22
GaudiPython.GaudiAlgs.write
write
Definition: GaudiAlgs.py:1144
Gaudi::Functional::details::apply
constexpr void apply(const Fun &, Container &, Args...)
Definition: FunctionalDetails.h:444
genconfuser.loadConfigurableDb
def loadConfigurableDb()
Definition: genconfuser.py:40
genconfuser.main
def main()
Definition: genconfuser.py:129