3
# Perforce Defect Tracking Integration Project
4
# <http://www.ravenbrook.com/project/p4dti/>
6
# COVERAGE.PY -- COVERAGE TESTING
8
# Gareth Rees, Ravenbrook Limited, 2001-12-04
9
# Ned Batchelder, 2004-12-12
10
# http://nedbatchelder.com/code/modules/coverage.html
15
# This module provides coverage testing for Python code.
17
# The intended readership is all Python developers.
19
# This document is not confidential.
21
# See [GDR 2001-12-04a] for the command-line interface, programmatic
22
# interface and limitations. See [GDR 2001-12-04b] for requirements and
27
coverage.py -x [-p] MODULE.py [ARG1 ARG2 ...]
28
Execute module, passing the given command-line arguments, collecting
29
coverage data. With the -p option, write to a temporary file containing
30
the machine name and process ID.
33
Erase collected coverage data.
36
Collect data from multiple coverage files (as created by -p option above)
37
and store it into a single file representing the union of the coverage.
39
coverage.py -r [-m] [-o dir1,dir2,...] FILE1 FILE2 ...
40
Report on the statement coverage for the given files. With the -m
41
option, show line numbers of the statements that weren't executed.
43
coverage.py -a [-d dir] [-o dir1,dir2,...] FILE1 FILE2 ...
44
Make annotated copies of the given files, marking statements that
45
are executed with > and statements that are missed with !. With
46
the -d option, make the copies in that directory. Without the -d
47
option, make each copy in the same directory as the original.
50
Omit reporting or annotating files when their filename path starts with
51
a directory listed in the omit list.
52
e.g. python coverage.py -i -r -o c:\python23,lib\enthought\traits
54
Coverage data is saved in the file .coverage by default. Set the
55
COVERAGE_FILE environment variable to save it somewhere else."""
57
__version__ = "2.85.20080914" # see detailed history at the end of this file.
60
import compiler.visitor
71
from socket import gethostname
73
# Python version compatibility
75
strclass = basestring # new to 2.3
81
# This uses the "singleton" pattern.
83
# The word "morf" means a module object (from which the source file can
84
# be deduced by suitable manipulation of the __file__ attribute) or a
87
# When we generate a coverage report we have to canonicalize every
88
# filename in the coverage dictionary just in case it refers to the
89
# module we are reporting on. It seems a shame to throw away this
90
# information so the data in the coverage dictionary is transferred to
91
# the 'cexecuted' dictionary under the canonical filenames.
93
# The coverage dictionary is called "c" and the trace function "t". The
94
# reason for these short names is that Python looks up variables by name
95
# at runtime and so execution time depends on the length of variables!
96
# In the bottleneck of this application it's appropriate to abbreviate
97
# names to increase speed.
99
class StatementFindingAstVisitor(compiler.visitor.ASTVisitor):
100
""" A visitor for a parsed Abstract Syntax Tree which finds executable
103
def __init__(self, statements, excluded, suite_spots):
104
compiler.visitor.ASTVisitor.__init__(self)
105
self.statements = statements
106
self.excluded = excluded
107
self.suite_spots = suite_spots
108
self.excluding_suite = 0
110
def doRecursive(self, node):
111
for n in node.getChildNodes():
114
visitStmt = visitModule = doRecursive
116
def doCode(self, node):
117
if hasattr(node, 'decorators') and node.decorators:
118
self.dispatch(node.decorators)
119
self.recordAndDispatch(node.code)
121
self.doSuite(node, node.code)
123
visitFunction = visitClass = doCode
125
def getFirstLine(self, node):
126
# Find the first line in the tree node.
128
for n in node.getChildNodes():
129
f = self.getFirstLine(n)
131
lineno = min(lineno, f)
136
def getLastLine(self, node):
137
# Find the first line in the tree node.
139
for n in node.getChildNodes():
140
lineno = max(lineno, self.getLastLine(n))
143
def doStatement(self, node):
144
self.recordLine(self.getFirstLine(node))
146
visitAssert = visitAssign = visitAssTuple = visitPrint = \
147
visitPrintnl = visitRaise = visitSubscript = visitDecorators = \
150
def visitPass(self, node):
151
# Pass statements have weird interactions with docstrings. If this
152
# pass statement is part of one of those pairs, claim that the statement
153
# is on the later of the two lines.
156
lines = self.suite_spots.get(l, [l,l])
157
self.statements[lines[1]] = 1
159
def visitDiscard(self, node):
160
# Discard nodes are statements that execute an expression, but then
161
# discard the results. This includes function calls, so we can't
162
# ignore them all. But if the expression is a constant, the statement
163
# won't be "executed", so don't count it now.
164
if node.expr.__class__.__name__ != 'Const':
165
self.doStatement(node)
167
def recordNodeLine(self, node):
168
# Stmt nodes often have None, but shouldn't claim the first line of
169
# their children (because the first child might be an ignorable line
171
if node.__class__.__name__ != 'Stmt':
172
return self.recordLine(self.getFirstLine(node))
176
def recordLine(self, lineno):
177
# Returns a bool, whether the line is included or excluded.
179
# Multi-line tests introducing suites have to get charged to their
181
if lineno in self.suite_spots:
182
lineno = self.suite_spots[lineno][0]
183
# If we're inside an excluded suite, record that this line was
185
if self.excluding_suite:
186
self.excluded[lineno] = 1
188
# If this line is excluded, or suite_spots maps this line to
189
# another line that is exlcuded, then we're excluded.
190
elif self.excluded.has_key(lineno) or \
191
self.suite_spots.has_key(lineno) and \
192
self.excluded.has_key(self.suite_spots[lineno][1]):
194
# Otherwise, this is an executable line.
196
self.statements[lineno] = 1
200
default = recordNodeLine
202
def recordAndDispatch(self, node):
203
self.recordNodeLine(node)
206
def doSuite(self, intro, body, exclude=0):
207
exsuite = self.excluding_suite
208
if exclude or (intro and not self.recordNodeLine(intro)):
209
self.excluding_suite = 1
210
self.recordAndDispatch(body)
211
self.excluding_suite = exsuite
213
def doPlainWordSuite(self, prevsuite, suite):
214
# Finding the exclude lines for else's is tricky, because they aren't
215
# present in the compiler parse tree. Look at the previous suite,
216
# and find its last line. If any line between there and the else's
217
# first line are excluded, then we exclude the else.
218
lastprev = self.getLastLine(prevsuite)
219
firstelse = self.getFirstLine(suite)
220
for l in range(lastprev+1, firstelse):
221
if self.suite_spots.has_key(l):
222
self.doSuite(None, suite, exclude=self.excluded.has_key(l))
225
self.doSuite(None, suite)
227
def doElse(self, prevsuite, node):
229
self.doPlainWordSuite(prevsuite, node.else_)
231
def visitFor(self, node):
232
self.doSuite(node, node.body)
233
self.doElse(node.body, node)
235
visitWhile = visitFor
237
def visitIf(self, node):
238
# The first test has to be handled separately from the rest.
239
# The first test is credited to the line with the "if", but the others
240
# are credited to the line with the test for the elif.
241
self.doSuite(node, node.tests[0][1])
242
for t, n in node.tests[1:]:
244
self.doElse(node.tests[-1][1], node)
246
def visitTryExcept(self, node):
247
self.doSuite(node, node.body)
248
for i in range(len(node.handlers)):
249
a, b, h = node.handlers[i]
251
# It's a plain "except:". Find the previous suite.
253
prev = node.handlers[i-1][2]
256
self.doPlainWordSuite(prev, h)
259
self.doElse(node.handlers[-1][2], node)
261
def visitTryFinally(self, node):
262
self.doSuite(node, node.body)
263
self.doPlainWordSuite(node.body, node.final)
265
def visitWith(self, node):
266
self.doSuite(node, node.body)
268
def visitGlobal(self, node):
269
# "global" statements don't execute like others (they don't call the
270
# trace function), so don't record their line numbers.
275
class CoverageException(Exception):
279
# Name of the cache file (unless environment variable is set).
280
cache_default = ".coverage"
282
# Environment variable naming the cache file.
283
cache_env = "COVERAGE_FILE"
285
# A dictionary with an entry for (Python source file name, line number
286
# in that file) if that line has been executed.
289
# A map from canonical Python source file name to a dictionary in
290
# which there's an entry for each line number that has been
294
# Cache of results of calling the analysis2() method, so that you can
295
# specify both -r and -a without doing double work.
298
# Cache of results of calling the canonical_filename() method, to
299
# avoid duplicating work.
300
canonical_filename_cache = {}
305
raise CoverageException("Only one coverage object allowed.")
308
self.parallel_mode = False
313
self.relative_dir = self.abs_file(os.curdir)+os.sep
314
self.exclude('# *pragma[: ]*[nN][oO] *[cC][oO][vV][eE][rR]')
316
# t(f, x, y). This method is passed to sys.settrace as a trace function.
317
# See [van Rossum 2001-07-20b, 9.2] for an explanation of sys.settrace and
318
# the arguments and return value of the trace function.
319
# See [van Rossum 2001-07-20a, 3.2] for a description of frame and code
322
def t(self, f, w, unused): #pragma: no cover
324
self.c[(f.f_code.co_filename, f.f_lineno)] = 1
325
#-for c in self.cstack:
326
#- c[(f.f_code.co_filename, f.f_lineno)] = 1
329
def help(self, error=None): #pragma: no cover
336
def command_line(self, argv, help_fn=None):
338
help_fn = help_fn or self.help
346
'-i': 'ignore-errors',
347
'-m': 'show-missing',
348
'-p': 'parallel-mode',
353
short_opts = string.join(map(lambda o: o[1:], optmap.keys()), '')
354
long_opts = optmap.values()
355
options, args = getopt.getopt(argv, short_opts, long_opts)
357
if optmap.has_key(o):
358
settings[optmap[o]] = 1
359
elif optmap.has_key(o + ':'):
360
settings[optmap[o + ':']] = a
361
elif o[2:] in long_opts:
363
elif o[2:] + '=' in long_opts:
364
settings[o[2:]+'='] = a
365
else: #pragma: no cover
366
pass # Can't get here, because getopt won't return anything unknown.
368
if settings.get('help'):
371
for i in ['erase', 'execute']:
372
for j in ['annotate', 'report', 'collect']:
373
if settings.get(i) and settings.get(j):
374
help_fn("You can't specify the '%s' and '%s' "
375
"options at the same time." % (i, j))
377
args_needed = (settings.get('execute')
378
or settings.get('annotate')
379
or settings.get('report'))
380
action = (settings.get('erase')
381
or settings.get('collect')
384
help_fn("You must specify at least one of -e, -x, -c, -r, or -a.")
385
if not args_needed and args:
386
help_fn("Unexpected arguments: %s" % " ".join(args))
388
self.parallel_mode = settings.get('parallel-mode')
391
if settings.get('erase'):
393
if settings.get('execute'):
395
help_fn("Nothing to do.")
399
sys.path[0] = os.path.dirname(sys.argv[0])
400
execfile(sys.argv[0], __main__.__dict__)
401
if settings.get('collect'):
404
args = self.cexecuted.keys()
406
ignore_errors = settings.get('ignore-errors')
407
show_missing = settings.get('show-missing')
408
directory = settings.get('directory=')
410
omit = settings.get('omit=')
412
omit = [self.abs_file(p) for p in omit.split(',')]
416
if settings.get('report'):
417
self.report(args, show_missing, ignore_errors, omit_prefixes=omit)
418
if settings.get('annotate'):
419
self.annotate(args, directory, ignore_errors, omit_prefixes=omit)
421
def use_cache(self, usecache, cache_file=None):
422
self.usecache = usecache
423
if cache_file and not self.cache:
424
self.cache_default = cache_file
426
def get_ready(self, parallel_mode=False):
427
if self.usecache and not self.cache:
428
self.cache = os.environ.get(self.cache_env, self.cache_default)
429
if self.parallel_mode:
430
self.cache += "." + gethostname() + "." + str(os.getpid())
432
self.analysis_cache = {}
434
def start(self, parallel_mode=False):
436
if self.nesting == 0: #pragma: no cover
438
if hasattr(threading, 'settrace'):
439
threading.settrace(self.t)
444
if self.nesting == 0: #pragma: no cover
446
if hasattr(threading, 'settrace'):
447
threading.settrace(None)
452
self.analysis_cache = {}
454
if self.cache and os.path.exists(self.cache):
455
os.remove(self.cache)
457
def exclude(self, re):
459
self.exclude_re += "|"
460
self.exclude_re += "(" + re + ")"
462
def begin_recursive(self):
463
self.cstack.append(self.c)
464
self.xstack.append(self.exclude_re)
466
def end_recursive(self):
467
self.c = self.cstack.pop()
468
self.exclude_re = self.xstack.pop()
470
# save(). Save coverage data to the coverage cache.
473
if self.usecache and self.cache:
474
self.canonicalize_filenames()
475
cache = open(self.cache, 'wb')
477
marshal.dump(self.cexecuted, cache)
480
# restore(). Restore coverage data from the coverage cache (if it exists).
486
if os.path.exists(self.cache):
487
self.cexecuted = self.restore_file(self.cache)
489
def restore_file(self, file_name):
491
cache = open(file_name, 'rb')
493
cexecuted = marshal.load(cache)
495
if isinstance(cexecuted, types.DictType):
502
# collect(). Collect data in multiple files produced by parallel mode
505
cache_dir, local = os.path.split(self.cache)
506
for f in os.listdir(cache_dir or '.'):
507
if not f.startswith(local):
510
full_path = os.path.join(cache_dir, f)
511
cexecuted = self.restore_file(full_path)
512
self.merge_data(cexecuted)
514
def merge_data(self, new_data):
515
for file_name, file_data in new_data.items():
516
if self.cexecuted.has_key(file_name):
517
self.merge_file_data(self.cexecuted[file_name], file_data)
519
self.cexecuted[file_name] = file_data
521
def merge_file_data(self, cache_data, new_data):
522
for line_number in new_data.keys():
523
if not cache_data.has_key(line_number):
524
cache_data[line_number] = new_data[line_number]
526
def abs_file(self, filename):
527
""" Helper function to turn a filename into an absolute normalized
530
return os.path.normcase(os.path.abspath(os.path.realpath(filename)))
532
def get_zip_data(self, filename):
533
""" Get data from `filename` if it is a zip file path, or return None
536
markers = ['.zip'+os.sep, '.egg'+os.sep]
537
for marker in markers:
538
if marker in filename:
539
parts = filename.split(marker)
541
zi = zipimport.zipimporter(parts[0]+marker[:-1])
542
except zipimport.ZipImportError:
545
data = zi.get_data(parts[1])
551
# canonical_filename(filename). Return a canonical filename for the
552
# file (that is, an absolute path with no redundant components and
553
# normalized case). See [GDR 2001-12-04b, 3.3].
555
def canonical_filename(self, filename):
556
if not self.canonical_filename_cache.has_key(filename):
558
if os.path.isabs(f) and not os.path.exists(f):
559
if not self.get_zip_data(f):
560
f = os.path.basename(f)
561
if not os.path.isabs(f):
562
for path in [os.curdir] + sys.path:
563
g = os.path.join(path, f)
564
if os.path.exists(g):
567
cf = self.abs_file(f)
568
self.canonical_filename_cache[filename] = cf
569
return self.canonical_filename_cache[filename]
571
# canonicalize_filenames(). Copy results from "c" to "cexecuted",
572
# canonicalizing filenames on the way. Clear the "c" map.
574
def canonicalize_filenames(self):
575
for filename, lineno in self.c.keys():
576
if filename == '<string>':
577
# Can't do anything useful with exec'd strings, so skip them.
579
f = self.canonical_filename(filename)
580
if not self.cexecuted.has_key(f):
581
self.cexecuted[f] = {}
582
self.cexecuted[f][lineno] = 1
585
# morf_filename(morf). Return the filename for a module or file.
587
def morf_filename(self, morf):
588
if hasattr(morf, '__file__'):
592
return self.canonical_filename(f)
594
# analyze_morf(morf). Analyze the module or filename passed as
595
# the argument. If the source code can't be found, raise an error.
596
# Otherwise, return a tuple of (1) the canonical filename of the
597
# source code for the module, (2) a list of lines of statements
598
# in the source code, (3) a list of lines of excluded statements,
599
# and (4), a map of line numbers to multi-line line number ranges, for
600
# statements that cross lines.
602
def analyze_morf(self, morf):
603
if self.analysis_cache.has_key(morf):
604
return self.analysis_cache[morf]
605
filename = self.morf_filename(morf)
606
ext = os.path.splitext(filename)[1]
607
source, sourcef = None, None
609
if not os.path.exists(filename[:-1]):
610
source = self.get_zip_data(filename[:-1])
612
raise CoverageException(
613
"No source for compiled code '%s'." % filename
615
filename = filename[:-1]
617
sourcef = open(filename, 'rU')
618
source = sourcef.read()
620
lines, excluded_lines, line_map = self.find_executable_statements(
621
source, exclude=self.exclude_re
623
except SyntaxError, synerr:
624
raise CoverageException(
625
"Couldn't parse '%s' as Python source: '%s' at line %d" %
626
(filename, synerr.msg, synerr.lineno)
630
result = filename, lines, excluded_lines, line_map
631
self.analysis_cache[morf] = result
634
def first_line_of_tree(self, tree):
636
if len(tree) == 3 and type(tree[2]) == type(1):
640
def last_line_of_tree(self, tree):
642
if len(tree) == 3 and type(tree[2]) == type(1):
646
def find_docstring_pass_pair(self, tree, spots):
647
for i in range(1, len(tree)):
648
if self.is_string_constant(tree[i]) and self.is_pass_stmt(tree[i+1]):
649
first_line = self.first_line_of_tree(tree[i])
650
last_line = self.last_line_of_tree(tree[i+1])
651
self.record_multiline(spots, first_line, last_line)
653
def is_string_constant(self, tree):
655
return tree[0] == symbol.stmt and tree[1][1][1][0] == symbol.expr_stmt
659
def is_pass_stmt(self, tree):
661
return tree[0] == symbol.stmt and tree[1][1][1][0] == symbol.pass_stmt
665
def record_multiline(self, spots, i, j):
666
for l in range(i, j+1):
669
def get_suite_spots(self, tree, spots):
670
""" Analyze a parse tree to find suite introducers which span a number
673
for i in range(1, len(tree)):
674
if type(tree[i]) == type(()):
675
if tree[i][0] == symbol.suite:
676
# Found a suite, look back for the colon and keyword.
677
lineno_colon = lineno_word = None
678
for j in range(i-1, 0, -1):
679
if tree[j][0] == token.COLON:
680
# Colons are never executed themselves: we want the
681
# line number of the last token before the colon.
682
lineno_colon = self.last_line_of_tree(tree[j-1])
683
elif tree[j][0] == token.NAME:
684
if tree[j][1] == 'elif':
685
# Find the line number of the first non-terminal
688
while t and token.ISNONTERMINAL(t[0]):
693
lineno_word = tree[j][2]
695
elif tree[j][0] == symbol.except_clause:
696
# "except" clauses look like:
697
# ('except_clause', ('NAME', 'except', lineno), ...)
698
if tree[j][1][0] == token.NAME:
699
lineno_word = tree[j][1][2]
701
if lineno_colon and lineno_word:
702
# Found colon and keyword, mark all the lines
703
# between the two with the two line numbers.
704
self.record_multiline(spots, lineno_word, lineno_colon)
706
# "pass" statements are tricky: different versions of Python
707
# treat them differently, especially in the common case of a
708
# function with a doc string and a single pass statement.
709
self.find_docstring_pass_pair(tree[i], spots)
711
elif tree[i][0] == symbol.simple_stmt:
712
first_line = self.first_line_of_tree(tree[i])
713
last_line = self.last_line_of_tree(tree[i])
714
if first_line != last_line:
715
self.record_multiline(spots, first_line, last_line)
716
self.get_suite_spots(tree[i], spots)
718
def find_executable_statements(self, text, exclude=None):
719
# Find lines which match an exclusion pattern.
723
reExclude = re.compile(exclude)
724
lines = text.split('\n')
725
for i in range(len(lines)):
726
if reExclude.search(lines[i]):
729
# Parse the code and analyze the parse tree to find out which statements
730
# are multiline, and where suites begin and end.
732
tree = parser.suite(text+'\n\n').totuple(1)
733
self.get_suite_spots(tree, suite_spots)
734
#print "Suite spots:", suite_spots
736
# Use the compiler module to parse the text and find the executable
737
# statements. We add newlines to be impervious to final partial lines.
739
ast = compiler.parse(text+'\n\n')
740
visitor = StatementFindingAstVisitor(statements, excluded, suite_spots)
741
compiler.walk(ast, visitor, walker=visitor)
743
lines = statements.keys()
745
excluded_lines = excluded.keys()
746
excluded_lines.sort()
747
return lines, excluded_lines, suite_spots
749
# format_lines(statements, lines). Format a list of line numbers
750
# for printing by coalescing groups of lines as long as the lines
751
# represent consecutive statements. This will coalesce even if
752
# there are gaps between statements, so if statements =
753
# [1,2,3,4,5,10,11,12,13,14] and lines = [1,2,5,10,11,13,14] then
754
# format_lines will return "1-2, 5-11, 13-14".
756
def format_lines(self, statements, lines):
762
while i < len(statements) and j < len(lines):
763
if statements[i] == lines[j]:
769
pairs.append((start, end))
773
pairs.append((start, end))
779
return "%d-%d" % (start, end)
780
ret = string.join(map(stringify, pairs), ", ")
783
# Backward compatibility with version 1.
784
def analysis(self, morf):
785
f, s, _, m, mf = self.analysis2(morf)
788
def analysis2(self, morf):
789
filename, statements, excluded, line_map = self.analyze_morf(morf)
790
self.canonicalize_filenames()
791
if not self.cexecuted.has_key(filename):
792
self.cexecuted[filename] = {}
794
for line in statements:
795
lines = line_map.get(line, [line, line])
796
for l in range(lines[0], lines[1]+1):
797
if self.cexecuted[filename].has_key(l):
801
return (filename, statements, excluded, missing,
802
self.format_lines(statements, missing))
804
def relative_filename(self, filename):
805
""" Convert filename to relative filename from self.relative_dir.
807
return filename.replace(self.relative_dir, "")
809
def morf_name(self, morf):
810
""" Return the name of morf as used in report.
812
if hasattr(morf, '__name__'):
815
return self.relative_filename(os.path.splitext(morf)[0])
817
def filter_by_prefix(self, morfs, omit_prefixes):
818
""" Return list of morfs where the morf name does not begin
819
with any one of the omit_prefixes.
823
for prefix in omit_prefixes:
824
if self.morf_name(morf).startswith(prefix):
827
filtered_morfs.append(morf)
829
return filtered_morfs
831
def morf_name_compare(self, x, y):
832
return cmp(self.morf_name(x), self.morf_name(y))
834
def report(self, morfs, show_missing=1, ignore_errors=0, file=None, omit_prefixes=[]):
835
if not isinstance(morfs, types.ListType):
837
# On windows, the shell doesn't expand wildcards. Do it here.
840
if isinstance(morf, strclass):
841
globbed.extend(glob.glob(morf))
846
morfs = self.filter_by_prefix(morfs, omit_prefixes)
847
morfs.sort(self.morf_name_compare)
849
max_name = max([5,] + map(len, map(self.morf_name, morfs)))
850
fmt_name = "%%- %ds " % max_name
851
fmt_err = fmt_name + "%s: %s"
852
header = fmt_name % "Name" + " Stmts Exec Cover"
853
fmt_coverage = fmt_name + "% 6d % 6d % 5d%%"
855
header = header + " Missing"
856
fmt_coverage = fmt_coverage + " %s"
860
print >>file, "-" * len(header)
864
name = self.morf_name(morf)
866
_, statements, _, missing, readable = self.analysis2(morf)
873
args = (name, n, m, pc)
875
args = args + (readable,)
876
print >>file, fmt_coverage % args
877
total_statements = total_statements + n
878
total_executed = total_executed + m
879
except KeyboardInterrupt: #pragma: no cover
882
if not ignore_errors:
883
typ, msg = sys.exc_info()[:2]
884
print >>file, fmt_err % (name, typ, msg)
886
print >>file, "-" * len(header)
887
if total_statements > 0:
888
pc = 100.0 * total_executed / total_statements
891
args = ("TOTAL", total_statements, total_executed, pc)
894
print >>file, fmt_coverage % args
896
# annotate(morfs, ignore_errors).
898
blank_re = re.compile(r"\s*(#|$)")
899
else_re = re.compile(r"\s*else\s*:\s*(#|$)")
901
def annotate(self, morfs, directory=None, ignore_errors=0, omit_prefixes=[]):
902
morfs = self.filter_by_prefix(morfs, omit_prefixes)
905
filename, statements, excluded, missing, _ = self.analysis2(morf)
906
self.annotate_file(filename, statements, excluded, missing, directory)
907
except KeyboardInterrupt:
910
if not ignore_errors:
913
def annotate_file(self, filename, statements, excluded, missing, directory=None):
914
source = open(filename, 'r')
916
dest_file = os.path.join(directory,
917
os.path.basename(filename)
920
dest_file = filename + ',cover'
921
dest = open(dest_file, 'w')
927
line = source.readline()
931
while i < len(statements) and statements[i] < lineno:
933
while j < len(missing) and missing[j] < lineno:
935
if i < len(statements) and statements[i] == lineno:
936
covered = j >= len(missing) or missing[j] > lineno
937
if self.blank_re.match(line):
939
elif self.else_re.match(line):
940
# Special logic for lines containing only 'else:'.
941
# See [GDR 2001-12-04b, 3.2].
942
if i >= len(statements) and j >= len(missing):
944
elif i >= len(statements) or j >= len(missing):
946
elif statements[i] == missing[j]:
950
elif lineno in excluded:
961
the_coverage = coverage()
963
# Module functions call methods in the singleton object.
964
def use_cache(*args, **kw):
965
return the_coverage.use_cache(*args, **kw)
967
def start(*args, **kw):
968
return the_coverage.start(*args, **kw)
970
def stop(*args, **kw):
971
return the_coverage.stop(*args, **kw)
973
def erase(*args, **kw):
974
return the_coverage.erase(*args, **kw)
976
def begin_recursive(*args, **kw):
977
return the_coverage.begin_recursive(*args, **kw)
979
def end_recursive(*args, **kw):
980
return the_coverage.end_recursive(*args, **kw)
982
def exclude(*args, **kw):
983
return the_coverage.exclude(*args, **kw)
985
def analysis(*args, **kw):
986
return the_coverage.analysis(*args, **kw)
988
def analysis2(*args, **kw):
989
return the_coverage.analysis2(*args, **kw)
991
def report(*args, **kw):
992
return the_coverage.report(*args, **kw)
994
def annotate(*args, **kw):
995
return the_coverage.annotate(*args, **kw)
997
def annotate_file(*args, **kw):
998
return the_coverage.annotate_file(*args, **kw)
1000
# Save coverage data when Python exits. (The atexit module wasn't
1001
# introduced until Python 2.0, so use sys.exitfunc when it's not
1005
atexit.register(the_coverage.save)
1007
sys.exitfunc = the_coverage.save
1010
the_coverage.command_line(sys.argv[1:])
1012
# Command-line interface.
1013
if __name__ == '__main__':
1019
# [GDR 2001-12-04a] "Statement coverage for Python"; Gareth Rees;
1020
# Ravenbrook Limited; 2001-12-04;
1021
# <http://www.nedbatchelder.com/code/modules/rees-coverage.html>.
1023
# [GDR 2001-12-04b] "Statement coverage for Python: design and
1024
# analysis"; Gareth Rees; Ravenbrook Limited; 2001-12-04;
1025
# <http://www.nedbatchelder.com/code/modules/rees-design.html>.
1027
# [van Rossum 2001-07-20a] "Python Reference Manual (releae 2.1.1)";
1028
# Guide van Rossum; 2001-07-20;
1029
# <http://www.python.org/doc/2.1.1/ref/ref.html>.
1031
# [van Rossum 2001-07-20b] "Python Library Reference"; Guido van Rossum;
1032
# 2001-07-20; <http://www.python.org/doc/2.1.1/lib/lib.html>.
1035
# B. DOCUMENT HISTORY
1037
# 2001-12-04 GDR Created.
1039
# 2001-12-06 GDR Added command-line interface and source code
1042
# 2001-12-09 GDR Moved design and interface to separate documents.
1044
# 2001-12-10 GDR Open cache file as binary on Windows. Allow
1045
# simultaneous -e and -x, or -a and -r.
1047
# 2001-12-12 GDR Added command-line help. Cache analysis so that it
1048
# only needs to be done once when you specify -a and -r.
1050
# 2001-12-13 GDR Improved speed while recording. Portable between
1051
# Python 1.5.2 and 2.1.1.
1053
# 2002-01-03 GDR Module-level functions work correctly.
1055
# 2002-01-07 GDR Update sys.path when running a file with the -x option,
1056
# so that it matches the value the program would get if it were run on
1059
# 2004-12-12 NMB Significant code changes.
1060
# - Finding executable statements has been rewritten so that docstrings and
1061
# other quirks of Python execution aren't mistakenly identified as missing
1063
# - Lines can be excluded from consideration, even entire suites of lines.
1064
# - The filesystem cache of covered lines can be disabled programmatically.
1065
# - Modernized the code.
1067
# 2004-12-14 NMB Minor tweaks. Return 'analysis' to its original behavior
1068
# and add 'analysis2'. Add a global for 'annotate', and factor it, adding
1071
# 2004-12-31 NMB Allow for keyword arguments in the module global functions.
1074
# 2005-12-02 NMB Call threading.settrace so that all threads are measured.
1075
# Thanks Martin Fuzzey. Add a file argument to report so that reports can be
1076
# captured to a different destination.
1078
# 2005-12-03 NMB coverage.py can now measure itself.
1080
# 2005-12-04 NMB Adapted Greg Rogers' patch for using relative filenames,
1081
# and sorting and omitting files to report on.
1083
# 2006-07-23 NMB Applied Joseph Tate's patch for function decorators.
1085
# 2006-08-21 NMB Applied Sigve Tjora and Mark van der Wal's fixes for argument
1088
# 2006-08-22 NMB Applied Geoff Bache's parallel mode patch.
1090
# 2006-08-23 NMB Refactorings to improve testability. Fixes to command-line
1091
# logic for parallel mode and collect.
1093
# 2006-08-25 NMB "#pragma: nocover" is excluded by default.
1095
# 2006-09-10 NMB Properly ignore docstrings and other constant expressions that
1096
# appear in the middle of a function, a problem reported by Tim Leslie.
1097
# Minor changes to avoid lint warnings.
1099
# 2006-09-17 NMB coverage.erase() shouldn't clobber the exclude regex.
1100
# Change how parallel mode is invoked, and fix erase() so that it erases the
1101
# cache when called programmatically.
1103
# 2007-07-21 NMB In reports, ignore code executed from strings, since we can't
1104
# do anything useful with it anyway.
1105
# Better file handling on Linux, thanks Guillaume Chazarain.
1106
# Better shell support on Windows, thanks Noel O'Boyle.
1107
# Python 2.2 support maintained, thanks Catherine Proulx.
1109
# 2007-07-22 NMB Python 2.5 now fully supported. The method of dealing with
1110
# multi-line statements is now less sensitive to the exact line that Python
1111
# reports during execution. Pass statements are handled specially so that their
1112
# disappearance during execution won't throw off the measurement.
1114
# 2007-07-23 NMB Now Python 2.5 is *really* fully supported: the body of the
1115
# new with statement is counted as executable.
1117
# 2007-07-29 NMB Better packaging.
1119
# 2007-09-30 NMB Don't try to predict whether a file is Python source based on
1120
# the extension. Extensionless files are often Pythons scripts. Instead, simply
1121
# parse the file and catch the syntax errors. Hat tip to Ben Finney.
1123
# 2008-05-25 NMB Open files in rU mode to avoid line ending craziness.
1124
# Thanks, Edward Loper.
1126
# 2008-09-14 NMB Add support for finding source files in eggs.
1127
# Don't check for morf's being instances of ModuleType, instead use duck typing
1128
# so that pseudo-modules can participate. Thanks, Imri Goldberg.
1129
# Use os.realpath as part of the fixing of filenames so that symlinks won't
1130
# confuse things. Thanks, Patrick Mezard.
1133
# C. COPYRIGHT AND LICENCE
1135
# Copyright 2001 Gareth Rees. All rights reserved.
1136
# Copyright 2004-2008 Ned Batchelder. All rights reserved.
1138
# Redistribution and use in source and binary forms, with or without
1139
# modification, are permitted provided that the following conditions are
1142
# 1. Redistributions of source code must retain the above copyright
1143
# notice, this list of conditions and the following disclaimer.
1145
# 2. Redistributions in binary form must reproduce the above copyright
1146
# notice, this list of conditions and the following disclaimer in the
1147
# documentation and/or other materials provided with the
1150
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
1151
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
1152
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
1153
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
1154
# HOLDERS AND CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
1155
# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
1156
# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
1157
# OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
1158
# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
1159
# TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
1160
# USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
1163
# $Id: coverage.py 100 2008-10-12 12:08:22Z nedbat $