8 Sebastien Binet (binet@cern.ch)
12 from functools
import cache
17 """Helper function to remember which libraries have been already loaded
20 if not lib.startswith(lib):
22 return cppyy.load_library(lib)
27 ROOT.gROOT.SetBatch(
True)
34 _clid_typename_aliases = {
36 'vector<int>' :
'std::vector<int>',
37 'vector<unsigned int>' :
'std::vector<unsigned int>',
38 'vector<float>' :
'std::vector<float>',
39 'vector<double>' :
'std::vector<double>',
40 'string' :
'std::string',
43 'INavigable4MomentumCollection' :
'DataVector<INavigable4Momentum>',
44 'DataVector<IParticle>' :
'IParticleContainer',
45 'ParticleBaseContainer' :
'DataVector<ParticleBase>',
46 'TrackCollection' :
'DataVector<Trk::Track>',
47 'Trk::TrackCollection' :
'DataVector<Trk::Track>',
48 'DataVector<Track>' :
'TrackCollection',
49 'AthenaHitsVector<TrackRecord>' :
'TrackRecordCollection',
50 'Trk::SegmentCollection' :
'DataVector<Trk::Segment>',
56 """Placeholder class to register callbacks for 'pythonizations' of C++
58 FIXME: find a better mechanism ?
60 msg = logging.getLogger(
'AthenaBindingsCatalog')
65 """Register a class name `klass` with an initialization method.
66 If no callback method has been given, the default is to call:
70 if cb
is None: eval(
'cb = _py_init_%s'%klass )
71 except Exception
as err:
72 _msg = _PyAthenaBindingsCatalog.msg
73 _msg.error(
"Problem registering callback for [%s]", klass)
74 _msg.error(
"Exception: %s", err)
76 _PyAthenaBindingsCatalog.instances[klass] = cb
82 """Initialize the python binding with the callback previously registered
83 If no callback was registered, swallow the warning...
86 try: klass = _PyAthenaBindingsCatalog.instances[name]()
89 from AthenaServices.Dso
import registry
90 registry.load_type (name)
95 klass=getattr(cppyy.gbl,name)
96 except AttributeError:
97 raise AttributeError(
"no reflex-dict for type [%s]"%name)
102 def py_svc(svcName, createIf=True, iface=None):
104 Helper function to retrieve a service by name, using Gaudi python bindings.
105 @param svcName: the name of the service one wants to retrieve (possibly a
106 fully qualified name as in: 'MySvcClass/TheSvcName')
107 @param createIf: If True, the service will be created if it hasn't been yet
109 @param iface: type one wants to cast the service to (can be a string or the
113 s = svcName.split(
'/')
115 if len(s)==2: svcName=s[1]
118 from .Configurables
import PyComponents
119 if svcType
in _PyAthenaBindingsCatalog.instances:
120 pytype = _PyAthenaBindingsCatalog.init( svcType )
123 if iface
is None: iface = pytype
125 from GaudiPython.Bindings
import gbl,InterfaceCast
126 svcLocator = gbl.Gaudi.svcLocator()
127 svc = gbl.GaudiPython.Helper.service(svcLocator, fullName, createIf)
128 if svc
and not(iface
is None):
129 svc = InterfaceCast(iface).cast(svc)
133 if svcName
in PyComponents.instances:
134 svc = PyComponents.instances[svcName]
137 from AthenaPython
import PyAthena
138 setattr(PyAthena.services, svcName, svc)
143 def py_tool(toolName, createIf=True, iface=None):
145 Helper function to retrieve a tool (owned by the ToolSvc) by name, using
146 Gaudi python bindings.
147 @param toolName: the name of the tool one wants to retrieve (possibly a
148 fully qualified name as in: 'MyToolClass/TheToolName')
149 @param createIf: If True, the tool will be created if it hasn't been yet
151 @param iface: type one wants to cast the tool to (can be a string or the
155 ## retrieve default interface (ie: GaudiKernel/IAlgTool)
156 tool = py_tool('LArOnlDbPrepTool')
157 assert(type(tool) == cppyy.gbl.IAlgTool)
159 ## retrieve with specified interface
160 tool = py_tool('LArOnlDbPrepTool', iface='ILArOnlDbPrepTool')
161 assert(type(tool) == cppyy.gbl.ILArOnlDbPrepTool)
164 t = toolName.split(
'/')
166 if len(t)==2: toolName=t[1]
169 from .Configurables
import PyComponents
170 if toolType
in _PyAthenaBindingsCatalog.instances:
171 pytype = _PyAthenaBindingsCatalog.init( toolType )
174 if iface
is None: iface = pytype
176 from GaudiPython.Bindings
import gbl,InterfaceCast
177 _py_tool = gbl.GaudiPython.Helper.tool
178 toolSvc =
py_svc(
'ToolSvc', iface=
'IToolSvc')
179 tool = _py_tool(toolSvc, toolType, toolName, 0, createIf)
180 if tool
and not(iface
is None):
181 tool = InterfaceCast(iface).cast(tool)
185 if toolName
in PyComponents.instances:
186 tool = PyComponents.instances[toolName]
189 from AthenaPython
import PyAthena
190 setattr(PyAthena.services.ToolSvc, toolName, tool)
196 Helper function to retrieve an IAlgorithm (managed by the IAlgManager_) by
197 name, using Gaudi python bindings.
198 @param algName: the name of the algorithm's instance one wants to retrieve
200 @param iface: type one wants to cast the tool to (can be a string or the
204 ## retrieve default interface (ie: GaudiKernel/IAlgorithm)
205 alg = py_alg('McAodBuilder')
206 assert(type(alg) == cppyy.gbl.IAlgorithm)
208 ## retrieve with specified interface
209 alg = py_alg('McAodBuilder', iface='Algorithm')
210 assert(type(alg) == cppyy.gbl.Algorithm)
213 algmgr =
py_svc(
'ApplicationMgr',iface=
'IAlgManager')
215 msg = logging.getLogger(
'PyAthena.py_alg')
216 error =
'could not retrieve IAlgManager/ApplicationMgr'
218 raise RuntimeError (error)
221 from .Configurables
import PyComponents
223 alg = ROOT.MakeNullPointer(iface)
224 if not algmgr.getAlgorithm(algName, alg).isSuccess():
229 if algName
in PyComponents.instances:
230 alg = PyComponents.instances[algName]
233 from AthenaPython
import PyAthena
234 setattr(PyAthena.algs, algName, alg)
242 import RootUtils.PyROOTFixes
244 try: RootUtils.PyROOTFixes.enable_pickling()
245 except Exception:
pass
246 from StoreGateBindings.Bindings
import StoreGateSvc
259 IIncidentSvc = cppyy.gbl.IIncidentSvc
261 IIncidentSvc._cpp_addListener = IIncidentSvc.addListener
262 def addListener (self, *args):
264 if hasattr (listener,
'_cppHandle'):
265 args = (listener._cppHandle,) + args[1:]
266 return self._cpp_addListener (*args)
267 addListener.__doc__ = IIncidentSvc._cpp_addListener.__doc__
268 IIncidentSvc.addListener = addListener
271 IIncidentSvc._cpp_removeListener = IIncidentSvc.removeListener
272 def removeListener (self, *args):
274 if hasattr (listener,
'_cppHandle'):
275 args = (listener._cppHandle,) + args[1:]
276 return self._cpp_removeListener (*args)
277 removeListener.__doc__ = IIncidentSvc._cpp_removeListener.__doc__
278 IIncidentSvc.removeListener = removeListener
291 IClassIDSvc = cppyy.gbl.IClassIDSvc
294 'DataHistory' : 83814411,
295 83814411 :
'DataHistory',
300 from CLIDComps.clidGenerator
import clidGenerator
301 IClassIDSvc._clidgen = clidGenerator(db=
None)
305 def _clid (self, name):
307 try: name = _clid_typename_aliases[name]
308 except KeyError:
pass
310 return _missing_clids[name]
311 except KeyError:
pass
312 return self._clidgen.getClidFromName(name)
313 IClassIDSvc.clid = _clid
320 return _missing_clids[clid]
323 return self._clidgen.getNameFromClid(clid)
324 IClassIDSvc.typename = _typename
339 ITHistSvc = cppyy.gbl.ITHistSvc
345 return self.__py_cache
346 except AttributeError:
348 return self.__py_cache
349 ITHistSvc._py_cache = _py_cache
353 for n
in (
'Hist',
'Graph',
'Efficiency',
'Tree'):
354 code =
"ITHistSvc._cpp_reg%s = ITHistSvc.reg%s" % (n,n)
355 exec (code, globals(),locals())
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 =
'_cpp_regHist'
393 elif isinstance(obj, (ROOT.TGraph,)):
394 meth =
'_cpp_regGraph'
395 elif isinstance(obj, (ROOT.TEfficiency,)):
396 meth =
'_cpp_regEfficiency'
397 elif isinstance(obj, (ROOT.TTree,)):
398 meth =
'_cpp_regTree'
400 raise TypeError(
"invalid type '%r'"%
type(obj))
401 if getattr(self,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
507 for n
in (
'Hist',
'Graph',
'Efficiency',
'Tree'):
509 def reg%s(self, oid, oid_type=None):
510 if not (oid_type is None):
511 return self.book(oid,obj=oid_type)
512 if ITHistSvc._cpp_reg%s(self,oid).isSuccess():
515 err = ''.join(['invalid arguments oid=',repr(oid),' oid_type=',
517 raise ValueError(err)
518 ITHistSvc.reg%s = reg%s
519 del reg%s""" % (n,n,n,n,n)
520 exec (code, globals(),locals())
522 def load(self, oid, oid_type):
523 """Helper method to load a given object `oid' from a stream, knowing
524 its type. `oid_type' is a string whose value is either:
525 - 'hist', to load any THx and TProfiles
526 - 'tree', to load TTrees
527 - 'efficiency', to load TEfficiency
528 - 'graph', to load TGraph and TGraphErrors
530 _allowed_values = (
'hist',
'tree',
'efficiency',
'graph')
531 if oid_type
not in _allowed_values:
533 'oid_type (=%r) MUST be one of %r'%(oid_type,
536 return getattr(self,
'reg%s'%oid_type.capitalize())(oid)
537 ITHistSvc.load = load
542 for n
in (
'__contains__',
546 'items',
'iteritems',
547 'iterkeys',
'itervalues',
551 def %s(self, *args, **kw):
552 return self._py_cache.%s(*args,**kw)
554 del %s""" % (n,n,n,n,n)
555 exec (code, globals(),locals())
558 assert self.deReg(obj).isSuccess(), \
559 "could not remove object [%r]"%k
565 k = self.iterkeys().
next()
566 return (k, self.pop(k))
567 ITHistSvc.popitem = popitem
595 ESI = cppyy.gbl.EventStreamInfo
597 PyESI= cppyy.gbl.PyEventStreamInfo
599 self._run_numbers = PyESI.runNumbers(self)
600 return list(self._run_numbers)
602 self._evt_types = PyESI.eventTypes(self)
603 return list(self._evt_types)
605 self._item_list = PyESI.itemList(self)
606 return list(tuple(i)
for i
in self._item_list)
607 def lumi_blocks(self):
608 self._lumi_blocks = PyESI.lumiBlockNumbers(self)
609 return list(self._lumi_blocks)
610 def processing_tags(self):
611 self._processing_tags = PyESI.processingTags(self)
612 return list(self._processing_tags)
613 for fct
in (
'run_numbers',
'evt_types',
'item_list',
614 'lumi_blocks',
'processing_tags'):
615 setattr(ESI, fct, locals()[fct])
627 cls = cppyy.gbl.EventType
628 cls.bit_mask_typecodes = [
629 (
'IS_DATA',
'IS_SIMULATION'),
630 (
'IS_ATLAS',
'IS_TESTBEAM'),
631 (
'IS_PHYSICS',
'IS_CALIBRATION'),
634 py_cls = cppyy.gbl.PyEventType
636 self._raw_bit_mask = py_cls.bit_mask(self)
637 return self._raw_bit_mask
638 cls.raw_bit_mask = property(raw_bit_mask)
640 def decode_bitmask(idx):
641 if len(self.raw_bit_mask) <= idx:
642 return self.bit_mask_typecodes[idx][0]
643 isa_idx = self.raw_bit_mask[idx]
644 return self.bit_mask_typecodes[idx][isa_idx]
645 bm = map(decode_bitmask,
646 range(len(self.bit_mask_typecodes)))
648 cls.bit_mask = property(bit_mask)
654 return _gen_data_link
659 return _gen_element_link
674 """helper method to easily instantiate a DataLink class.
675 Sensible default for the storage policy is chosen if none given (it usually
676 boils down to DataProxyStorage)
679 >>> DLink = PyAthena.DataLink('CompositeParticleContainer')
681 >>> cp = DLink('MyStoreGateKey')
683 ROOT = _import_ROOT ()
684 if isinstance(klass, str):
685 klass = getattr(ROOT, klass)
686 if storage_policy
is None:
687 storage_policy = ROOT.DataProxyStorage(klass)
688 return ROOT.DataLink(klass, storage_policy)
693 """helper method to easily instantiate an ElementLink class.
694 Sensible defaults for the storage and indexing policies are chosen if none
695 given (it usually boils down to DataProxyStorage and ForwardIndexingPolicy)
698 >>> CPLink = PyAthena.ElementLink('CompositeParticleContainer')
700 >>> EleLink = PyAthena.ElementLink(PyAthena.ElectronContainer)
703 ROOT = _import_ROOT ()
704 if isinstance(klass, str):
705 klass = getattr(ROOT, klass)
711 return ROOT.ElementLink(klass)
715 def _gen_elv(klass, storage_policy=None, indexing_policy=None):
716 """helper method to easily instantiate an ElementLinkVector class.
717 Sensible defaults for the storage and indexing policies are chosen if none
718 given (it usually boils down to DataProxyStorage and ForwardIndexingPolicy)
721 >>> IELV = PyAthena.ElementLinkVector('INavigable4MomentumCollection')
724 ROOT = _import_ROOT ()
725 if isinstance(klass, str):
726 klass = getattr(ROOT, klass)
727 if storage_policy
is None:
728 storage_policy = ROOT.DataProxyStorage(klass)
729 if indexing_policy
is None:
730 indexing_policy = ROOT.ForwardIndexingPolicy(klass)
731 return ROOT.ElementLinkVector(klass, storage_policy, indexing_policy)
736 """helper method to easily instantiate a NavigationToken class.
737 Sensible default for the weight and hash parameters are chosen if none are
741 >>> cls = PyAthena.NavigationToken('CaloCell')
744 ROOT = _import_ROOT ()
745 if isinstance(klass, str):
746 klass = getattr(ROOT, klass)
747 if weight_cls
is None:
748 weight_cls = getattr(ROOT,
'NavigationDefaults::DefaultWeight')
750 hash_cls = getattr(ROOT,
'SG::hash<const %s *>' % (klass.__name__,))
751 return ROOT.NavigationToken(klass, weight_cls, hash_cls)
756 return self.find(k) != self.end()
757 cls.__contains__ = __contains__
761 self.insert(itr, self.__class__.
value_type(k,v))
763 cls.__setitem__ = __setitem__
765 cls.__cxx_getitem__ = cls.__getitem__
770 return self.__cxx_getitem__(k)
771 cls.__getitem__ = __getitem__
773 if not hasattr(cls,
'__iter__'):
776 yield beg.__deref__()
781 for i
in toiter(self.begin(), self.end()):
783 cls.__iter__ = __iter__
802 cls.iterkeys = iterkeys
807 cls.itervalues = itervalues
811 yield (i.first, i.second)
812 cls.iteritems = iteritems
819 _register = _PyAthenaBindingsCatalog.register
820 _register(
'StoreGateSvc', _py_init_StoreGateSvc)
822 _register(
'IncidentSvc', _py_init_IIncidentSvc)
823 _register(
'IIncidentSvc', _py_init_IIncidentSvc)
825 _register(
'ClassIDSvc', _py_init_ClassIDSvc)
826 _register(
'IClassIDSvc', _py_init_ClassIDSvc)
828 _register(
'THistSvc', _py_init_THistSvc)
829 _register(
'ITHistSvc', _py_init_THistSvc)
831 _register(
'EventStreamInfo', _py_init_EventStreamInfo)
832 _register(
'EventType', _py_init_EventType)
834 _register(
'DataLink', _py_init_DataLink)
835 _register(
'ElementLink', _py_init_ElementLink)
836 _register(
'ElementLinkVector', _py_init_ElementLinkVector)