Loading [MathJax]/extensions/tex2jax.js
The Gaudi Framework  v36r16 (ea80daf8)
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Modules Pages
_db.py
Go to the documentation of this file.
1 
12 import atexit
13 import logging
14 import os
15 import sys
16 
17 
18 class ConfDB2(object):
19  def __init__(self):
20  import shelve
21 
22  self._dbs = {}
23  pathvar = "DYLD_LIBRARY_PATH" if sys.platform == "darwin" else "LD_LIBRARY_PATH"
24  for path in os.getenv(pathvar, "").split(os.pathsep):
25  if not os.path.isdir(path):
26  continue
27  dbfiles = [
28  os.path.join(path, f)
29  for f in os.listdir(path)
30  if f.endswith(".confdb2") and os.path.isfile(os.path.join(path, f))
31  ]
32  dbfiles.sort()
33  for db in [shelve.open(f, "r") for f in dbfiles]:
34  for key in db:
35  if key not in self._dbs:
36  self._dbs[key] = db
37 
38  def __getitem__(self, key):
39  return self._dbs[key][key]
40 
41  def __contains__(self, key):
42  return key in self._dbs
43 
44  def __iter__(self):
45  return iter(self._dbs)
46 
47 
48 # allow overriding the low level DB access for testing
49 if "GAUDICONFIG2_DB" in os.environ:
50  exec(
51  "from {} import {} as _DB".format(*os.environ["GAUDICONFIG2_DB"].rsplit(".", 1))
52  )
53 else: # pragma no cover
54  _DB = ConfDB2()
55 
56 
57 # Workaround for a bug in Python (2) clean up
58 # see https://stackoverflow.com/q/2180946
59 def _fix_clean_up(): # pragma no cover
60  global _DB
61  del _DB
62 
63 
64 atexit.register(_fix_clean_up)
65 
66 if sys.version_info >= (3,): # pragma no cover
67  maketrans = str.maketrans
68 else: # pragma no cover
69  from string import maketrans
70 _TRANS_TABLE = maketrans("<>&*,: ().", "__rp__s___")
71 
72 
74  """
75  Translate a C++ type name (with templates etc.) to Python identifier.
76  """
77  return name.replace(", ", ",").translate(_TRANS_TABLE)
78 
79 
80 def split_namespace(typename):
81  """
82  Split a C++ qualified namespace in the tuple (top_namespace, rest) starting
83  searching the separator from pos.
84 
85  >>> split_namespace('std::chrono::time_point')
86  ('std', 'chrono::time_point')
87  """
88  # find next namespace separator skipping template arguments
89  tpos = typename.find("<")
90  pos = typename.find("::")
91  # '<' can appear only in a class name, if we find a '::'
92  # earlier than a '<', then we got a namespace, else a class
93  if pos > 0 and (tpos < 0 or pos < tpos):
94  head = typename[:pos]
95  tail = typename[pos + 2 :]
96  else:
97  head = None
98  tail = typename
99  return (head, tail)
100 
101 
102 class ConfigurablesDB(object):
103  """
104  Helper to expose Configurables classes (from Configurables database) as
105  a tree of subpackages, each mapped to a namespace.
106  """
107 
108  def __init__(self, modulename, root=None):
109  """
110  @param modulename: name of the module
111  @param root: name of the root modules (that pointing to the root C++
112  namespace), None is ewuivalent to pass modulename as root
113  """
114  self._log = logging.getLogger(modulename)
115  self._log.debug("initializing module %r (with root %r)", modulename, root)
116 
117  self.__name__ = modulename
118  self.__loader__ = None
119  self._root = root or modulename
120  assert (not root) or modulename.startswith(
121  root + "."
122  ), "modulename should be (indirect submodule of root)"
123 
124  self._namespace = modulename[len(root) + 1 :].replace(".", "::") if root else ""
125  self._log.debug("%r mapping namespace %r", modulename, self._namespace or "::")
126 
127  self._namespaces, self._classes = self._getEntries()
128  self._alt_names = {}
129  for cname in self._classes:
130  alt_name = _normalize_cpp_type_name(cname)
131  if alt_name != cname:
132  self._alt_names[alt_name] = cname
133  if " " in cname: # allow matching of 'T<A, B>' a well as 'T<A,B>'
134  self._alt_names[cname.replace(" ", "")] = cname
135  self.__all__ = list(
136  self._namespaces.union(self._classes).union(self._alt_names)
137  )
138 
139  sys.modules[modulename] = self
140 
141  for submodule in self._namespaces:
142  setattr(
143  self,
144  submodule,
145  ConfigurablesDB(".".join([self.__name__, submodule]), self._root),
146  )
147 
148  def _getEntries(self):
149  """
150  Extract from the Configurables DB the namespaces and classes names in
151  the namespace this instance represents.
152  """
153  self._log.debug("getting list of entries under %r", self._namespace)
154  prefix = self._namespace + "::" if self._namespace else ""
155  prefix_len = len(prefix)
156 
157  namespaces = set()
158  classes = set()
159  for name in _DB:
160  if name.startswith(prefix):
161  head, tail = split_namespace(name[prefix_len:])
162  if head:
163  namespaces.add(head)
164  else:
165  classes.add(tail)
166 
167  self._log.debug(
168  "found %d namespaces and %d classes", len(namespaces), len(classes)
169  )
170  return (namespaces, classes)
171 
172  def __getattr__(self, name):
173  """
174  Helper to instantiate on demand Configurable classes.
175  """
176  if name in self._classes:
177  fullname = "::".join([self._namespace, name]) if self._namespace else name
178  from ._configurables import makeConfigurableClass
179 
180  self._log.debug("generating %r (%s)", name, fullname)
181  entry = makeConfigurableClass(
182  name,
183  __module__=self.__name__,
184  __qualname__=name,
185  __cpp_type__=fullname,
186  **_DB[fullname]
187  )
188  elif name.replace(" ", "") in self._alt_names:
189  entry = getattr(self, self._alt_names[name.replace(" ", "")])
190  elif name == "__spec__": # pragma no cover
191  import importlib
192 
193  entry = importlib.machinery.ModuleSpec(
194  name=self.__package__,
195  loader=self.__loader__,
196  )
197  elif name == "__package__": # pragma no cover
198  entry = self.__name__
199  else:
200  raise AttributeError(
201  "module {!r} has no attribute {!r}".format(self.__name__, name)
202  )
203  setattr(self, name, entry)
204  return entry
205 
206  def getByType(self, typename):
207  """
208  Return a configurable from the fully qualified type name (relative to
209  the current namespace).any
210  """
211  head, tail = split_namespace(typename)
212  if head:
213  return getattr(self, head).getByType(tail)
214  else:
215  return getattr(self, tail)
GaudiConfig2._db.ConfigurablesDB.getByType
def getByType(self, typename)
Definition: _db.py:206
GaudiConfig2._db._normalize_cpp_type_name
def _normalize_cpp_type_name(name)
Definition: _db.py:73
GaudiConfig2._db.ConfDB2.__contains__
def __contains__(self, key)
Definition: _db.py:41
GaudiConfig2._db.maketrans
maketrans
Definition: _db.py:67
GaudiConfig2._db.ConfDB2.__iter__
def __iter__(self)
Definition: _db.py:44
GaudiConfig2._db.ConfigurablesDB._alt_names
_alt_names
Definition: _db.py:128
GaudiConfig2._db._fix_clean_up
def _fix_clean_up()
Definition: _db.py:59
GaudiConfig2._db.ConfigurablesDB.__all__
__all__
Definition: _db.py:135
GaudiConfig2._db.ConfDB2
Definition: _db.py:18
GaudiConfig2._db.ConfDB2.__getitem__
def __getitem__(self, key)
Definition: _db.py:38
GaudiConfig2._db.ConfigurablesDB.__name__
__name__
Definition: _db.py:117
GaudiConfig2._db.ConfigurablesDB._classes
_classes
Definition: _db.py:127
GaudiConfig2._db.split_namespace
def split_namespace(typename)
Definition: _db.py:80
GaudiConfig2._db.ConfigurablesDB._namespace
_namespace
Definition: _db.py:124
GaudiConfig2._db.ConfDB2.__init__
def __init__(self)
Definition: _db.py:19
GaudiConfig2._db.ConfigurablesDB.__loader__
__loader__
Definition: _db.py:118
format
GAUDI_API std::string format(const char *,...)
MsgStream format utility "a la sprintf(...)".
Definition: MsgStream.cpp:119
GaudiConfig2._db.ConfigurablesDB._log
_log
Definition: _db.py:114
GaudiConfig2._db.ConfigurablesDB.__getattr__
def __getattr__(self, name)
Definition: _db.py:172
GaudiConfig2._db.ConfDB2._dbs
_dbs
Definition: _db.py:22
GaudiConfig2._db.ConfigurablesDB
Definition: _db.py:102
GaudiConfig2._db.ConfigurablesDB._root
_root
Definition: _db.py:119
GaudiConfig2._db.ConfigurablesDB.__init__
def __init__(self, modulename, root=None)
Definition: _db.py:108
GaudiConfig2._db.ConfigurablesDB._getEntries
def _getEntries(self)
Definition: _db.py:148
GaudiConfig2._configurables.makeConfigurableClass
def makeConfigurableClass(name, **namespace)
Definition: _configurables.py:328