PyXR

c:\python24\lib \ trace.py



0001 #!/usr/bin/env python
0002 
0003 # portions copyright 2001, Autonomous Zones Industries, Inc., all rights...
0004 # err...  reserved and offered to the public under the terms of the
0005 # Python 2.2 license.
0006 # Author: Zooko O'Whielacronx
0007 # http://zooko.com/
0008 # mailto:zooko@zooko.com
0009 #
0010 # Copyright 2000, Mojam Media, Inc., all rights reserved.
0011 # Author: Skip Montanaro
0012 #
0013 # Copyright 1999, Bioreason, Inc., all rights reserved.
0014 # Author: Andrew Dalke
0015 #
0016 # Copyright 1995-1997, Automatrix, Inc., all rights reserved.
0017 # Author: Skip Montanaro
0018 #
0019 # Copyright 1991-1995, Stichting Mathematisch Centrum, all rights reserved.
0020 #
0021 #
0022 # Permission to use, copy, modify, and distribute this Python software and
0023 # its associated documentation for any purpose without fee is hereby
0024 # granted, provided that the above copyright notice appears in all copies,
0025 # and that both that copyright notice and this permission notice appear in
0026 # supporting documentation, and that the name of neither Automatrix,
0027 # Bioreason or Mojam Media be used in advertising or publicity pertaining to
0028 # distribution of the software without specific, written prior permission.
0029 #
0030 """program/module to trace Python program or function execution
0031 
0032 Sample use, command line:
0033   trace.py -c -f counts --ignore-dir '$prefix' spam.py eggs
0034   trace.py -t --ignore-dir '$prefix' spam.py eggs
0035   trace.py --trackcalls spam.py eggs
0036 
0037 Sample use, programmatically
0038    # create a Trace object, telling it what to ignore, and whether to
0039    # do tracing or line-counting or both.
0040    trace = trace.Trace(ignoredirs=[sys.prefix, sys.exec_prefix,], trace=0,
0041                        count=1)
0042    # run the new command using the given trace
0043    trace.run('main()')
0044    # make a report, telling it where you want output
0045    r = trace.results()
0046    r.write_results(show_missing=True)
0047 """
0048 
0049 import linecache
0050 import os
0051 import re
0052 import sys
0053 import threading
0054 import token
0055 import tokenize
0056 import types
0057 import gc
0058 
0059 try:
0060     import cPickle
0061     pickle = cPickle
0062 except ImportError:
0063     import pickle
0064 
0065 def usage(outfile):
0066     outfile.write("""Usage: %s [OPTIONS] <file> [ARGS]
0067 
0068 Meta-options:
0069 --help                Display this help then exit.
0070 --version             Output version information then exit.
0071 
0072 Otherwise, exactly one of the following three options must be given:
0073 -t, --trace           Print each line to sys.stdout before it is executed.
0074 -c, --count           Count the number of times each line is executed
0075                       and write the counts to <module>.cover for each
0076                       module executed, in the module's directory.
0077                       See also `--coverdir', `--file', `--no-report' below.
0078 -l, --listfuncs       Keep track of which functions are executed at least
0079                       once and write the results to sys.stdout after the
0080                       program exits.
0081 -T, --trackcalls      Keep track of caller/called pairs and write the
0082                       results to sys.stdout after the program exits.
0083 -r, --report          Generate a report from a counts file; do not execute
0084                       any code.  `--file' must specify the results file to
0085                       read, which must have been created in a previous run
0086                       with `--count --file=FILE'.
0087 
0088 Modifiers:
0089 -f, --file=<file>     File to accumulate counts over several runs.
0090 -R, --no-report       Do not generate the coverage report files.
0091                       Useful if you want to accumulate over several runs.
0092 -C, --coverdir=<dir>  Directory where the report files.  The coverage
0093                       report for <package>.<module> is written to file
0094                       <dir>/<package>/<module>.cover.
0095 -m, --missing         Annotate executable lines that were not executed
0096                       with '>>>>>> '.
0097 -s, --summary         Write a brief summary on stdout for each file.
0098                       (Can only be used with --count or --report.)
0099 
0100 Filters, may be repeated multiple times:
0101 --ignore-module=<mod> Ignore the given module and its submodules
0102                       (if it is a package).
0103 --ignore-dir=<dir>    Ignore files in the given directory (multiple
0104                       directories can be joined by os.pathsep).
0105 """ % sys.argv[0])
0106 
0107 PRAGMA_NOCOVER = "#pragma NO COVER"
0108 
0109 # Simple rx to find lines with no code.
0110 rx_blank = re.compile(r'^\s*(#.*)?$')
0111 
0112 class Ignore:
0113     def __init__(self, modules = None, dirs = None):
0114         self._mods = modules or []
0115         self._dirs = dirs or []
0116 
0117         self._dirs = map(os.path.normpath, self._dirs)
0118         self._ignore = { '<string>': 1 }
0119 
0120     def names(self, filename, modulename):
0121         if self._ignore.has_key(modulename):
0122             return self._ignore[modulename]
0123 
0124         # haven't seen this one before, so see if the module name is
0125         # on the ignore list.  Need to take some care since ignoring
0126         # "cmp" musn't mean ignoring "cmpcache" but ignoring
0127         # "Spam" must also mean ignoring "Spam.Eggs".
0128         for mod in self._mods:
0129             if mod == modulename:  # Identical names, so ignore
0130                 self._ignore[modulename] = 1
0131                 return 1
0132             # check if the module is a proper submodule of something on
0133             # the ignore list
0134             n = len(mod)
0135             # (will not overflow since if the first n characters are the
0136             # same and the name has not already occured, then the size
0137             # of "name" is greater than that of "mod")
0138             if mod == modulename[:n] and modulename[n] == '.':
0139                 self._ignore[modulename] = 1
0140                 return 1
0141 
0142         # Now check that __file__ isn't in one of the directories
0143         if filename is None:
0144             # must be a built-in, so we must ignore
0145             self._ignore[modulename] = 1
0146             return 1
0147 
0148         # Ignore a file when it contains one of the ignorable paths
0149         for d in self._dirs:
0150             # The '+ os.sep' is to ensure that d is a parent directory,
0151             # as compared to cases like:
0152             #  d = "/usr/local"
0153             #  filename = "/usr/local.py"
0154             # or
0155             #  d = "/usr/local.py"
0156             #  filename = "/usr/local.py"
0157             if filename.startswith(d + os.sep):
0158                 self._ignore[modulename] = 1
0159                 return 1
0160 
0161         # Tried the different ways, so we don't ignore this module
0162         self._ignore[modulename] = 0
0163         return 0
0164 
0165 def modname(path):
0166     """Return a plausible module name for the patch."""
0167 
0168     base = os.path.basename(path)
0169     filename, ext = os.path.splitext(base)
0170     return filename
0171 
0172 def fullmodname(path):
0173     """Return a plausible module name for the path."""
0174 
0175     # If the file 'path' is part of a package, then the filename isn't
0176     # enough to uniquely identify it.  Try to do the right thing by
0177     # looking in sys.path for the longest matching prefix.  We'll
0178     # assume that the rest is the package name.
0179 
0180     longest = ""
0181     for dir in sys.path:
0182         if path.startswith(dir) and path[len(dir)] == os.path.sep:
0183             if len(dir) > len(longest):
0184                 longest = dir
0185 
0186     if longest:
0187         base = path[len(longest) + 1:]
0188     else:
0189         base = path
0190     base = base.replace(os.sep, ".")
0191     if os.altsep:
0192         base = base.replace(os.altsep, ".")
0193     filename, ext = os.path.splitext(base)
0194     return filename
0195 
0196 class CoverageResults:
0197     def __init__(self, counts=None, calledfuncs=None, infile=None,
0198                  callers=None, outfile=None):
0199         self.counts = counts
0200         if self.counts is None:
0201             self.counts = {}
0202         self.counter = self.counts.copy() # map (filename, lineno) to count
0203         self.calledfuncs = calledfuncs
0204         if self.calledfuncs is None:
0205             self.calledfuncs = {}
0206         self.calledfuncs = self.calledfuncs.copy()
0207         self.callers = callers
0208         if self.callers is None:
0209             self.callers = {}
0210         self.callers = self.callers.copy()
0211         self.infile = infile
0212         self.outfile = outfile
0213         if self.infile:
0214             # Try to merge existing counts file.
0215             try:
0216                 counts, calledfuncs, callers = \
0217                         pickle.load(open(self.infile, 'rb'))
0218                 self.update(self.__class__(counts, calledfuncs, callers))
0219             except (IOError, EOFError, ValueError), err:
0220                 print >> sys.stderr, ("Skipping counts file %r: %s"
0221                                       % (self.infile, err))
0222 
0223     def update(self, other):
0224         """Merge in the data from another CoverageResults"""
0225         counts = self.counts
0226         calledfuncs = self.calledfuncs
0227         callers = self.callers
0228         other_counts = other.counts
0229         other_calledfuncs = other.calledfuncs
0230         other_callers = other.callers
0231 
0232         for key in other_counts.keys():
0233             counts[key] = counts.get(key, 0) + other_counts[key]
0234 
0235         for key in other_calledfuncs.keys():
0236             calledfuncs[key] = 1
0237 
0238         for key in other_callers.keys():
0239             callers[key] = 1
0240 
0241     def write_results(self, show_missing=True, summary=False, coverdir=None):
0242         """
0243         @param coverdir
0244         """
0245         if self.calledfuncs:
0246             print
0247             print "functions called:"
0248             calls = self.calledfuncs.keys()
0249             calls.sort()
0250             for filename, modulename, funcname in calls:
0251                 print ("filename: %s, modulename: %s, funcname: %s"
0252                        % (filename, modulename, funcname))
0253 
0254         if self.callers:
0255             print
0256             print "calling relationships:"
0257             calls = self.callers.keys()
0258             calls.sort()
0259             lastfile = lastcfile = ""
0260             for ((pfile, pmod, pfunc), (cfile, cmod, cfunc)) in calls:
0261                 if pfile != lastfile:
0262                     print
0263                     print "***", pfile, "***"
0264                     lastfile = pfile
0265                     lastcfile = ""
0266                 if cfile != pfile and lastcfile != cfile:
0267                     print "  -->", cfile
0268                     lastcfile = cfile
0269                 print "    %s.%s -> %s.%s" % (pmod, pfunc, cmod, cfunc)
0270 
0271         # turn the counts data ("(filename, lineno) = count") into something
0272         # accessible on a per-file basis
0273         per_file = {}
0274         for filename, lineno in self.counts.keys():
0275             lines_hit = per_file[filename] = per_file.get(filename, {})
0276             lines_hit[lineno] = self.counts[(filename, lineno)]
0277 
0278         # accumulate summary info, if needed
0279         sums = {}
0280 
0281         for filename, count in per_file.iteritems():
0282             # skip some "files" we don't care about...
0283             if filename == "<string>":
0284                 continue
0285 
0286             if filename.endswith(".pyc") or filename.endswith(".pyo"):
0287                 filename = filename[:-1]
0288 
0289             if coverdir is None:
0290                 dir = os.path.dirname(os.path.abspath(filename))
0291                 modulename = modname(filename)
0292             else:
0293                 dir = coverdir
0294                 if not os.path.exists(dir):
0295                     os.makedirs(dir)
0296                 modulename = fullmodname(filename)
0297 
0298             # If desired, get a list of the line numbers which represent
0299             # executable content (returned as a dict for better lookup speed)
0300             if show_missing:
0301                 lnotab = find_executable_linenos(filename)
0302             else:
0303                 lnotab = {}
0304 
0305             source = linecache.getlines(filename)
0306             coverpath = os.path.join(dir, modulename + ".cover")
0307             n_hits, n_lines = self.write_results_file(coverpath, source,
0308                                                       lnotab, count)
0309 
0310             if summary and n_lines:
0311                 percent = int(100 * n_hits / n_lines)
0312                 sums[modulename] = n_lines, percent, modulename, filename
0313 
0314         if summary and sums:
0315             mods = sums.keys()
0316             mods.sort()
0317             print "lines   cov%   module   (path)"
0318             for m in mods:
0319                 n_lines, percent, modulename, filename = sums[m]
0320                 print "%5d   %3d%%   %s   (%s)" % sums[m]
0321 
0322         if self.outfile:
0323             # try and store counts and module info into self.outfile
0324             try:
0325                 pickle.dump((self.counts, self.calledfuncs, self.callers),
0326                             open(self.outfile, 'wb'), 1)
0327             except IOError, err:
0328                 print >> sys.stderr, "Can't save counts files because %s" % err
0329 
0330     def write_results_file(self, path, lines, lnotab, lines_hit):
0331         """Return a coverage results file in path."""
0332 
0333         try:
0334             outfile = open(path, "w")
0335         except IOError, err:
0336             print >> sys.stderr, ("trace: Could not open %r for writing: %s"
0337                                   "- skipping" % (path, err))
0338             return 0, 0
0339 
0340         n_lines = 0
0341         n_hits = 0
0342         for i, line in enumerate(lines):
0343             lineno = i + 1
0344             # do the blank/comment match to try to mark more lines
0345             # (help the reader find stuff that hasn't been covered)
0346             if lineno in lines_hit:
0347                 outfile.write("%5d: " % lines_hit[lineno])
0348                 n_hits += 1
0349                 n_lines += 1
0350             elif rx_blank.match(line):
0351                 outfile.write("       ")
0352             else:
0353                 # lines preceded by no marks weren't hit
0354                 # Highlight them if so indicated, unless the line contains
0355                 # #pragma: NO COVER
0356                 if lineno in lnotab and not PRAGMA_NOCOVER in lines[i]:
0357                     outfile.write(">>>>>> ")
0358                     n_lines += 1
0359                 else:
0360                     outfile.write("       ")
0361             outfile.write(lines[i].expandtabs(8))
0362         outfile.close()
0363 
0364         return n_hits, n_lines
0365 
0366 def find_lines_from_code(code, strs):
0367     """Return dict where keys are lines in the line number table."""
0368     linenos = {}
0369 
0370     line_increments = [ord(c) for c in code.co_lnotab[1::2]]
0371     table_length = len(line_increments)
0372     docstring = False
0373 
0374     lineno = code.co_firstlineno
0375     for li in line_increments:
0376         lineno += li
0377         if lineno not in strs:
0378             linenos[lineno] = 1
0379 
0380     return linenos
0381 
0382 def find_lines(code, strs):
0383     """Return lineno dict for all code objects reachable from code."""
0384     # get all of the lineno information from the code of this scope level
0385     linenos = find_lines_from_code(code, strs)
0386 
0387     # and check the constants for references to other code objects
0388     for c in code.co_consts:
0389         if isinstance(c, types.CodeType):
0390             # find another code object, so recurse into it
0391             linenos.update(find_lines(c, strs))
0392     return linenos
0393 
0394 def find_strings(filename):
0395     """Return a dict of possible docstring positions.
0396 
0397     The dict maps line numbers to strings.  There is an entry for
0398     line that contains only a string or a part of a triple-quoted
0399     string.
0400     """
0401     d = {}
0402     # If the first token is a string, then it's the module docstring.
0403     # Add this special case so that the test in the loop passes.
0404     prev_ttype = token.INDENT
0405     f = open(filename)
0406     for ttype, tstr, start, end, line in tokenize.generate_tokens(f.readline):
0407         if ttype == token.STRING:
0408             if prev_ttype == token.INDENT:
0409                 sline, scol = start
0410                 eline, ecol = end
0411                 for i in range(sline, eline + 1):
0412                     d[i] = 1
0413         prev_ttype = ttype
0414     f.close()
0415     return d
0416 
0417 def find_executable_linenos(filename):
0418     """Return dict where keys are line numbers in the line number table."""
0419     assert filename.endswith('.py')
0420     try:
0421         prog = open(filename, "rU").read()
0422     except IOError, err:
0423         print >> sys.stderr, ("Not printing coverage data for %r: %s"
0424                               % (filename, err))
0425         return {}
0426     code = compile(prog, filename, "exec")
0427     strs = find_strings(filename)
0428     return find_lines(code, strs)
0429 
0430 class Trace:
0431     def __init__(self, count=1, trace=1, countfuncs=0, countcallers=0,
0432                  ignoremods=(), ignoredirs=(), infile=None, outfile=None):
0433         """
0434         @param count true iff it should count number of times each
0435                      line is executed
0436         @param trace true iff it should print out each line that is
0437                      being counted
0438         @param countfuncs true iff it should just output a list of
0439                      (filename, modulename, funcname,) for functions
0440                      that were called at least once;  This overrides
0441                      `count' and `trace'
0442         @param ignoremods a list of the names of modules to ignore
0443         @param ignoredirs a list of the names of directories to ignore
0444                      all of the (recursive) contents of
0445         @param infile file from which to read stored counts to be
0446                      added into the results
0447         @param outfile file in which to write the results
0448         """
0449         self.infile = infile
0450         self.outfile = outfile
0451         self.ignore = Ignore(ignoremods, ignoredirs)
0452         self.counts = {}   # keys are (filename, linenumber)
0453         self.blabbed = {} # for debugging
0454         self.pathtobasename = {} # for memoizing os.path.basename
0455         self.donothing = 0
0456         self.trace = trace
0457         self._calledfuncs = {}
0458         self._callers = {}
0459         self._caller_cache = {}
0460         if countcallers:
0461             self.globaltrace = self.globaltrace_trackcallers
0462         elif countfuncs:
0463             self.globaltrace = self.globaltrace_countfuncs
0464         elif trace and count:
0465             self.globaltrace = self.globaltrace_lt
0466             self.localtrace = self.localtrace_trace_and_count
0467         elif trace:
0468             self.globaltrace = self.globaltrace_lt
0469             self.localtrace = self.localtrace_trace
0470         elif count:
0471             self.globaltrace = self.globaltrace_lt
0472             self.localtrace = self.localtrace_count
0473         else:
0474             # Ahem -- do nothing?  Okay.
0475             self.donothing = 1
0476 
0477     def run(self, cmd):
0478         import __main__
0479         dict = __main__.__dict__
0480         if not self.donothing:
0481             sys.settrace(self.globaltrace)
0482             threading.settrace(self.globaltrace)
0483         try:
0484             exec cmd in dict, dict
0485         finally:
0486             if not self.donothing:
0487                 sys.settrace(None)
0488                 threading.settrace(None)
0489 
0490     def runctx(self, cmd, globals=None, locals=None):
0491         if globals is None: globals = {}
0492         if locals is None: locals = {}
0493         if not self.donothing:
0494             sys.settrace(self.globaltrace)
0495             threading.settrace(self.globaltrace)
0496         try:
0497             exec cmd in globals, locals
0498         finally:
0499             if not self.donothing:
0500                 sys.settrace(None)
0501                 threading.settrace(None)
0502 
0503     def runfunc(self, func, *args, **kw):
0504         result = None
0505         if not self.donothing:
0506             sys.settrace(self.globaltrace)
0507         try:
0508             result = func(*args, **kw)
0509         finally:
0510             if not self.donothing:
0511                 sys.settrace(None)
0512         return result
0513 
0514     def file_module_function_of(self, frame):
0515         code = frame.f_code
0516         filename = code.co_filename
0517         if filename:
0518             modulename = modname(filename)
0519         else:
0520             modulename = None
0521 
0522         funcname = code.co_name
0523         clsname = None
0524         if code in self._caller_cache:
0525             if self._caller_cache[code] is not None:
0526                 clsname = self._caller_cache[code]
0527         else:
0528             self._caller_cache[code] = None
0529             ## use of gc.get_referrers() was suggested by Michael Hudson
0530             # all functions which refer to this code object
0531             funcs = [f for f in gc.get_referrers(code)
0532                          if hasattr(f, "func_doc")]
0533             # require len(func) == 1 to avoid ambiguity caused by calls to
0534             # new.function(): "In the face of ambiguity, refuse the
0535             # temptation to guess."
0536             if len(funcs) == 1:
0537                 dicts = [d for d in gc.get_referrers(funcs[0])
0538                              if isinstance(d, dict)]
0539                 if len(dicts) == 1:
0540                     classes = [c for c in gc.get_referrers(dicts[0])
0541                                    if hasattr(c, "__bases__")]
0542                     if len(classes) == 1:
0543                         # ditto for new.classobj()
0544                         clsname = str(classes[0])
0545                         # cache the result - assumption is that new.* is
0546                         # not called later to disturb this relationship
0547                         # _caller_cache could be flushed if functions in
0548                         # the new module get called.
0549                         self._caller_cache[code] = clsname
0550         if clsname is not None:
0551             # final hack - module name shows up in str(cls), but we've already
0552             # computed module name, so remove it
0553             clsname = clsname.split(".")[1:]
0554             clsname = ".".join(clsname)
0555             funcname = "%s.%s" % (clsname, funcname)
0556 
0557         return filename, modulename, funcname
0558 
0559     def globaltrace_trackcallers(self, frame, why, arg):
0560         """Handler for call events.
0561 
0562         Adds information about who called who to the self._callers dict.
0563         """
0564         if why == 'call':
0565             # XXX Should do a better job of identifying methods
0566             this_func = self.file_module_function_of(frame)
0567             parent_func = self.file_module_function_of(frame.f_back)
0568             self._callers[(parent_func, this_func)] = 1
0569 
0570     def globaltrace_countfuncs(self, frame, why, arg):
0571         """Handler for call events.
0572 
0573         Adds (filename, modulename, funcname) to the self._calledfuncs dict.
0574         """
0575         if why == 'call':
0576             this_func = self.file_module_function_of(frame)
0577             self._calledfuncs[this_func] = 1
0578 
0579     def globaltrace_lt(self, frame, why, arg):
0580         """Handler for call events.
0581 
0582         If the code block being entered is to be ignored, returns `None',
0583         else returns self.localtrace.
0584         """
0585         if why == 'call':
0586             code = frame.f_code
0587             filename = code.co_filename
0588             if filename:
0589                 # XXX modname() doesn't work right for packages, so
0590                 # the ignore support won't work right for packages
0591                 modulename = modname(filename)
0592                 if modulename is not None:
0593                     ignore_it = self.ignore.names(filename, modulename)
0594                     if not ignore_it:
0595                         if self.trace:
0596                             print (" --- modulename: %s, funcname: %s"
0597                                    % (modulename, code.co_name))
0598                         return self.localtrace
0599             else:
0600                 return None
0601 
0602     def localtrace_trace_and_count(self, frame, why, arg):
0603         if why == "line":
0604             # record the file name and line number of every trace
0605             filename = frame.f_code.co_filename
0606             lineno = frame.f_lineno
0607             key = filename, lineno
0608             self.counts[key] = self.counts.get(key, 0) + 1
0609 
0610             bname = os.path.basename(filename)
0611             print "%s(%d): %s" % (bname, lineno,
0612                                   linecache.getline(filename, lineno)),
0613         return self.localtrace
0614 
0615     def localtrace_trace(self, frame, why, arg):
0616         if why == "line":
0617             # record the file name and line number of every trace
0618             filename = frame.f_code.co_filename
0619             lineno = frame.f_lineno
0620 
0621             bname = os.path.basename(filename)
0622             print "%s(%d): %s" % (bname, lineno,
0623                                   linecache.getline(filename, lineno)),
0624         return self.localtrace
0625 
0626     def localtrace_count(self, frame, why, arg):
0627         if why == "line":
0628             filename = frame.f_code.co_filename
0629             lineno = frame.f_lineno
0630             key = filename, lineno
0631             self.counts[key] = self.counts.get(key, 0) + 1
0632         return self.localtrace
0633 
0634     def results(self):
0635         return CoverageResults(self.counts, infile=self.infile,
0636                                outfile=self.outfile,
0637                                calledfuncs=self._calledfuncs,
0638                                callers=self._callers)
0639 
0640 def _err_exit(msg):
0641     sys.stderr.write("%s: %s\n" % (sys.argv[0], msg))
0642     sys.exit(1)
0643 
0644 def main(argv=None):
0645     import getopt
0646 
0647     if argv is None:
0648         argv = sys.argv
0649     try:
0650         opts, prog_argv = getopt.getopt(argv[1:], "tcrRf:d:msC:lT",
0651                                         ["help", "version", "trace", "count",
0652                                          "report", "no-report", "summary",
0653                                          "file=", "missing",
0654                                          "ignore-module=", "ignore-dir=",
0655                                          "coverdir=", "listfuncs",
0656                                          "trackcalls"])
0657 
0658     except getopt.error, msg:
0659         sys.stderr.write("%s: %s\n" % (sys.argv[0], msg))
0660         sys.stderr.write("Try `%s --help' for more information\n"
0661                          % sys.argv[0])
0662         sys.exit(1)
0663 
0664     trace = 0
0665     count = 0
0666     report = 0
0667     no_report = 0
0668     counts_file = None
0669     missing = 0
0670     ignore_modules = []
0671     ignore_dirs = []
0672     coverdir = None
0673     summary = 0
0674     listfuncs = False
0675     countcallers = False
0676 
0677     for opt, val in opts:
0678         if opt == "--help":
0679             usage(sys.stdout)
0680             sys.exit(0)
0681 
0682         if opt == "--version":
0683             sys.stdout.write("trace 2.0\n")
0684             sys.exit(0)
0685 
0686         if opt == "-T" or opt == "--trackcalls":
0687             countcallers = True
0688             continue
0689 
0690         if opt == "-l" or opt == "--listfuncs":
0691             listfuncs = True
0692             continue
0693 
0694         if opt == "-t" or opt == "--trace":
0695             trace = 1
0696             continue
0697 
0698         if opt == "-c" or opt == "--count":
0699             count = 1
0700             continue
0701 
0702         if opt == "-r" or opt == "--report":
0703             report = 1
0704             continue
0705 
0706         if opt == "-R" or opt == "--no-report":
0707             no_report = 1
0708             continue
0709 
0710         if opt == "-f" or opt == "--file":
0711             counts_file = val
0712             continue
0713 
0714         if opt == "-m" or opt == "--missing":
0715             missing = 1
0716             continue
0717 
0718         if opt == "-C" or opt == "--coverdir":
0719             coverdir = val
0720             continue
0721 
0722         if opt == "-s" or opt == "--summary":
0723             summary = 1
0724             continue
0725 
0726         if opt == "--ignore-module":
0727             ignore_modules.append(val)
0728             continue
0729 
0730         if opt == "--ignore-dir":
0731             for s in val.split(os.pathsep):
0732                 s = os.path.expandvars(s)
0733                 # should I also call expanduser? (after all, could use $HOME)
0734 
0735                 s = s.replace("$prefix",
0736                               os.path.join(sys.prefix, "lib",
0737                                            "python" + sys.version[:3]))
0738                 s = s.replace("$exec_prefix",
0739                               os.path.join(sys.exec_prefix, "lib",
0740                                            "python" + sys.version[:3]))
0741                 s = os.path.normpath(s)
0742                 ignore_dirs.append(s)
0743             continue
0744 
0745         assert 0, "Should never get here"
0746 
0747     if listfuncs and (count or trace):
0748         _err_exit("cannot specify both --listfuncs and (--trace or --count)")
0749 
0750     if not (count or trace or report or listfuncs or countcallers):
0751         _err_exit("must specify one of --trace, --count, --report, "
0752                   "--listfuncs, or --trackcalls")
0753 
0754     if report and no_report:
0755         _err_exit("cannot specify both --report and --no-report")
0756 
0757     if report and not counts_file:
0758         _err_exit("--report requires a --file")
0759 
0760     if no_report and len(prog_argv) == 0:
0761         _err_exit("missing name of file to run")
0762 
0763     # everything is ready
0764     if report:
0765         results = CoverageResults(infile=counts_file, outfile=counts_file)
0766         results.write_results(missing, summary=summary, coverdir=coverdir)
0767     else:
0768         sys.argv = prog_argv
0769         progname = prog_argv[0]
0770         sys.path[0] = os.path.split(progname)[0]
0771 
0772         t = Trace(count, trace, countfuncs=listfuncs,
0773                   countcallers=countcallers, ignoremods=ignore_modules,
0774                   ignoredirs=ignore_dirs, infile=counts_file,
0775                   outfile=counts_file)
0776         try:
0777             t.run('execfile(%r)' % (progname,))
0778         except IOError, err:
0779             _err_exit("Cannot run file %r because: %s" % (sys.argv[0], err))
0780         except SystemExit:
0781             pass
0782 
0783         results = t.results()
0784 
0785         if not no_report:
0786             results.write_results(missing, summary=summary, coverdir=coverdir)
0787 
0788 if __name__=='__main__':
0789     main()
0790 

Generated by PyXR 0.9.4
SourceForge.net Logo