Trace exceptions,traceexceptions,#!/usr/bin/e


#!/usr/bin/env python# $Id: trace.py,v 1.9 1999/08/20 20:44:24 skip Exp $## Copyright 1995-1997, Automatrix, Inc., all rights reserved.# Author: Skip Montanaro## Copyright 1991-1995, Stichting Mathematisch Centrum, all rights reserved.## Permission to use, copy, modify, and distribute this Python software and# its associated documentation for any purpose without fee is hereby# granted, provided that the above copyright notice appears in all copies,# and that both that copyright notice and this permission notice appear in# supporting documentation, and that the name of Automatrix not be used in# advertising or publicity pertaining to distribution of the software# without specific, written prior permission.## Summary of recent changes:#   Added run-time display of statements being executed#   Incorporated portability and performance fixes from Greg Stein#   Incorporated main program from Michael Scharf# Sample use:#    # create a StatementCoverage object, telling it where you want output#    t = trace.StatementCoverage('/usr/local/Automatrix/concerts/coverage')#    # run the application or function#    t.run('main()')#    # generate annotated listings, excluding several system modules#    t.list(exclude_list=['regsub.py', 'string.py', 'copy.py',#        'traceback.py'])import sys, timefrom string import split, rstripclass StatementCoverage:    # by default, any coverage files are written in the current    # directory    def __init__(self, dir = '.', verbose=0, dotimes=0):  import marshal, os, stat  self.tracedir = dir  self.docounts = (not verbose)  self.files = {'<string>': None}  status = os.stat(self.tracedir)  if not stat.S_ISDIR(status[stat.ST_MODE]):      import tempfile      d = tempfile.gettempdir()      sys.stderr.write('%s: %s is not a directory - using %s instead...\n' %           (__name__, self.tracedir, d))      self.tracedir = d      self.counts = {}  self.counts_file = os.path.join(self.tracedir, 'counts')  try:      self.counts = marshal.load(open(self.counts_file, 'rb'))  except IOError:      self.counts = {}  self.dotimes = dotimes  self.time = time.clock()  self.last_key = None    # straight from profile.py    def run(self, cmd):  import __main__  dict = __main__.__dict__  self.runctx(cmd, dict, dict)    # from profile.py, with obvious changes    def runctx(self, cmd, globals=None, locals=None):  if globals is None: globals = {}  if locals is None: locals = {}  sys.settrace(self.trace)  try:      exec cmd in globals, locals  finally:      sys.settrace(None)    def runfunc(self, func, *args, **kw):  result = None  sys.settrace(self.trace)  try:      result = apply(func, args, kw)  finally:      sys.settrace(None)  return result    # thanks to Greg Stein for speeding this up somewhat...    def trace(self, frame, why, arg):  if why == 'line':      if self.docounts:    if self.dotimes and self.last_key is not None:        # time increment is for the previous line        newt = time.clock()        count, t = self.counts[self.last_key]        t = t + newt - self.time        self.counts[self.last_key] = count, t        self.time = time.clock()    # counter is for this line    key = self.last_key = \          (frame.f_code.co_filename, frame.f_lineno)    try:        count, t = self.counts[key]    except KeyError:        count, t = (0, 0.0)    count = count+1    self.counts[key] = (count, t)      else:    # display the current line being executed...    fname = frame.f_code.co_filename    line = frame.f_lineno    files = self.files    if fname != '<string>' and not files.has_key(fname):        try:      files[fname] = map(rstrip, open(fname).readlines())        except IOError:      files[fname] = None    if files[fname] != None:        print '%s(%d): %s' % (split(fname, '/')[-1], line,           files[fname][line-1])    else:        print '%s(%d): ??' % (split(fname, '/')[-1], line)  return self.trace    # create an annotated listing file for each Python module.    # note that statements like    #   for i in range(len(foo)): foo[i] = foo[i] + 1    # count both the for statement and the assignment statement.    # this is only a small nit for my purposes.   if you are    # so inclined, feel free to correct things    #    # use exclude_list to exclude modules from being listed    #    def list(self, exclude_list=[]):  from string import split, join, expandtabs  import stat, sys, marshal, os, regex  marshal.dump(self.counts, open(self.counts_file, 'wb'))  per_file = { }  for fname, lineno in self.counts.keys():      try:    lines_hit = per_file[fname]      except KeyError:    lines_hit = per_file[fname] = { }      lines_hit[lineno] = self.counts[(fname, lineno)]  blank = regex.compile('[ \t\r\n]*\(\|#.*\)$')  for fname in per_file.keys():      if fname == '<string>' or os.path.basename(fname) in exclude_list:    continue      try:    lines = open(fname, 'r').readlines()      except IOError:    sys.stderr.write('%s: Could not open %s for reading - skipping\n' %           (__name__, fname))    continue      lines_hit = per_file[fname]      # build list file name by appending 'l' to filename component of      # input and tacking it onto the trace directory      file = os.path.join(self.tracedir, os.path.basename(fname) + 'l')      try:    out = open(file, 'w')      except IOError:    sys.stderr.write('%s: Could not open %s for writing - skipping\n' %           (__name__, file))    continue      for i in range(len(lines)):    line = lines[i]    # do the blank/comment match to try to mark more lines    # (help the reader find stuff that hasn't been covered)    if lines_hit.has_key(i+1):        count, t = lines_hit[i+1]        # count precedes the lines that we captured        if self.dotimes:      out.write('%5d(%7.3fs): ' % (count, t))        else:      out.write('%5d: ' % count)    elif blank.match(line) != -1:        # blank lines and comments are preceded by dots        out.write('    .          ')    else:        # lines preceded by no marks weren't hit        out.write('#'*16)    out.write(expandtabs(lines[i], 8))      out.close()def main():    import os    # split the args into two parts    dir='.'    verbose=0    dotimes=0    n=len(sys.argv)    if n==1:  sys.stderr.write('%s [-v] [-d directory] program {arg}\n'%sys.argv[0])  sys.exit(-1)    i=1    while i<n:  arg=sys.argv[i]  if arg=='-d':      i=i+1      dir=arg=sys.argv[i]  elif arg=='-v':      verbose=1  elif arg=='-t':      dotimes=1  else:      break  i=i+1    prog_argv=sys.argv[i:]    # set the sys.argv    sys.argv=prog_argv    # set the first entry of path to the path of the    # main program    progname=prog_argv[0]    if eval(sys.version[:3])>1.3:  sys.path[0]=os.path.split(progname)[0]    tracer=StatementCoverage(dir,verbose,dotimes)    tracer.run('execfile(' + 'progname' + ')')if __name__=='__main__':    main()

评论关闭