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 algorithm 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
218 alg = algmgr.algorithm(algName)
222 if iface
is not None:
223 from GaudiPython.Bindings
import InterfaceCast
224 alg = InterfaceCast(iface).cast(alg)
228 if algName
in PyComponents.instances:
229 alg = PyComponents.instances[algName]
232 from AthenaPython
import PyAthena
233 setattr(PyAthena.algs, algName, alg)
241 import RootUtils.PyROOTFixes
243 try: RootUtils.PyROOTFixes.enable_pickling()
244 except Exception:
pass
245 from StoreGateBindings.Bindings
import StoreGateSvc
258 IIncidentSvc = cppyy.gbl.IIncidentSvc
260 IIncidentSvc._cpp_addListener = IIncidentSvc.addListener
261 def addListener (self, *args):
263 if hasattr (listener,
'_cppHandle'):
264 args = (listener._cppHandle,) + args[1:]
265 return self._cpp_addListener (*args)
266 addListener.__doc__ = IIncidentSvc._cpp_addListener.__doc__
267 IIncidentSvc.addListener = addListener
270 IIncidentSvc._cpp_removeListener = IIncidentSvc.removeListener
271 def removeListener (self, *args):
273 if hasattr (listener,
'_cppHandle'):
274 args = (listener._cppHandle,) + args[1:]
275 return self._cpp_removeListener (*args)
276 removeListener.__doc__ = IIncidentSvc._cpp_removeListener.__doc__
277 IIncidentSvc.removeListener = removeListener
290 IClassIDSvc = cppyy.gbl.IClassIDSvc
293 'DataHistory' : 83814411,
294 83814411 :
'DataHistory',
299 from CLIDComps.clidGenerator
import clidGenerator
300 IClassIDSvc._clidgen = clidGenerator(db=
None)
304 def _clid (self, name):
306 try: name = _clid_typename_aliases[name]
307 except KeyError:
pass
309 return _missing_clids[name]
310 except KeyError:
pass
311 return self._clidgen.getClidFromName(name)
312 IClassIDSvc.clid = _clid
319 return _missing_clids[clid]
322 return self._clidgen.getNameFromClid(clid)
323 IClassIDSvc.typename = _typename
338 ITHistSvc = cppyy.gbl.ITHistSvc
344 return self.__py_cache
345 except AttributeError:
346 self.__py_cache = dict()
347 return self.__py_cache
348 ITHistSvc._py_cache = _py_cache
352 ITHistSvc._cpp_regHist = ITHistSvc.regHist
353 ITHistSvc._cpp_regGraph = ITHistSvc.regGraph
354 ITHistSvc._cpp_regEfficiency = ITHistSvc.regEfficiency
355 ITHistSvc._cpp_regTree = ITHistSvc.regTree
357 def book(self, oid, obj=None, *args, **kw):
358 """book a histogram, profile or tree
359 @param oid is the unique object identifier even across streams,
361 @param obj either an already full-fledge constructed ROOT object
362 or None (then `*args` or `**kw` need to be correctly setup)
363 @param *args list of arguments to give to the constructor of the
364 ROOT object one wants to book
365 @param **kw a dictionary containing a key 'args' being the list of
366 arguments to the constructor of the ROOT objects one wants to
369 >>> th.book('/temp/1d/h1', 'TH1D', args=('h1','h1',100,0.,100.))
370 >>> th.book('/temp/1d/h2', ROOT.TH1D, args=('h2','h2',100,0.,100.))
371 >>> th.book('/temp/1d/h3', ROOT.TH1D, 'h3','h3',100,0.,100.)
372 >>> th.book('/temp/1d/h4', ROOT.TH1D('h4','h4',100,0.,100.))
373 >>> th.book('/temp/1d/h5', obj=ROOT.TH1D('h5','h5',100,0.,100.))
374 >>> th.book('/temp/1d/h6', klass='TH1D', args=('h6','h6',100,0.,100.))
376 >>> th.book('/temp/tree/t1', ROOT.TTree('t1','t1'))
377 >>> th.book('/temp/tree/t2', obj=ROOT.TTree('t2','t2'))
378 >>> th.book('/temp/tree/t3', klass='TTree', args=('t3','t3'))
380 _err =
"please provide _either_ an already constructed ROOT object or"\
381 "a class name/class type (with appropriate arguments)"
382 klass = kw.get(
'klass',
None)
383 assert not (obj
is None and klass
is None), _err
384 assert not (obj
is not None and klass
is not None), _err
386 if isinstance(obj, (str,type)):
390 if isinstance(obj, ROOT.TH1):
392 meth = self._cpp_regHist
393 elif isinstance(obj, (ROOT.TGraph,)):
394 meth = self._cpp_regGraph
395 elif isinstance(obj, (ROOT.TEfficiency,)):
396 meth = self._cpp_regEfficiency
397 elif isinstance(obj, (ROOT.TTree,)):
398 meth = self._cpp_regTree
400 raise TypeError(
"invalid type '%r'"%
type(obj))
401 if meth(oid, obj).isSuccess():
402 self._py_cache[oid]=obj
404 raise RuntimeError(
'could not book object [%r]'%obj)
407 if isinstance(klass, str):
408 klass = getattr(ROOT, klass)
410 return self.book(oid, obj=
klass(*args))
411 if kw
and 'args' in kw:
412 return self.book(oid, obj=
klass(*kw[
'args']))
413 err =
"invalid arguments: either provide a valid `*args` or "\
414 "a `**kw` containing a 'args' key"
415 raise RuntimeError(err)
416 raise RuntimeError(
"unforseen case: oid='%r' obj='%r' args='%r' "
417 "kw='%r'"%(oid,obj,args,kw))
419 ITHistSvc.book = book
421 def get(self, oid, klass=None):
422 """retrieve an already booked ROOT object.
423 If the object was booked on the C++ side, try to use the `klass` hint
424 (the usual string or type) to find the object in the correct 'folder'
425 (histograms, graphs or trees).
426 If `klass` is None, then go through all the folders iteratively (slow)
429 return self._py_cache[oid]
432 def _get_helper(klass, hsvc, meth, oid, update_cache=True):
433 makeNullPtr = ROOT.MakeNullPointer
434 o = makeNullPtr(klass)
435 if meth(oid, o).isSuccess():
437 hsvc._py_cache[oid] = o
441 if isinstance(klass, str):
442 klass = getattr(ROOT, klass)
443 if issubclass(klass, (ROOT.TH1,)):
444 return _get_helper(klass, self, self.getHist, oid)
445 if issubclass(klass, (ROOT.TGraph,)):
446 return _get_helper(klass, self, self.getGraph, oid)
447 if issubclass(klass, (ROOT.TEfficiency,)):
448 return _get_helper(klass, self, self.getEfficiency, oid)
449 if issubclass(klass, (ROOT.TTree,)):
450 return _get_helper(klass, self, self.getTree, oid)
451 raise RuntimeError(
'unsupported type [%r]'%klass)
457 oids = [n
for n
in self.getHists()
if n
not in self._py_cache.
keys()]
459 obj = _get_helper(ROOT.TH1, self, self.getHist, name,
463 klass = getattr(ROOT, obj.ClassName())
464 obj = _get_helper(klass, self, self.getHist, name)
467 oids = [n
for n
in self.getGraphs()
if n
not in self._py_cache.
keys()]
469 _get_helper(ROOT.TGraph, self, self.getGraph, name)
472 oids = [n
for n
in self.getEfficiencies()
if n
not in self._py_cache.
keys()]
474 _get_helper(ROOT.TEfficiency, self, self.getEfficiency, name)
477 oids = [n
for n
in self.getTrees()
if n
not in self._py_cache.
keys()]
479 _get_helper(ROOT.TTree, self, self.getTree, name)
482 return self._py_cache[oid]
487 def getitem(self, oid):
489 ITHistSvc.__getitem__ = getitem
492 def delitem(self, oid):
493 if isinstance(oid, str):
495 del self._py_cache[oid]
496 assert self.deReg(oid).isSuccess(), \
497 "could not remove object [%r]"%oid
499 ITHistSvc.__delitem__ = delitem
501 def setitem(self, k, v):
502 return self.book(k, obj=v)
503 ITHistSvc.__setitem__ = setitem
506 def regObject(self, regFcn, oid, oid_type=None):
507 """Helper method to register object 'oid' using 'regFcn'."""
508 if oid_type
is not None:
509 return self.book(oid,obj=oid_type)
510 if regFcn(self,oid).isSuccess():
513 err =
''.
join([
'invalid arguments oid=',
repr(oid),
' oid_type=',
515 raise ValueError(err)
517 ITHistSvc.regHist = partialmethod(regObject, ITHistSvc._cpp_regHist)
518 ITHistSvc.regTree = partialmethod(regObject, ITHistSvc._cpp_regTree)
519 ITHistSvc.regEfficiency = partialmethod(regObject, ITHistSvc._cpp_regEfficiency)
520 ITHistSvc.regGraph = partialmethod(regObject, ITHistSvc._cpp_regGraph)
523 def load(self, oid, oid_type):
524 """Helper method to load a given object `oid' from a stream, knowing
525 its type. `oid_type' is a string whose value is either:
526 - 'hist', to load any THx and TProfiles
527 - 'tree', to load TTrees
528 - 'efficiency', to load TEfficiency
529 - 'graph', to load TGraph and TGraphErrors
531 if oid_type ==
'hist':
532 return self.regHist(oid)
533 elif oid_type ==
'tree':
534 return self.regTree(oid)
535 elif oid_type ==
'efficiency':
536 return self.regEfficiency(oid)
537 elif oid_type ==
'graph':
538 return self.regGraph(oid)
540 raise ValueError(f
'oid_type (={oid_type}) MUST be one of hist, tree, efficiency, graph')
542 ITHistSvc.load = load
547 for n
in (
'__contains__',
551 'items',
'iteritems',
552 'iterkeys',
'itervalues',
555 def %s(self, *args, **kw):
556 return self._py_cache.%s(*args,**kw)
558 del %s""" % (n,n,n,n,n)
559 exec (code, globals(),locals())
563 return self
is not None
564 ITHistSvc.__bool__ = __bool__
569 assert self.deReg(obj).isSuccess(), \
570 "could not remove object [%r]"%k
576 k = self.iterkeys().
next()
577 return (k, self.pop(k))
578 ITHistSvc.popitem = popitem
606 ESI = cppyy.gbl.EventStreamInfo
608 PyESI= cppyy.gbl.PyEventStreamInfo
610 self._run_numbers = PyESI.runNumbers(self)
611 return list(self._run_numbers)
613 self._evt_types = PyESI.eventTypes(self)
614 return list(self._evt_types)
616 self._item_list = PyESI.itemList(self)
617 return list(tuple(i)
for i
in self._item_list)
618 def lumi_blocks(self):
619 self._lumi_blocks = PyESI.lumiBlockNumbers(self)
620 return list(self._lumi_blocks)
621 def processing_tags(self):
622 self._processing_tags = PyESI.processingTags(self)
623 return list(self._processing_tags)
624 for fct
in (
'run_numbers',
'evt_types',
'item_list',
625 'lumi_blocks',
'processing_tags'):
626 setattr(ESI, fct, locals()[fct])
638 cls = cppyy.gbl.EventType
639 cls.bit_mask_typecodes = [
640 (
'IS_DATA',
'IS_SIMULATION'),
641 (
'IS_ATLAS',
'IS_TESTBEAM'),
642 (
'IS_PHYSICS',
'IS_CALIBRATION'),
645 py_cls = cppyy.gbl.PyEventType
647 self._raw_bit_mask = py_cls.bit_mask(self)
648 return self._raw_bit_mask
649 cls.raw_bit_mask = property(raw_bit_mask)
651 def decode_bitmask(idx):
652 if len(self.raw_bit_mask) <= idx:
653 return self.bit_mask_typecodes[idx][0]
654 isa_idx = self.raw_bit_mask[idx]
655 return self.bit_mask_typecodes[idx][isa_idx]
656 bm = map(decode_bitmask,
657 range(len(self.bit_mask_typecodes)))
659 cls.bit_mask = property(bit_mask)
665 return _gen_data_link
670 return _gen_element_link
685 """helper method to easily instantiate a DataLink class.
686 Sensible default for the storage policy is chosen if none given (it usually
687 boils down to DataProxyStorage)
690 >>> DLink = PyAthena.DataLink('CompositeParticleContainer')
692 >>> cp = DLink('MyStoreGateKey')
694 ROOT = _import_ROOT ()
695 if isinstance(klass, str):
696 klass = getattr(ROOT, klass)
697 if storage_policy
is None:
698 storage_policy = ROOT.DataProxyStorage(klass)
699 return ROOT.DataLink(klass, storage_policy)
704 """helper method to easily instantiate an ElementLink class.
705 Sensible defaults for the storage and indexing policies are chosen if none
706 given (it usually boils down to DataProxyStorage and ForwardIndexingPolicy)
709 >>> CPLink = PyAthena.ElementLink('CompositeParticleContainer')
711 >>> EleLink = PyAthena.ElementLink(PyAthena.ElectronContainer)
714 ROOT = _import_ROOT ()
715 if isinstance(klass, str):
716 klass = getattr(ROOT, klass)
722 return ROOT.ElementLink(klass)
726 def _gen_elv(klass, storage_policy=None, indexing_policy=None):
727 """helper method to easily instantiate an ElementLinkVector class.
728 Sensible defaults for the storage and indexing policies are chosen if none
729 given (it usually boils down to DataProxyStorage and ForwardIndexingPolicy)
732 >>> IELV = PyAthena.ElementLinkVector('INavigable4MomentumCollection')
735 ROOT = _import_ROOT ()
736 if isinstance(klass, str):
737 klass = getattr(ROOT, klass)
738 if storage_policy
is None:
739 storage_policy = ROOT.DataProxyStorage(klass)
740 if indexing_policy
is None:
741 indexing_policy = ROOT.ForwardIndexingPolicy(klass)
742 return ROOT.ElementLinkVector(klass, storage_policy, indexing_policy)
747 """helper method to easily instantiate a NavigationToken class.
748 Sensible default for the weight and hash parameters are chosen if none are
752 >>> cls = PyAthena.NavigationToken('CaloCell')
755 ROOT = _import_ROOT ()
756 if isinstance(klass, str):
757 klass = getattr(ROOT, klass)
758 if weight_cls
is None:
759 weight_cls = getattr(ROOT,
'NavigationDefaults::DefaultWeight')
761 hash_cls = getattr(ROOT,
'SG::hash<const %s *>' % (klass.__name__,))
762 return ROOT.NavigationToken(klass, weight_cls, hash_cls)
767 return self.find(k) != self.end()
768 cls.__contains__ = __contains__
772 self.insert(itr, self.__class__.
value_type(k,v))
774 cls.__setitem__ = __setitem__
776 cls.__cxx_getitem__ = cls.__getitem__
781 return self.__cxx_getitem__(k)
782 cls.__getitem__ = __getitem__
784 if not hasattr(cls,
'__iter__'):
787 yield beg.__deref__()
792 for i
in toiter(self.begin(), self.end()):
794 cls.__iter__ = __iter__
813 cls.iterkeys = iterkeys
818 cls.itervalues = itervalues
822 yield (i.first, i.second)
823 cls.iteritems = iteritems
830 _register = _PyAthenaBindingsCatalog.register
831 _register(
'StoreGateSvc', _py_init_StoreGateSvc)
833 _register(
'IncidentSvc', _py_init_IIncidentSvc)
834 _register(
'IIncidentSvc', _py_init_IIncidentSvc)
836 _register(
'ClassIDSvc', _py_init_ClassIDSvc)
837 _register(
'IClassIDSvc', _py_init_ClassIDSvc)
839 _register(
'THistSvc', _py_init_THistSvc)
840 _register(
'ITHistSvc', _py_init_THistSvc)
842 _register(
'EventStreamInfo', _py_init_EventStreamInfo)
843 _register(
'EventType', _py_init_EventType)
845 _register(
'DataLink', _py_init_DataLink)
846 _register(
'ElementLink', _py_init_ElementLink)
847 _register(
'ElementLinkVector', _py_init_ElementLinkVector)