| The Gaudi Framework v29r1 (5cd95fa2)

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