7 __author__ =
"Sebastien Binet (binet@cern.ch)"
10 from functools
import cache, partialmethod
11 from AthenaCommon.Logging
import logging
15 """Helper function to remember which libraries have been already loaded
18 if not lib.startswith(lib):
20 return cppyy.load_library(lib)
25 ROOT.gROOT.SetBatch(
True)
32 _clid_typename_aliases = {
34 'vector<int>' :
'std::vector<int>',
35 'vector<unsigned int>' :
'std::vector<unsigned int>',
36 'vector<float>' :
'std::vector<float>',
37 'vector<double>' :
'std::vector<double>',
38 'string' :
'std::string',
41 'INavigable4MomentumCollection' :
'DataVector<INavigable4Momentum>',
42 'DataVector<IParticle>' :
'IParticleContainer',
43 'ParticleBaseContainer' :
'DataVector<ParticleBase>',
44 'TrackCollection' :
'DataVector<Trk::Track>',
45 'Trk::TrackCollection' :
'DataVector<Trk::Track>',
46 'DataVector<Track>' :
'TrackCollection',
47 'AthenaHitsVector<TrackRecord>' :
'TrackRecordCollection',
48 'Trk::SegmentCollection' :
'DataVector<Trk::Segment>',
54 """Placeholder class to register callbacks for 'pythonizations' of C++
56 FIXME: find a better mechanism ?
58 msg = logging.getLogger(
'AthenaBindingsCatalog')
63 """Register a class name `klass` with an initialization method.
64 If no callback method has been given, the default is to call:
68 if cb
is None: eval(
'cb = _py_init_%s'%klass )
69 except Exception
as err:
70 _msg = _PyAthenaBindingsCatalog.msg
71 _msg.error(
"Problem registering callback for [%s]", klass)
72 _msg.error(
"Exception: %s", err)
74 _PyAthenaBindingsCatalog.instances[klass] = cb
80 """Initialize the python binding with the callback previously registered
81 If no callback was registered, swallow the warning...
84 try: klass = _PyAthenaBindingsCatalog.instances[name]()
87 from AthenaServices.Dso
import registry
88 registry.load_type (name)
91 klass=getattr(cppyy.gbl,name)
92 except AttributeError:
93 raise AttributeError(
"no reflex-dict for type [%s]"%name)
98 def py_svc(svcName, createIf=True, iface=None):
100 Helper function to retrieve a service by name, using Gaudi python bindings.
101 @param svcName: the name of the service one wants to retrieve (possibly a
102 fully qualified name as in: 'MySvcClass/TheSvcName')
103 @param createIf: If True, the service will be created if it hasn't been yet
105 @param iface: type one wants to cast the service to (can be a string or the
109 s = svcName.split(
'/')
111 if len(s)==2: svcName=s[1]
114 from .Configurables
import PyComponents
115 if svcType
in _PyAthenaBindingsCatalog.instances:
116 pytype = _PyAthenaBindingsCatalog.init( svcType )
119 if iface
is None: iface = pytype
121 from GaudiPython.Bindings
import gbl,InterfaceCast
122 svcLocator = gbl.Gaudi.svcLocator()
123 svc = gbl.GaudiPython.Helper.service(svcLocator, fullName, createIf)
124 if svc
and not(iface
is None):
125 svc = InterfaceCast(iface).cast(svc)
129 if svcName
in PyComponents.instances:
130 svc = PyComponents.instances[svcName]
133 from AthenaPython
import PyAthena
134 setattr(PyAthena.services, svcName, svc)
139 def py_tool(toolName, createIf=True, iface=None):
141 Helper function to retrieve a tool (owned by the ToolSvc) by name, using
142 Gaudi python bindings.
143 @param toolName: the name of the tool one wants to retrieve (possibly a
144 fully qualified name as in: 'MyToolClass/TheToolName')
145 @param createIf: If True, the tool will be created if it hasn't been yet
147 @param iface: type one wants to cast the tool to (can be a string or the
151 ## retrieve default interface (ie: GaudiKernel/IAlgTool)
152 tool = py_tool('LArOnlDbPrepTool')
153 assert(type(tool) == cppyy.gbl.IAlgTool)
155 ## retrieve with specified interface
156 tool = py_tool('LArOnlDbPrepTool', iface='ILArOnlDbPrepTool')
157 assert(type(tool) == cppyy.gbl.ILArOnlDbPrepTool)
160 t = toolName.split(
'/')
162 if len(t)==2: toolName=t[1]
165 from .Configurables
import PyComponents
166 if toolType
in _PyAthenaBindingsCatalog.instances:
167 pytype = _PyAthenaBindingsCatalog.init( toolType )
170 if iface
is None: iface = pytype
172 from GaudiPython.Bindings
import gbl,InterfaceCast
173 _py_tool = gbl.GaudiPython.Helper.tool
174 toolSvc =
py_svc(
'ToolSvc', iface=
'IToolSvc')
175 tool = _py_tool(toolSvc, toolType, toolName, 0, createIf)
176 if tool
and not(iface
is None):
177 tool = InterfaceCast(iface).cast(tool)
181 if toolName
in PyComponents.instances:
182 tool = PyComponents.instances[toolName]
185 from AthenaPython
import PyAthena
186 setattr(PyAthena.services.ToolSvc, toolName, tool)
192 Helper function to retrieve an IAlgorithm (managed by the IAlgManager_) by
193 name, using Gaudi python bindings.
194 @param algName: the name of the algorithm's instance one wants to retrieve
196 @param iface: type one wants to cast the tool to (can be a string or the
200 ## retrieve default interface (ie: GaudiKernel/IAlgorithm)
201 alg = py_alg('McAodBuilder')
202 assert(type(alg) == cppyy.gbl.IAlgorithm)
204 ## retrieve with specified interface
205 alg = py_alg('McAodBuilder', iface='Algorithm')
206 assert(type(alg) == cppyy.gbl.Algorithm)
209 algmgr =
py_svc(
'ApplicationMgr',iface=
'IAlgManager')
211 msg = logging.getLogger(
'PyAthena.py_alg')
212 error =
'could not retrieve IAlgManager/ApplicationMgr'
214 raise RuntimeError (error)
217 from .Configurables
import PyComponents
219 alg = ROOT.MakeNullPointer(iface)
220 if not algmgr.getAlgorithm(algName, alg).isSuccess():
225 if algName
in PyComponents.instances:
226 alg = PyComponents.instances[algName]
229 from AthenaPython
import PyAthena
230 setattr(PyAthena.algs, algName, alg)
238 import RootUtils.PyROOTFixes
240 try: RootUtils.PyROOTFixes.enable_pickling()
241 except Exception:
pass
242 from StoreGateBindings.Bindings
import StoreGateSvc
255 IIncidentSvc = cppyy.gbl.IIncidentSvc
257 IIncidentSvc._cpp_addListener = IIncidentSvc.addListener
258 def addListener (self, *args):
260 if hasattr (listener,
'_cppHandle'):
261 args = (listener._cppHandle,) + args[1:]
262 return self._cpp_addListener (*args)
263 addListener.__doc__ = IIncidentSvc._cpp_addListener.__doc__
264 IIncidentSvc.addListener = addListener
267 IIncidentSvc._cpp_removeListener = IIncidentSvc.removeListener
268 def removeListener (self, *args):
270 if hasattr (listener,
'_cppHandle'):
271 args = (listener._cppHandle,) + args[1:]
272 return self._cpp_removeListener (*args)
273 removeListener.__doc__ = IIncidentSvc._cpp_removeListener.__doc__
274 IIncidentSvc.removeListener = removeListener
287 IClassIDSvc = cppyy.gbl.IClassIDSvc
290 'DataHistory' : 83814411,
291 83814411 :
'DataHistory',
296 from CLIDComps.clidGenerator
import clidGenerator
297 IClassIDSvc._clidgen = clidGenerator(db=
None)
301 def _clid (self, name):
303 try: name = _clid_typename_aliases[name]
304 except KeyError:
pass
306 return _missing_clids[name]
307 except KeyError:
pass
308 return self._clidgen.getClidFromName(name)
309 IClassIDSvc.clid = _clid
316 return _missing_clids[clid]
319 return self._clidgen.getNameFromClid(clid)
320 IClassIDSvc.typename = _typename
335 ITHistSvc = cppyy.gbl.ITHistSvc
341 return self.__py_cache
342 except AttributeError:
343 self.__py_cache = dict()
344 return self.__py_cache
345 ITHistSvc._py_cache = _py_cache
349 ITHistSvc._cpp_regHist = ITHistSvc.regHist
350 ITHistSvc._cpp_regGraph = ITHistSvc.regGraph
351 ITHistSvc._cpp_regEfficiency = ITHistSvc.regEfficiency
352 ITHistSvc._cpp_regTree = ITHistSvc.regTree
354 def book(self, oid, obj=None, *args, **kw):
355 """book a histogram, profile or tree
356 @param oid is the unique object identifier even across streams,
358 @param obj either an already full-fledge constructed ROOT object
359 or None (then `*args` or `**kw` need to be correctly setup)
360 @param *args list of arguments to give to the constructor of the
361 ROOT object one wants to book
362 @param **kw a dictionary containing a key 'args' being the list of
363 arguments to the constructor of the ROOT objects one wants to
366 >>> th.book('/temp/1d/h1', 'TH1D', args=('h1','h1',100,0.,100.))
367 >>> th.book('/temp/1d/h2', ROOT.TH1D, args=('h2','h2',100,0.,100.))
368 >>> th.book('/temp/1d/h3', ROOT.TH1D, 'h3','h3',100,0.,100.)
369 >>> th.book('/temp/1d/h4', ROOT.TH1D('h4','h4',100,0.,100.))
370 >>> th.book('/temp/1d/h5', obj=ROOT.TH1D('h5','h5',100,0.,100.))
371 >>> th.book('/temp/1d/h6', klass='TH1D', args=('h6','h6',100,0.,100.))
373 >>> th.book('/temp/tree/t1', ROOT.TTree('t1','t1'))
374 >>> th.book('/temp/tree/t2', obj=ROOT.TTree('t2','t2'))
375 >>> th.book('/temp/tree/t3', klass='TTree', args=('t3','t3'))
377 _err =
"please provide _either_ an already constructed ROOT object or"\
378 "a class name/class type (with appropriate arguments)"
379 klass = kw.get(
'klass',
None)
380 assert not (obj
is None and klass
is None), _err
381 assert not (obj
is not None and klass
is not None), _err
383 if isinstance(obj, (str,type)):
387 if isinstance(obj, ROOT.TH1):
389 meth = self._cpp_regHist
390 elif isinstance(obj, (ROOT.TGraph,)):
391 meth = self._cpp_regGraph
392 elif isinstance(obj, (ROOT.TEfficiency,)):
393 meth = self._cpp_regEfficiency
394 elif isinstance(obj, (ROOT.TTree,)):
395 meth = self._cpp_regTree
397 raise TypeError(
"invalid type '%r'"%
type(obj))
398 if meth(oid, obj).isSuccess():
399 self._py_cache[oid]=obj
401 raise RuntimeError(
'could not book object [%r]'%obj)
404 if isinstance(klass, str):
405 klass = getattr(ROOT, klass)
407 return self.book(oid, obj=
klass(*args))
408 if kw
and 'args' in kw:
409 return self.book(oid, obj=
klass(*kw[
'args']))
410 err =
"invalid arguments: either provide a valid `*args` or "\
411 "a `**kw` containing a 'args' key"
412 raise RuntimeError(err)
413 raise RuntimeError(
"unforseen case: oid='%r' obj='%r' args='%r' "
414 "kw='%r'"%(oid,obj,args,kw))
416 ITHistSvc.book = book
418 def get(self, oid, klass=None):
419 """retrieve an already booked ROOT object.
420 If the object was booked on the C++ side, try to use the `klass` hint
421 (the usual string or type) to find the object in the correct 'folder'
422 (histograms, graphs or trees).
423 If `klass` is None, then go through all the folders iteratively (slow)
426 return self._py_cache[oid]
429 def _get_helper(klass, hsvc, meth, oid, update_cache=True):
430 makeNullPtr = ROOT.MakeNullPointer
431 o = makeNullPtr(klass)
432 if meth(oid, o).isSuccess():
434 hsvc._py_cache[oid] = o
438 if isinstance(klass, str):
439 klass = getattr(ROOT, klass)
440 if issubclass(klass, (ROOT.TH1,)):
441 return _get_helper(klass, self, self.getHist, oid)
442 if issubclass(klass, (ROOT.TGraph,)):
443 return _get_helper(klass, self, self.getGraph, oid)
444 if issubclass(klass, (ROOT.TEfficiency,)):
445 return _get_helper(klass, self, self.getEfficiency, oid)
446 if issubclass(klass, (ROOT.TTree,)):
447 return _get_helper(klass, self, self.getTree, oid)
448 raise RuntimeError(
'unsupported type [%r]'%klass)
454 oids = [n
for n
in self.getHists()
if n
not in self._py_cache.
keys()]
456 obj = _get_helper(ROOT.TH1, self, self.getHist, name,
460 klass = getattr(ROOT, obj.ClassName())
461 obj = _get_helper(klass, self, self.getHist, name)
464 oids = [n
for n
in self.getGraphs()
if n
not in self._py_cache.
keys()]
466 _get_helper(ROOT.TGraph, self, self.getGraph, name)
469 oids = [n
for n
in self.getEfficiencies()
if n
not in self._py_cache.
keys()]
471 _get_helper(ROOT.TEfficiency, self, self.getEfficiency, name)
474 oids = [n
for n
in self.getTrees()
if n
not in self._py_cache.
keys()]
476 _get_helper(ROOT.TTree, self, self.getTree, name)
479 return self._py_cache[oid]
484 def getitem(self, oid):
486 ITHistSvc.__getitem__ = getitem
489 def delitem(self, oid):
490 if isinstance(oid, str):
492 del self._py_cache[oid]
493 assert self.deReg(oid).isSuccess(), \
494 "could not remove object [%r]"%oid
496 ITHistSvc.__delitem__ = delitem
498 def setitem(self, k, v):
499 return self.book(k, obj=v)
500 ITHistSvc.__setitem__ = setitem
503 def regObject(self, regFcn, oid, oid_type=None):
504 """Helper method to register object 'oid' using 'regFcn'."""
505 if oid_type
is not None:
506 return self.book(oid,obj=oid_type)
507 if regFcn(self,oid).isSuccess():
510 err =
''.
join([
'invalid arguments oid=',
repr(oid),
' oid_type=',
512 raise ValueError(err)
514 ITHistSvc.regHist = partialmethod(regObject, ITHistSvc._cpp_regHist)
515 ITHistSvc.regTree = partialmethod(regObject, ITHistSvc._cpp_regTree)
516 ITHistSvc.regEfficiency = partialmethod(regObject, ITHistSvc._cpp_regEfficiency)
517 ITHistSvc.regGraph = partialmethod(regObject, ITHistSvc._cpp_regGraph)
520 def load(self, oid, oid_type):
521 """Helper method to load a given object `oid' from a stream, knowing
522 its type. `oid_type' is a string whose value is either:
523 - 'hist', to load any THx and TProfiles
524 - 'tree', to load TTrees
525 - 'efficiency', to load TEfficiency
526 - 'graph', to load TGraph and TGraphErrors
528 if oid_type ==
'hist':
529 return self.regHist(oid)
530 elif oid_type ==
'tree':
531 return self.regTree(oid)
532 elif oid_type ==
'efficiency':
533 return self.regEfficiency(oid)
534 elif oid_type ==
'graph':
535 return self.regGraph(oid)
537 raise ValueError(f
'oid_type (={oid_type}) MUST be one of hist, tree, efficiency, graph')
539 ITHistSvc.load = load
544 for n
in (
'__contains__',
548 'items',
'iteritems',
549 'iterkeys',
'itervalues',
552 def %s(self, *args, **kw):
553 return self._py_cache.%s(*args,**kw)
555 del %s""" % (n,n,n,n,n)
556 exec (code, globals(),locals())
560 return self
is not None
561 ITHistSvc.__bool__ = __bool__
566 assert self.deReg(obj).isSuccess(), \
567 "could not remove object [%r]"%k
573 k = self.iterkeys().
next()
574 return (k, self.pop(k))
575 ITHistSvc.popitem = popitem
603 ESI = cppyy.gbl.EventStreamInfo
605 PyESI= cppyy.gbl.PyEventStreamInfo
607 self._run_numbers = PyESI.runNumbers(self)
608 return list(self._run_numbers)
610 self._evt_types = PyESI.eventTypes(self)
611 return list(self._evt_types)
613 self._item_list = PyESI.itemList(self)
614 return list(tuple(i)
for i
in self._item_list)
615 def lumi_blocks(self):
616 self._lumi_blocks = PyESI.lumiBlockNumbers(self)
617 return list(self._lumi_blocks)
618 def processing_tags(self):
619 self._processing_tags = PyESI.processingTags(self)
620 return list(self._processing_tags)
621 for fct
in (
'run_numbers',
'evt_types',
'item_list',
622 'lumi_blocks',
'processing_tags'):
623 setattr(ESI, fct, locals()[fct])
635 cls = cppyy.gbl.EventType
636 cls.bit_mask_typecodes = [
637 (
'IS_DATA',
'IS_SIMULATION'),
638 (
'IS_ATLAS',
'IS_TESTBEAM'),
639 (
'IS_PHYSICS',
'IS_CALIBRATION'),
642 py_cls = cppyy.gbl.PyEventType
644 self._raw_bit_mask = py_cls.bit_mask(self)
645 return self._raw_bit_mask
646 cls.raw_bit_mask = property(raw_bit_mask)
648 def decode_bitmask(idx):
649 if len(self.raw_bit_mask) <= idx:
650 return self.bit_mask_typecodes[idx][0]
651 isa_idx = self.raw_bit_mask[idx]
652 return self.bit_mask_typecodes[idx][isa_idx]
653 bm = map(decode_bitmask,
654 range(len(self.bit_mask_typecodes)))
656 cls.bit_mask = property(bit_mask)
662 return _gen_data_link
667 return _gen_element_link
682 """helper method to easily instantiate a DataLink class.
683 Sensible default for the storage policy is chosen if none given (it usually
684 boils down to DataProxyStorage)
687 >>> DLink = PyAthena.DataLink('CompositeParticleContainer')
689 >>> cp = DLink('MyStoreGateKey')
691 ROOT = _import_ROOT ()
692 if isinstance(klass, str):
693 klass = getattr(ROOT, klass)
694 if storage_policy
is None:
695 storage_policy = ROOT.DataProxyStorage(klass)
696 return ROOT.DataLink(klass, storage_policy)
701 """helper method to easily instantiate an ElementLink class.
702 Sensible defaults for the storage and indexing policies are chosen if none
703 given (it usually boils down to DataProxyStorage and ForwardIndexingPolicy)
706 >>> CPLink = PyAthena.ElementLink('CompositeParticleContainer')
708 >>> EleLink = PyAthena.ElementLink(PyAthena.ElectronContainer)
711 ROOT = _import_ROOT ()
712 if isinstance(klass, str):
713 klass = getattr(ROOT, klass)
719 return ROOT.ElementLink(klass)
723 def _gen_elv(klass, storage_policy=None, indexing_policy=None):
724 """helper method to easily instantiate an ElementLinkVector class.
725 Sensible defaults for the storage and indexing policies are chosen if none
726 given (it usually boils down to DataProxyStorage and ForwardIndexingPolicy)
729 >>> IELV = PyAthena.ElementLinkVector('INavigable4MomentumCollection')
732 ROOT = _import_ROOT ()
733 if isinstance(klass, str):
734 klass = getattr(ROOT, klass)
735 if storage_policy
is None:
736 storage_policy = ROOT.DataProxyStorage(klass)
737 if indexing_policy
is None:
738 indexing_policy = ROOT.ForwardIndexingPolicy(klass)
739 return ROOT.ElementLinkVector(klass, storage_policy, indexing_policy)
744 """helper method to easily instantiate a NavigationToken class.
745 Sensible default for the weight and hash parameters are chosen if none are
749 >>> cls = PyAthena.NavigationToken('CaloCell')
752 ROOT = _import_ROOT ()
753 if isinstance(klass, str):
754 klass = getattr(ROOT, klass)
755 if weight_cls
is None:
756 weight_cls = getattr(ROOT,
'NavigationDefaults::DefaultWeight')
758 hash_cls = getattr(ROOT,
'SG::hash<const %s *>' % (klass.__name__,))
759 return ROOT.NavigationToken(klass, weight_cls, hash_cls)
764 return self.find(k) != self.end()
765 cls.__contains__ = __contains__
769 self.insert(itr, self.__class__.
value_type(k,v))
771 cls.__setitem__ = __setitem__
773 cls.__cxx_getitem__ = cls.__getitem__
778 return self.__cxx_getitem__(k)
779 cls.__getitem__ = __getitem__
781 if not hasattr(cls,
'__iter__'):
784 yield beg.__deref__()
789 for i
in toiter(self.begin(), self.end()):
791 cls.__iter__ = __iter__
810 cls.iterkeys = iterkeys
815 cls.itervalues = itervalues
819 yield (i.first, i.second)
820 cls.iteritems = iteritems
827 _register = _PyAthenaBindingsCatalog.register
828 _register(
'StoreGateSvc', _py_init_StoreGateSvc)
830 _register(
'IncidentSvc', _py_init_IIncidentSvc)
831 _register(
'IIncidentSvc', _py_init_IIncidentSvc)
833 _register(
'ClassIDSvc', _py_init_ClassIDSvc)
834 _register(
'IClassIDSvc', _py_init_ClassIDSvc)
836 _register(
'THistSvc', _py_init_THistSvc)
837 _register(
'ITHistSvc', _py_init_THistSvc)
839 _register(
'EventStreamInfo', _py_init_EventStreamInfo)
840 _register(
'EventType', _py_init_EventType)
842 _register(
'DataLink', _py_init_DataLink)
843 _register(
'ElementLink', _py_init_ElementLink)
844 _register(
'ElementLinkVector', _py_init_ElementLinkVector)