131
140
def doStatement(self, node):
132
141
self.recordLine(self.getFirstLine(node))
134
visitAssert = visitAssign = visitAssTuple = visitDiscard = visitPrint = \
143
visitAssert = visitAssign = visitAssTuple = visitPrint = \
135
144
visitPrintnl = visitRaise = visitSubscript = visitDecorators = \
147
def visitPass(self, node):
148
# Pass statements have weird interactions with docstrings. If this
149
# pass statement is part of one of those pairs, claim that the statement
150
# is on the later of the two lines.
153
lines = self.suite_spots.get(l, [l,l])
154
self.statements[lines[1]] = 1
156
def visitDiscard(self, node):
157
# Discard nodes are statements that execute an expression, but then
158
# discard the results. This includes function calls, so we can't
159
# ignore them all. But if the expression is a constant, the statement
160
# won't be "executed", so don't count it now.
161
if node.expr.__class__.__name__ != 'Const':
162
self.doStatement(node)
138
164
def recordNodeLine(self, node):
139
return self.recordLine(node.lineno)
165
# Stmt nodes often have None, but shouldn't claim the first line of
166
# their children (because the first child might be an ignorable line
168
if node.__class__.__name__ != 'Stmt':
169
return self.recordLine(self.getFirstLine(node))
141
173
def recordLine(self, lineno):
142
174
# Returns a bool, whether the line is included or excluded.
280
315
# See [van Rossum 2001-07-20a, 3.2] for a description of frame and code
283
def t(self, f, w, a): #pragma: no cover
318
def t(self, f, w, unused): #pragma: no cover
285
320
self.c[(f.f_code.co_filename, f.f_lineno)] = 1
286
for c in self.cstack:
287
c[(f.f_code.co_filename, f.f_lineno)] = 1
321
#-for c in self.cstack:
322
#- c[(f.f_code.co_filename, f.f_lineno)] = 1
290
def help(self, error=None):
325
def help(self, error=None): #pragma: no cover
297
def command_line(self, argv, help=None):
332
def command_line(self, argv, help_fn=None):
299
help = help or self.help
334
help_fn = help_fn or self.help
302
337
'-a': 'annotate',
342
377
or settings.get('collect')
345
help("You must specify at least one of -e, -x, -c, -r, or -a.")
380
help_fn("You must specify at least one of -e, -x, -c, -r, or -a.")
346
381
if not args_needed and args:
347
help("Unexpected arguments: %s" % " ".join(args))
382
help_fn("Unexpected arguments: %s" % " ".join(args))
349
self.get_ready(settings.get('parallel-mode'))
350
self.exclude('#pragma[: ]+[nN][oO] [cC][oO][vV][eE][rR]')
384
self.parallel_mode = settings.get('parallel-mode')
352
387
if settings.get('erase'):
354
389
if settings.get('execute'):
356
help("Nothing to do.")
391
help_fn("Nothing to do.")
519
557
def morf_filename(self, morf):
520
558
if isinstance(morf, types.ModuleType):
521
559
if not hasattr(morf, '__file__'):
522
raise CoverageException, "Module has no __file__ attribute."
560
raise CoverageException("Module has no __file__ attribute.")
526
return self.canonical_filename(file)
564
return self.canonical_filename(f)
528
566
# analyze_morf(morf). Analyze the module or filename passed as
529
567
# the argument. If the source code can't be found, raise an error.
530
568
# Otherwise, return a tuple of (1) the canonical filename of the
531
569
# source code for the module, (2) a list of lines of statements
532
# in the source code, and (3) a list of lines of excluded statements.
570
# in the source code, (3) a list of lines of excluded statements,
571
# and (4), a map of line numbers to multi-line line number ranges, for
572
# statements that cross lines.
534
574
def analyze_morf(self, morf):
535
575
if self.analysis_cache.has_key(morf):
536
576
return self.analysis_cache[morf]
537
577
filename = self.morf_filename(morf)
538
578
ext = os.path.splitext(filename)[1]
539
579
if ext == '.pyc':
540
if not os.path.exists(filename[0:-1]):
541
raise CoverageException, ("No source for compiled code '%s'."
543
filename = filename[0:-1]
545
raise CoverageException, "File '%s' not Python source." % filename
546
source = open(filename, 'r')
547
lines, excluded_lines = self.find_executable_statements(
548
source.read(), exclude=self.exclude_re
580
if not os.path.exists(filename[:-1]):
581
raise CoverageException(
582
"No source for compiled code '%s'." % filename
584
filename = filename[:-1]
585
source = open(filename, 'rU')
587
lines, excluded_lines, line_map = self.find_executable_statements(
588
source.read(), exclude=self.exclude_re
590
except SyntaxError, synerr:
591
raise CoverageException(
592
"Couldn't parse '%s' as Python source: '%s' at line %d" %
593
(filename, synerr.msg, synerr.lineno)
551
result = filename, lines, excluded_lines
596
result = filename, lines, excluded_lines, line_map
552
597
self.analysis_cache[morf] = result
600
def first_line_of_tree(self, tree):
602
if len(tree) == 3 and type(tree[2]) == type(1):
606
def last_line_of_tree(self, tree):
608
if len(tree) == 3 and type(tree[2]) == type(1):
612
def find_docstring_pass_pair(self, tree, spots):
613
for i in range(1, len(tree)):
614
if self.is_string_constant(tree[i]) and self.is_pass_stmt(tree[i+1]):
615
first_line = self.first_line_of_tree(tree[i])
616
last_line = self.last_line_of_tree(tree[i+1])
617
self.record_multiline(spots, first_line, last_line)
619
def is_string_constant(self, tree):
621
return tree[0] == symbol.stmt and tree[1][1][1][0] == symbol.expr_stmt
625
def is_pass_stmt(self, tree):
627
return tree[0] == symbol.stmt and tree[1][1][1][0] == symbol.pass_stmt
631
def record_multiline(self, spots, i, j):
632
for l in range(i, j+1):
555
635
def get_suite_spots(self, tree, spots):
636
""" Analyze a parse tree to find suite introducers which span a number
557
639
for i in range(1, len(tree)):
558
640
if type(tree[i]) == type(()):
559
641
if tree[i][0] == symbol.suite:
583
667
if lineno_colon and lineno_word:
584
668
# Found colon and keyword, mark all the lines
585
669
# between the two with the two line numbers.
586
for l in range(lineno_word, lineno_colon+1):
587
spots[l] = (lineno_word, lineno_colon)
670
self.record_multiline(spots, lineno_word, lineno_colon)
672
# "pass" statements are tricky: different versions of Python
673
# treat them differently, especially in the common case of a
674
# function with a doc string and a single pass statement.
675
self.find_docstring_pass_pair(tree[i], spots)
677
elif tree[i][0] == symbol.simple_stmt:
678
first_line = self.first_line_of_tree(tree[i])
679
last_line = self.last_line_of_tree(tree[i])
680
if first_line != last_line:
681
self.record_multiline(spots, first_line, last_line)
588
682
self.get_suite_spots(tree[i], spots)
590
684
def find_executable_statements(self, text, exclude=None):
654
752
return f, s, m, mf
656
754
def analysis2(self, morf):
657
filename, statements, excluded = self.analyze_morf(morf)
755
filename, statements, excluded, line_map = self.analyze_morf(morf)
658
756
self.canonicalize_filenames()
659
757
if not self.cexecuted.has_key(filename):
660
758
self.cexecuted[filename] = {}
662
760
for line in statements:
663
if not self.cexecuted[filename].has_key(line):
761
lines = line_map.get(line, [line, line])
762
for l in range(lines[0], lines[1]+1):
763
if self.cexecuted[filename].has_key(l):
664
766
missing.append(line)
665
767
return (filename, statements, excluded, missing,
666
768
self.format_lines(statements, missing))
816
927
the_coverage = coverage()
818
929
# Module functions call methods in the singleton object.
819
def use_cache(*args, **kw): return the_coverage.use_cache(*args, **kw)
820
def start(*args, **kw): return the_coverage.start(*args, **kw)
821
def stop(*args, **kw): return the_coverage.stop(*args, **kw)
822
def erase(*args, **kw): return the_coverage.erase(*args, **kw)
823
def begin_recursive(*args, **kw): return the_coverage.begin_recursive(*args, **kw)
824
def end_recursive(*args, **kw): return the_coverage.end_recursive(*args, **kw)
825
def exclude(*args, **kw): return the_coverage.exclude(*args, **kw)
826
def analysis(*args, **kw): return the_coverage.analysis(*args, **kw)
827
def analysis2(*args, **kw): return the_coverage.analysis2(*args, **kw)
828
def report(*args, **kw): return the_coverage.report(*args, **kw)
829
def annotate(*args, **kw): return the_coverage.annotate(*args, **kw)
830
def annotate_file(*args, **kw): return the_coverage.annotate_file(*args, **kw)
930
def use_cache(*args, **kw):
931
return the_coverage.use_cache(*args, **kw)
933
def start(*args, **kw):
934
return the_coverage.start(*args, **kw)
936
def stop(*args, **kw):
937
return the_coverage.stop(*args, **kw)
939
def erase(*args, **kw):
940
return the_coverage.erase(*args, **kw)
942
def begin_recursive(*args, **kw):
943
return the_coverage.begin_recursive(*args, **kw)
945
def end_recursive(*args, **kw):
946
return the_coverage.end_recursive(*args, **kw)
948
def exclude(*args, **kw):
949
return the_coverage.exclude(*args, **kw)
951
def analysis(*args, **kw):
952
return the_coverage.analysis(*args, **kw)
954
def analysis2(*args, **kw):
955
return the_coverage.analysis2(*args, **kw)
957
def report(*args, **kw):
958
return the_coverage.report(*args, **kw)
960
def annotate(*args, **kw):
961
return the_coverage.annotate(*args, **kw)
963
def annotate_file(*args, **kw):
964
return the_coverage.annotate_file(*args, **kw)
832
966
# Save coverage data when Python exits. (The atexit module wasn't
833
967
# introduced until Python 2.0, so use sys.exitfunc when it's not
919
1056
# 2006-08-23 NMB Refactorings to improve testability. Fixes to command-line
920
1057
# logic for parallel mode and collect.
1059
# 2006-08-25 NMB "#pragma: nocover" is excluded by default.
1061
# 2006-09-10 NMB Properly ignore docstrings and other constant expressions that
1062
# appear in the middle of a function, a problem reported by Tim Leslie.
1063
# Minor changes to avoid lint warnings.
1065
# 2006-09-17 NMB coverage.erase() shouldn't clobber the exclude regex.
1066
# Change how parallel mode is invoked, and fix erase() so that it erases the
1067
# cache when called programmatically.
1069
# 2007-07-21 NMB In reports, ignore code executed from strings, since we can't
1070
# do anything useful with it anyway.
1071
# Better file handling on Linux, thanks Guillaume Chazarain.
1072
# Better shell support on Windows, thanks Noel O'Boyle.
1073
# Python 2.2 support maintained, thanks Catherine Proulx.
1075
# 2007-07-22 NMB Python 2.5 now fully supported. The method of dealing with
1076
# multi-line statements is now less sensitive to the exact line that Python
1077
# reports during execution. Pass statements are handled specially so that their
1078
# disappearance during execution won't throw off the measurement.
1080
# 2007-07-23 NMB Now Python 2.5 is *really* fully supported: the body of the
1081
# new with statement is counted as executable.
1083
# 2007-07-29 NMB Better packaging.
1085
# 2007-09-30 NMB Don't try to predict whether a file is Python source based on
1086
# the extension. Extensionless files are often Pythons scripts. Instead, simply
1087
# parse the file and catch the syntax errors. Hat tip to Ben Finney.
1089
# 2008-05-25 NMB Open files in rU mode to avoid line ending craziness.
1090
# Thanks, Edward Loper.
922
1092
# C. COPYRIGHT AND LICENCE
924
1094
# Copyright 2001 Gareth Rees. All rights reserved.
925
# Copyright 2004-2006 Ned Batchelder. All rights reserved.
1095
# Copyright 2004-2008 Ned Batchelder. All rights reserved.
927
1097
# Redistribution and use in source and binary forms, with or without
928
1098
# modification, are permitted provided that the following conditions are