| Classes | Job Modules | Data Objects | Services | Algorithms | Tools | Packages | Directories | Tracs |

In This Package:

Include.py

Go to the documentation of this file.
00001 # Stolen from:
00002 # File: AthenaCommon/python/Include.py
00003 # Author: Wim Lavrijsen (WLavrijsen@lbl.gov)
00004 # Lightly modified for Daya Bay by bv@bnl.gov Thu Sep 18 11:40:00 2008
00005 
00006 """
00007 Handle NuWa options file inclusion. Files are located through the
00008 JOBOPTPATH envar and globally executed. If requested, files will
00009 be traced. Note, however, that this option interferes with pdb and
00010 trace.
00011 """
00012 
00013 import os, sys, re, fnmatch, string
00014 import __main__
00015 
00016 from unixtools import FindFile
00017 
00018 
00019 ### data ---------------------------------------------------------------------
00020 __version__ = '1.3.0'
00021 __author__  = 'Wim Lavrijsen (WLavrijsen@lbl.gov)'
00022 
00023 __all__ = [ 'include', 'marker', 'lineMarker', 'fidMarker',
00024             'callMarker', 'returnMarker', 'activeMarker', 'silentMarker',
00025             'tracedMarker', 'tracePattern' ]
00026 
00027 marker       = ' -+-'
00028 __marker__   = ' -+-'
00029 silentMarker = ' '
00030 activeMarker = 'A'
00031 tracedMarker = 'T'
00032 callMarker   = 'C'
00033 returnMarker = 'R'
00034 lineMarker   = '%3d'
00035 fidMarker    = '%2d'
00036 
00037 # do not trace any files that fnmatch these names:
00038 excludeTracePattern = [
00039    '*/GaudiPython/*', '*/GaudiKernel/*',          # Gaudi framework files
00040    '*/InstallArea/*/DybPython/*',              # NuWa framework files
00041    '*/python%d.%d/*' % sys.version_info[:2],      # python system
00042    '*/InstallArea/python/*/*Conf.py' ]            # generated conf files
00043 
00044 # unless they are explicitly included here:
00045 includeTracePattern = [  ]
00046 
00047 
00048 ### logging and messages -----------------------------------------------------
00049 import logging
00050 log = logging.getLogger( 'NuWa' )
00051 
00052 class IncludeError( RuntimeError ):
00053    pass
00054 
00055 
00056 ### files locator ------------------------------------------------------------
00057 try:
00058    optionsPathEnv = os.environ[ 'JOBOPTPATH' ]
00059 except:
00060    optionsPathEnv = os.curdir
00061 
00062 optionsPath = re.split( ',|' + os.pathsep, optionsPathEnv )
00063 if '' in optionsPath:
00064    optionsPath[ optionsPath.index( '' ) ] = str(os.curdir)
00065 
00066 
00067 ### files inclusion ----------------------------------------------------------
00068 def basename2( fn ):
00069    return os.path.join( os.path.basename( os.path.dirname( fn ) ), os.path.basename( fn ) )
00070 
00071 _filecache = {}
00072 _linecache = {}
00073 _notrcache = {}
00074 
00075 class Include:
00076    fid = 0
00077 
00078    def __init__( self, show = 1 ):
00079       self._show = show
00080       self._once = []
00081       self._fcurrent = ''
00082 
00083    def setShowIncludes( self, show ):
00084       self._show = show
00085 
00086    def __call__( self, fn, *args, **kw ):
00087       """Include <fn> in the current scope by executing it globally."""
00088 
00089     # don't include file if not allowed (has to be exact match in py code)
00090       if fn in self._once:
00091          log.debug( 'file "%s" is blocked; not included', fn )
00092          return
00093 
00094     # locate the file
00095       name = FindFile( os.path.expanduser( os.path.expandvars( fn ) ), optionsPath, os.R_OK )
00096       if not name:
00097          name = FindFile( os.path.basename( fn ), optionsPath, os.R_OK )
00098          if name:
00099             log.warning( 'using %s instead of %s', name, fn )
00100          else:
00101             raise IncludeError( 'include file %s can not be found' % fn )
00102 
00103       log.debug( 'located %s as %s', fn, name )
00104 
00105     # print if 'show' is set to non-null
00106       show = self._show
00107       if 'show' in kw:
00108          show = kw[ 'show' ]
00109 
00110     # notify of start of file inclusion
00111       if show:
00112          log.info( 'including file "%s" with ID %d', fn, self.fid )
00113       else:
00114          log.info( 'including file "%s"', fn )
00115       self._fcurrent = name
00116 
00117     # actual inclusion
00118       if show and self._doTrace( name ):
00119        # traced
00120          _filecache[ name ] = open( name, 'r' ).readlines()
00121          _linecache[ name ] = 0, self.fid
00122          self.fid += 1
00123   
00124          sys.settrace( self._trace_include )
00125          execfile( name, __main__.__dict__, __main__.__dict__ )
00126          sys.settrace( sys._getframe(0).f_trace )
00127 
00128        # finish file printout
00129          ncur, fid = _linecache[ name ]
00130          buf  = _filecache[ name ]
00131          for i in range( ncur, len(buf) ):
00132             self._oneline( fid, i, silentMarker, buf )
00133 
00134          del _filecache[ name ]
00135          del _linecache[ name ]
00136 
00137          log.info( 'end of "%s"', fn )
00138 
00139       else:
00140        # non-traced
00141          execfile( name, __main__.__dict__, __main__.__dict__ )
00142 
00143    def block( self, fn ):
00144       """Disallow the given filename(s) from being included again."""
00145 
00146       if type(fn) == list:
00147          self._once += fn
00148       else:
00149          self._once.append( fn )
00150 
00151    def unblock( self, fn ):
00152       """Re-allow the given filename from being included."""
00153 
00154       self._once.remove( fn )
00155 
00156  # match files to trace ------------------------------------------------------
00157    def _doTrace( self, fn ):
00158     # Tracing into non-included files is controlled with two variables:
00159     # excludeTracePattern and includeTracePattern. The former goes first,
00160     # the latter can override any excluded results.
00161 
00162       if fn in _notrcache:
00163          return False
00164 
00165       doTrace = True
00166       for tracePattern in excludeTracePattern:
00167          if fnmatch.fnmatch( fn, tracePattern ):
00168             doTrace = False
00169             break
00170 
00171       if not doTrace:
00172          for tracePattern in includeTracePattern:
00173             if fnmatch.fnmatch( fn, tracePattern ):
00174                doTrace = True
00175                break
00176 
00177       if not os.path.exists( fn ):
00178          doTrace = False
00179 
00180       if not doTrace:
00181          _notrcache[ fn ] = 1
00182 
00183       return doTrace
00184 
00185  # code tracer ---------------------------------------------------------------
00186    def _trace_include( self, frame, event, arg ):
00187       fn  = frame.f_code.co_filename
00188 
00189       if not self._doTrace( fn ):
00190          return self._trace_include
00191 
00192       if not _filecache.has_key( fn ):
00193        # wait until importing of the module is done to minimize pollution
00194          f = frame.f_back
00195          while f is not None:
00196             try:
00197                if 'import' in _filecache[ f.f_code.co_filename ][ f.f_lineno ]:
00198                   return self._trace_include
00199             except:
00200                pass
00201             f = f.f_back
00202          del f
00203 
00204        # import is done, and we're back, accept this file from this point on
00205          _filecache[ fn ] = open( fn, 'r' ).readlines() or '\n'
00206          _linecache[ fn ] = sys.maxint, self.fid
00207          self.fid += 1
00208 
00209       lno = frame.f_lineno
00210       aln = lno - 1 > 0 and lno - 1 or 0
00211 
00212       ncur, fid = _linecache[ fn ]
00213       buf = _filecache[ fn ]
00214 
00215       if self._fcurrent != fn:
00216          log.info( 'continued trace of "%s"', basename2( fn ) )
00217          self._fcurrent = fn
00218 
00219       if event == 'line':
00220          for i in range( ncur, aln ):
00221             self._oneline( fid, i, silentMarker, buf )
00222 
00223          if ncur <= aln:
00224             self._oneline( fid, aln, activeMarker, buf )
00225          elif 0 <= aln:
00226             self._oneline( fid, aln, tracedMarker, buf )
00227 
00228          if ncur < lno:
00229             _linecache[ fn ] = lno, fid
00230 
00231       elif event == 'call':
00232          if lno < ncur:
00233             self._oneline( fid, aln, callMarker, buf )
00234 
00235       elif event == 'return':
00236          if lno < ncur:
00237             fln = frame.f_code.co_firstlineno - 1
00238             self._oneline( fid, fln, returnMarker, None )
00239 
00240       return self._trace_include
00241 
00242  # formatted line printer
00243    def _oneline( self, fid, lineno, detail, buf ):
00244       print marker, fidMarker % fid, lineMarker % lineno, detail,
00245 
00246     # simple eol case
00247       if not buf or not buf[ lineno ]:
00248          print
00249          return
00250 
00251     # in general, an interpreter "line" may be longer than a file line
00252       line = buf[ lineno ].rstrip()
00253       while line and ( line[-1] == '(' or line[-1] == '\\' ):
00254        # this line appears to have a continuation ...
00255          try:
00256           # output traced line
00257             print line
00258 
00259           # output continued line
00260             lineno += 1
00261             print marker, fidMarker % fid, lineMarker % lineno, detail,
00262             line = buf[ lineno ].rstrip()
00263          except IndexError:
00264           # shouldn't happen; but must mean that the diagnosis above is
00265           # wrong and that there is no continuation, keep silent
00266             break
00267 
00268       print line
00269 
00270 # use this for backward compatibility
00271 include = Include()
| Classes | Job Modules | Data Objects | Services | Algorithms | Tools | Packages | Directories | Tracs |

Generated on Mon Apr 11 20:13:00 2011 for DybPython by doxygen 1.4.7