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
29 coverage.py -x [-p] MODULE.py [ARG1 ARG2 ...]
30 Execute module, passing the given command-line arguments, collecting
31 coverage data. With the -p option, write to a temporary file containing
32 the machine name and process ID.
35 Erase collected coverage data.
38 Collect data from multiple coverage files (as created by -p option above)
39 and store it into a single file representing the union of the coverage.
41 coverage.py -r [-m] [-o dir1,dir2,...] FILE1 FILE2 ...
42 Report on the statement coverage for the given files. With the -m
43 option, show line numbers of the statements that weren't executed.
45 coverage.py -a [-d dir] [-o dir1,dir2,...] FILE1 FILE2 ...
46 Make annotated copies of the given files, marking statements that
47 are executed with > and statements that are missed with !. With
48 the -d option, make the copies in that directory. Without the -d
49 option, make each copy in the same directory as the original.
52 Omit reporting or annotating files when their filename path starts with
53 a directory listed in the omit list.
54 e.g. python coverage.py -i -r -o c:\python23,lib\enthought\traits
56 Coverage data is saved in the file .coverage by default. Set the
57 COVERAGE_FILE environment variable to save it somewhere else."""
59 __version__
= "2.78.20070930" # see detailed history at the end of this file.
62 import compiler
.visitor
72 from socket
import gethostname
74 # Python version compatibility
76 strclass
= basestring
# new to 2.3
82 # This uses the "singleton" pattern.
84 # The word "morf" means a module object (from which the source file can
85 # be deduced by suitable manipulation of the __file__ attribute) or a
88 # When we generate a coverage report we have to canonicalize every
89 # filename in the coverage dictionary just in case it refers to the
90 # module we are reporting on. It seems a shame to throw away this
91 # information so the data in the coverage dictionary is transferred to
92 # the 'cexecuted' dictionary under the canonical filenames.
94 # The coverage dictionary is called "c" and the trace function "t". The
95 # reason for these short names is that Python looks up variables by name
96 # at runtime and so execution time depends on the length of variables!
97 # In the bottleneck of this application it's appropriate to abbreviate
98 # names to increase speed.
100 class StatementFindingAstVisitor(compiler
.visitor
.ASTVisitor
):
101 """ A visitor for a parsed Abstract Syntax Tree which finds executable
104 def __init__(self
, statements
, excluded
, suite_spots
):
105 compiler
.visitor
.ASTVisitor
.__init
__(self
)
106 self
.statements
= statements
107 self
.excluded
= excluded
108 self
.suite_spots
= suite_spots
109 self
.excluding_suite
= 0
111 def doRecursive(self
, node
):
112 for n
in node
.getChildNodes():
115 visitStmt
= visitModule
= doRecursive
117 def doCode(self
, node
):
118 if hasattr(node
, 'decorators') and node
.decorators
:
119 self
.dispatch(node
.decorators
)
120 self
.recordAndDispatch(node
.code
)
122 self
.doSuite(node
, node
.code
)
124 visitFunction
= visitClass
= doCode
126 def getFirstLine(self
, node
):
127 # Find the first line in the tree node.
129 for n
in node
.getChildNodes():
130 f
= self
.getFirstLine(n
)
132 lineno
= min(lineno
, f
)
137 def getLastLine(self
, node
):
138 # Find the first line in the tree node.
140 for n
in node
.getChildNodes():
141 lineno
= max(lineno
, self
.getLastLine(n
))
144 def doStatement(self
, node
):
145 self
.recordLine(self
.getFirstLine(node
))
147 visitAssert
= visitAssign
= visitAssTuple
= visitPrint
= \
148 visitPrintnl
= visitRaise
= visitSubscript
= visitDecorators
= \
151 def visitPass(self
, node
):
152 # Pass statements have weird interactions with docstrings. If this
153 # pass statement is part of one of those pairs, claim that the statement
154 # is on the later of the two lines.
157 lines
= self
.suite_spots
.get(l
, [l
,l
])
158 self
.statements
[lines
[1]] = 1
160 def visitDiscard(self
, node
):
161 # Discard nodes are statements that execute an expression, but then
162 # discard the results. This includes function calls, so we can't
163 # ignore them all. But if the expression is a constant, the statement
164 # won't be "executed", so don't count it now.
165 if node
.expr
.__class
__.__name
__ != 'Const':
166 self
.doStatement(node
)
168 def recordNodeLine(self
, node
):
169 # Stmt nodes often have None, but shouldn't claim the first line of
170 # their children (because the first child might be an ignorable line
172 if node
.__class
__.__name
__ != 'Stmt':
173 return self
.recordLine(self
.getFirstLine(node
))
177 def recordLine(self
, lineno
):
178 # Returns a bool, whether the line is included or excluded.
180 # Multi-line tests introducing suites have to get charged to their
182 if lineno
in self
.suite_spots
:
183 lineno
= self
.suite_spots
[lineno
][0]
184 # If we're inside an excluded suite, record that this line was
186 if self
.excluding_suite
:
187 self
.excluded
[lineno
] = 1
189 # If this line is excluded, or suite_spots maps this line to
190 # another line that is exlcuded, then we're excluded.
191 elif self
.excluded
.has_key(lineno
) or \
192 self
.suite_spots
.has_key(lineno
) and \
193 self
.excluded
.has_key(self
.suite_spots
[lineno
][1]):
195 # Otherwise, this is an executable line.
197 self
.statements
[lineno
] = 1
201 default
= recordNodeLine
203 def recordAndDispatch(self
, node
):
204 self
.recordNodeLine(node
)
207 def doSuite(self
, intro
, body
, exclude
=0):
208 exsuite
= self
.excluding_suite
209 if exclude
or (intro
and not self
.recordNodeLine(intro
)):
210 self
.excluding_suite
= 1
211 self
.recordAndDispatch(body
)
212 self
.excluding_suite
= exsuite
214 def doPlainWordSuite(self
, prevsuite
, suite
):
215 # Finding the exclude lines for else's is tricky, because they aren't
216 # present in the compiler parse tree. Look at the previous suite,
217 # and find its last line. If any line between there and the else's
218 # first line are excluded, then we exclude the else.
219 lastprev
= self
.getLastLine(prevsuite
)
220 firstelse
= self
.getFirstLine(suite
)
221 for l
in range(lastprev
+1, firstelse
):
222 if self
.suite_spots
.has_key(l
):
223 self
.doSuite(None, suite
, exclude
=self
.excluded
.has_key(l
))
226 self
.doSuite(None, suite
)
228 def doElse(self
, prevsuite
, node
):
230 self
.doPlainWordSuite(prevsuite
, node
.else_
)
232 def visitFor(self
, node
):
233 self
.doSuite(node
, node
.body
)
234 self
.doElse(node
.body
, node
)
236 visitWhile
= visitFor
238 def visitIf(self
, node
):
239 # The first test has to be handled separately from the rest.
240 # The first test is credited to the line with the "if", but the others
241 # are credited to the line with the test for the elif.
242 self
.doSuite(node
, node
.tests
[0][1])
243 for t
, n
in node
.tests
[1:]:
245 self
.doElse(node
.tests
[-1][1], node
)
247 def visitTryExcept(self
, node
):
248 self
.doSuite(node
, node
.body
)
249 for i
in range(len(node
.handlers
)):
250 a
, b
, h
= node
.handlers
[i
]
252 # It's a plain "except:". Find the previous suite.
254 prev
= node
.handlers
[i
-1][2]
257 self
.doPlainWordSuite(prev
, h
)
260 self
.doElse(node
.handlers
[-1][2], node
)
262 def visitTryFinally(self
, node
):
263 self
.doSuite(node
, node
.body
)
264 self
.doPlainWordSuite(node
.body
, node
.final
)
266 def visitWith(self
, node
):
267 self
.doSuite(node
, node
.body
)
269 def visitGlobal(self
, node
):
270 # "global" statements don't execute like others (they don't call the
271 # trace function), so don't record their line numbers.
276 class CoverageException(Exception): pass
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
= os
.path
.normcase(os
.path
.abspath(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 #print "Executing %s @ %d" % (f.f_code.co_filename, f.f_lineno)
325 self
.c
[(f
.f_code
.co_filename
, f
.f_lineno
)] = 1
326 for c
in self
.cstack
:
327 c
[(f
.f_code
.co_filename
, f
.f_lineno
)] = 1
330 def help(self
, error
=None): #pragma: no cover
337 def command_line(self
, argv
, help_fn
=None):
339 help_fn
= help_fn
or self
.help
347 '-i': 'ignore-errors',
348 '-m': 'show-missing',
349 '-p': 'parallel-mode',
354 short_opts
= string
.join(map(lambda o
: o
[1:], optmap
.keys()), '')
355 long_opts
= optmap
.values()
356 options
, args
= getopt
.getopt(argv
, short_opts
, long_opts
)
359 if optmap
.has_key(o
):
360 settings
[optmap
[o
]] = 1
361 elif optmap
.has_key(o
+ ':'):
362 settings
[optmap
[o
+ ':']] = a
363 elif o
[2:] in long_opts
:
365 elif o
[2:] + '=' in long_opts
:
366 settings
[o
[2:]+'='] = a
367 else: #pragma: no cover
368 pass # Can't get here, because getopt won't return anything unknown.
370 if settings
.get('help'):
373 for i
in ['erase', 'execute']:
374 for j
in ['annotate', 'report', 'collect']:
375 if settings
.get(i
) and settings
.get(j
):
376 help_fn("You can't specify the '%s' and '%s' "
377 "options at the same time." % (i
, j
))
379 args_needed
= (settings
.get('execute')
380 or settings
.get('annotate')
381 or settings
.get('report'))
382 action
= (settings
.get('erase')
383 or settings
.get('collect')
386 help_fn("You must specify at least one of -e, -x, -c, -r, or -a.")
387 if not args_needed
and args
:
388 help_fn("Unexpected arguments: %s" % " ".join(args
))
390 self
.parallel_mode
= settings
.get('parallel-mode')
393 if settings
.get('erase'):
395 if settings
.get('execute'):
397 help_fn("Nothing to do.")
401 sys
.path
[0] = os
.path
.dirname(sys
.argv
[0])
402 # the line below is needed since otherwise __file__ gets fucked
403 __main__
.__dict
__["__file__"] = sys
.argv
[0]
404 execfile(sys
.argv
[0], __main__
.__dict
__)
405 if settings
.get('collect'):
408 args
= self
.cexecuted
.keys()
410 ignore_errors
= settings
.get('ignore-errors')
411 show_missing
= settings
.get('show-missing')
412 directory
= settings
.get('directory=')
414 omit
= settings
.get('omit=')
416 omit
= omit
.split(',')
420 if settings
.get('report'):
421 self
.report(args
, show_missing
, ignore_errors
, omit_prefixes
=omit
)
422 if settings
.get('annotate'):
423 self
.annotate(args
, directory
, ignore_errors
, omit_prefixes
=omit
)
425 def use_cache(self
, usecache
, cache_file
=None):
426 self
.usecache
= usecache
427 if cache_file
and not self
.cache
:
428 self
.cache_default
= cache_file
430 def get_ready(self
, parallel_mode
=False):
431 if self
.usecache
and not self
.cache
:
432 self
.cache
= os
.environ
.get(self
.cache_env
, self
.cache_default
)
433 if self
.parallel_mode
:
434 self
.cache
+= "." + gethostname() + "." + str(os
.getpid())
436 self
.analysis_cache
= {}
438 def start(self
, parallel_mode
=False):
440 if self
.nesting
== 0: #pragma: no cover
442 if hasattr(threading
, 'settrace'):
443 threading
.settrace(self
.t
)
448 if self
.nesting
== 0: #pragma: no cover
450 if hasattr(threading
, 'settrace'):
451 threading
.settrace(None)
456 self
.analysis_cache
= {}
458 if self
.cache
and os
.path
.exists(self
.cache
):
459 os
.remove(self
.cache
)
461 def exclude(self
, re
):
463 self
.exclude_re
+= "|"
464 self
.exclude_re
+= "(" + re
+ ")"
466 def begin_recursive(self
):
467 self
.cstack
.append(self
.c
)
468 self
.xstack
.append(self
.exclude_re
)
470 def end_recursive(self
):
471 self
.c
= self
.cstack
.pop()
472 self
.exclude_re
= self
.xstack
.pop()
474 # save(). Save coverage data to the coverage cache.
477 if self
.usecache
and self
.cache
:
478 self
.canonicalize_filenames()
479 cache
= open(self
.cache
, 'wb')
481 marshal
.dump(self
.cexecuted
, cache
)
484 # restore(). Restore coverage data from the coverage cache (if it exists).
490 if os
.path
.exists(self
.cache
):
491 self
.cexecuted
= self
.restore_file(self
.cache
)
493 def restore_file(self
, file_name
):
495 cache
= open(file_name
, 'rb')
497 cexecuted
= marshal
.load(cache
)
499 if isinstance(cexecuted
, types
.DictType
):
506 # collect(). Collect data in multiple files produced by parallel mode
509 cache_dir
, local
= os
.path
.split(self
.cache
)
510 for f
in os
.listdir(cache_dir
or '.'):
511 if not f
.startswith(local
):
514 full_path
= os
.path
.join(cache_dir
, f
)
515 cexecuted
= self
.restore_file(full_path
)
516 self
.merge_data(cexecuted
)
518 def merge_data(self
, new_data
):
519 for file_name
, file_data
in new_data
.items():
520 if self
.cexecuted
.has_key(file_name
):
521 self
.merge_file_data(self
.cexecuted
[file_name
], file_data
)
523 self
.cexecuted
[file_name
] = file_data
525 def merge_file_data(self
, cache_data
, new_data
):
526 for line_number
in new_data
.keys():
527 if not cache_data
.has_key(line_number
):
528 cache_data
[line_number
] = new_data
[line_number
]
530 # canonical_filename(filename). Return a canonical filename for the
531 # file (that is, an absolute path with no redundant components and
532 # normalized case). See [GDR 2001-12-04b, 3.3].
534 def canonical_filename(self
, filename
):
535 if not self
.canonical_filename_cache
.has_key(filename
):
537 if os
.path
.isabs(f
) and not os
.path
.exists(f
):
538 f
= os
.path
.basename(f
)
539 if not os
.path
.isabs(f
):
540 for path
in [os
.curdir
] + sys
.path
:
541 g
= os
.path
.join(path
, f
)
542 if os
.path
.exists(g
):
545 cf
= os
.path
.normcase(os
.path
.abspath(f
))
546 self
.canonical_filename_cache
[filename
] = cf
547 return self
.canonical_filename_cache
[filename
]
549 # canonicalize_filenames(). Copy results from "c" to "cexecuted",
550 # canonicalizing filenames on the way. Clear the "c" map.
552 def canonicalize_filenames(self
):
553 for filename
, lineno
in self
.c
.keys():
554 if filename
== '<string>':
555 # Can't do anything useful with exec'd strings, so skip them.
557 f
= self
.canonical_filename(filename
)
558 if not self
.cexecuted
.has_key(f
):
559 self
.cexecuted
[f
] = {}
560 self
.cexecuted
[f
][lineno
] = 1
563 # morf_filename(morf). Return the filename for a module or file.
565 def morf_filename(self
, morf
):
566 if isinstance(morf
, types
.ModuleType
):
567 if not hasattr(morf
, '__file__'):
568 raise CoverageException("Module has no __file__ attribute.")
572 return self
.canonical_filename(f
)
574 # analyze_morf(morf). Analyze the module or filename passed as
575 # the argument. If the source code can't be found, raise an error.
576 # Otherwise, return a tuple of (1) the canonical filename of the
577 # source code for the module, (2) a list of lines of statements
578 # in the source code, (3) a list of lines of excluded statements,
579 # and (4), a map of line numbers to multi-line line number ranges, for
580 # statements that cross lines.
582 def analyze_morf(self
, morf
):
583 if self
.analysis_cache
.has_key(morf
):
584 return self
.analysis_cache
[morf
]
585 filename
= self
.morf_filename(morf
)
586 ext
= os
.path
.splitext(filename
)[1]
588 if not os
.path
.exists(filename
[:-1]):
589 raise CoverageException(
590 "No source for compiled code '%s'." % filename
592 filename
= filename
[:-1]
593 source
= open(filename
, 'r')
595 lines
, excluded_lines
, line_map
= self
.find_executable_statements(
596 source
.read(), exclude
=self
.exclude_re
598 except SyntaxError, synerr
:
599 raise CoverageException(
600 "Couldn't parse '%s' as Python source: '%s' at line %d" %
601 (filename
, synerr
.msg
, synerr
.lineno
)
604 result
= filename
, lines
, excluded_lines
, line_map
605 self
.analysis_cache
[morf
] = result
608 def first_line_of_tree(self
, tree
):
610 if len(tree
) == 3 and type(tree
[2]) == type(1):
614 def last_line_of_tree(self
, tree
):
616 if len(tree
) == 3 and type(tree
[2]) == type(1):
620 def find_docstring_pass_pair(self
, tree
, spots
):
621 for i
in range(1, len(tree
)):
622 if self
.is_string_constant(tree
[i
]) and self
.is_pass_stmt(tree
[i
+1]):
623 first_line
= self
.first_line_of_tree(tree
[i
])
624 last_line
= self
.last_line_of_tree(tree
[i
+1])
625 self
.record_multiline(spots
, first_line
, last_line
)
627 def is_string_constant(self
, tree
):
629 return tree
[0] == symbol
.stmt
and tree
[1][1][1][0] == symbol
.expr_stmt
633 def is_pass_stmt(self
, tree
):
635 return tree
[0] == symbol
.stmt
and tree
[1][1][1][0] == symbol
.pass_stmt
639 def record_multiline(self
, spots
, i
, j
):
640 for l
in range(i
, j
+1):
643 def get_suite_spots(self
, tree
, spots
):
644 """ Analyze a parse tree to find suite introducers which span a number
647 for i
in range(1, len(tree
)):
648 if type(tree
[i
]) == type(()):
649 if tree
[i
][0] == symbol
.suite
:
650 # Found a suite, look back for the colon and keyword.
651 lineno_colon
= lineno_word
= None
652 for j
in range(i
-1, 0, -1):
653 if tree
[j
][0] == token
.COLON
:
654 # Colons are never executed themselves: we want the
655 # line number of the last token before the colon.
656 lineno_colon
= self
.last_line_of_tree(tree
[j
-1])
657 elif tree
[j
][0] == token
.NAME
:
658 if tree
[j
][1] == 'elif':
659 # Find the line number of the first non-terminal
662 while t
and token
.ISNONTERMINAL(t
[0]):
667 lineno_word
= tree
[j
][2]
669 elif tree
[j
][0] == symbol
.except_clause
:
670 # "except" clauses look like:
671 # ('except_clause', ('NAME', 'except', lineno), ...)
672 if tree
[j
][1][0] == token
.NAME
:
673 lineno_word
= tree
[j
][1][2]
675 if lineno_colon
and lineno_word
:
676 # Found colon and keyword, mark all the lines
677 # between the two with the two line numbers.
678 self
.record_multiline(spots
, lineno_word
, lineno_colon
)
680 # "pass" statements are tricky: different versions of Python
681 # treat them differently, especially in the common case of a
682 # function with a doc string and a single pass statement.
683 self
.find_docstring_pass_pair(tree
[i
], spots
)
685 elif tree
[i
][0] == symbol
.simple_stmt
:
686 first_line
= self
.first_line_of_tree(tree
[i
])
687 last_line
= self
.last_line_of_tree(tree
[i
])
688 if first_line
!= last_line
:
689 self
.record_multiline(spots
, first_line
, last_line
)
690 self
.get_suite_spots(tree
[i
], spots
)
692 def find_executable_statements(self
, text
, exclude
=None):
693 # Find lines which match an exclusion pattern.
697 reExclude
= re
.compile(exclude
)
698 lines
= text
.split('\n')
699 for i
in range(len(lines
)):
700 if reExclude
.search(lines
[i
]):
703 # Parse the code and analyze the parse tree to find out which statements
704 # are multiline, and where suites begin and end.
706 tree
= parser
.suite(text
+'\n\n').totuple(1)
707 self
.get_suite_spots(tree
, suite_spots
)
708 #print "Suite spots:", suite_spots
710 # Use the compiler module to parse the text and find the executable
711 # statements. We add newlines to be impervious to final partial lines.
713 ast
= compiler
.parse(text
+'\n\n')
714 visitor
= StatementFindingAstVisitor(statements
, excluded
, suite_spots
)
715 compiler
.walk(ast
, visitor
, walker
=visitor
)
717 lines
= statements
.keys()
719 excluded_lines
= excluded
.keys()
720 excluded_lines
.sort()
721 return lines
, excluded_lines
, suite_spots
723 # format_lines(statements, lines). Format a list of line numbers
724 # for printing by coalescing groups of lines as long as the lines
725 # represent consecutive statements. This will coalesce even if
726 # there are gaps between statements, so if statements =
727 # [1,2,3,4,5,10,11,12,13,14] and lines = [1,2,5,10,11,13,14] then
728 # format_lines will return "1-2, 5-11, 13-14".
730 def format_lines(self
, statements
, lines
):
736 while i
< len(statements
) and j
< len(lines
):
737 if statements
[i
] == lines
[j
]:
743 pairs
.append((start
, end
))
747 pairs
.append((start
, end
))
753 return "%d-%d" % (start
, end
)
754 ret
= string
.join(map(stringify
, pairs
), ", ")
757 # Backward compatibility with version 1.
758 def analysis(self
, morf
):
759 f
, s
, _
, m
, mf
= self
.analysis2(morf
)
762 def analysis2(self
, morf
):
763 filename
, statements
, excluded
, line_map
= self
.analyze_morf(morf
)
764 self
.canonicalize_filenames()
765 if not self
.cexecuted
.has_key(filename
):
766 self
.cexecuted
[filename
] = {}
768 for line
in statements
:
769 lines
= line_map
.get(line
, [line
, line
])
770 for l
in range(lines
[0], lines
[1]+1):
771 if self
.cexecuted
[filename
].has_key(l
):
775 return (filename
, statements
, excluded
, missing
,
776 self
.format_lines(statements
, missing
))
778 def relative_filename(self
, filename
):
779 """ Convert filename to relative filename from self.relative_dir.
781 return filename
.replace(self
.relative_dir
, "")
783 def morf_name(self
, morf
):
784 """ Return the name of morf as used in report.
786 if isinstance(morf
, types
.ModuleType
):
789 return self
.relative_filename(os
.path
.splitext(morf
)[0])
791 def filter_by_prefix(self
, morfs
, omit_prefixes
):
792 """ Return list of morfs where the morf name does not begin
793 with any one of the omit_prefixes.
797 for prefix
in omit_prefixes
:
798 if self
.morf_name(morf
).startswith(prefix
):
801 filtered_morfs
.append(morf
)
803 return filtered_morfs
805 def morf_name_compare(self
, x
, y
):
806 return cmp(self
.morf_name(x
), self
.morf_name(y
))
808 def report(self
, morfs
, show_missing
=1, ignore_errors
=0, file=None, omit_prefixes
=[]):
809 if not isinstance(morfs
, types
.ListType
):
811 # On windows, the shell doesn't expand wildcards. Do it here.
814 if isinstance(morf
, strclass
):
815 globbed
.extend(glob
.glob(morf
))
820 morfs
= self
.filter_by_prefix(morfs
, omit_prefixes
)
821 morfs
.sort(self
.morf_name_compare
)
823 max_name
= max([5,] + map(len, map(self
.morf_name
, morfs
)))
824 fmt_name
= "%%- %ds " % max_name
825 fmt_err
= fmt_name
+ "%s: %s"
826 header
= fmt_name
% "Name" + " Stmts Exec Cover"
827 fmt_coverage
= fmt_name
+ "% 6d % 6d % 5d%%"
829 header
= header
+ " Missing"
830 fmt_coverage
= fmt_coverage
+ " %s"
834 print >>file, "-" * len(header
)
838 name
= self
.morf_name(morf
)
840 _
, statements
, _
, missing
, readable
= self
.analysis2(morf
)
847 args
= (name
, n
, m
, pc
)
849 args
= args
+ (readable
,)
850 print >>file, fmt_coverage
% args
851 total_statements
= total_statements
+ n
852 total_executed
= total_executed
+ m
853 except KeyboardInterrupt: #pragma: no cover
856 if not ignore_errors
:
857 typ
, msg
= sys
.exc_info()[:2]
858 print >>file, fmt_err
% (name
, typ
, msg
)
860 print >>file, "-" * len(header
)
861 if total_statements
> 0:
862 pc
= 100.0 * total_executed
/ total_statements
865 args
= ("TOTAL", total_statements
, total_executed
, pc
)
868 print >>file, fmt_coverage
% args
870 # annotate(morfs, ignore_errors).
872 blank_re
= re
.compile(r
"\s*(#|$)")
873 else_re
= re
.compile(r
"\s*else\s*:\s*(#|$)")
875 def annotate(self
, morfs
, directory
=None, ignore_errors
=0, omit_prefixes
=[]):
876 morfs
= self
.filter_by_prefix(morfs
, omit_prefixes
)
879 filename
, statements
, excluded
, missing
, _
= self
.analysis2(morf
)
880 self
.annotate_file(filename
, statements
, excluded
, missing
, directory
)
881 except KeyboardInterrupt:
884 if not ignore_errors
:
887 def annotate_file(self
, filename
, statements
, excluded
, missing
, directory
=None):
888 source
= open(filename
, 'r')
890 dest_file
= os
.path
.join(directory
,
891 os
.path
.basename(filename
)
894 dest_file
= filename
+ ',cover'
895 dest
= open(dest_file
, 'w')
901 line
= source
.readline()
905 while i
< len(statements
) and statements
[i
] < lineno
:
907 while j
< len(missing
) and missing
[j
] < lineno
:
909 if i
< len(statements
) and statements
[i
] == lineno
:
910 covered
= j
>= len(missing
) or missing
[j
] > lineno
911 if self
.blank_re
.match(line
):
913 elif self
.else_re
.match(line
):
914 # Special logic for lines containing only 'else:'.
915 # See [GDR 2001-12-04b, 3.2].
916 if i
>= len(statements
) and j
>= len(missing
):
918 elif i
>= len(statements
) or j
>= len(missing
):
920 elif statements
[i
] == missing
[j
]:
924 elif lineno
in excluded
:
935 the_coverage
= coverage()
937 # Module functions call methods in the singleton object.
938 def use_cache(*args
, **kw
):
939 return the_coverage
.use_cache(*args
, **kw
)
941 def start(*args
, **kw
):
942 return the_coverage
.start(*args
, **kw
)
944 def stop(*args
, **kw
):
945 return the_coverage
.stop(*args
, **kw
)
947 def erase(*args
, **kw
):
948 return the_coverage
.erase(*args
, **kw
)
950 def begin_recursive(*args
, **kw
):
951 return the_coverage
.begin_recursive(*args
, **kw
)
953 def end_recursive(*args
, **kw
):
954 return the_coverage
.end_recursive(*args
, **kw
)
956 def exclude(*args
, **kw
):
957 return the_coverage
.exclude(*args
, **kw
)
959 def analysis(*args
, **kw
):
960 return the_coverage
.analysis(*args
, **kw
)
962 def analysis2(*args
, **kw
):
963 return the_coverage
.analysis2(*args
, **kw
)
965 def report(*args
, **kw
):
966 return the_coverage
.report(*args
, **kw
)
968 def annotate(*args
, **kw
):
969 return the_coverage
.annotate(*args
, **kw
)
971 def annotate_file(*args
, **kw
):
972 return the_coverage
.annotate_file(*args
, **kw
)
974 # Save coverage data when Python exits. (The atexit module wasn't
975 # introduced until Python 2.0, so use sys.exitfunc when it's not
979 atexit
.register(the_coverage
.save
)
981 sys
.exitfunc
= the_coverage
.save
983 # Command-line interface.
984 if __name__
== '__main__':
985 the_coverage
.command_line(sys
.argv
[1:])
990 # [GDR 2001-12-04a] "Statement coverage for Python"; Gareth Rees;
991 # Ravenbrook Limited; 2001-12-04;
992 # <http://www.nedbatchelder.com/code/modules/rees-coverage.html>.
994 # [GDR 2001-12-04b] "Statement coverage for Python: design and
995 # analysis"; Gareth Rees; Ravenbrook Limited; 2001-12-04;
996 # <http://www.nedbatchelder.com/code/modules/rees-design.html>.
998 # [van Rossum 2001-07-20a] "Python Reference Manual (releae 2.1.1)";
999 # Guide van Rossum; 2001-07-20;
1000 # <http://www.python.org/doc/2.1.1/ref/ref.html>.
1002 # [van Rossum 2001-07-20b] "Python Library Reference"; Guido van Rossum;
1003 # 2001-07-20; <http://www.python.org/doc/2.1.1/lib/lib.html>.
1006 # B. DOCUMENT HISTORY
1008 # 2001-12-04 GDR Created.
1010 # 2001-12-06 GDR Added command-line interface and source code
1013 # 2001-12-09 GDR Moved design and interface to separate documents.
1015 # 2001-12-10 GDR Open cache file as binary on Windows. Allow
1016 # simultaneous -e and -x, or -a and -r.
1018 # 2001-12-12 GDR Added command-line help. Cache analysis so that it
1019 # only needs to be done once when you specify -a and -r.
1021 # 2001-12-13 GDR Improved speed while recording. Portable between
1022 # Python 1.5.2 and 2.1.1.
1024 # 2002-01-03 GDR Module-level functions work correctly.
1026 # 2002-01-07 GDR Update sys.path when running a file with the -x option,
1027 # so that it matches the value the program would get if it were run on
1030 # 2004-12-12 NMB Significant code changes.
1031 # - Finding executable statements has been rewritten so that docstrings and
1032 # other quirks of Python execution aren't mistakenly identified as missing
1034 # - Lines can be excluded from consideration, even entire suites of lines.
1035 # - The filesystem cache of covered lines can be disabled programmatically.
1036 # - Modernized the code.
1038 # 2004-12-14 NMB Minor tweaks. Return 'analysis' to its original behavior
1039 # and add 'analysis2'. Add a global for 'annotate', and factor it, adding
1042 # 2004-12-31 NMB Allow for keyword arguments in the module global functions.
1045 # 2005-12-02 NMB Call threading.settrace so that all threads are measured.
1046 # Thanks Martin Fuzzey. Add a file argument to report so that reports can be
1047 # captured to a different destination.
1049 # 2005-12-03 NMB coverage.py can now measure itself.
1051 # 2005-12-04 NMB Adapted Greg Rogers' patch for using relative filenames,
1052 # and sorting and omitting files to report on.
1054 # 2006-07-23 NMB Applied Joseph Tate's patch for function decorators.
1056 # 2006-08-21 NMB Applied Sigve Tjora and Mark van der Wal's fixes for argument
1059 # 2006-08-22 NMB Applied Geoff Bache's parallel mode patch.
1061 # 2006-08-23 NMB Refactorings to improve testability. Fixes to command-line
1062 # logic for parallel mode and collect.
1064 # 2006-08-25 NMB "#pragma: nocover" is excluded by default.
1066 # 2006-09-10 NMB Properly ignore docstrings and other constant expressions that
1067 # appear in the middle of a function, a problem reported by Tim Leslie.
1068 # Minor changes to avoid lint warnings.
1070 # 2006-09-17 NMB coverage.erase() shouldn't clobber the exclude regex.
1071 # Change how parallel mode is invoked, and fix erase() so that it erases the
1072 # cache when called programmatically.
1074 # 2007-07-21 NMB In reports, ignore code executed from strings, since we can't
1075 # do anything useful with it anyway.
1076 # Better file handling on Linux, thanks Guillaume Chazarain.
1077 # Better shell support on Windows, thanks Noel O'Boyle.
1078 # Python 2.2 support maintained, thanks Catherine Proulx.
1080 # 2007-07-22 NMB Python 2.5 now fully supported. The method of dealing with
1081 # multi-line statements is now less sensitive to the exact line that Python
1082 # reports during execution. Pass statements are handled specially so that their
1083 # disappearance during execution won't throw off the measurement.
1085 # 2007-07-23 NMB Now Python 2.5 is *really* fully supported: the body of the
1086 # new with statement is counted as executable.
1088 # 2007-07-29 NMB Better packaging.
1090 # 2007-09-30 NMB Don't try to predict whether a file is Python source based on
1091 # the extension. Extensionless files are often Pythons scripts. Instead, simply
1092 # parse the file and catch the syntax errors. Hat tip to Ben Finney.
1094 # C. COPYRIGHT AND LICENCE
1096 # Copyright 2001 Gareth Rees. All rights reserved.
1097 # Copyright 2004-2007 Ned Batchelder. All rights reserved.
1099 # Redistribution and use in source and binary forms, with or without
1100 # modification, are permitted provided that the following conditions are
1103 # 1. Redistributions of source code must retain the above copyright
1104 # notice, this list of conditions and the following disclaimer.
1106 # 2. Redistributions in binary form must reproduce the above copyright
1107 # notice, this list of conditions and the following disclaimer in the
1108 # documentation and/or other materials provided with the
1111 # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
1112 # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
1113 # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
1114 # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
1115 # HOLDERS AND CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
1116 # INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
1117 # BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
1118 # OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
1119 # ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
1120 # TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
1121 # USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
1124 # $Id: coverage.py 79 2007-10-01 01:01:52Z nedbat $