The Gaudi Framework  master (69a68366)
Loading...
Searching...
No Matches
ConfigurableDb.py
Go to the documentation of this file.
13"""A singleton holding informations on the whereabouts of all the automatically
14generated Configurables.
15This repository of (informations on) Configurables is used by the PropertyProxy
16class to locate Configurables and feed the JobOptionsSvc. It could also be used
17to feed the AthenaEmacs module..."""
18
19__all__ = ["CfgDb", "cfgDb", "loadConfigurableDb", "getConfigurable"]
20
21import logging
22
23log = logging.getLogger("ConfigurableDb")
24
25
26_TRANS_TABLE = str.maketrans("<>&*,: ().", "__rp__s___")
27
28
30 """
31 Translate a C++ type name (with templates etc.) to Python identifier.
32 """
33 return name.replace(", ", ",").translate(_TRANS_TABLE)
34
35
36class _CfgDb(dict):
37 """
38 A singleton class holding informations about automatically generated
39 Configurables.
40 --> package holding that Configurable
41 --> library holding the components related to that Configurable
42 --> python module holding the Configurable
43 --> a dictionary of duplicates
44 """
45
46 __slots__ = {
47 "_duplicates": {},
48 }
49
50 def __init__(self):
51 object.__init__(self)
52 self._duplicates = {}
53
54 def add(self, configurable, package, module, lib):
55 """Method to populate the Db.
56 It is called from the auto-generated Xyz_confDb.py files (genconf.cpp)
57 @param configurable: the name of the configurable being added
58 @param package: the name of the package which holds this Configurable
59 @param module: the name of the python module holding the Configurable
60 @param lib: the name of the library holding the component(s) (ie: the
61 C++ Gaudi component which is mapped by the Configurable)
62 """
63 cfg = {"package": package, "module": module, "lib": lib}
64 if configurable in self:
65 # check if it comes from the same library...
66 if cfg["lib"] != self[configurable]["lib"]:
67 log.debug(
68 "dup!! [%s] p=%s m=%s lib=%s", configurable, package, module, lib
69 )
70 if configurable in self._duplicates:
71 self._duplicates[configurable] += [cfg]
72 else:
73 self._duplicates[configurable] = [cfg]
74 else:
75 log.debug("added [%s] p=%s m=%s lib=%s", configurable, package, module, lib)
76 self[configurable] = cfg
77
78 def duplicates(self):
79 return self._duplicates
80
81 def _loadModule(self, fname):
82 f = open(fname)
83 for i, ll in enumerate(f):
84 l = ll.strip()
85 if l.startswith("#") or len(l) <= 0:
86 continue
87 try:
88 line = l.split()
89 cname = line[2]
90 pkg = line[0].split(".")[0]
91 module = line[0]
92 lib = line[1]
93 self.add(cname, pkg, module, lib)
94 except IndexError:
95 f.close()
96 raise Exception("invalid line format: %s:%d: %r" % (fname, i + 1, ll))
97 f.close()
98
99
100class _Singleton(object):
101 # the object this singleton is holding
102 # No other object will be created...
103 __obj = _CfgDb()
104
105 def __call__(self):
106 return self.__obj
107
108
109CfgDb = _Singleton()
110
111# clean-up
112del _Singleton
113del _CfgDb
114
115# default name for CfgDb instance
116cfgDb = CfgDb()
117
118# Helper function to load all ConfigurableDb files holding informations
119
120
122 """Helper function to load all ConfigurableDb files (modules) holding
123 informations about Configurables
124 """
125 import os
126 from os.path import join as path_join
127
128 log.debug("loading confDb files...")
129 nFiles = 0 # counter of imported files
130 pathlist = os.getenv("GAUDI_PLUGIN_PATH", "").split(os.pathsep) + os.getenv(
131 "LD_LIBRARY_PATH", ""
132 ).split(os.pathsep)
133 ignored_files = set(os.environ.get("CONFIGURABLE_DB_IGNORE", "").split(","))
134 for path in pathlist:
135 if not os.path.isdir(path):
136 continue
137 log.debug("walking in [%s]...", path)
138 confDbFiles = [
139 f
140 for f in [
141 path_join(path, f) for f in os.listdir(path) if f.endswith(".confdb")
142 ]
143 if os.path.isfile(f) and f not in ignored_files
144 ]
145 # check if we use "*_merged.confdb"
146 mergedConfDbFiles = [f for f in confDbFiles if f.endswith("_merged.confdb")]
147 if mergedConfDbFiles:
148 # use only the merged ones
149 confDbFiles = mergedConfDbFiles
150
151 for confDb in confDbFiles:
152 log.debug("\t-loading [%s]...", confDb)
153 try:
154 cfgDb._loadModule(confDb)
155 except Exception as err:
156 log.warning("Could not load file [%s] !", confDb)
157 log.warning("Reason: %s", err)
158 nFiles += 1
159 log.debug("loading confDb files... [DONE]")
160 nPkgs = len(set([k["package"] for k in cfgDb.values()]))
161 log.debug("loaded %i confDb packages", nPkgs)
162 return nFiles
163
164
165def getConfigurable(className, requester="", assumeCxxClass=True):
166 confClass = className
167 if assumeCxxClass:
168 # assume className is C++: --> translate to python
169 confClass = _normalize_cpp_type_name(confClass)
170
171 # see if I have it in my dictionary
172 confClassInfo = cfgDb.get(confClass)
173 if not confClassInfo:
174 confClassInfo = cfgDb.get(confClass)
175 # get the python module
176 confMod = confClassInfo and confClassInfo.get("module")
177 if not confMod:
178 log.warning("%s: Class %s not in database", requester, className)
179 return None
180 # load the module
181 try:
182 mod = __import__(confMod, globals(), locals(), confClass)
183 except ImportError:
184 log.warning(
185 "%s: Module %s not found (needed for configurable %s)",
186 requester,
187 confMod,
188 className,
189 )
190 return None
191 # get the class
192 try:
193 confClass = getattr(mod, confClass)
194 except AttributeError:
195 log.warning(
196 "%s: Configurable %s not found in module %s", requester, confClass, confMod
197 )
198 return None
199 # Got it!
200 log.debug("%s: Found configurable %s in module %s", requester, confClass, confMod)
201
202 return confClass
add(self, configurable, package, module, lib)
getConfigurable(className, requester="", assumeCxxClass=True)