home *** CD-ROM | disk | FTP | other *** search
/ PC Extra 07 & 08 / pca1507.iso / Software / psp8 / Data1.cab / log.py < prev    next >
Encoding:
Python Source  |  2003-04-22  |  5.0 KB  |  158 lines

  1. import _hotshot
  2. import os.path
  3. import parser
  4. import symbol
  5. import sys
  6.  
  7. from _hotshot import \
  8.      WHAT_ENTER, \
  9.      WHAT_EXIT, \
  10.      WHAT_LINENO, \
  11.      WHAT_DEFINE_FILE, \
  12.      WHAT_DEFINE_FUNC, \
  13.      WHAT_ADD_INFO
  14.  
  15.  
  16. __all__ = ["LogReader", "ENTER", "EXIT", "LINE"]
  17.  
  18.  
  19. ENTER = WHAT_ENTER
  20. EXIT  = WHAT_EXIT
  21. LINE  = WHAT_LINENO
  22.  
  23.  
  24. try:
  25.     StopIteration
  26. except NameError:
  27.     StopIteration = IndexError
  28.  
  29.  
  30. class LogReader:
  31.     def __init__(self, logfn):
  32.         # fileno -> filename
  33.         self._filemap = {}
  34.         # (fileno, lineno) -> filename, funcname
  35.         self._funcmap = {}
  36.  
  37.         self._reader = _hotshot.logreader(logfn)
  38.         self._nextitem = self._reader.next
  39.         self._info = self._reader.info
  40.         self._stack = []
  41.  
  42.     def addinfo(self, key, value):
  43.         """This method is called for each additional ADD_INFO record.
  44.  
  45.         This can be overridden by applications that want to receive
  46.         these events.  The default implementation does not need to be
  47.         called by alternate implementations.
  48.  
  49.         The initial set of ADD_INFO records do not pass through this
  50.         mechanism; this is only needed to receive notification when
  51.         new values are added.  Subclasses can inspect self._info after
  52.         calling LogReader.__init__().
  53.         """
  54.         pass
  55.  
  56.     # Iteration support:
  57.     # This adds an optional (& ignored) parameter to next() so that the
  58.     # same bound method can be used as the __getitem__() method -- this
  59.     # avoids using an additional method call which kills the performance.
  60.  
  61.     def next(self, index=0):
  62.         while 1:
  63.             try:
  64.                 what, tdelta, fileno, lineno = self._nextitem()
  65.             except TypeError:
  66.                 # logreader().next() returns None at the end
  67.                 self._reader.close()
  68.                 raise StopIteration()
  69.             if what == WHAT_DEFINE_FILE:
  70.                 self._filemap[fileno] = tdelta
  71.                 continue
  72.             if what == WHAT_DEFINE_FUNC:
  73.                 filename = self._filemap[fileno]
  74.                 self._funcmap[(fileno, lineno)] = (filename, tdelta)
  75.                 continue
  76.             if what == WHAT_ADD_INFO:
  77.                 # value already loaded into self.info; call the
  78.                 # overridable addinfo() handler so higher-level code
  79.                 # can pick up the new value
  80.                 self.addinfo(tdelta, lineno)
  81.                 continue
  82.             if what == WHAT_ENTER:
  83.                 t = self._decode_location(fileno, lineno)
  84.                 filename, funcname = t
  85.                 self._stack.append((filename, funcname, lineno))
  86.             elif what == WHAT_EXIT:
  87.                 filename, funcname, lineno = self._stack.pop()
  88.             else:
  89.                 filename, funcname, firstlineno = self._stack[-1]
  90.             return what, (filename, lineno, funcname), tdelta
  91.  
  92.     if sys.version < "2.2":
  93.         # Don't add this for newer Python versions; we only want iteration
  94.         # support, not general sequence support.
  95.         __getitem__ = next
  96.     else:
  97.         def __iter__(self):
  98.             return self
  99.  
  100.     #
  101.     #  helpers
  102.     #
  103.  
  104.     def _decode_location(self, fileno, lineno):
  105.         try:
  106.             return self._funcmap[(fileno, lineno)]
  107.         except KeyError:
  108.             #
  109.             # This should only be needed when the log file does not
  110.             # contain all the DEFINE_FUNC records needed to allow the
  111.             # function name to be retrieved from the log file.
  112.             #
  113.             if self._loadfile(fileno):
  114.                 filename = funcname = None
  115.             try:
  116.                 filename, funcname = self._funcmap[(fileno, lineno)]
  117.             except KeyError:
  118.                 filename = self._filemap.get(fileno)
  119.                 funcname = None
  120.                 self._funcmap[(fileno, lineno)] = (filename, funcname)
  121.         return filename, funcname
  122.  
  123.     def _loadfile(self, fileno):
  124.         try:
  125.             filename = self._filemap[fileno]
  126.         except KeyError:
  127.             print "Could not identify fileId", fileno
  128.             return 1
  129.         if filename is None:
  130.             return 1
  131.         absname = os.path.normcase(os.path.join(self.cwd, filename))
  132.  
  133.         try:
  134.             fp = open(absname)
  135.         except IOError:
  136.             return
  137.         st = parser.suite(fp.read())
  138.         fp.close()
  139.  
  140.         # Scan the tree looking for def and lambda nodes, filling in
  141.         # self._funcmap with all the available information.
  142.         funcdef = symbol.funcdef
  143.         lambdef = symbol.lambdef
  144.  
  145.         stack = [st.totuple(1)]
  146.  
  147.         while stack:
  148.             tree = stack.pop()
  149.             try:
  150.                 sym = tree[0]
  151.             except (IndexError, TypeError):
  152.                 continue
  153.             if sym == funcdef:
  154.                 self._funcmap[(fileno, tree[2][2])] = filename, tree[2][1]
  155.             elif sym == lambdef:
  156.                 self._funcmap[(fileno, tree[1][2])] = filename, "<lambda>"
  157.             stack.extend(list(tree[1:]))
  158.