PYTHON   6

ROOT.py

Guest on 20th July 2021 02:49:08 PM

  1. from __future__ import generators
  2. # @(#)root/pyroot:$Id: ROOT.py  wlav $
  3. # Author: Wim Lavrijsen (WLavrijsen@lbl.gov)
  4.  
  5.  
  6. """PyROOT user module.
  7.  
  8. o) install lazy ROOT class/variable lookup as appropriate
  9. o) feed gSystem and gInterpreter for display updates
  10. o) add readline completion (if supported by python build)
  11. o) enable some ROOT/CINT style commands
  12. o) handle a few special cases such as gPad, STL, etc.
  13. o) execute rootlogon.py/.C scripts
  14.  
  15. """
  16.  
  17. __version__ = '6.0.1'
  18. __author__  = 'Wim Lavrijsen (WLavrijsen@lbl.gov)'
  19.  
  20.  
  21. ### system and interpreter setup ------------------------------------------------
  22. import os, sys, types
  23. import string as pystring
  24.  
  25. ## there's no version_info in 1.5.2
  26. if sys.version[0:3] < '2.2':
  27.    raise ImportError, 'Python Version 2.2 or above is required.'
  28.  
  29. ## 2.2 has 10 instructions as default, > 2.3 has 100 ... make same
  30. if sys.version[0:3] == '2.2':
  31.    sys.setcheckinterval( 100 )
  32.  
  33. ## readline support, if available
  34. try:
  35.    import rlcompleter, readline
  36.  
  37.    class FileNameCompleter( rlcompleter.Completer ):
  38.       def file_matches( self, text ):
  39.          matches = []
  40.          path, name = os.path.split( text )
  41.  
  42.          try:
  43.             for fn in os.listdir( path or os.curdir ):
  44.                if fn[:len(name)] == name:
  45.                   full = os.path.join( path, fn )
  46.                   matches.append( full )
  47.  
  48.                   if os.path.isdir( full ):
  49.                      matches += map( lambda x: os.path.join( full, x ), os.listdir( full ) )
  50.          except OSError:
  51.             pass
  52.  
  53.          return matches
  54.  
  55.       def global_matches( self, text ):
  56.          matches = rlcompleter.Completer.global_matches( self, text )
  57.          if not matches:
  58.             matches = []
  59.          return matches + self.file_matches( text )
  60.  
  61.    readline.set_completer( FileNameCompleter().complete )
  62.    readline.set_completer_delims(
  63.       pystring.replace( readline.get_completer_delims(), os.sep , '' ) )
  64.  
  65.    readline.parse_and_bind( 'tab: complete' )
  66.    readline.parse_and_bind( 'set show-all-if-ambiguous On' )
  67. except:
  68.  # module readline typically doesn't exist on non-Unix platforms
  69.    pass
  70.  
  71. ## special filter on MacOS X (warnings caused by linking that is still required)
  72. if sys.platform == 'darwin':
  73.    import warnings
  74.    warnings.filterwarnings( action='ignore', category=RuntimeWarning, module='ROOT',\
  75.       message='class \S* already in TClassTable$' )
  76.  
  77. ### load PyROOT C++ extension module, special case for linux and Sun ------------
  78. needsGlobal =  ( 0 <= pystring.find( sys.platform, 'linux' ) ) or\
  79.                ( 0 <= pystring.find( sys.platform, 'sunos' ) )
  80. if needsGlobal:
  81.  # change dl flags to load dictionaries from pre-linked .so's
  82.    dlflags = sys.getdlopenflags()
  83.    sys.setdlopenflags( 0x100 | 0x2 )    # RTLD_GLOBAL | RTLD_NOW
  84.  
  85. import libPyROOT as _root
  86.  
  87. # reset dl flags if needed
  88. if needsGlobal:
  89.    sys.setdlopenflags( dlflags )
  90. del needsGlobal
  91.  
  92. ## convince 2.2 it's ok to use the expand function
  93. if sys.version[0:3] == '2.2':
  94.    import copy_reg
  95.    copy_reg.constructor( _root._ObjectProxy__expand__ )
  96.  
  97. ## convince inspect that PyROOT method proxies are possible drop-ins for python
  98. ## methods and classes for pydoc
  99. import inspect
  100.  
  101. inspect._old_isfunction = inspect.isfunction
  102. def isfunction( object ):
  103.    if type(object) == _root.MethodProxy and not object.im_class:
  104.       return True
  105.    return inspect._old_isfunction( object )
  106. inspect.isfunction = isfunction
  107.  
  108. inspect._old_ismethod = inspect.ismethod
  109. def ismethod( object ):
  110.    if type(object) == _root.MethodProxy:
  111.       return True
  112.    return inspect._old_ismethod( object )
  113. inspect.ismethod = ismethod
  114.  
  115. del isfunction, ismethod
  116.  
  117.  
  118. ### configuration ---------------------------------------------------------------
  119. class _Configuration( object ):
  120.    __slots__ = [ 'IgnoreCommandLineOptions', 'StartGuiThread', '_gts' ]
  121.  
  122.    def __init__( self ):
  123.       self.IgnoreCommandLineOptions = 0
  124.       self.StartGuiThread = 1
  125.       self._gts = []
  126.  
  127.    def __setGTS( self, value ):
  128.       for c in value:
  129.          if not callable( c ):
  130.             raise ValueError( '"%s" is not callable' % str(c) );
  131.       self._gts = value
  132.  
  133.    def __getGTS( self ):
  134.       return self._gts
  135.  
  136.    GUIThreadScheduleOnce = property( __getGTS, __setGTS )
  137.  
  138. PyConfig = _Configuration()
  139. del _Configuration
  140.  
  141.  
  142. ### choose interactive-favored policies -----------------------------------------
  143. _root.SetMemoryPolicy( _root.kMemoryHeuristics )
  144. _root.SetSignalPolicy( _root.kSignalSafe )
  145.  
  146.  
  147. ### data ________________________________________________________________________
  148. __pseudo__all__ = [ 'gROOT', 'gSystem', 'gInterpreter',
  149.                     'AddressOf', 'MakeNullPointer', 'Template', 'std' ]
  150. __all__         = []                         # purposedly empty
  151.  
  152. _orig_ehook = sys.excepthook
  153.  
  154. ## for setting memory and speed policies; not exported
  155. _memPolicyAPI = [ 'SetMemoryPolicy', 'SetOwnership', 'kMemoryHeuristics', 'kMemoryStrict' ]
  156. _sigPolicyAPI = [ 'SetSignalPolicy', 'kSignalFast', 'kSignalSafe' ]
  157.  
  158.  
  159. ### helpers ---------------------------------------------------------------------
  160. def split( str ):
  161.    npos = pystring.find( str, ' ' )
  162.    if 0 <= npos:
  163.       return str[:npos], str[npos+1:]
  164.    else:
  165.       return str, ''
  166.  
  167.  
  168. ### template support ------------------------------------------------------------
  169. class Template:
  170.    def __init__( self, name ):
  171.       self.__name__ = name
  172.  
  173.    def __call__( self, *args ):
  174.       newargs = [ self.__name__[ 0 <= self.__name__.find( 'std::' ) and 5 or 0:] ]
  175.       for arg in args:
  176.          if type(arg) == str:
  177.             arg = pystring.join(
  178.                map( lambda x: pystring.strip(x), pystring.split(arg,',') ), ',' )
  179.          newargs.append( arg )
  180.       result = _root.MakeRootTemplateClass( *newargs )
  181.  
  182.     # special case pythonization (builtin_map is not available from the C-API)
  183.       if hasattr( result, 'push_back' ):
  184.          def iadd( self, ll ):
  185.             map( self.push_back, ll )
  186.             return self
  187.  
  188.          result.__iadd__ = iadd
  189.  
  190.       return result
  191.  
  192. _root.Template = Template
  193.  
  194.  
  195. ### scope place holder for STL classes ------------------------------------------
  196. class std:
  197.    stlclasses = ( 'complex', 'exception', 'pair', \
  198.       'deque', 'list', 'queue', 'stack', 'vector', 'map', 'multimap', 'set', 'multiset' )
  199.  
  200.    for name in stlclasses:
  201.       exec '%(name)s = Template( "std::%(name)s" )' % { 'name' : name }
  202.  
  203.    string = _root.MakeRootClass( 'string' )
  204.  
  205. _root.std = std
  206.  
  207.  
  208. ### special cases for gPad, gVirtualX (are C++ macro's) -------------------------
  209. class _ExpandMacroFunction( object ):
  210.    def __init__( self, klass, func ):
  211.       c = _root.MakeRootClass( klass )
  212.       self.func = getattr( c, func )
  213.  
  214.    def __getattr__( self, what ):
  215.       return getattr( self.__dict__[ 'func' ](), what )
  216.  
  217.    def __cmp__( self, other ):
  218.       return cmp( self.func(), other )
  219.  
  220.    def __len__( self ):
  221.       if self.func():
  222.          return 1
  223.       return 0
  224.  
  225. _root.gPad      = _ExpandMacroFunction( "TVirtualPad", "Pad" )
  226. _root.gVirtualX = _ExpandMacroFunction( "TVirtualX",   "Instance" )
  227.  
  228.  
  229. ### special case pythonization --------------------------------------------------
  230. def _TTree__iter__( self ):
  231.    i = 0
  232.    while self.GetEntry(i):
  233.       yield self                   # TODO: not sure how to do this w/ C-API ...
  234.       i += 1
  235.  
  236. _root.MakeRootClass( "TTree" ).__iter__    = _TTree__iter__
  237.  
  238.  
  239. ### RINT command emulation ------------------------------------------------------
  240. def _excepthook( exctype, value, traceb ):
  241.  # catch syntax errors only (they contain the full line)
  242.    if isinstance( value, SyntaxError ) and value.text:
  243.       cmd, arg = split( value.text[:-1] )
  244.  
  245.     # mimic ROOT/CINT commands
  246.       if cmd == '.q':
  247.          sys.exit( 0 )
  248.       elif cmd == '.?' or cmd == '.help':
  249.          print """PyROOT emulation of CINT commands.
  250. All emulated commands must be preceded by a . (dot).
  251. ===========================================================================
  252. Help:        ?         : this help
  253.             help      : this help
  254. Shell:       ![shell]  : execute shell command
  255. Evaluation:  x [file]  : load [file] and evaluate {statements} in the file
  256. Load/Unload: L [lib]   : load [lib]
  257. Quit:        q         : quit python session
  258.  
  259. The standard python help system is available through a call to 'help()' or
  260. 'help(<id>)' where <id> is an identifier, e.g. a class or function such as
  261. TPad or TPad.cd, etc."""
  262.          return
  263.       elif cmd == '.!' and arg:
  264.          return os.system( arg )
  265.       elif cmd == '.x' and arg:
  266.          import __main__
  267.          fn = os.path.expanduser( os.path.expandvars( arg ) )
  268.          execfile( fn, __main__.__dict__, __main__.__dict__ )
  269.          return
  270.       elif cmd == '.L':
  271.          return _root.gSystem.Load( arg )
  272.       elif cmd == '.cd' and arg:
  273.          os.chdir( arg )
  274.          return
  275.       elif cmd == '.ls':
  276.          return sys.modules[ __name__ ].gDirectory.ls()
  277.       elif cmd == '.pwd':
  278.          return sys.modules[ __name__ ].gDirectory.pwd()
  279.    elif isinstance( value, SyntaxError ) and \
  280.       value.msg == "can't assign to function call":
  281.          print """Are you trying to assign a value to a reference return, for example to the
  282. result of a call to "double& SMatrix<>::operator()(int,int)"? If so, then
  283. please use operator[] instead, as in e.g. "mymatrix[i,j] = somevalue".
  284. """
  285.  
  286.  # normal exception processing
  287.    _orig_ehook( exctype, value, traceb )
  288.  
  289. if not __builtins__.has_key( '__IPYTHON__' ):
  290.  # IPython has its own ways of executing shell commands etc.
  291.    sys.excepthook = _excepthook
  292.  
  293.  
  294. ### call EndOfLineAction after each interactive command (to update display etc.)
  295. _orig_dhook = sys.displayhook
  296. def _displayhook( v ):
  297.    _root.gInterpreter.EndOfLineAction()
  298.    return _orig_dhook( v )
  299.  
  300.  
  301. ### helper to prevent GUIs from starving
  302. def _processRootEvents( controller ):
  303.    import time
  304.    gSystemProcessEvents = _root.gSystem.ProcessEvents
  305.  
  306.    while controller.keeppolling:
  307.       try:
  308.          gSystemProcessEvents()
  309.          if PyConfig.GUIThreadScheduleOnce:
  310.             for guicall in PyConfig.GUIThreadScheduleOnce:
  311.                guicall()
  312.             PyConfig.GUIThreadScheduleOnce = []
  313.          time.sleep( 0.01 )
  314.       except: # in case gSystem gets destroyed early on exit
  315.          pass
  316.  
  317.  
  318. ### allow loading ROOT classes as attributes ------------------------------------
  319. class ModuleFacade( types.ModuleType ):
  320.    def __init__( self, module ):
  321.       types.ModuleType.__init__( self, 'ROOT' )
  322.  
  323.       self.__dict__[ 'module' ]   = module
  324.  
  325.       self.__dict__[ '__doc__'  ] = self.module.__doc__
  326.       self.__dict__[ '__name__' ] = self.module.__name__
  327.  
  328.       self.__dict__[ 'keeppolling' ] = 0
  329.       self.__dict__[ 'PyConfig' ]    = self.module.PyConfig
  330.  
  331.       class gROOTWrapper( object ):
  332.          def __init__( self, gROOT, master ):
  333.             self.__dict__[ '_gROOT' ]  = gROOT
  334.             self.__dict__[ '_master' ] = master
  335.  
  336.          def __getattr__( self, name ):
  337.            if name != 'SetBatch' and self._master.__dict__[ 'gROOT' ] != self._gROOT:
  338.               self._master._ModuleFacade__finalSetup()
  339.               del self._master.__class__._ModuleFacade__finalSetup
  340.               self._master.__dict__[ 'gROOT' ] = self._gROOT
  341.            return getattr( self._gROOT, name )
  342.  
  343.          def __setattr__( self, name, value ):
  344.            return setattr( self._gROOT, name, value )
  345.              
  346.       self.__dict__[ 'gROOT' ] = gROOTWrapper( _root.gROOT, self )
  347.  
  348.     # begin with startup gettattr/setattr
  349.       self.__class__.__getattr__ = self.__class__.__getattr1
  350.       del self.__class__.__getattr1
  351.       self.__class__.__setattr__ = self.__class__.__setattr1
  352.       del self.__class__.__setattr1
  353.  
  354.    def __setattr1( self, name, value ):      # "start-up" setattr
  355.     # create application, thread etc.
  356.       self.__finalSetup()
  357.       del self.__class__.__finalSetup
  358.  
  359.     # let "running" setattr handle setting
  360.       return setattr( self, name, value )
  361.  
  362.    def __setattr2( self, name, value ):     # "running" getattr
  363.     # to allow assignments to ROOT globals such as ROOT.gDebug
  364.       if not name in self.__dict__:
  365.          try:
  366.           # assignment to an existing ROOT global (establishes proxy)
  367.             setattr( self.__class__, name, _root.GetRootGlobal( name ) )
  368.          except LookupError:
  369.           # allow a few limited cases where new globals can be set
  370.             tcnv = { bool        : 'bool %s = %d;',
  371.                      int         : 'int %s = %d;',
  372.                      long        : 'long %s = %d;',
  373.                      float       : 'double %s = %f;',
  374.                      str         : 'string %s = "%s";' }
  375.             try:
  376.                _root.gROOT.ProcessLine( tcnv[ type(value) ] % (name,value) );
  377.                setattr( self.__class__, name, _root.GetRootGlobal( name ) )
  378.             except KeyError:
  379.                pass           # can still assign normally, to the module
  380.  
  381.     # actual assignment through descriptor, or normal python way
  382.       return super( self.__class__, self ).__setattr__( name, value )
  383.  
  384.    def __getattr1( self, name ):             # "start-up" getattr
  385.     # special case, to allow "from ROOT import gROOT" w/o starting GUI thread
  386.       if name == '__path__':
  387.          raise AttributeError( name )
  388.  
  389.     # create application, thread etc.
  390.       self.__finalSetup()
  391.       del self.__class__.__finalSetup
  392.  
  393.     # let "running" getattr handle lookup
  394.       return getattr( self, name )
  395.  
  396.    def __getattr2( self, name ):             # "running" getattr
  397.     # handle "from ROOT import *" ... can be called multiple times
  398.       if name == '__all__':
  399.          caller = sys.modules[ sys._getframe( 1 ).f_globals[ '__name__' ] ]
  400.  
  401.        # we may be calling in from __getattr1, verify and if so, go one frame up
  402.          if caller == self:
  403.             caller = sys.modules[ sys._getframe( 2 ).f_globals[ '__name__' ] ]
  404.  
  405.        # setup the pre-defined globals
  406.          for name in self.module.__pseudo__all__:
  407.             caller.__dict__[ name ] = getattr( _root, name )
  408.  
  409.        # install the hook
  410.          _root.SetRootLazyLookup( caller.__dict__ )
  411.  
  412.        # return empty list, to prevent further copying
  413.          return self.module.__all__
  414.  
  415.     # lookup into ROOT (which may cause python-side enum/class/global creation)
  416.       attr = _root.LookupRootEntity( name )
  417.  
  418.     # the call above will raise AttributeError as necessary; so if we get here,
  419.     # attr is valid: cache as appropriate, so we don't come back
  420.       if type(attr) == _root.PropertyProxy:
  421.          setattr( self.__class__, name, attr )         # descriptor
  422.          return getattr( self, name )
  423.       else:
  424.          self.__dict__[ name ] = attr                  # normal member
  425.          return attr
  426.  
  427.     # reaching this point means failure ...
  428.       raise AttributeError( name )
  429.  
  430.    def __delattr__( self, name ):
  431.     # this is for convenience, as typically lookup results are kept at two places
  432.       try:
  433.          delattr( self.module._root, name )
  434.       except AttributeError:
  435.          pass
  436.  
  437.       return super( self.__class__, self ).__delattr__( name )
  438.  
  439.    def __finalSetup( self ):
  440.     # switch to running gettattr/setattr
  441.       self.__class__.__getattr__ = self.__class__.__getattr2
  442.       del self.__class__.__getattr2
  443.       self.__class__.__setattr__ = self.__class__.__setattr2
  444.       del self.__class__.__setattr2
  445.  
  446.     # normally, you'll want a ROOT application; don't init any further if
  447.     # one pre-exists from some C++ code somewhere
  448.       if PyConfig.IgnoreCommandLineOptions:
  449.          argv = sys.argv
  450.          sys.argv = []
  451.  
  452.       appc = _root.MakeRootClass( 'PyROOT::TPyROOTApplication' )
  453.       if appc.CreatePyROOTApplication():
  454.          appc.InitROOTGlobals()
  455.          appc.InitCINTMessageCallback();
  456.          appc.InitROOTMessageCallback();
  457.  
  458.       if PyConfig.IgnoreCommandLineOptions:
  459.          sys.argv = argv
  460.  
  461.     # must be called after gApplication creation:
  462.       if __builtins__.has_key( '__IPYTHON__' ):
  463.        # IPython's FakeModule hack otherwise prevents usage of python from CINT
  464.          _root.gROOT.ProcessLine( 'TPython::Exec( "" )' )
  465.          sys.modules[ '__main__' ].__builtins__ = __builtins__
  466.  
  467.     # custom logon file (must be after creation of ROOT globals)
  468.       if not '-n' in sys.argv:
  469.          rootlogon = os.path.expanduser( '~/.rootlogon.py' )
  470.          if os.path.exists( rootlogon ):
  471.           # could also have used execfile, but import is likely to give fewer surprises
  472.             import imp
  473.             imp.load_module( 'rootlogon', open( rootlogon, 'r' ), rootlogon, ('.py','r',1) )
  474.             del imp
  475.          else:  # if the .py version of rootlogon exists, the .C is ignored (the user can
  476.                 # load the .C from the .py, if so desired)
  477.  
  478.           # system logon, user logon, and local logon (skip Rint.Logon)
  479.             name = '.rootlogon.C'
  480.             logons = [ os.path.join( self.gRootDir, 'etc', 'system' + name ),
  481.                        os.path.expanduser( os.path.join( '~', name ) ) ]
  482.             if logons[-1] != os.path.join( os.getcwd(), name ):
  483.                logons.append( name )
  484.             for rootlogon in logons:
  485.                if os.path.exists( rootlogon ):
  486.                   appc.ExecuteFile( rootlogon )
  487.             del rootlogon, logons
  488.  
  489.     # root thread, if needed, to prevent GUIs from starving, as needed
  490.       if self.PyConfig.StartGuiThread and \
  491.             not ( self.keeppolling or _root.gROOT.IsBatch() ):
  492.          import threading
  493.          self.__dict__[ 'keeppolling' ] = 1
  494.          self.__dict__[ 'PyGUIThread' ] = \
  495.             threading.Thread( None, _processRootEvents, None, ( self, ) )
  496.  
  497.          def _finishSchedule( ROOT = self ):
  498.             import threading
  499.             if threading.currentThread() != self.PyGUIThread:
  500.                while self.PyConfig.GUIThreadScheduleOnce:
  501.                   self.PyGUIThread.join( 0.1 )
  502.  
  503.          self.PyGUIThread.finishSchedule = _finishSchedule
  504.          self.PyGUIThread.setDaemon( 1 )
  505.          self.PyGUIThread.start()
  506.  
  507.     # store already available ROOT objects to prevent spurious lookups
  508.       for name in self.module.__pseudo__all__ + _memPolicyAPI + _sigPolicyAPI:
  509.          self.__dict__[ name ] = getattr( _root, name )
  510.  
  511.       for name in std.stlclasses:
  512.          setattr( _root, name, getattr( std, name ) )
  513.  
  514.     # set the display hook
  515.       sys.displayhook = _displayhook
  516.  
  517.  
  518. sys.modules[ __name__ ] = ModuleFacade( sys.modules[ __name__ ] )
  519. del ModuleFacade
  520.  
  521.  
  522. ### b/c of circular references, the facade needs explicit cleanup ---------------
  523. import atexit
  524. def cleanup():
  525.  # restore hooks
  526.    import sys
  527.    sys.displayhook = sys.__displayhook__
  528.    if not __builtins__.has_key( '__IPYTHON__' ):
  529.       sys.excepthook = sys.__excepthook__
  530.  
  531.    facade = sys.modules[ __name__ ]
  532.  
  533.  # prevent spurious lookups into ROOT libraries
  534.    del facade.__class__.__getattr__
  535.    del facade.__class__.__setattr__
  536.  
  537.  # shutdown GUI thread, as appropriate
  538.    if hasattr( facade, 'PyGUIThread' ):
  539.       facade.keeppolling = 0
  540.  
  541.     # if not shutdown from GUI (often the case), wait for it
  542.       import threading
  543.       if threading.currentThread() != facade.PyGUIThread:
  544.          facade.PyGUIThread.join( 3. )                 # arbitrary
  545.       del threading
  546.  
  547.  # remove otherwise (potentially) circular references
  548.    import types
  549.    for k, v in facade.module.__dict__.items():
  550.       if type(v) == types.ModuleType:
  551.          del facade.module.__dict__[ k ]
  552.    del v, k, types
  553.  
  554.  # destroy facade
  555.    del sys.modules[ __name__ ], facade
  556.  
  557.  # run part the gROOT shutdown sequence ... running it here ensures that
  558.  # it is done before any ROOT libraries are off-loaded, with unspecified
  559.  # order of static object destruction; so far it only seemed needed for
  560.  # sockets with PROOF, whereas files should not be touched this early ...
  561.    gROOT = sys.modules[ 'libPyROOT' ].gROOT
  562.    if gROOT.GetListOfSockets():
  563.       gROOT.GetListOfSockets().Delete()
  564.    del gROOT
  565.  
  566.  # cleanup cached python strings
  567.    sys.modules[ 'libPyROOT' ]._DestroyPyStrings()
  568.  
  569.  # destroy ROOT extension module
  570.    del sys.modules[ 'libPyROOT' ]
  571.  
  572. atexit.register( cleanup )
  573. del cleanup, atexit

Raw Paste


Login or Register to edit or fork this paste. It's free.