summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--CHANGES.txt22
-rw-r--r--Makefile8
-rw-r--r--coverage/__init__.py4
-rw-r--r--coverage/annotate.py18
-rw-r--r--coverage/bytecode.py22
-rw-r--r--coverage/cmdline.py58
-rw-r--r--coverage/codeunit.py34
-rw-r--r--coverage/collector.py43
-rw-r--r--coverage/control.py73
-rw-r--r--coverage/data.py46
-rw-r--r--coverage/execfile.py6
-rw-r--r--coverage/files.py12
-rw-r--r--coverage/html.py24
-rw-r--r--coverage/misc.py12
-rw-r--r--coverage/parser.py158
-rw-r--r--coverage/phystokens.py12
-rw-r--r--coverage/report.py16
-rw-r--r--coverage/results.py24
-rw-r--r--coverage/summary.py6
-rw-r--r--coverage/templite.py38
-rw-r--r--coverage/tracer.c42
-rw-r--r--coverage/xmlreport.py20
-rw-r--r--doc/api.rst8
-rw-r--r--doc/branch.rst14
-rw-r--r--doc/changes.rst12
-rw-r--r--doc/cmd.rst8
-rw-r--r--doc/excluding.rst4
-rw-r--r--doc/index.rst6
-rw-r--r--howto.txt2
-rw-r--r--setup.py4
-rw-r--r--test/backtest.py12
-rw-r--r--test/backunittest.py10
-rw-r--r--test/coverage_coverage.py10
-rw-r--r--test/coveragetest.py70
-rw-r--r--test/osinfo.py6
-rw-r--r--test/test_api.py32
-rw-r--r--test/test_arcs.py8
-rw-r--r--test/test_cmdline.py30
-rw-r--r--test/test_codeunit.py3
-rw-r--r--test/test_coverage.py158
-rw-r--r--test/test_data.py22
-rw-r--r--test/test_execfile.py6
-rw-r--r--test/test_farm.py74
-rw-r--r--test/test_oddball.py42
-rw-r--r--test/test_parser.py10
-rw-r--r--test/test_phystokens.py2
-rw-r--r--test/test_results.py4
-rw-r--r--test/test_summary.py4
-rw-r--r--test/test_templite.py14
49 files changed, 637 insertions, 636 deletions
diff --git a/CHANGES.txt b/CHANGES.txt
index 722cb774..02974ada 100644
--- a/CHANGES.txt
+++ b/CHANGES.txt
@@ -68,9 +68,9 @@ Version 3.2b1, 10 November 2009
- Some exceptions reported by the command line interface have been cleaned up
so that tracebacks inside coverage.py aren't shown. Fixes `issue 23`_.
-
+
.. _issue 23: http://bitbucket.org/ned/coveragepy/issue/23
-
+
Version 3.1, 4 October 2009
---------------------------
@@ -144,10 +144,10 @@ Version 3.0, 13 June 2009
- Fixed the way the Python library was ignored. Too much code was being
excluded the old way.
-
+
- Tabs are now properly converted in HTML reports. Previously indentation was
lost. Fixed `issue 6`.
-
+
- Nested modules now get a proper flat_rootname. Thanks, Christian Heimes.
.. _issue 6: http://bitbucket.org/ned/coveragepy/issue/6
@@ -158,7 +158,7 @@ Version 3.0b3, 16 May 2009
- Added parameters to coverage.__init__ for options that had been set on the
coverage object itself.
-
+
- Added clear_exclude() and get_exclude_list() methods for programmatic
manipulation of the exclude regexes.
@@ -216,16 +216,16 @@ Major overhaul.
- Executable lines are identified by reading the line number tables in the
compiled code, removing a great deal of complicated analysis code.
-
+
- Precisely which lines are considered executable has changed in some cases.
Therefore, your coverage stats may also change slightly.
- The singleton coverage object is only created if the module-level functions
are used. This maintains the old interface while allowing better
programmatic use of Coverage.
-
+
- The minimum supported Python version is 2.3.
-
+
Version 2.85, 14 September 2008
-------------------------------
@@ -233,7 +233,7 @@ Version 2.85, 14 September 2008
- Add support for finding source files in eggs. Don't check for
morf's being instances of ModuleType, instead use duck typing so that
pseudo-modules can participate. Thanks, Imri Goldberg.
-
+
- Use os.realpath as part of the fixing of file names so that symlinks won't
confuse things. Thanks, Patrick Mezard.
@@ -288,7 +288,7 @@ Version 2.7, 21 July 2007
- In reports, ignore code executed from strings, since we can't do anything
useful with it anyway.
-
+
- Better file handling on Linux, thanks Guillaume Chazarain.
- Better shell support on Windows, thanks Noel O'Boyle.
@@ -316,7 +316,7 @@ Version 2.5, 4 December 2005
- Call threading.settrace so that all threads are measured. Thanks Martin
Fuzzey.
-
+
- Add a file argument to report so that reports can be captured to a different
destination.
diff --git a/Makefile b/Makefile
index 84c75ce5..7ae4bf0d 100644
--- a/Makefile
+++ b/Makefile
@@ -9,7 +9,7 @@ TEST_EGG = test/eggsrc/dist/covtestegg1-0.0.0-py*.egg
clean:
python test/test_farm.py clean
-rm -rf build coverage.egg-info dist htmlcov
- -rm -f *.pyd */*.pyd
+ -rm -f *.pyd */*.pyd
-rm -f *.pyc */*.pyc */*/*.pyc */*/*/*.pyc */*/*/*/*.pyc */*/*/*/*/*.pyc
-rm -f *.pyo */*.pyo */*/*.pyo */*/*/*.pyo */*/*/*/*.pyo */*/*/*/*/*.pyo
-rm -f *.bak */*.bak */*/*.bak */*/*/*.bak */*/*/*/*.bak */*/*/*/*/*.bak
@@ -22,8 +22,8 @@ clean:
-rm -rf doc/_build/*
LINTABLE = coverage setup.py test
-
-lint:
+
+lint:
-python -x /Python25/Scripts/pylint.bat --rcfile=.pylintrc $(LINTABLE)
python /Python25/Lib/tabnanny.py $(LINTABLE)
python checkeol.py
@@ -52,7 +52,7 @@ install:
DEVINST_FILE = coverage.egg-info/PKG-INFO
devinst: $(DEVINST_FILE)
-$(DEVINST_FILE): coverage/tracer.c
+$(DEVINST_FILE): coverage/tracer.c
-rm coverage/tracer.pyd
python setup.py develop
diff --git a/coverage/__init__.py b/coverage/__init__.py
index a41dafd3..4db12408 100644
--- a/coverage/__init__.py
+++ b/coverage/__init__.py
@@ -26,10 +26,10 @@ _the_coverage = None
def _singleton_method(name):
"""Return a function to the `name` method on a singleton `coverage` object.
-
+
The singleton object is created the first time one of these functions is
called.
-
+
"""
def wrapper(*args, **kwargs):
"""Singleton wrapper around a coverage method."""
diff --git a/coverage/annotate.py b/coverage/annotate.py
index 2fa9d5cf..2117b657 100644
--- a/coverage/annotate.py
+++ b/coverage/annotate.py
@@ -6,11 +6,11 @@ from coverage.report import Reporter
class AnnotateReporter(Reporter):
"""Generate annotated source files showing line coverage.
-
+
This reporter creates annotated copies of the measured source files. Each
.py file is copied as a .py,cover file, with a left-hand margin annotating
each line::
-
+
> def h(x):
- if 0: #pragma: no cover
- pass
@@ -18,30 +18,30 @@ class AnnotateReporter(Reporter):
! a = 1
> else:
> a = 2
-
+
> h(2)
Executed lines use '>', lines not executed use '!', lines excluded from
consideration use '-'.
-
+
"""
def __init__(self, coverage, ignore_errors=False):
super(AnnotateReporter, self).__init__(coverage, ignore_errors)
self.directory = None
-
+
blank_re = re.compile(r"\s*(#|$)")
else_re = re.compile(r"\s*else\s*:\s*(#|$)")
def report(self, morfs, directory=None, omit_prefixes=None):
"""Run the report."""
self.report_files(self.annotate_file, morfs, directory, omit_prefixes)
-
+
def annotate_file(self, cu, analysis):
"""Annotate a single file.
-
+
`cu` is the CodeUnit for the file to annotate.
-
+
"""
if not cu.relative:
return
@@ -77,7 +77,7 @@ class AnnotateReporter(Reporter):
if self.blank_re.match(line):
dest.write(' ')
elif self.else_re.match(line):
- # Special logic for lines containing only 'else:'.
+ # Special logic for lines containing only 'else:'.
if i >= len(statements) and j >= len(missing):
dest.write('! ')
elif i >= len(statements) or j >= len(missing):
diff --git a/coverage/bytecode.py b/coverage/bytecode.py
index 62a19bae..ac280342 100644
--- a/coverage/bytecode.py
+++ b/coverage/bytecode.py
@@ -14,14 +14,14 @@ class ByteCode(object):
class ByteCodes(object):
"""Iterator over byte codes in `code`.
-
+
Returns `ByteCode` objects.
-
+
"""
def __init__(self, code):
self.code = code
self.offset = 0
-
+
if sys.hexversion > 0x03000000:
def __getitem__(self, i):
return self.code[i]
@@ -31,30 +31,30 @@ class ByteCodes(object):
def __iter__(self):
return self
-
+
def __next__(self):
if self.offset >= len(self.code):
raise StopIteration
-
+
bc = ByteCode()
bc.op = self[self.offset]
bc.offset = self.offset
-
+
next_offset = self.offset+1
if bc.op >= opcode.HAVE_ARGUMENT:
bc.arg = self[self.offset+1] + 256*self[self.offset+2]
next_offset += 2
-
+
label = -1
if bc.op in opcode.hasjrel:
label = next_offset + bc.arg
elif bc.op in opcode.hasjabs:
label = bc.arg
bc.jump_to = label
-
+
bc.next_offset = self.offset = next_offset
return bc
-
+
next = __next__ # Py2k uses an old-style non-dunder name.
@@ -62,10 +62,10 @@ class CodeObjects(object):
"""Iterate over all the code objects in `code`."""
def __init__(self, code):
self.stack = [code]
-
+
def __iter__(self):
return self
-
+
def __next__(self):
if self.stack:
# We're going to return the code object on the stack, but first
diff --git a/coverage/cmdline.py b/coverage/cmdline.py
index 224f871e..fe8da549 100644
--- a/coverage/cmdline.py
+++ b/coverage/cmdline.py
@@ -8,7 +8,7 @@ from coverage.misc import CoverageException
class Opts(object):
"""A namespace class for individual options we'll build parsers from."""
-
+
append = optparse.Option(
'-a', '--append', action='store_false', dest="erase_first",
help="Append coverage data to .coverage, otherwise it is started "
@@ -72,13 +72,14 @@ class Opts(object):
'', '--version', action='store_true',
help="Display version information and exit."
)
-
+
+
class CoverageOptionParser(optparse.OptionParser, object):
"""Base OptionParser for coverage.
-
+
Problems don't exit the program.
Defaults are initialized for all options.
-
+
"""
def __init__(self, *args, **kwargs):
@@ -106,12 +107,12 @@ class CoverageOptionParser(optparse.OptionParser, object):
class OptionParserError(Exception):
"""Used to stop the optparse error handler ending the process."""
pass
-
+
def parse_args(self, args=None, options=None):
"""Call optparse.parse_args, but return a triple:
-
+
(ok, options, args)
-
+
"""
try:
options, args = \
@@ -119,7 +120,7 @@ class CoverageOptionParser(optparse.OptionParser, object):
except self.OptionParserError:
return False, None, None
return True, options, args
-
+
def error(self, msg):
"""Override optparse.error so sys.exit doesn't get called."""
self.help_fn(msg)
@@ -131,7 +132,7 @@ class ClassicOptionParser(CoverageOptionParser):
def __init__(self):
super(ClassicOptionParser, self).__init__()
-
+
self.add_action('-a', '--annotate', 'annotate')
self.add_action('-b', '--html', 'html')
self.add_action('-c', '--combine', 'combine')
@@ -157,7 +158,7 @@ class ClassicOptionParser(CoverageOptionParser):
callback=self._append_action
)
option.action_code = action_code
-
+
def _append_action(self, option, opt_unused, value_unused, parser):
"""Callback for an option that adds to the `actions` list."""
parser.values.actions.append(option.action_code)
@@ -165,19 +166,19 @@ class ClassicOptionParser(CoverageOptionParser):
class CmdOptionParser(CoverageOptionParser):
"""Parse one of the new-style commands for coverage.py."""
-
+
def __init__(self, action, options=None, defaults=None, usage=None,
cmd=None, description=None
):
"""Create an OptionParser for a coverage command.
-
+
`action` is the slug to put into `options.actions`.
`options` is a list of Option's for the command.
`defaults` is a dict of default value for options.
`usage` is the usage string to display in help.
`cmd` is the command name, if different than `action`.
`description` is the description of the command, for the help text.
-
+
"""
if usage:
usage = "%prog " + usage
@@ -228,7 +229,7 @@ CMDS = {
"Each file gets its own page, with the source decorated to show "
"executed, excluded, and missed lines."
),
-
+
'combine': CmdOptionParser("combine", [Opts.help],
usage = " ",
description = "Combine data from multiple coverage files collected "
@@ -269,12 +270,12 @@ CMDS = {
Opts.timid,
Opts.help,
],
- defaults = {'erase_first':True},
+ defaults = {'erase_first': True},
cmd = "run",
usage = "[options] <pyfile> [program options]",
description = "Run a Python program, measuring code execution."
),
-
+
'xml': CmdOptionParser("xml",
[
Opts.ignore_errors,
@@ -292,9 +293,10 @@ CMDS = {
OK, ERR = 0, 1
+
class CoverageScript(object):
"""The command-line interface to Coverage."""
-
+
def __init__(self, _covpkg=None, _run_python_file=None, _help_fn=None):
# _covpkg is for dependency injection, so we can test this code.
if _covpkg:
@@ -302,13 +304,13 @@ class CoverageScript(object):
else:
import coverage
self.covpkg = coverage
-
+
# _run_python_file is for dependency injection also.
self.run_python_file = _run_python_file or run_python_file
-
+
# _help_fn is for dependency injection.
self.help_fn = _help_fn or self.help
-
+
self.coverage = None
def help(self, error=None, topic=None, parser=None):
@@ -331,14 +333,14 @@ class CoverageScript(object):
def command_line(self, argv):
"""The bulk of the command line interface to Coverage.
-
+
`argv` is the argument list to process.
Returns 0 if all is well, 1 if something went wrong.
"""
# Collect the command-line options.
-
+
if not argv:
self.help_fn(topic='minimum_help')
return OK
@@ -408,11 +410,11 @@ class CoverageScript(object):
if not args_allowed and args:
self.help_fn("Unexpected arguments: %s" % " ".join(args))
return ERR
-
+
if 'execute' in options.actions and not args:
self.help_fn("Nothing to do.")
return ERR
-
+
# Do something.
self.coverage = self.covpkg.coverage(
data_suffix = bool(options.parallel_mode),
@@ -481,7 +483,7 @@ class CoverageScript(object):
if options.omit:
omit = options.omit.split(',')
report_args['omit_prefixes'] = omit
-
+
if 'report' in options.actions:
self.coverage.report(
show_missing=options.show_missing, **report_args)
@@ -556,7 +558,7 @@ usage: coverage <command> [options] [args]
Commands:
annotate Annotate source files with execution information.
- combine Combine a number of data files.
+ combine Combine a number of data files.
erase Erase previously collected coverage data.
help Get help on using coverage.py.
html Create an HTML report.
@@ -579,9 +581,9 @@ Coverage.py, version %(__version__)s. %(__url__)s
def main():
"""The main entrypoint to Coverage.
-
+
This is installed as the script entrypoint.
-
+
"""
try:
status = CoverageScript().command_line(sys.argv[1:])
diff --git a/coverage/codeunit.py b/coverage/codeunit.py
index 6d156da7..73baaa06 100644
--- a/coverage/codeunit.py
+++ b/coverage/codeunit.py
@@ -8,20 +8,20 @@ from coverage.misc import CoverageException
def code_unit_factory(morfs, file_locator, omit_prefixes=None):
"""Construct a list of CodeUnits from polymorphic inputs.
-
+
`morfs` is a module or a filename, or a list of same.
`file_locator` is a FileLocator that can help resolve filenames.
`omit_prefixes` is a list of prefixes. CodeUnits that match those prefixes
will be omitted from the list.
-
+
Returns a list of CodeUnit objects.
-
+
"""
# Be sure we have a list.
if not isinstance(morfs, (list, tuple)):
morfs = [morfs]
-
+
# On Windows, the shell doesn't expand wildcards. Do it here.
globbed = []
for morf in morfs:
@@ -32,7 +32,7 @@ def code_unit_factory(morfs, file_locator, omit_prefixes=None):
morfs = globbed
code_units = [CodeUnit(morf, file_locator) for morf in morfs]
-
+
if omit_prefixes:
assert not isinstance(omit_prefixes, string_class) # common mistake
prefixes = [file_locator.abs_file(p) for p in omit_prefixes]
@@ -43,7 +43,7 @@ def code_unit_factory(morfs, file_locator, omit_prefixes=None):
break
else:
filtered.append(cu)
-
+
code_units = filtered
return code_units
@@ -51,13 +51,13 @@ def code_unit_factory(morfs, file_locator, omit_prefixes=None):
class CodeUnit(object):
"""Code unit: a filename or module.
-
+
Instance attributes:
-
+
`name` is a human-readable name for this code unit.
`filename` is the os path from which we can read the source.
`relative` is a boolean.
-
+
"""
def __init__(self, morf, file_locator):
@@ -92,34 +92,34 @@ class CodeUnit(object):
# Annoying comparison operators. Py3k wants __lt__ etc, and Py2k needs all
# of them defined.
-
+
def __lt__(self, other):
return self.name < other.name
-
+
def __le__(self, other):
return self.name <= other.name
def __eq__(self, other):
return self.name == other.name
-
+
def __ne__(self, other):
return self.name != other.name
def __gt__(self, other):
return self.name > other.name
-
+
def __ge__(self, other):
return self.name >= other.name
def flat_rootname(self):
"""A base for a flat filename to correspond to this code unit.
-
+
Useful for writing files about the code where you want all the files in
the same directory, but need to differentiate same-named files from
different directories.
-
+
For example, the file a/b/c.py might return 'a_b_c'
-
+
"""
if self.modname:
return self.modname.replace('.', '_')
@@ -137,7 +137,7 @@ class CodeUnit(object):
source = self.file_locator.get_zip_data(self.filename)
if source is not None:
return StringIO(source)
-
+
# Couldn't find source.
raise CoverageException(
"No source for code %r." % self.filename
diff --git a/coverage/collector.py b/coverage/collector.py
index 6ea419ee..29dddf6b 100644
--- a/coverage/collector.py
+++ b/coverage/collector.py
@@ -12,7 +12,7 @@ except ImportError:
class PyTracer(object):
"""Python implementation of the raw data tracer."""
-
+
# Because of poor implementations of trace-function-manipulating tools,
# the Python trace function must be kept very simple. In particular, there
# must be only one function ever set as the trace function, both through
@@ -41,10 +41,10 @@ class PyTracer(object):
def _trace(self, frame, event, arg_unused):
"""The trace function passed to sys.settrace."""
-
+
#print "trace event: %s %r @%d" % (
# event, frame.f_code.co_filename, frame.f_lineno)
-
+
if self.last_exc_back:
if frame == self.last_exc_back:
# Someone forgot a return event.
@@ -52,7 +52,7 @@ class PyTracer(object):
self.cur_file_data[(self.last_line, -1)] = None
self.cur_file_data, self.last_line = self.data_stack.pop()
self.last_exc_back = None
-
+
if event == 'call':
# Entering a new function context. Decide if we should trace
# in this file.
@@ -85,7 +85,7 @@ class PyTracer(object):
#print "exc", self.last_line, frame.f_lineno
self.last_exc_back = frame.f_back
return self._trace
-
+
def start(self):
"""Start this Tracer."""
sys.settrace(self._trace)
@@ -102,18 +102,19 @@ class PyTracer(object):
class Collector(object):
"""Collects trace data.
- Creates a Tracer object for each thread, since they track stack information.
- Each Tracer points to the same shared data, contributing traced data points.
-
+ Creates a Tracer object for each thread, since they track stack
+ information. Each Tracer points to the same shared data, contributing
+ traced data points.
+
When the Collector is started, it creates a Tracer for the current thread,
and installs a function to create Tracers for each new thread started.
When the Collector is stopped, all active Tracers are stopped.
-
+
Threads started while the Collector is stopped will never have Tracers
associated with them.
-
+
"""
-
+
# The stack of active Collectors. Collectors are added here when started,
# and popped when stopped. Collectors on the stack are paused when not
# the top, and resumed when they become the top again.
@@ -121,20 +122,20 @@ class Collector(object):
def __init__(self, should_trace, timid, branch):
"""Create a collector.
-
+
`should_trace` is a function, taking a filename, and returning a
canonicalized filename, or False depending on whether the file should
be traced or not.
-
+
If `timid` is true, then a slower simpler trace function will be
used. This is important for some environments where manipulation of
tracing functions make the faster more sophisticated trace function not
operate properly.
-
+
If `branch` is true, then branches will be measured. This involves
collecting data on which statements followed each other (arcs). Use
`get_arc_data` to get the arc data.
-
+
"""
self.should_trace = should_trace
self.branch = branch
@@ -160,7 +161,7 @@ class Collector(object):
# A dictionary mapping filenames to dicts with linenumber keys,
# or mapping filenames to dicts with linenumber pairs as keys.
self.data = {}
-
+
# A cache of the results from should_trace, the decision about whether
# to trace execution in a file. A dict of filename to (filename or
# False).
@@ -214,7 +215,7 @@ class Collector(object):
self.pause()
self.tracers = []
-
+
# Remove this Collector from the stack, and resume the one underneath
# (if any).
self._collectors.pop()
@@ -231,7 +232,7 @@ class Collector(object):
for k in sorted(stats.keys()):
print("%16s: %s" % (k, stats[k]))
threading.settrace(None)
-
+
def resume(self):
"""Resume tracing after a `pause`."""
for tracer in self.tracers:
@@ -240,9 +241,9 @@ class Collector(object):
def get_line_data(self):
"""Return the line data collected.
-
+
Data is { filename: { lineno: None, ...}, ...}
-
+
"""
if self.branch:
# If we were measuring branches, then we have to re-build the dict
@@ -259,7 +260,7 @@ class Collector(object):
def get_arc_data(self):
"""Return the arc data collected.
-
+
Data is { filename: { (l1, l2): None, ...}, ...}
Note that no data is collected or returned if the Collector wasn't
diff --git a/coverage/control.py b/coverage/control.py
index 7efc3492..15bbe982 100644
--- a/coverage/control.py
+++ b/coverage/control.py
@@ -17,9 +17,9 @@ class coverage(object):
"""Programmatic access to Coverage.
To use::
-
+
from coverage import coverage
-
+
cov = coverage()
cov.start()
#.. blah blah (run your code) blah blah ..
@@ -30,39 +30,39 @@ class coverage(object):
def __init__(self, data_file=None, data_suffix=False, cover_pylib=False,
auto_data=False, timid=False, branch=False):
- """
+ """
`data_file` is the base name of the data file to use, defaulting to
".coverage". `data_suffix` is appended to `data_file` to create the
final file name. If `data_suffix` is simply True, then a suffix is
created with the machine and process identity included.
-
+
`cover_pylib` is a boolean determining whether Python code installed
with the Python interpreter is measured. This includes the Python
standard library and any packages installed with the interpreter.
-
+
If `auto_data` is true, then any existing data file will be read when
coverage measurement starts, and data will be saved automatically when
measurement stops.
-
+
If `timid` is true, then a slower and simpler trace function will be
used. This is important for some environments where manipulation of
tracing functions breaks the faster trace function.
-
+
If `branch` is true, then branch coverage will be measured in addition
to the usual statement coverage.
"""
from coverage import __version__
-
+
self.cover_pylib = cover_pylib
self.auto_data = auto_data
self.atexit_registered = False
self.exclude_re = ""
self.exclude_list = []
-
+
self.file_locator = FileLocator()
-
+
# Timidity: for nose users, read an environment variable. This is a
# cheap hack, since the rest of the command line arguments aren't
# recognized, but it solves some users' problems.
@@ -101,13 +101,13 @@ class coverage(object):
def _should_trace(self, filename, frame):
"""Decide whether to trace execution in `filename`
-
+
This function is called from the trace function. As each new file name
is encountered, this function determines whether it is traced or not.
-
+
Returns a canonicalized filename if it should be traced, False if it
should not.
-
+
"""
if filename == '<string>':
# There's no point in ever tracing string executions, we can't do
@@ -153,9 +153,9 @@ class coverage(object):
def use_cache(self, usecache):
"""Control the use of a data file (incorrectly called a cache).
-
+
`usecache` is true or false, whether to read and write data on disk.
-
+
"""
self.data.usefile(usecache)
@@ -163,7 +163,7 @@ class coverage(object):
"""Load previously-collected coverage data from the data file."""
self.collector.reset()
self.data.read()
-
+
def start(self):
"""Start measuring code coverage."""
if self.auto_data:
@@ -173,7 +173,7 @@ class coverage(object):
atexit.register(self.save)
self.atexit_registered = True
self.collector.start()
-
+
def stop(self):
"""Stop measuring code coverage."""
self.collector.stop()
@@ -181,10 +181,10 @@ class coverage(object):
def erase(self):
"""Erase previously-collected coverage data.
-
+
This removes the in-memory data collected in this session as well as
discarding the data file.
-
+
"""
self.collector.reset()
self.data.erase()
@@ -196,12 +196,12 @@ class coverage(object):
def exclude(self, regex):
"""Exclude source lines from execution consideration.
-
+
`regex` is a regular expression. Lines matching this expression are
not considered executable when reporting code coverage. A list of
regexes is maintained; this function adds a new regex to the list.
Matching any of the regexes excludes a source line.
-
+
"""
self.exclude_list.append(regex)
self.exclude_re = "(" + ")|(".join(self.exclude_list) + ")"
@@ -217,11 +217,11 @@ class coverage(object):
def combine(self):
"""Combine together a number of similarly-named coverage data files.
-
+
All coverage data files whose name starts with `data_file` (from the
coverage() constructor) will be read, and combined together into the
current measurements.
-
+
"""
self.data.combine_parallel_data()
@@ -239,14 +239,15 @@ class coverage(object):
def analysis2(self, morf):
"""Analyze a module.
-
+
`morf` is a module or a filename. It will be analyzed to determine
its coverage statistics. The return value is a 5-tuple:
-
+
* The filename for the module.
* A list of line numbers of executable statements.
* A list of line numbers of excluded statements.
- * A list of line numbers of statements not run (missing from execution).
+ * A list of line numbers of statements not run (missing from
+ execution).
* A readable formatted string of the missing line numbers.
The analysis uses the source file itself and the current measured
@@ -261,22 +262,22 @@ class coverage(object):
def _analyze(self, it):
"""Analyze a single morf or code unit.
-
+
Returns an `Analysis` object.
"""
if not isinstance(it, CodeUnit):
it = code_unit_factory(it, self.file_locator)[0]
-
+
return Analysis(self, it)
def report(self, morfs=None, show_missing=True, ignore_errors=False,
file=None, omit_prefixes=None): # pylint: disable-msg=W0622
"""Write a summary report to `file`.
-
+
Each module in `morfs` is listed, with counts of statements, executed
statements, missing statements, and a list of lines missed.
-
+
"""
reporter = SummaryReporter(self, show_missing, ignore_errors)
reporter.report(morfs, outfile=file, omit_prefixes=omit_prefixes)
@@ -284,12 +285,12 @@ class coverage(object):
def annotate(self, morfs=None, directory=None, ignore_errors=False,
omit_prefixes=None):
"""Annotate a list of modules.
-
+
Each module in `morfs` is annotated. The source is written to a new
file, named with a ",cover" suffix, with each line prefixed with a
marker to indicate the coverage of the line. Covered lines have ">",
excluded lines have "-", and missing lines have "!".
-
+
"""
reporter = AnnotateReporter(self, ignore_errors)
reporter.report(
@@ -298,7 +299,7 @@ class coverage(object):
def html_report(self, morfs=None, directory=None, ignore_errors=False,
omit_prefixes=None):
"""Generate an HTML report.
-
+
"""
reporter = HtmlReporter(self, ignore_errors)
reporter.report(
@@ -307,9 +308,9 @@ class coverage(object):
def xml_report(self, morfs=None, outfile=None, ignore_errors=False,
omit_prefixes=None):
"""Generate an XML report of coverage results.
-
+
The report is compatible with Cobertura reports.
-
+
"""
if outfile:
outfile = open(outfile, "w")
@@ -322,7 +323,7 @@ class coverage(object):
def sysinfo(self):
"""Return a list of key,value pairs showing internal information."""
-
+
import coverage as covmod
import platform, re, sys
diff --git a/coverage/data.py b/coverage/data.py
index 452ce73d..11c7c01d 100644
--- a/coverage/data.py
+++ b/coverage/data.py
@@ -7,20 +7,20 @@ from coverage.backward import pickle, sorted # pylint: disable-msg=W0622
class CoverageData(object):
"""Manages collected coverage data, including file storage.
-
+
The data file format is a pickled dict, with these keys:
-
+
* collector: a string identifying the collecting software
* lines: a dict mapping filenames to sorted lists of line numbers
executed:
{ 'file1': [17,23,45], 'file2': [1,2,3], ... }
-
+
* arcs: a dict mapping filenames to sorted lists of line number pairs:
{ 'file1': [(17,23), (17,25), (25,26)], ... }
"""
-
+
# Name of the data file (unless environment variable is set).
filename_default = ".coverage"
@@ -29,9 +29,9 @@ class CoverageData(object):
def __init__(self, basename=None, suffix=None, collector=None):
"""Create a CoverageData.
-
+
`basename` is the name of the file to use for storing data.
-
+
`suffix` is a suffix to append to the base file name. This can be used
for multiple or parallel execution, so that many coverage data files
can exist simultaneously.
@@ -40,7 +40,7 @@ class CoverageData(object):
"""
self.collector = collector
-
+
self.use_file = True
# Construct the filename that will be used for data file storage, if we
@@ -61,14 +61,14 @@ class CoverageData(object):
# }
#
self.lines = {}
-
+
# A map from canonical Python source file name to a dictionary with an
# entry for each pair of line numbers forming an arc:
#
# { filename: { (l1,l2): None, ... }, ...}
#
self.arcs = {}
-
+
def usefile(self, use_file=True):
"""Set whether or not to use a disk file for data."""
self.use_file = use_file
@@ -92,7 +92,7 @@ class CoverageData(object):
os.remove(self.filename)
self.lines = {}
self.arcs = {}
-
+
def line_data(self):
"""Return the map from filenames to lists of line numbers executed."""
return dict(
@@ -104,11 +104,11 @@ class CoverageData(object):
return dict(
[(f, sorted(amap.keys())) for f, amap in self.arcs.items()]
)
-
+
def write_file(self, filename):
"""Write the coverage data to `filename`."""
- # Create the file data.
+ # Create the file data.
data = {}
data['lines'] = self.line_data()
@@ -141,10 +141,10 @@ class CoverageData(object):
def _read_file(self, filename):
"""Return the stored coverage data from the given file.
-
+
Returns two values, suitable for assigning to `self.lines` and
`self.arcs`.
-
+
"""
lines = {}
arcs = {}
@@ -167,10 +167,10 @@ class CoverageData(object):
def combine_parallel_data(self):
"""Combine a number of data files together.
-
+
Treat `self.filename` as a file prefix, and combine the data from all
of the data files starting with that prefix.
-
+
"""
data_dir, local = os.path.split(self.filename)
for f in os.listdir(data_dir or '.'):
@@ -184,18 +184,18 @@ class CoverageData(object):
def add_line_data(self, line_data):
"""Add executed line data.
-
+
`line_data` is { filename: { lineno: None, ... }, ...}
-
+
"""
for filename, linenos in line_data.items():
self.lines.setdefault(filename, {}).update(linenos)
def add_arc_data(self, arc_data):
"""Add measured arc data.
-
+
`arc_data` is { filename: { (l1,l2): None, ... }, ...}
-
+
"""
for filename, arcs in arc_data.items():
self.arcs.setdefault(filename, {}).update(arcs)
@@ -206,7 +206,7 @@ class CoverageData(object):
def executed_lines(self, filename):
"""A map containing all the line numbers executed in `filename`.
-
+
If `filename` hasn't been collected at all (because it wasn't executed)
then return an empty map.
@@ -219,11 +219,11 @@ class CoverageData(object):
def summary(self, fullpath=False):
"""Return a dict summarizing the coverage data.
-
+
Keys are based on the filenames, and values are the number of executed
lines. If `fullpath` is true, then the keys are the full pathnames of
the files, otherwise they are the basenames of the files.
-
+
"""
summ = {}
if fullpath:
diff --git a/coverage/execfile.py b/coverage/execfile.py
index ddcfa149..15f0a5f8 100644
--- a/coverage/execfile.py
+++ b/coverage/execfile.py
@@ -16,11 +16,11 @@ except KeyError:
def run_python_file(filename, args):
"""Run a python file as if it were the main program on the command line.
-
+
`filename` is the path to the file to execute, it need not be a .py file.
`args` is the argument array to present as sys.argv, including the first
element representing the file being executed.
-
+
"""
# Create a module to serve as __main__
old_main_mod = sys.modules['__main__']
@@ -44,7 +44,7 @@ def run_python_file(filename, args):
finally:
# Restore the old __main__
sys.modules['__main__'] = old_main_mod
-
+
# Restore the old argv and path
sys.argv = old_argv
sys.path[0] = old_path0
diff --git a/coverage/files.py b/coverage/files.py
index 400646ca..ba228c23 100644
--- a/coverage/files.py
+++ b/coverage/files.py
@@ -18,18 +18,18 @@ class FileLocator(object):
def relative_filename(self, filename):
"""Return the relative form of `filename`.
-
+
The filename will be relative to the current directory when the
FileLocator was constructed.
-
+
"""
return filename.replace(self.relative_dir, "")
def canonical_filename(self, filename):
"""Return a canonical filename for `filename`.
-
+
An absolute path with no redundant components and normalized case.
-
+
"""
if filename not in self.canonical_filename_cache:
f = filename
@@ -48,11 +48,11 @@ class FileLocator(object):
def get_zip_data(self, filename):
"""Get data from `filename` if it is a zip file path.
-
+
Returns the string data read from the zip file, or None if no zip file
could be found or `filename` isn't in it. The data returned will be
an empty string if the file is empty.
-
+
"""
import zipimport
markers = ['.zip'+os.sep, '.egg'+os.sep]
diff --git a/coverage/html.py b/coverage/html.py
index 3671f036..4d51eb34 100644
--- a/coverage/html.py
+++ b/coverage/html.py
@@ -18,29 +18,29 @@ def data_filename(fname):
def data(fname):
"""Return the contents of a data file of ours."""
return open(data_filename(fname)).read()
-
+
class HtmlReporter(Reporter):
"""HTML reporting."""
-
+
def __init__(self, coverage, ignore_errors=False):
super(HtmlReporter, self).__init__(coverage, ignore_errors)
self.directory = None
self.source_tmpl = Templite(data("htmlfiles/pyfile.html"), globals())
-
+
self.files = []
self.arcs = coverage.data.has_arcs()
def report(self, morfs, directory, omit_prefixes=None):
"""Generate an HTML report for `morfs`.
-
+
`morfs` is a list of modules or filenames. `directory` is where to put
the HTML files. `omit_prefixes` is a list of strings, prefixes of
modules to omit from the report.
-
+
"""
assert directory, "must provide a directory for html reporting"
-
+
# Process all the files.
self.report_files(self.html_file, morfs, directory, omit_prefixes)
@@ -59,10 +59,10 @@ class HtmlReporter(Reporter):
def html_file(self, cu, analysis):
"""Generate an HTML file for one source file."""
-
+
source = cu.source_file().read()
- nums = analysis.numbers
+ nums = analysis.numbers
missing_branch_arcs = analysis.missing_branch_arcs()
n_par = 0 # accumulated below.
@@ -75,7 +75,7 @@ class HtmlReporter(Reporter):
c_par = " par" + c_run
lines = []
-
+
for lineno, line in enumerate(source_token_lines(source)):
lineno += 1 # 1-based line numbers.
# Figure out how to mark this line.
@@ -104,7 +104,7 @@ class HtmlReporter(Reporter):
annotate_title = "no jump to this line number"
elif lineno in analysis.statements:
line_class += c_run
-
+
# Build the HTML for the line
html = ""
for tok_type, tok_text in line:
@@ -173,10 +173,10 @@ def format_pct(p):
def spaceless(html):
"""Squeeze out some annoying extra space from an HTML string.
-
+
Nicely-formatted templates mean lots of extra space in the result. Get
rid of some.
-
+
"""
html = re.sub(">\s+<p ", ">\n<p ", html)
return html
diff --git a/coverage/misc.py b/coverage/misc.py
index aa61fc98..0e6bcf99 100644
--- a/coverage/misc.py
+++ b/coverage/misc.py
@@ -2,10 +2,10 @@
def nice_pair(pair):
"""Make a nice string representation of a pair of numbers.
-
+
If the numbers are equal, just return the number, otherwise return the pair
with a dash between them, indicating the range.
-
+
"""
start, end = pair
if start == end:
@@ -20,10 +20,10 @@ def format_lines(statements, lines):
Format a list of line numbers for printing by coalescing groups of lines as
long as the lines represent consecutive statements. This will coalesce
even if there are gaps between statements.
-
+
For example, if `statements` is [1,2,3,4,5,10,11,12,13,14] and
`lines` is [1,2,5,10,11,13,14] then the result will be "1-2, 5-11, 13-14".
-
+
"""
pairs = []
i = 0
@@ -47,9 +47,9 @@ def format_lines(statements, lines):
def expensive(fn):
"""A decorator to cache the result of an expensive operation.
-
+
Only applies to methods with no arguments.
-
+
"""
attr = "_cache_" + fn.__name__
def _wrapped(self):
diff --git a/coverage/parser.py b/coverage/parser.py
index a1a24dd6..43f691f5 100644
--- a/coverage/parser.py
+++ b/coverage/parser.py
@@ -9,13 +9,13 @@ from coverage.misc import nice_pair, CoverageException, NoSource, expensive
class CodeParser(object):
"""Parse code to find executable lines, excluded lines, etc."""
-
+
def __init__(self, text=None, filename=None, exclude=None):
"""
Source can be provided as `text`, the text itself, or `filename`, from
- which text will be read. Excluded lines are those that match `exclude`,
- a regex.
-
+ which text will be read. Excluded lines are those that match
+ `exclude`, a regex.
+
"""
assert text or filename, "CodeParser needs either text or filename"
self.filename = filename or "<code>"
@@ -33,7 +33,7 @@ class CodeParser(object):
self.text = self.text.replace('\r\n', '\n')
self.exclude = exclude
-
+
self.show_tokens = False
# The text lines of the parsed code.
@@ -41,22 +41,22 @@ class CodeParser(object):
# The line numbers of excluded lines of code.
self.excluded = set()
-
+
# The line numbers of docstring lines.
self.docstrings = set()
-
+
# The line numbers of class definitions.
self.classdefs = set()
# A dict mapping line numbers to (lo,hi) for multi-line statements.
self.multiline = {}
-
+
# The line numbers that start statements.
self.statement_starts = set()
# Lazily-created ByteParser
self._byte_parser = None
-
+
def _get_byte_parser(self):
"""Create a ByteParser on demand."""
if not self._byte_parser:
@@ -67,9 +67,9 @@ class CodeParser(object):
def _raw_parse(self):
"""Parse the source to find the interesting facts about its lines.
-
+
A handful of member fields are updated.
-
+
"""
# Find lines which match an exclusion pattern.
if self.exclude:
@@ -77,7 +77,7 @@ class CodeParser(object):
for i, ltext in enumerate(self.lines):
if re_exclude.search(ltext):
self.excluded.add(i+1)
-
+
# Tokenize, to find excluded suites, to find docstrings, and to find
# multi-line statements.
indent = 0
@@ -125,7 +125,7 @@ class CodeParser(object):
for l in range(first_line, elineno+1):
self.multiline[l] = rng
first_line = None
-
+
if ttext.strip() and toktype != tokenize.COMMENT:
# A non-whitespace token.
if first_line is None:
@@ -137,7 +137,7 @@ class CodeParser(object):
excluding = False
if excluding:
self.excluded.add(elineno)
-
+
prev_toktype = toktype
# Find the starts of the executable statements.
@@ -155,11 +155,11 @@ class CodeParser(object):
def first_lines(self, lines, ignore=None):
"""Map the line numbers in `lines` to the correct first line of the
statement.
-
+
Skip any line mentioned in `ignore`.
-
+
Returns a sorted list of the first lines.
-
+
"""
ignore = ignore or []
lset = set()
@@ -170,31 +170,31 @@ class CodeParser(object):
if new_l not in ignore:
lset.add(new_l)
return sorted(lset)
-
+
def parse_source(self):
"""Parse source text to find executable lines, excluded lines, etc.
Return values are 1) a sorted list of executable line numbers, and
2) a sorted list of excluded line numbers.
-
+
Reported line numbers are normalized to the first line of multi-line
statements.
-
+
"""
self._raw_parse()
-
+
excluded_lines = self.first_lines(self.excluded)
ignore = excluded_lines + list(self.docstrings)
lines = self.first_lines(self.statement_starts, ignore)
-
+
return lines, excluded_lines
def arcs(self):
"""Get information about the arcs available in the code.
-
+
Returns a sorted list of line number pairs. Line numbers have been
normalized to the first line of multiline statements.
-
+
"""
all_arcs = []
for l1, l2 in self.byte_parser._all_arcs():
@@ -207,9 +207,9 @@ class CodeParser(object):
def exit_counts(self):
"""Get a mapping from line numbers to count of exits from that line.
-
+
Excluded lines are excluded.
-
+
"""
excluded_lines = self.first_lines(self.excluded)
exit_counts = {}
@@ -232,7 +232,7 @@ class CodeParser(object):
# Ensure key is there: classdefs can include excluded lines.
if l in exit_counts:
exit_counts[l] -= 1
-
+
return exit_counts
exit_counts = expensive(exit_counts)
@@ -303,13 +303,13 @@ class ByteParser(object):
def child_parsers(self):
"""Iterate over all the code objects nested within this one.
-
+
The iteration includes `self` as its first value.
-
+
"""
return map(lambda c: ByteParser(code=c), CodeObjects(self.code))
- # Getting numbers from the lnotab value changed in Py3.0.
+ # Getting numbers from the lnotab value changed in Py3.0.
if sys.hexversion >= 0x03000000:
def _lnotab_increments(self, lnotab):
"""Return a list of ints from the lnotab bytes in 3.x"""
@@ -321,15 +321,15 @@ class ByteParser(object):
def _bytes_lines(self):
"""Map byte offsets to line numbers in `code`.
-
+
Uses co_lnotab described in Python/compile.c to map byte offsets to
line numbers. Returns a list: [(b0, l0), (b1, l1), ...]
-
+
"""
# Adapted from dis.py in the standard library.
byte_increments = self._lnotab_increments(self.code.co_lnotab[0::2])
line_increments = self._lnotab_increments(self.code.co_lnotab[1::2])
-
+
bytes_lines = []
last_line_num = None
line_num = self.code.co_firstlineno
@@ -344,13 +344,13 @@ class ByteParser(object):
if line_num != last_line_num:
bytes_lines.append((byte_num, line_num))
return bytes_lines
-
+
def _find_statements(self):
"""Find the statements in `self.code`.
-
+
Return a set of line numbers that start statements. Recurses into all
code objects reachable from `self.code`.
-
+
"""
stmts = set()
for bp in self.child_parsers():
@@ -358,12 +358,12 @@ class ByteParser(object):
for _, l in bp._bytes_lines():
stmts.add(l)
return stmts
-
+
def _disassemble(self): # pragma: no cover
"""Disassemble code, for ad-hoc experimenting."""
-
+
import dis
-
+
for bp in self.child_parsers():
print("\n%s: " % bp.code)
dis.dis(bp.code)
@@ -373,24 +373,24 @@ class ByteParser(object):
def _split_into_chunks(self):
"""Split the code object into a list of `Chunk` objects.
-
+
Each chunk is only entered at its first instruction, though there can
be many exits from a chunk.
-
+
Returns a list of `Chunk` objects.
-
+
"""
# The list of chunks so far, and the one we're working on.
chunks = []
chunk = None
bytes_lines_map = dict(self._bytes_lines())
-
+
# The block stack: loops and try blocks get pushed here for the
# implicit jumps that can occur.
# Each entry is a tuple: (block type, destination)
block_stack = []
-
+
# Some op codes are followed by branches that should be ignored. This
# is a count of how many ignores are left.
ignore_branch = 0
@@ -405,12 +405,12 @@ class ByteParser(object):
chunk.exits.add(bc.offset)
chunk = Chunk(bc.offset, bytes_lines_map[bc.offset])
chunks.append(chunk)
-
+
if not chunk:
chunk = Chunk(bc.offset)
chunks.append(chunk)
- # Look at the opcode
+ # Look at the opcode
if bc.jump_to >= 0 and bc.op not in OPS_NO_JUMP:
if ignore_branch:
# Someone earlier wanted us to ignore this branch.
@@ -418,7 +418,7 @@ class ByteParser(object):
else:
# The opcode has a jump, it's an exit for this chunk.
chunk.exits.add(bc.jump_to)
-
+
if bc.op in OPS_CODE_END:
# The opcode can exit the code object.
chunk.exits.add(-1)
@@ -454,7 +454,7 @@ class ByteParser(object):
penult = ult
ult = bc
-
+
if chunks:
# The last two bytecodes could be a dummy "return None" that
# shouldn't be counted as real code. Every Python code object seems
@@ -483,35 +483,35 @@ class ByteParser(object):
def _arcs(self):
"""Find the executable arcs in the code.
-
+
Returns a set of pairs, (from,to). From and to are integer line
numbers. If from is -1, then the arc is an entrance into the code
object. If to is -1, the arc is an exit from the code object.
-
+
"""
chunks = self._split_into_chunks()
-
+
# A map from byte offsets to chunks jumped into.
byte_chunks = dict([(c.byte, c) for c in chunks])
# Build a map from byte offsets to actual lines reached.
byte_lines = {-1:[-1]}
bytes_to_add = set([c.byte for c in chunks])
-
+
while bytes_to_add:
byte_to_add = bytes_to_add.pop()
if byte_to_add in byte_lines or byte_to_add == -1:
continue
-
+
# Which lines does this chunk lead to?
bytes_considered = set()
bytes_to_consider = [byte_to_add]
lines = set()
-
+
while bytes_to_consider:
byte = bytes_to_consider.pop()
bytes_considered.add(byte)
-
+
# Find chunk for byte
try:
ch = byte_chunks[byte]
@@ -523,7 +523,7 @@ class ByteParser(object):
# No chunk for this byte!
raise Exception("Couldn't find chunk @ %d" % byte)
byte_chunks[byte] = ch
-
+
if ch.line:
lines.add(ch.line)
else:
@@ -536,7 +536,7 @@ class ByteParser(object):
bytes_to_add.update(ch.exits)
byte_lines[byte_to_add] = lines
-
+
# Figure out for each chunk where the exits go.
arcs = set()
for chunk in chunks:
@@ -547,56 +547,56 @@ class ByteParser(object):
arcs.add((chunk.line, exit_line))
for line in byte_lines[0]:
arcs.add((-1, line))
-
+
return arcs
-
+
def _all_chunks(self):
"""Returns a list of `Chunk` objects for this code and its children.
-
+
See `_split_into_chunks` for details.
-
+
"""
chunks = []
for bp in self.child_parsers():
chunks.extend(bp._split_into_chunks())
-
+
return chunks
def _all_arcs(self):
"""Get the set of all arcs in this code object and its children.
-
+
See `_arcs` for details.
-
+
"""
arcs = set()
for bp in self.child_parsers():
arcs.update(bp._arcs())
-
+
return arcs
class Chunk(object):
"""A sequence of bytecodes with a single entrance.
-
+
To analyze byte code, we have to divide it into chunks, sequences of byte
codes such that each basic block has only one entrance, the first
- instruction in the block.
-
+ instruction in the block.
+
This is almost the CS concept of `basic block`_, except that we're willing
to have many exits from a chunk, and "basic block" is a more cumbersome
term.
-
+
.. _basic block: http://en.wikipedia.org/wiki/Basic_block
-
+
An exit of -1 means the chunk can leave the code (return).
-
+
"""
def __init__(self, byte, line=0):
self.byte = byte
self.line = line
self.length = 0
self.exits = set()
-
+
def __repr__(self):
return "<%d+%d @%d %r>" % (
self.byte, self.length, self.line, list(self.exits)
@@ -605,7 +605,7 @@ class Chunk(object):
class AdHocMain(object): # pragma: no cover
"""An ad-hoc main for code parsing experiments."""
-
+
def main(self, args):
"""A main function for trying the code from the command line."""
@@ -632,7 +632,7 @@ class AdHocMain(object): # pragma: no cover
"-t", action="store_true", dest="tokens",
help="Show tokens"
)
-
+
options, args = parser.parse_args()
if options.recursive:
if args:
@@ -647,12 +647,12 @@ class AdHocMain(object): # pragma: no cover
def adhoc_one_file(self, options, filename):
"""Process just one file."""
-
+
if options.dis or options.chunks:
try:
bp = ByteParser(filename=filename)
except CoverageException:
- _, err, _ = sys.exc_info()
+ _, err, _ = sys.exc_info()
print("%s" % (err,))
return
@@ -679,7 +679,7 @@ class AdHocMain(object): # pragma: no cover
arc_width, arc_chars = self.arc_ascii_art(arcs)
else:
arc_width, arc_chars = 0, {}
-
+
exit_counts = cp.exit_counts()
for i, ltext in enumerate(cp.lines):
@@ -703,10 +703,10 @@ class AdHocMain(object): # pragma: no cover
def arc_ascii_art(self, arcs):
"""Draw arcs as ascii art.
-
+
Returns a width of characters needed to draw all the arcs, and a
dictionary mapping line numbers to ascii strings to draw for that line.
-
+
"""
arc_chars = {}
for lfrom, lto in sorted(arcs):
diff --git a/coverage/phystokens.py b/coverage/phystokens.py
index 131b362a..5824b9b9 100644
--- a/coverage/phystokens.py
+++ b/coverage/phystokens.py
@@ -5,13 +5,13 @@ from coverage.backward import StringIO # pylint: disable-msg=W0622
def phys_tokens(toks):
"""Return all physical tokens, even line continuations.
-
+
tokenize.generate_tokens() doesn't return a token for the backslash that
continues lines. This wrapper provides those tokens so that we can
re-create a faithful representation of the original source.
-
+
Returns the same values as generate_tokens()
-
+
"""
last_line = None
last_lineno = -1
@@ -61,13 +61,13 @@ def phys_tokens(toks):
def source_token_lines(source):
"""Generate a series of lines, one for each line in `source`.
-
+
Each line is a list of pairs, each pair is a token::
-
+
[('key', 'def'), ('ws', ' '), ('nam', 'hello'), ('op', '('), ... ]
Each pair has a token class, and the token text.
-
+
If you concatenate all the token texts, and then join them with newlines,
you should have your original `source` back, with two differences:
trailing whitespace is not preserved, and a final line with no newline
diff --git a/coverage/report.py b/coverage/report.py
index c2215521..5b66f999 100644
--- a/coverage/report.py
+++ b/coverage/report.py
@@ -6,30 +6,30 @@ from coverage.misc import CoverageException, NoSource
class Reporter(object):
"""A base class for all reporters."""
-
+
def __init__(self, coverage, ignore_errors=False):
"""Create a reporter.
-
+
`coverage` is the coverage instance. `ignore_errors` controls how
skittish the reporter will be during file processing.
"""
self.coverage = coverage
self.ignore_errors = ignore_errors
-
+
# The code units to report on. Set by find_code_units.
self.code_units = []
-
+
# The directory into which to place the report, used by some derived
# classes.
self.directory = None
def find_code_units(self, morfs, omit_prefixes):
"""Find the code units we'll report on.
-
+
`morfs` is a list of modules or filenames. `omit_prefixes` is a list
of prefixes to leave out of the list.
-
+
"""
morfs = morfs or self.coverage.data.executed_files()
self.code_units = code_unit_factory(
@@ -39,9 +39,9 @@ class Reporter(object):
def report_files(self, report_fn, morfs, directory=None,
omit_prefixes=None):
"""Run a reporting function on a number of morfs.
-
+
`report_fn` is called for each relative morf in `morfs`.
-
+
"""
self.find_code_units(morfs, omit_prefixes)
diff --git a/coverage/results.py b/coverage/results.py
index 77c461ad..e80ec0a4 100644
--- a/coverage/results.py
+++ b/coverage/results.py
@@ -9,11 +9,11 @@ from coverage.parser import CodeParser
class Analysis(object):
"""The results of analyzing a code unit."""
-
+
def __init__(self, cov, code_unit):
self.coverage = cov
self.code_unit = code_unit
-
+
self.filename = self.code_unit.filename
ext = os.path.splitext(self.filename)[1]
source = None
@@ -40,10 +40,10 @@ class Analysis(object):
n_missing_branches = sum([len(v) for v in mba.values()])
else:
n_branches = n_missing_branches = 0
-
+
self.numbers = Numbers(
n_files=1,
- n_statements=len(self.statements),
+ n_statements=len(self.statements),
n_excluded=len(self.excluded),
n_missing=len(self.missing),
n_branches=n_branches,
@@ -52,9 +52,9 @@ class Analysis(object):
def missing_formatted(self):
"""The missing line numbers, formatted nicely.
-
+
Returns a string like "1-2, 5-11, 13-14".
-
+
"""
return format_lines(self.statements, self.missing)
@@ -102,12 +102,12 @@ class Analysis(object):
"""How many total branches are there?"""
exit_counts = self.parser.exit_counts()
return sum([count for count in exit_counts.values() if count > 1])
-
+
def missing_branch_arcs(self):
"""Return arcs that weren't executed from branch lines.
-
+
Returns {l1:[l2a,l2b,...], ...}
-
+
"""
missing = self.arcs_missing()
branch_lines = set(self.branch_lines())
@@ -122,7 +122,7 @@ class Analysis(object):
class Numbers(object):
"""The numerical results of measuring coverage.
-
+
This holds the basic statistics from `Analysis`, and is used to roll
up statistics across files.
@@ -141,12 +141,12 @@ class Numbers(object):
"""Returns the number of executed statements."""
return self.n_statements - self.n_missing
n_executed = property(_get_n_executed)
-
+
def _get_n_executed_branches(self):
"""Returns the number of executed branches."""
return self.n_branches - self.n_missing_branches
n_executed_branches = property(_get_n_executed_branches)
-
+
def _get_pc_covered(self):
"""Returns a single percentage value for coverage."""
if self.n_statements > 0:
diff --git a/coverage/summary.py b/coverage/summary.py
index e0e9eba7..f4d3c2c6 100644
--- a/coverage/summary.py
+++ b/coverage/summary.py
@@ -8,7 +8,7 @@ from coverage.results import Numbers
class SummaryReporter(Reporter):
"""A reporter for writing the summary report."""
-
+
def __init__(self, coverage, show_missing=True, ignore_errors=False):
super(SummaryReporter, self).__init__(coverage, ignore_errors)
self.show_missing = show_missing
@@ -16,7 +16,7 @@ class SummaryReporter(Reporter):
def report(self, morfs, omit_prefixes=None, outfile=None):
"""Writes a report summarizing coverage statistics per module."""
-
+
self.find_code_units(morfs, omit_prefixes)
# Prepare the formatting strings
@@ -45,7 +45,7 @@ class SummaryReporter(Reporter):
outfile.write(rule)
total = Numbers()
-
+
for cu in self.code_units:
try:
analysis = self.coverage._analyze(cu)
diff --git a/coverage/templite.py b/coverage/templite.py
index 0654f292..d3c673c6 100644
--- a/coverage/templite.py
+++ b/coverage/templite.py
@@ -8,40 +8,40 @@ class Templite(object):
"""A simple template renderer, for a nano-subset of Django syntax.
Supported constructs are extended variable access::
-
+
{{var.modifer.modifier|filter|filter}}
-
+
loops::
-
+
{% for var in list %}...{% endfor %}
-
+
and ifs::
-
+
{% if var %}...{% endif %}
Comments are within curly-hash markers::
-
+
{# This will be ignored #}
Construct a Templite with the template text, then use `render` against a
dictionary context to create a finished string.
-
+
"""
def __init__(self, text, *contexts):
"""Construct a Templite with the given `text`.
-
+
`contexts` are dictionaries of values to use for future renderings.
These are good for filters and global values.
-
+
"""
self.text = text
self.context = {}
for context in contexts:
self.context.update(context)
-
+
# Split the text to form a list of tokens.
toks = re.split(r"(?s)({{.*?}}|{%.*?%}|{#.*?#})", text)
-
+
# Parse the tokens into a nested list of operations. Each item in the
# list is a tuple with an opcode, and arguments. They'll be
# interpreted by TempliteEngine.
@@ -83,21 +83,21 @@ class Templite(object):
raise SyntaxError("Don't understand tag %r" % words)
else:
ops.append(('lit', tok))
-
+
assert not ops_stack, "Unmatched action tag: %r" % ops_stack[-1][0]
self.ops = ops
def render(self, context=None):
"""Render this template by applying it to `context`.
-
+
`context` is a dictionary of values to use in this rendering.
-
+
"""
# Make the complete context we'll use.
ctx = dict(self.context)
if context:
ctx.update(context)
-
+
# Run it through an engine, and return the result.
engine = _TempliteEngine(ctx)
engine.execute(self.ops)
@@ -112,9 +112,9 @@ class _TempliteEngine(object):
def execute(self, ops):
"""Execute `ops` in the engine.
-
+
Called recursively for the bodies of if's and loops.
-
+
"""
for op, args in ops:
if op == 'lit':
@@ -142,9 +142,9 @@ class _TempliteEngine(object):
def evaluate(self, expr):
"""Evaluate an expression.
-
+
`expr` can have pipes and dots to indicate data access and filtering.
-
+
"""
if "|" in expr:
pipes = expr.split("|")
diff --git a/coverage/tracer.c b/coverage/tracer.c
index 304190e0..8193c34d 100644
--- a/coverage/tracer.c
+++ b/coverage/tracer.c
@@ -60,7 +60,7 @@ typedef struct {
PyObject * data;
PyObject * should_trace_cache;
PyObject * arcs;
-
+
/* Has the tracer been started? */
int started;
/* Are we tracing arcs, or just lines? */
@@ -71,7 +71,7 @@ typedef struct {
data for a single source file. The data stack parallels the call stack:
each call pushes the new frame's file data onto the data stack, and each
return pops file data off.
-
+
The file data is a dictionary whose form depends on the tracing options.
If tracing arcs, the keys are line number pairs. If not tracing arcs,
the keys are line numbers. In both cases, the value is irrelevant
@@ -130,7 +130,7 @@ Tracer_init(Tracer *self, PyObject *args, PyObject *kwds)
self->data = NULL;
self->should_trace_cache = NULL;
self->arcs = NULL;
-
+
self->started = 0;
self->tracing_arcs = 0;
@@ -143,7 +143,7 @@ Tracer_init(Tracer *self, PyObject *args, PyObject *kwds)
}
self->data_stack_alloc = STACK_DELTA;
- self->cur_file_data = NULL;
+ self->cur_file_data = NULL;
self->last_line = -1;
self->last_exc_back = NULL;
@@ -171,7 +171,7 @@ Tracer_dealloc(Tracer *self)
static const char *
indent(int n)
{
- static const char * spaces =
+ static const char * spaces =
" "
" "
" "
@@ -220,7 +220,7 @@ static int
Tracer_record_pair(Tracer *self, int l1, int l2)
{
int ret = 0;
-
+
PyObject * t = PyTuple_New(2);
if (t != NULL) {
PyTuple_SET_ITEM(t, 0, MyInt_FromLong(l1));
@@ -248,11 +248,11 @@ Tracer_trace(Tracer *self, PyFrameObject *frame, int what, PyObject *arg)
PyObject * filename = NULL;
PyObject * tracename = NULL;
- #if WHAT_LOG
+ #if WHAT_LOG
if (what <= sizeof(what_sym)/sizeof(const char *)) {
printf("trace: %s @ %s %d\n", what_sym[what], MyText_AS_STRING(frame->f_code->co_filename), frame->f_lineno);
}
- #endif
+ #endif
#if TRACE_LOG
if (strstr(MyText_AS_STRING(frame->f_code->co_filename), start_file) && frame->f_lineno == start_line) {
@@ -269,7 +269,7 @@ Tracer_trace(Tracer *self, PyFrameObject *frame, int what, PyObject *arg)
that frame is gone. Our handling for RETURN doesn't need the
actual frame, but we do log it, so that will look a little off if
you're looking at the detailed log.
-
+
If someday we need to examine the frame when doing RETURN, then
we'll need to keep more of the missed frame's state.
*/
@@ -288,7 +288,7 @@ Tracer_trace(Tracer *self, PyFrameObject *frame, int what, PyObject *arg)
}
self->last_exc_back = NULL;
}
-
+
switch (what) {
case PyTrace_CALL: /* 0 */
@@ -361,12 +361,12 @@ Tracer_trace(Tracer *self, PyFrameObject *frame, int what, PyObject *arg)
self->cur_file_data = NULL;
SHOWLOG(self->depth, frame->f_lineno, filename, "skipped");
}
-
+
Py_DECREF(tracename);
self->last_line = -1;
break;
-
+
case PyTrace_RETURN: /* 3 */
STATS( self->stats.returns++; )
/* A near-copy of this code is above in the missing-return handler. */
@@ -383,7 +383,7 @@ Tracer_trace(Tracer *self, PyFrameObject *frame, int what, PyObject *arg)
self->depth--;
}
break;
-
+
case PyTrace_LINE: /* 2 */
STATS( self->stats.lines++; )
if (self->depth >= 0) {
@@ -414,29 +414,29 @@ Tracer_trace(Tracer *self, PyFrameObject *frame, int what, PyObject *arg)
self->last_line = frame->f_lineno;
}
break;
-
+
case PyTrace_EXCEPTION:
/* Some code (Python 2.3, and pyexpat anywhere) fires an exception event
without a return event. To detect that, we'll keep a copy of the
parent frame for an exception event. If the next event is in that
frame, then we must have returned without a return event. We can
synthesize the missing event then.
-
+
Python itself fixed this problem in 2.4. Pyexpat still has the bug.
I've reported the problem with pyexpat as http://bugs.python.org/issue6359 .
If it gets fixed, this code should still work properly. Maybe some day
the bug will be fixed everywhere coverage.py is supported, and we can
remove this missing-return detection.
-
+
More about this fix: http://nedbatchelder.com/blog/200907/a_nasty_little_bug.html
*/
STATS( self->stats.exceptions++; )
self->last_exc_back = frame->f_back;
break;
-
+
default:
STATS( self->stats.others++; )
- break;
+ break;
}
return 0;
@@ -586,7 +586,7 @@ PyInit_tracer(void)
if (mod == NULL) {
return NULL;
}
-
+
TracerType.tp_new = PyType_GenericNew;
if (PyType_Ready(&TracerType) < 0) {
Py_DECREF(mod);
@@ -595,8 +595,8 @@ PyInit_tracer(void)
Py_INCREF(&TracerType);
PyModule_AddObject(mod, "Tracer", (PyObject *)&TracerType);
-
- return mod;
+
+ return mod;
}
#else
diff --git a/coverage/xmlreport.py b/coverage/xmlreport.py
index 9cc6567a..ab44025d 100644
--- a/coverage/xmlreport.py
+++ b/coverage/xmlreport.py
@@ -14,20 +14,20 @@ def rate(hit, num):
class XmlReporter(Reporter):
"""A reporter for writing Cobertura-style XML coverage results."""
-
+
def __init__(self, coverage, ignore_errors=False):
super(XmlReporter, self).__init__(coverage, ignore_errors)
-
+
self.packages = None
self.xml_out = None
self.arcs = coverage.data.has_arcs()
def report(self, morfs, omit_prefixes=None, outfile=None):
"""Generate a Cobertura-compatible XML report for `morfs`.
-
+
`morfs` is a list of modules or filenames. `omit_prefixes` is a list
of strings, prefixes of modules to omit from the report.
-
+
"""
# Initial setup.
outfile = outfile or sys.stdout
@@ -39,7 +39,7 @@ class XmlReporter(Reporter):
"http://cobertura.sourceforge.net/xml/coverage-03.dtd"
)
self.xml_out = impl.createDocument(None, "coverage", docType)
-
+
# Write header stuff.
xcoverage = self.xml_out.documentElement
xcoverage.setAttribute("version", __version__)
@@ -56,7 +56,7 @@ class XmlReporter(Reporter):
lnum_tot, lhits_tot = 0, 0
bnum_tot, bhits_tot = 0, 0
-
+
# Populate the XML DOM with the package info.
for pkg_name, pkg_data in self.packages.items():
class_elts, lhits, lnum, bhits, bnum = pkg_data
@@ -75,16 +75,16 @@ class XmlReporter(Reporter):
lhits_tot += lhits
bnum_tot += bnum
bhits_tot += bhits
-
+
xcoverage.setAttribute("line-rate", str(rate(lhits_tot, lnum_tot)))
xcoverage.setAttribute("branch-rate", str(rate(bhits_tot, bnum_tot)))
-
+
# Use the DOM to write the output file.
outfile.write(self.xml_out.toprettyxml())
def xml_file(self, cu, analysis):
"""Add to the XML report for a single file."""
-
+
# Create the 'lines' and 'package' XML elements, which
# are populated later. Note that a package == a directory.
dirname, fname = os.path.split(cu.name)
@@ -133,7 +133,7 @@ class XmlReporter(Reporter):
else:
class_branches = 0.0
class_branch_hits = 0.0
-
+
# Finalize the statistics that are collected in the XML DOM.
line_rate = rate(class_hits, class_lines)
branch_rate = rate(class_branch_hits, class_branches)
diff --git a/doc/api.rst b/doc/api.rst
index 17f74b64..98187a8f 100644
--- a/doc/api.rst
+++ b/doc/api.rst
@@ -13,12 +13,12 @@ coverage object correspond to operations available in the command line
interface. For example, a simple use would be::
import coverage
-
+
cov = coverage.coverage()
cov.start()
-
+
# .. run your code ..
-
+
cov.stop()
cov.save()
@@ -29,4 +29,4 @@ The coverage module
.. module:: coverage
.. autoclass:: coverage
- :members:
+ :members:
diff --git a/doc/branch.rst b/doc/branch.rst
index 262ce1a5..7e156034 100644
--- a/doc/branch.rst
+++ b/doc/branch.rst
@@ -18,9 +18,9 @@ For example::
if x: # 2
y = 10 # 3
return y # 4
-
+
my_partial_fn(1)
-
+
In this code, line 2 is an ``if`` statement which can go next to either line 3
or line 4. Statement coverage would show all lines of the function as executed.
But the if was never evaluated as false, so line 2 never jumps to line 4.
@@ -35,7 +35,7 @@ How to measure branch coverage
To measure branch coverage, run coverage.py with the ``--branch`` flag::
coverage run --branch myprog.py
-
+
When you report on the results with ``coverage report`` or ``coverage html``,
the percentage of branch possibilities taken will be included in the percentage
covered total for each file. The coverage percentage for a file is the actual
@@ -48,7 +48,7 @@ far right showing branch destination line numbers that were not exercised.
The XML report produced by ``coverage xml`` also includes branch information,
including separate statement and branch coverage percentages. Each line is
-annotated with
+annotated with
How it works
@@ -91,10 +91,10 @@ unconditional loop will be marked as partially executed::
while True: # line 1
if some_condition(): # 2
- break
+ break
body_of_loop() # 4
-
+
keep_working() # 6
Because the loop never terminates naturally (jumping from line 1 to 6),
-coverage.py considers the branch partially executed.
+coverage.py considers the branch partially executed.
diff --git a/doc/changes.rst b/doc/changes.rst
index 97d9a8e6..bdf0ac71 100644
--- a/doc/changes.rst
+++ b/doc/changes.rst
@@ -38,7 +38,7 @@ Version 3.2
- Some exceptions reported by the command line interface have been cleaned up
so that tracebacks inside coverage.py aren't shown. Fixes `issue 23`_.
-
+
- Fixed some problems syntax coloring sources with line continuations and
source with tabs: `issue 30`_ and `issue 31`_.
@@ -116,7 +116,7 @@ Version 3.0, 13 June 2009
other encouragement.
- The minimum supported Python version is 2.3.
-
+
- When using the object api (that is, constructing a coverage() object), data
is no longer saved automatically on process exit. You can re-enable it with
the ``auto_data=True`` parameter on the coverage() constructor.
@@ -130,12 +130,12 @@ Version 3.0, 13 June 2009
- Added parameters to coverage.__init__ for options that had been set on
the coverage object itself.
-
+
- Added clear_exclude() and get_exclude_list() methods for programmatic
manipulation of the exclude regexes.
-
+
- Added coverage.load() to read previously-saved data from the data file.
-
+
- coverage.annotate_file is no longer available.
-
+
- Removed the undocumented cache_file argument to coverage.usecache().
diff --git a/doc/cmd.rst b/doc/cmd.rst
index 41de00c9..ab93845e 100644
--- a/doc/cmd.rst
+++ b/doc/cmd.rst
@@ -71,7 +71,7 @@ can set a new file name with the COVERAGE_FILE environment variable. By default
each run of your program starts with an empty data set. If you need to run your
program multiple times to get complete data (for example, because you need to
supply disjoint options), you can accumulate data across runs with the ``-a``
-flag on the **run** command.
+flag on the **run** command.
To erase the collected data, use the **erase** command::
@@ -113,7 +113,7 @@ as a percentage.
The ``-m`` flag also shows the line numbers of missing statements::
- $ coverage report -m
+ $ coverage report -m
Name Stmts Exec Cover Missing
-------------------------------------------------------
my_program 20 16 80% 33-35, 39
@@ -178,7 +178,7 @@ Coverage status for each line of source is indicated with a character prefix::
For example::
# A simple function, never called with x==1
-
+
> def h(x):
"""Silly function."""
- if 0: #pragma: no cover
@@ -187,7 +187,7 @@ For example::
! a = 1
> else:
> a = 2
-
+
XML reporting
-------------
diff --git a/doc/excluding.rst b/doc/excluding.rst
index 1333f5c2..1b91fc9a 100644
--- a/doc/excluding.rst
+++ b/doc/excluding.rst
@@ -30,7 +30,7 @@ function is not reported as missing::
def __init__(self):
blah1()
blah2()
-
+
def __repr__(self): # pragma: no cover
return "<MyObject>"
@@ -71,7 +71,7 @@ in debugging code, and are uninteresting to test themselves. You could exclude
all of them by adding a regex to the exclusion list::
coverage.exclude('def __repr__')
-
+
Here's a list of exclusions I've used::
coverage.exclude('def __repr__')
diff --git a/doc/index.rst b/doc/index.rst
index eff3106e..5acbc9e9 100644
--- a/doc/index.rst
+++ b/doc/index.rst
@@ -43,7 +43,7 @@ Getting started is easy:
.. code-block:: console
- $ coverage report -m
+ $ coverage report -m
Name Stmts Exec Cover Missing
-------------------------------------------------------
my_program 20 16 80% 33-35, 39
@@ -53,7 +53,7 @@ Getting started is easy:
#. For a nicer presentation, use ``coverage html`` to get annotated HTML
listings detailing missed lines:
-
+
.. code-block:: console
$ coverage html -d htmlcov
@@ -99,7 +99,7 @@ More information
.. toctree::
:maxdepth: 1
-
+
cmd
api
excluding
diff --git a/howto.txt b/howto.txt
index 316a8996..388db699 100644
--- a/howto.txt
+++ b/howto.txt
@@ -48,7 +48,7 @@
- On Py 3.x: need Distribute installed
- In each Python installation to be used, create a "coverage_test_egg.pth"
containing::
-
+
c:\ned\coverage\trunk\test\eggsrc\dist\covtestegg1-0.0.0-py2.5.egg
(or equivalent).
diff --git a/setup.py b/setup.py
index 1aeaab9a..6bd472ac 100644
--- a/setup.py
+++ b/setup.py
@@ -78,13 +78,13 @@ setup(
ext_modules = [
Extension("coverage.tracer", sources=["coverage/tracer.c"])
],
-
+
entry_points = {
'console_scripts': [
'coverage = coverage:main',
]
},
-
+
# We need to get HTML assets from our htmlfiles dir.
zip_safe = False,
diff --git a/test/backtest.py b/test/backtest.py
index 21a14d6d..12bdbc97 100644
--- a/test/backtest.py
+++ b/test/backtest.py
@@ -12,18 +12,18 @@ try:
except ImportError:
def run_command(cmd):
"""Run a command in a subprocess.
-
+
Returns the exit code and the combined stdout and stderr.
-
+
"""
_, stdouterr = os.popen4(cmd)
return 0, stdouterr.read()
else:
def run_command(cmd):
"""Run a command in a subprocess.
-
+
Returns the exit code and the combined stdout and stderr.
-
+
"""
if sys.hexversion > 0x03000000 and cmd.startswith("coverage "):
@@ -36,13 +36,13 @@ else:
stderr=subprocess.STDOUT
)
retcode = proc.wait()
-
+
# Get the output, and canonicalize it to strings with newlines.
output = proc.stdout.read()
if not isinstance(output, str):
output = output.decode('utf-8')
output = output.replace('\r', '')
-
+
return retcode, output
# No more execfile in Py3k
diff --git a/test/backunittest.py b/test/backunittest.py
index 2088f2f7..28978c78 100644
--- a/test/backunittest.py
+++ b/test/backunittest.py
@@ -12,10 +12,10 @@ def _need(method):
class TestCase(unittest.TestCase):
"""Just like unittest.TestCase, but with assert methods added.
-
+
Designed to be compatible with 3.1 unittest. Methods are only defined if
the builtin `unittest` doesn't have them.
-
+
"""
if _need('assertFalse'):
def assertFalse(self, exp):
@@ -69,16 +69,16 @@ class TestCase(unittest.TestCase):
if _need('assertMultiLineEqual'):
def assertMultiLineEqual(self, first, second):
"""Assert that two multi-line strings are equal.
-
+
If they aren't, show a nice diff.
-
+
"""
# Adapted from Py3.1 unittest.
self.assert_(isinstance(first, str), (
'First argument is not a string'))
self.assert_(isinstance(second, str), (
'Second argument is not a string'))
-
+
if first != second:
msg = ''.join(difflib.ndiff(first.splitlines(True),
second.splitlines(True)))
diff --git a/test/coverage_coverage.py b/test/coverage_coverage.py
index 73ff3be3..b7f903bf 100644
--- a/test/coverage_coverage.py
+++ b/test/coverage_coverage.py
@@ -8,7 +8,7 @@ HTML_DIR = "htmlcov"
def run_tests_with_coverage():
"""Run the test suite with coverage measuring itself."""
import coverage
-
+
tracer = os.environ.get('COVERAGE_TEST_TRACER', 'c')
version = "%s%s" % sys.version_info[:2]
suffix = ".%s_%s" % (version, tracer)
@@ -20,7 +20,7 @@ def run_tests_with_coverage():
cov.cover_prefix = "Please measure coverage.py!"
cov.erase()
cov.start()
-
+
# Re-import coverage to get it coverage tested! I don't understand all the
# mechanics here, but if I don't carry over the imported modules (in
# covmods), then things go haywire (os == None, eventually).
@@ -39,7 +39,7 @@ def run_tests_with_coverage():
# Run nosetests, with the arguments from our command line.
print(":: Running nosetests %s" % " ".join(sys.argv[1:]))
nose.run()
-
+
cov.stop()
print(":: Saving .coverage%s" % suffix)
cov.save()
@@ -59,7 +59,7 @@ def report_on_combined_files():
cov.exclude("def __repr__")
cov.exclude("if __name__ == .__main__.:")
cov.exclude("raise AssertionError")
-
+
cov.html_report(
directory=HTML_DIR, ignore_errors=True, omit_prefixes=["mock"]
)
@@ -69,7 +69,7 @@ try:
cmd = sys.argv[1]
except IndexError:
cmd = ''
-
+
if cmd == 'run':
# Ugly hack: nose.run reads sys.argv directly, so here I delete my command
# argument so that sys.argv is left as just nose arguments.
diff --git a/test/coveragetest.py b/test/coveragetest.py
index 073dc39f..4471392f 100644
--- a/test/coveragetest.py
+++ b/test/coveragetest.py
@@ -13,7 +13,7 @@ class Tee(object):
def __init__(self, *files):
"""Make a Tee that writes to all the files in `files.`"""
self.files = files
-
+
def write(self, data):
"""Write `data` to all the files."""
for f in self.files:
@@ -27,7 +27,7 @@ class CoverageTest(TestCase):
"""A base class for Coverage test cases."""
run_in_temp_dir = True
-
+
def setUp(self):
if self.run_in_temp_dir:
# Create a temporary directory.
@@ -37,14 +37,14 @@ class CoverageTest(TestCase):
os.makedirs(self.temp_dir)
self.old_dir = os.getcwd()
os.chdir(self.temp_dir)
-
+
# Preserve changes to PYTHONPATH.
self.old_pypath = os.environ.get('PYTHONPATH', '')
-
+
# Modules should be importable from this temp directory.
self.old_syspath = sys.path[:]
sys.path.insert(0, '')
-
+
# Keep a counter to make every call to check_coverage unique.
self.n = 0
@@ -52,17 +52,17 @@ class CoverageTest(TestCase):
self.old_stdout = sys.stdout
self.captured_stdout = StringIO()
sys.stdout = Tee(sys.stdout, self.captured_stdout)
-
+
def tearDown(self):
if self.run_in_temp_dir:
# Restore the original sys.path and PYTHONPATH
sys.path = self.old_syspath
os.environ['PYTHONPATH'] = self.old_pypath
-
+
# Get rid of the temporary directory.
os.chdir(self.old_dir)
shutil.rmtree(self.temp_root)
-
+
# Restore stdout.
sys.stdout = self.old_stdout
@@ -72,14 +72,14 @@ class CoverageTest(TestCase):
def make_file(self, filename, text):
"""Create a temp file.
-
+
`filename` is the file name, and `text` is the content.
-
+
"""
# Tests that call `make_file` should be run in a temp environment.
assert self.run_in_temp_dir
text = textwrap.dedent(text)
-
+
# Create the file.
f = open(filename, 'w')
f.write(text)
@@ -89,7 +89,7 @@ class CoverageTest(TestCase):
"""Import the module named modname, and return the module object."""
modfile = modname + '.py'
f = open(modfile, 'r')
-
+
for suff in imp.get_suffixes():
if suff[0] == '.py':
break
@@ -110,23 +110,23 @@ class CoverageTest(TestCase):
modname = 'coverage_test_' + self.noise + str(self.n)
self.n += 1
return modname
-
+
# Map chars to numbers for arcz_to_arcs
_arcz_map = {'.': -1}
_arcz_map.update(dict([(c, ord(c)-ord('0')) for c in '123456789']))
_arcz_map.update(dict(
[(c, 10+ord(c)-ord('A')) for c in 'ABCDEFGHIJKLMNOPQRSTUVWXYZ']
))
-
+
def arcz_to_arcs(self, arcz):
"""Convert a compact textual representation of arcs to a list of pairs.
-
+
The text has space-separated pairs of letters. Period is -1, 1-9 are
1-9, A-Z are 10 through 36. The resulting list is sorted regardless of
the order of the input pairs.
-
+
".1 12 2." --> [(-1,1), (1,2), (2,-1)]
-
+
"""
arcs = []
for a,b in arcz.split():
@@ -136,23 +136,23 @@ class CoverageTest(TestCase):
def check_coverage(self, text, lines=None, missing="", excludes=None,
report="", arcz=None, arcz_missing="", arcz_unpredicted=""):
"""Check the coverage measurement of `text`.
-
+
The source `text` is run and measured. `lines` are the line numbers
that are executable, `missing` are the lines not executed, `excludes`
are regexes to match against for excluding lines, and `report` is
the text of the measurement report.
-
+
For arc measurement, `arcz` is a string that can be decoded into arcs
in the code (see `arcz_to_arcs` for the encoding scheme),
`arcz_missing` are the arcs that are not executed, and
`arcs_unpredicted` are the arcs executed in the code, but not deducible
from the code.
-
+
"""
# We write the code into a file so that we can import it.
# Coverage wants to deal with things as modules with file names.
modname = self.get_module_name()
-
+
self.make_file(modname+".py", text)
arcs = arcs_missing = arcs_unpredicted = None
@@ -160,7 +160,7 @@ class CoverageTest(TestCase):
arcs = self.arcz_to_arcs(arcz)
arcs_missing = self.arcz_to_arcs(arcz_missing or "")
arcs_unpredicted = self.arcz_to_arcs(arcz_unpredicted or "")
-
+
# Start up Coverage.
cov = coverage.coverage(branch=(arcs_missing is not None))
cov.erase()
@@ -174,7 +174,7 @@ class CoverageTest(TestCase):
finally:
# Stop Coverage.
cov.stop()
-
+
# Clean up our side effects
del sys.modules[modname]
@@ -218,36 +218,36 @@ class CoverageTest(TestCase):
cov.report(mod, file=frep)
rep = " ".join(frep.getvalue().split("\n")[2].split()[1:])
self.assertEqual(report, rep)
-
+
def nice_file(self, *fparts):
"""Canonicalize the filename composed of the parts in `fparts`."""
fname = os.path.join(*fparts)
return os.path.normcase(os.path.abspath(os.path.realpath(fname)))
-
+
def command_line(self, args, ret=OK):
"""Run `args` through the command line.
-
+
Use this when you want to run the full coverage machinery, but in the
current process. Exceptions may be thrown from deep in the code.
Asserts that `ret` is returned by `CoverageScript.command_line`.
-
+
Compare with `run_command`.
-
+
Returns None.
-
+
"""
ret_actual = coverage.CoverageScript().command_line(shlex.split(args))
self.assertEqual(ret_actual, ret)
-
+
def run_command(self, cmd):
""" Run the command-line `cmd` in a subprocess, and print its output.
-
+
Use this when you need to test the process behavior of coverage.
-
+
Compare with `command_line`.
-
+
Returns the process' stdout text.
-
+
"""
# Add our test modules directory to PYTHONPATH. I'm sure there's too
# much path munging here, but...
@@ -259,7 +259,7 @@ class CoverageTest(TestCase):
pypath += os.pathsep
pypath += testmods + os.pathsep + zipfile
os.environ['PYTHONPATH'] = pypath
-
+
_, output = run_command(cmd)
print(output)
return output
diff --git a/test/osinfo.py b/test/osinfo.py
index 7a82610a..8bed2afd 100644
--- a/test/osinfo.py
+++ b/test/osinfo.py
@@ -23,7 +23,7 @@ if sys.hexversion >= 0x02050000 and sys.platform == 'win32':
('PeakPagefileUsage', ctypes.c_size_t),
('PrivateUsage', ctypes.c_size_t),
]
-
+
mem_struct = PROCESS_MEMORY_COUNTERS_EX()
ret = ctypes.windll.psapi.GetProcessMemoryInfo(
ctypes.windll.kernel32.GetCurrentProcess(),
@@ -37,9 +37,9 @@ if sys.hexversion >= 0x02050000 and sys.platform == 'win32':
elif sys.platform == 'linux2':
# Linux implementation
import os
-
+
_scale = {'kb': 1024, 'mb': 1024*1024}
-
+
def _VmB(key):
"""Read the /proc/PID/status file to find memory use."""
try:
diff --git a/test/test_api.py b/test/test_api.py
index 7308cdc6..2552d114 100644
--- a/test/test_api.py
+++ b/test/test_api.py
@@ -25,17 +25,17 @@ class ApiTest(CoverageTest):
c = 4
d = 5
""")
-
+
# Import the python file, executing it.
coverage.start()
self.import_module("mycode")
coverage.stop()
-
+
_, statements, missing, missingtext = coverage.analysis("mycode.py")
self.assertEqual(statements, [1,2,3,4,5])
self.assertEqual(missing, [4])
self.assertEqual(missingtext, "4")
-
+
def doReportWork(self, modname):
"""Create a module named `modname`, then measure it."""
coverage.erase()
@@ -49,12 +49,12 @@ class ApiTest(CoverageTest):
e = 6
f = 7
""")
-
+
# Import the python file, executing it.
coverage.start()
self.import_module(modname)
coverage.stop()
-
+
def testReport(self):
self.doReportWork("mycode2")
coverage.report(["mycode2.py"])
@@ -63,7 +63,7 @@ class ApiTest(CoverageTest):
---------------------------------------
mycode2 7 4 57% 4-6
"""))
-
+
def testReportFile(self):
# The file= argument of coverage.report makes the report go there.
self.doReportWork("mycode3")
@@ -93,16 +93,16 @@ class ApiTest(CoverageTest):
c = 4
d = 5
""")
-
+
self.make_file("not_run.py", """\
fooey = 17
""")
-
+
# Import the python file, executing it.
cov.start()
self.import_module("mycode")
cov.stop()
-
+
_, statements, missing, _ = cov.analysis("not_run.py")
self.assertEqual(statements, [1])
self.assertEqual(missing, [1])
@@ -113,22 +113,22 @@ class ApiTest(CoverageTest):
import mymod
a = 1
""")
-
+
self.make_file("mymod.py", """\
fooey = 17
""")
-
+
# Import the python file, executing it.
cov = coverage.coverage()
cov.start()
self.import_module("mymain")
cov.stop()
-
+
filename, _, _, _ = cov.analysis("mymain.py")
self.assertEqual(os.path.basename(filename), "mymain.py")
filename, _, _, _ = cov.analysis("mymod.py")
self.assertEqual(os.path.basename(filename), "mymod.py")
-
+
filename, _, _, _ = cov.analysis(sys.modules["mymain"])
self.assertEqual(os.path.basename(filename), "mymain.py")
filename, _, _, _ = cov.analysis(sys.modules["mymod"])
@@ -140,12 +140,12 @@ class ApiTest(CoverageTest):
cov.start()
self.import_module("mymain")
cov.stop()
-
+
filename, _, _, _ = cov.analysis("mymain.py")
self.assertEqual(os.path.basename(filename), "mymain.py")
filename, _, _, _ = cov.analysis("mymod.py")
self.assertEqual(os.path.basename(filename), "mymod.py")
-
+
filename, _, _, _ = cov.analysis(sys.modules["mymain"])
self.assertEqual(os.path.basename(filename), "mymain.py")
filename, _, _, _ = cov.analysis(sys.modules["mymod"])
@@ -157,7 +157,7 @@ class ApiTest(CoverageTest):
a = 1
hls = colorsys.rgb_to_hls(1.0, 0.5, 0.0)
""")
-
+
self.make_file("mymod.py", """\
fooey = 17
""")
diff --git a/test/test_arcs.py b/test/test_arcs.py
index 47a69987..45ab27e8 100644
--- a/test/test_arcs.py
+++ b/test/test_arcs.py
@@ -25,7 +25,7 @@ class SimpleArcTest(CoverageTest):
a = 2
b = 3
-
+
c = 5
""",
arcz=".2 23 35 5.")
@@ -34,7 +34,7 @@ class SimpleArcTest(CoverageTest):
self.check_coverage("""\
def foo():
a = 2
-
+
foo()
""",
arcz=".1 .2 14 2. 4.")
@@ -54,7 +54,7 @@ class SimpleArcTest(CoverageTest):
assert a == 1
""",
arcz=".1 12 23 24 34 4.", arcz_missing="23 34")
-
+
def test_if_else(self):
self.check_coverage("""\
if len([]) == 0:
@@ -139,7 +139,7 @@ class SimpleArcTest(CoverageTest):
class LoopArcTest(CoverageTest):
"""Arc-measuring tests involving loops."""
-
+
def test_loop(self):
self.check_coverage("""\
for i in range(10):
diff --git a/test/test_cmdline.py b/test/test_cmdline.py
index f1e48e63..258a08ac 100644
--- a/test/test_cmdline.py
+++ b/test/test_cmdline.py
@@ -10,7 +10,7 @@ from coveragetest import CoverageTest, OK, ERR
class CmdLineTest(CoverageTest):
"""Tests of execution paths through the command line interpreter."""
-
+
run_in_temp_dir = False
INIT_LOAD = """\
@@ -25,16 +25,16 @@ class CmdLineTest(CoverageTest):
def mock_command_line(self, args):
"""Run `args` through the command line, with a Mock.
-
+
Returns the Mock it used and the status code returned.
-
+
"""
m = self.model_object()
ret = coverage.CoverageScript(
_covpkg=m, _run_python_file=m.run_python_file, _help_fn=m.help_fn
).command_line(shlex.split(args))
return m, ret
-
+
def cmd_executes(self, args, code, ret=OK):
"""Assert that the `args` end up executing the sequence in `code`."""
m1, r1 = self.mock_command_line(args)
@@ -48,7 +48,7 @@ class CmdLineTest(CoverageTest):
code_obj = compile(code, "<code>", "exec")
eval(code_obj, globals(), { 'm2': m2 })
self.assertEqual(m1.method_calls, m2.method_calls)
-
+
def cmd_executes_same(self, args1, args2):
"""Assert that the `args1` executes the same as `args2`."""
m1, r1 = self.mock_command_line(args1)
@@ -58,10 +58,10 @@ class CmdLineTest(CoverageTest):
def cmd_help(self, args, help_msg=None, topic=None, ret=ERR):
"""Run a command line, and check that it prints the right help.
-
+
Only the last function call in the mock is checked, which should be the
help message that we want to see.
-
+
"""
m, r = self.mock_command_line(args)
self.assertEqual(r, ret,
@@ -75,7 +75,7 @@ class CmdLineTest(CoverageTest):
self.assertEqual(m.method_calls[-1],
('help_fn', (), {'topic':topic})
)
-
+
class ClassicCmdLineTest(CmdLineTest):
"""Tests of the classic coverage.py command line."""
@@ -90,7 +90,7 @@ class ClassicCmdLineTest(CmdLineTest):
def testExecute(self):
# coverage -x [-p] [-L] [--timid] MODULE.py [ARG1 ARG2 ...]
-
+
# -x calls coverage.load first.
self.cmd_executes("-x foo.py", """\
.coverage(cover_pylib=None, data_suffix=False, timid=None, branch=None)
@@ -275,7 +275,7 @@ class ClassicCmdLineTest(CmdLineTest):
self.cmd_help("--version", topic="version", ret=OK)
## Error cases
-
+
def testArglessActions(self):
self.cmd_help("-e foo bar", "Unexpected arguments: foo bar")
self.cmd_help("-c baz quux", "Unexpected arguments: baz quux")
@@ -349,7 +349,7 @@ class NewCmdLineTest(CmdLineTest):
out = self.stdout()
assert "version:" in out
assert "data_path:" in out
-
+
def testErase(self):
self.cmd_executes_same("erase", "-e")
@@ -387,7 +387,7 @@ class NewCmdLineTest(CmdLineTest):
self.cmd_executes_same("run -L f.py", "-e -x -L f.py")
self.cmd_executes_same("run --timid f.py", "-e -x --timid f.py")
self.cmd_executes_same("run", "-x")
-
+
def testXml(self):
# coverage xml [-i] [--omit DIR,...] [FILE1 FILE2 ...]
self.cmd_executes("xml", self.INIT_LOAD + """\
@@ -432,19 +432,19 @@ class NewCmdLineTest(CmdLineTest):
class CmdLineStdoutTest(CmdLineTest):
"""Test the command line with real stdout output."""
-
+
def testMinimumHelp(self):
self.command_line("")
out = self.stdout()
assert "Code coverage for Python." in out
assert out.count("\n") < 4
-
+
def testHelp(self):
self.command_line("help")
out = self.stdout()
assert "nedbatchelder.com" in out
assert out.count("\n") > 10
-
+
def testCmdHelp(self):
self.command_line("help run")
out = self.stdout()
diff --git a/test/test_codeunit.py b/test/test_codeunit.py
index 96df9633..ad073827 100644
--- a/test/test_codeunit.py
+++ b/test/test_codeunit.py
@@ -21,7 +21,7 @@ class CodeUnitTest(CoverageTest):
# Parent class saves and restores sys.path, we can just modify it.
testmods = self.nice_file(os.path.dirname(__file__), 'modules')
sys.path.append(testmods)
-
+
def test_filenames(self):
acu = code_unit_factory("aa/afile.py", FileLocator())
bcu = code_unit_factory("aa/bb/bfile.py", FileLocator())
@@ -81,4 +81,3 @@ class CodeUnitTest(CoverageTest):
self.assertEqual(cu[1].source_file().read().split("\n")[0],
"# My egg file!"
)
- \ No newline at end of file
diff --git a/test/test_coverage.py b/test/test_coverage.py
index 23990ccd..c1a72480 100644
--- a/test/test_coverage.py
+++ b/test/test_coverage.py
@@ -15,18 +15,18 @@ from coveragetest import CoverageTest
class BasicCoverageTest(CoverageTest):
"""The simplest tests, for quick smoke testing of fundamental changes."""
-
+
def testSimple(self):
self.check_coverage("""\
a = 1
b = 2
-
+
c = 4
# Nothing here
d = 6
""",
[1,2,4,6], report="4 4 100%")
-
+
def testIndentationWackiness(self):
# Partial final lines are OK.
self.check_coverage("""\
@@ -57,11 +57,11 @@ class BasicCoverageTest(CoverageTest):
assert l == [12, 14, 16, 18]
""",
[1,5], "")
-
+
class SimpleStatementTest(CoverageTest):
"""Testing simple single-line statements."""
-
+
def testExpression(self):
self.check_coverage("""\
1 + 2
@@ -73,7 +73,7 @@ class SimpleStatementTest(CoverageTest):
def testAssert(self):
self.check_coverage("""\
assert (1 + 2)
- assert (1 +
+ assert (1 +
2)
assert (1 + 2), 'the universe is broken'
assert (1 +
@@ -100,7 +100,7 @@ class SimpleStatementTest(CoverageTest):
assert a == 7 and b == 8 and c == 9
""",
[1,2,3], "")
-
+
def testAttributeAssignment(self):
# Attribute assignment
self.check_coverage("""\
@@ -113,7 +113,7 @@ class SimpleStatementTest(CoverageTest):
1
""",
[1,2,3,4,6], "")
-
+
def testListofAttributeAssignment(self):
self.check_coverage("""\
class obj: pass
@@ -127,7 +127,7 @@ class SimpleStatementTest(CoverageTest):
2
""",
[1,2,3,4,7], "")
-
+
def testAugmentedAssignment(self):
self.check_coverage("""\
a = 1
@@ -153,7 +153,7 @@ class SimpleStatementTest(CoverageTest):
'''
c = len('''
long expression
- ''' +
+ ''' +
'''
on many
lines.
@@ -197,7 +197,7 @@ class SimpleStatementTest(CoverageTest):
Foo().foo()
""",
([1,2,4,5], [1,2,5]), "")
-
+
def testDel(self):
self.check_coverage("""\
d = { 'a': 1, 'b': 1, 'c': 1, 'd': 1, 'e': 1 }
@@ -225,7 +225,7 @@ class SimpleStatementTest(CoverageTest):
print "goodbye",
""",
[1,2,4,5,6,8], "")
-
+
def testRaise(self):
self.check_coverage("""\
try:
@@ -253,7 +253,7 @@ class SimpleStatementTest(CoverageTest):
return (
a +
1)
-
+
x = fn()
assert(x == 2)
""",
@@ -264,7 +264,7 @@ class SimpleStatementTest(CoverageTest):
return (a,
a + 1,
a + 2)
-
+
x,y,z = fn()
assert x == 1 and y == 2 and z == 3
""",
@@ -284,7 +284,7 @@ class SimpleStatementTest(CoverageTest):
assert a == 1 and b == 9 and c == (1,2)
""",
[1,2,3,4,7,9,10], "")
-
+
def testBreak(self):
self.check_coverage("""\
for x in range(10):
@@ -294,7 +294,7 @@ class SimpleStatementTest(CoverageTest):
assert a == 2
""",
[1,2,3,4,5], "4")
-
+
def testContinue(self):
self.check_coverage("""\
for x in range(10):
@@ -304,7 +304,7 @@ class SimpleStatementTest(CoverageTest):
assert a == 11
""",
[1,2,3,4,5], "4")
-
+
if 0:
# Peephole optimization of jumps to jumps can mean that some statements
# never hit the line tracer. The behavior is different in different
@@ -321,7 +321,7 @@ class SimpleStatementTest(CoverageTest):
b += 1
c += 1
assert a == 50 and b == 50 and c == 50
-
+
a = b = c = 0
for n in range(100):
if n % 2:
@@ -334,7 +334,7 @@ class SimpleStatementTest(CoverageTest):
assert a == 33 and b == 50 and c == 50
""",
[1,2,3,4,5,6,8,9,10, 12,13,14,15,16,17,19,20,21], "")
-
+
def testImport(self):
self.check_coverage("""\
import string
@@ -381,7 +381,7 @@ class SimpleStatementTest(CoverageTest):
assert len(path) > 0
""",
[1,3], "")
-
+
def testGlobal(self):
self.check_coverage("""\
g = h = i = 1
@@ -488,24 +488,24 @@ class SimpleStatementTest(CoverageTest):
class CompoundStatementTest(CoverageTest):
"""Testing coverage of multi-line compound statements."""
-
+
def testStatementList(self):
self.check_coverage("""\
a = 1;
b = 2; c = 3
d = 4; e = 5;
-
+
assert (a,b,c,d,e) == (1,2,3,4,5)
""",
[1,2,3,5], "")
-
+
def testIf(self):
self.check_coverage("""\
a = 1
if a == 1:
x = 3
assert x == 3
- if (a ==
+ if (a ==
1):
x = 7
assert x == 7
@@ -541,7 +541,7 @@ class CompoundStatementTest(CoverageTest):
assert x == 4
""",
[1,2,3,4,6,8,9], "6-8")
-
+
def testElif(self):
self.check_coverage("""\
a = 1; b = 2; c = 3;
@@ -655,7 +655,7 @@ class CompoundStatementTest(CoverageTest):
assert z == 7
""",
[1,2,4,5,7,9,10], "4, 7")
-
+
def testPathologicalSplitIf(self):
self.check_coverage("""\
a = 1; b = 2; c = 3;
@@ -702,7 +702,7 @@ class CompoundStatementTest(CoverageTest):
assert z == 7
""",
[1,2,5,6,9,11,12], "5, 9")
-
+
def testAbsurdSplitIf(self):
self.check_coverage("""\
a = 1; b = 2; c = 3;
@@ -788,7 +788,7 @@ class CompoundStatementTest(CoverageTest):
assert a == 2 and b == 1
""",
[1,2,3,4,5,6,8,9], "6-8")
-
+
def testSplitWhile(self):
self.check_coverage("""\
a = 3; b = 0
@@ -836,7 +836,7 @@ class CompoundStatementTest(CoverageTest):
assert a == 1
""",
[1,2,3,4,5,6], "5")
-
+
def testForElse(self):
self.check_coverage("""\
a = 0
@@ -858,7 +858,7 @@ class CompoundStatementTest(CoverageTest):
assert a == 1
""",
[1,2,3,4,5,7,8], "5-7")
-
+
def testSplitFor(self):
self.check_coverage("""\
a = 0
@@ -878,7 +878,7 @@ class CompoundStatementTest(CoverageTest):
assert a == 15
""",
[1,2,6,7], "")
-
+
def testTryExcept(self):
self.check_coverage("""\
a = 0
@@ -948,7 +948,7 @@ class CompoundStatementTest(CoverageTest):
assert a == 99
""",
[1,2,3,4,5,6,8,9], "8")
-
+
def testTryFinally(self):
self.check_coverage("""\
a = 0
@@ -980,7 +980,7 @@ class CompoundStatementTest(CoverageTest):
''' docstring
'''
return 1
-
+
a = foo()
assert a == 1
""",
@@ -993,7 +993,7 @@ class CompoundStatementTest(CoverageTest):
''' docstring
'''
return a+b
-
+
x = foo(17, 23)
assert x == 40
""",
@@ -1009,7 +1009,7 @@ class CompoundStatementTest(CoverageTest):
''' docstring
'''
return a+b
-
+
x = foo()
assert x == 22
""",
@@ -1025,19 +1025,19 @@ class CompoundStatementTest(CoverageTest):
def __init__(self):
''' Another docstring. '''
self.a = 1
-
+
def foo(self):
return self.a
-
+
x = theClass().foo()
assert x == 1
""",
- [2,6,8,10,11,13,14], "")
+ [2,6,8,10,11,13,14], "")
class ExcludeTest(CoverageTest):
"""Tests of the exclusion feature to mark lines as not covered."""
-
+
def testSimple(self):
self.check_coverage("""\
a = 1; b = 2
@@ -1058,7 +1058,7 @@ class ExcludeTest(CoverageTest):
assert a == 1 and b == 2
""",
[1,3,5,7], "5", ['-cc', '-xx'])
-
+
def testExcludingIfSuite(self):
self.check_coverage("""\
a = 1; b = 2
@@ -1085,7 +1085,7 @@ class ExcludeTest(CoverageTest):
assert a == 8 and b == 9
""",
[1,8,9,10], "", ['if 0:'])
-
+
def testExcludingElseSuite(self):
self.check_coverage("""\
a = 1; b = 2
@@ -1107,14 +1107,14 @@ class ExcludeTest(CoverageTest):
a = 4
b = 5
c = 6
-
+
# Lots of comments to confuse the else handler.
# more.
-
+
else: #pragma: NO COVER
# Comments here too.
-
+
a = 8
b = 9
assert a == 4 and b == 5 and c == 6
@@ -1132,7 +1132,7 @@ class ExcludeTest(CoverageTest):
elif 1==0: #pragma: NO COVER
a = 8
b = 9
- else:
+ else:
a = 11
b = 12
assert a == 4 and b == 5 and c == 6
@@ -1145,7 +1145,7 @@ class ExcludeTest(CoverageTest):
a = 2
if 0: x = 3 # no cover
b = 4
-
+
foo()
""",
[1,2,4,6], "", ["no cover"])
@@ -1156,11 +1156,11 @@ class ExcludeTest(CoverageTest):
l = list(range(10))
a = l[:3] # no cover
b = 4
-
+
foo()
""",
[1,2,4,6], "", ["no cover"])
-
+
def testExcludingForSuite(self):
self.check_coverage("""\
a = 0
@@ -1188,7 +1188,7 @@ class ExcludeTest(CoverageTest):
assert a == 1
""",
[1,7], "", ['#pragma: NO COVER'])
-
+
def testExcludingForElse(self):
self.check_coverage("""\
a = 0
@@ -1201,7 +1201,7 @@ class ExcludeTest(CoverageTest):
assert a == 1
""",
[1,2,3,4,5,8], "5", ['#pragma: NO COVER'])
-
+
def testExcludingWhile(self):
self.check_coverage("""\
a = 3; b = 0
@@ -1292,7 +1292,7 @@ class ExcludeTest(CoverageTest):
assert a == 99
""",
[1,2,3,4,5,6,9], "", ['#pragma: NO COVER'])
-
+
def testExcludingTryExceptPass(self):
self.check_coverage("""\
a = 0
@@ -1338,7 +1338,7 @@ class ExcludeTest(CoverageTest):
assert a == 99
""",
[1,2,3,4,5,6,9], "", ['#pragma: NO COVER'])
-
+
def testExcludingIfPass(self):
# From a comment on the coverage page by Michael McNeil Forbes:
self.check_coverage("""\
@@ -1347,18 +1347,18 @@ class ExcludeTest(CoverageTest):
pass # This line still reported as missing
if False: # pragma: no cover
x = 1 # Now it is skipped.
-
+
f()
""",
[1,7], "", ["no cover"])
-
+
def testExcludingFunction(self):
self.check_coverage("""\
def fn(foo): #pragma: NO COVER
a = 1
b = 2
c = 3
-
+
x = 1
assert x == 1
""",
@@ -1369,24 +1369,24 @@ class ExcludeTest(CoverageTest):
class Fooey:
def __init__(self):
self.a = 1
-
+
def foo(self): #pragma: NO COVER
return self.a
-
+
x = Fooey()
assert x.a == 1
""",
[1,2,3,8,9], "", ['#pragma: NO COVER'])
-
+
def testExcludingClass(self):
self.check_coverage("""\
class Fooey: #pragma: NO COVER
def __init__(self):
self.a = 1
-
+
def foo(self):
return self.a
-
+
x = 1
assert x == 1
""",
@@ -1396,20 +1396,20 @@ class ExcludeTest(CoverageTest):
if sys.hexversion >= 0x020400f0:
class Py24Test(CoverageTest):
"""Tests of new syntax in Python 2.4."""
-
+
def testFunctionDecorators(self):
self.check_coverage("""\
def require_int(func):
def wrapper(arg):
assert isinstance(arg, int)
return func(arg)
-
+
return wrapper
-
+
@require_int
def p1(arg):
return arg*2
-
+
assert p1(10) == 20
""",
[1,2,3,4,6,8,10,12], "")
@@ -1422,11 +1422,11 @@ if sys.hexversion >= 0x020400f0:
return extra*func(arg)
return wrapper
return decorator
-
+
@boost_by(10)
def boosted(arg):
return arg*2
-
+
assert boosted(10) == 200
""",
[1,2,3,4,5,6,8,10,12], "")
@@ -1445,19 +1445,19 @@ if sys.hexversion >= 0x020400f0:
return extra*func(arg)
return wrapper
return decorator
-
+
@require_int
@boost_by(10)
def boosted1(arg):
return arg*2
-
+
assert boosted1(10) == 200
@boost_by(10)
@require_int
def boosted2(arg):
return arg*2
-
+
assert boosted2(10) == 200
""",
([1,2,3,4,5,7,8,9,10,11,12,14,15,17,19,21,22,24,26],
@@ -1471,19 +1471,19 @@ if sys.hexversion >= 0x020500f0:
def testWithStatement(self):
self.check_coverage("""\
from __future__ import with_statement
-
+
class Managed:
def __enter__(self):
desc = "enter"
-
+
def __exit__(self, type, value, tb):
desc = "exit"
-
+
m = Managed()
with m:
desc = "block1a"
desc = "block1b"
-
+
try:
with m:
desc = "block2"
@@ -1492,7 +1492,7 @@ if sys.hexversion >= 0x020500f0:
desc = "caught"
""",
[1,3,4,5,7,8,10,11,12,13,15,16,17,18,19,20], "")
-
+
def testTryExceptFinally(self):
self.check_coverage("""\
a = 0; b = 0
@@ -1574,7 +1574,7 @@ if sys.hexversion >= 0x020500f0:
assert a == 99 and b == 2
""",
[1,2,3,4,5,6,8,10,11], "8")
-
+
class ModuleTest(CoverageTest):
"""Tests for the module-level behavior of the `coverage` module."""
@@ -1593,7 +1593,7 @@ class ProcessTest(CoverageTest):
h = "Hello"
w = "world"
""")
-
+
self.assert_(not os.path.exists(".coverage"))
self.run_command("coverage -x mycode.py")
self.assert_(os.path.exists(".coverage"))
@@ -1611,7 +1611,7 @@ class ProcessTest(CoverageTest):
out = self.run_command("coverage -x mycode.py")
self.assert_(os.path.exists(".coverage"))
self.assertEqual(out, 'done\n')
-
+
def testCombineParallelData(self):
self.make_file("b_or_c.py", """\
import sys
@@ -1623,7 +1623,7 @@ class ProcessTest(CoverageTest):
d = 1
print ('done')
""")
-
+
out = self.run_command("coverage -x -p b_or_c.py b")
self.assertEqual(out, 'done\n')
self.assert_(not os.path.exists(".coverage"))
@@ -1631,7 +1631,7 @@ class ProcessTest(CoverageTest):
out = self.run_command("coverage -x -p b_or_c.py c")
self.assertEqual(out, 'done\n')
self.assert_(not os.path.exists(".coverage"))
-
+
# After two -p runs, there should be two .coverage.machine.123 files.
self.assertEqual(
len([f for f in os.listdir('.') if f.startswith('.coverage.')]),
diff --git a/test/test_data.py b/test/test_data.py
index 98acc2bb..4f784253 100644
--- a/test/test_data.py
+++ b/test/test_data.py
@@ -29,11 +29,11 @@ class DataTest(CoverageTest):
def assert_summary(self, covdata, summary):
"""Check that the summary of `covdata` is `summary`."""
self.assertEqual(covdata.summary(), summary)
-
+
def assert_executed_files(self, covdata, execed):
"""Check that `covdata`'s executed files are `execed`."""
self.assertSameElements(covdata.executed_files(), execed)
-
+
def test_reading_empty(self):
covdata = CoverageData()
covdata.read()
@@ -44,12 +44,12 @@ class DataTest(CoverageTest):
covdata.add_line_data(DATA_1)
self.assert_summary(covdata, SUMMARY_1)
self.assert_executed_files(covdata, EXECED_FILES_1)
-
+
def test_writing_and_reading(self):
covdata1 = CoverageData()
covdata1.add_line_data(DATA_1)
covdata1.write()
-
+
covdata2 = CoverageData()
covdata2.read()
self.assert_summary(covdata2, SUMMARY_1)
@@ -58,11 +58,11 @@ class DataTest(CoverageTest):
covdata1 = CoverageData(suffix='1')
covdata1.add_line_data(DATA_1)
covdata1.write()
-
+
covdata2 = CoverageData(suffix='2')
covdata2.add_line_data(DATA_2)
covdata2.write()
-
+
covdata3 = CoverageData()
covdata3.combine_parallel_data()
self.assert_summary(covdata3, SUMMARY_1_2)
@@ -74,7 +74,7 @@ class DataTest(CoverageTest):
covdata1.write()
covdata1.erase()
self.assert_summary(covdata1, {})
-
+
covdata2 = CoverageData()
covdata2.read()
self.assert_summary(covdata2, {})
@@ -84,13 +84,13 @@ class DataTest(CoverageTest):
covdata = CoverageData()
covdata.add_line_data(DATA_1)
covdata.write()
-
+
fdata = open(".coverage", 'rb')
try:
data = pickle.load(fdata)
finally:
fdata.close()
-
+
lines = data['lines']
self.assertSameElements(lines.keys(), EXECED_FILES_1)
self.assertSameElements(lines['a.py'], A_PY_LINES_1)
@@ -103,13 +103,13 @@ class DataTest(CoverageTest):
covdata = CoverageData()
covdata.add_arc_data(ARC_DATA_3)
covdata.write()
-
+
fdata = open(".coverage", 'rb')
try:
data = pickle.load(fdata)
finally:
fdata.close()
-
+
self.assertSameElements(data['lines'].keys(), [])
arcs = data['arcs']
self.assertSameElements(arcs['x.py'], X_PY_ARCS_3)
diff --git a/test/test_execfile.py b/test/test_execfile.py
index 5e9f4fd5..8c5e9a11 100644
--- a/test/test_execfile.py
+++ b/test/test_execfile.py
@@ -17,7 +17,7 @@ class RunTest(CoverageTest):
tryfile = os.path.join(here, "try_execfile.py")
run_python_file(tryfile, [tryfile, "arg1", "arg2"])
mod_globs = eval(self.stdout())
-
+
# The file should think it is __main__
self.assertEqual(mod_globs['__name__'], "__main__")
@@ -30,10 +30,10 @@ class RunTest(CoverageTest):
"Test file for run_python_file.")
self.assertEqual(mod_globs['DATA'], "xyzzy")
self.assertEqual(mod_globs['FN_VAL'], "my_fn('fooey')")
-
+
# It must be self-importable as __main__.
self.assertEqual(mod_globs['__main__.DATA'], "xyzzy")
-
+
# Argv should have the proper values.
self.assertEqual(mod_globs['argv'], [tryfile, "arg1", "arg2"])
diff --git a/test/test_farm.py b/test/test_farm.py
index dcebbac5..de07541b 100644
--- a/test/test_farm.py
+++ b/test/test_farm.py
@@ -15,9 +15,9 @@ def test_farm(clean_only=False):
class FarmTestCase(object):
"""A test case from the farm tree.
-
+
Tests are short Python script files, often called run.py:
-
+
copy("src", "out")
run('''
coverage -x white.py
@@ -29,14 +29,14 @@ class FarmTestCase(object):
Verbs (copy, run, compare, clean) are methods in this class. FarmTestCase
has options to allow various uses of the test cases (normal execution,
cleaning-only, or run and leave the results for debugging).
-
+
"""
def __init__(self, runpy, clean_only=False, dont_clean=False):
"""Create a test case from a run.py file.
-
+
`clean_only` means that only the clean() action is executed.
`dont_clean` means that the clean() action is not executed.
-
+
"""
self.description = runpy
self.dir, self.runpy = os.path.split(runpy)
@@ -54,14 +54,14 @@ class FarmTestCase(object):
oldpath = sys.path[:]
sys.path.insert(0, directory)
return oldpath
-
+
def restorepath(self, path):
"""Restore the system path to `path`."""
sys.path = path
def __call__(self):
"""Execute the test from the run.py file.
-
+
"""
cwd = self.cd(self.dir)
@@ -74,7 +74,7 @@ class FarmTestCase(object):
glo = dict([(fn, getattr(self, fn)) for fn in fns])
if self.dont_clean:
glo['clean'] = self.noop
-
+
try:
execfile(self.runpy, glo)
finally:
@@ -90,11 +90,11 @@ class FarmTestCase(object):
def fnmatch_list(self, files, file_pattern):
"""Filter the list of `files` to only those that match `file_pattern`.
-
+
If `file_pattern` is None, then return the entire list of files.
-
+
Returns a list of the filtered files.
-
+
"""
if file_pattern:
files = [f for f in files if fnmatch.fnmatch(f, file_pattern)]
@@ -106,7 +106,7 @@ class FarmTestCase(object):
# Modules should be importable from the current directory.
self.old_syspath = sys.path[:]
sys.path.insert(0, '')
-
+
def tearDown(self):
"""Test tear down, run by nose after __call__."""
# Make sure no matter what, the test is cleaned up.
@@ -118,11 +118,11 @@ class FarmTestCase(object):
sys.path = self.old_syspath
# Functions usable inside farm run.py files
-
+
def noop(self, *args, **kwargs):
"""A no-op function to stub out run, copy, etc, when only cleaning."""
pass
-
+
def copy(self, src, dst):
"""Copy a directory."""
@@ -132,11 +132,11 @@ class FarmTestCase(object):
def run(self, cmds, rundir="src", outfile=None):
"""Run a list of commands.
-
+
`cmds` is a string, commands separated by newlines.
`rundir` is the directory in which to run the commands.
`outfile` is a filename to redirect stdout to.
-
+
"""
cwd = self.cd(rundir)
try:
@@ -155,12 +155,12 @@ class FarmTestCase(object):
def runfunc(self, fn, rundir="src", addtopath=None):
"""Run a function.
-
+
`fn` is a callable.
`rundir` is the directory in which to run the function.
-
+
"""
-
+
cwd = self.cd(rundir)
oldpath = self.addtopath(addtopath)
try:
@@ -173,28 +173,28 @@ class FarmTestCase(object):
left_extra=False, right_extra=False, scrubs=None
):
"""Compare files matching `file_pattern` in `dir1` and `dir2`.
-
+
`dir2` is interpreted as a prefix, with Python version numbers appended
to find the actual directory to compare with. "foo" will compare against
"foo_v241", "foo_v24", "foo_v2", or "foo", depending on which directory
is found first.
-
+
`size_within` is a percentage delta for the file sizes. If non-zero,
then the file contents are not compared (since they are expected to
often be different), but the file sizes must be within this amount.
For example, size_within=10 means that the two files' sizes must be
within 10 percent of each other to compare equal.
-
+
`left_extra` true means the left directory can have extra files in it
without triggering an assertion. `right_extra` means the right
directory can.
-
+
`scrubs` is a list of pairs, regex find and replace patterns to use to
scrub the files of unimportant differences.
-
+
An assertion will be raised if the directories fail one of their
matches.
-
+
"""
# Search for a dir2 with a version suffix.
version_suff = ''.join(map(str, sys.version_info[:3]))
@@ -207,12 +207,12 @@ class FarmTestCase(object):
assert os.path.exists(dir1), "Left directory missing: %s" % dir1
assert os.path.exists(dir2), "Right directory missing: %s" % dir2
-
+
dc = filecmp.dircmp(dir1, dir2)
diff_files = self.fnmatch_list(dc.diff_files, file_pattern)
left_only = self.fnmatch_list(dc.left_only, file_pattern)
right_only = self.fnmatch_list(dc.right_only, file_pattern)
-
+
if size_within:
# The files were already compared, use the diff_files list as a
# guide for size comparison.
@@ -253,10 +253,10 @@ class FarmTestCase(object):
def _scrub(self, strlist, scrubs):
"""Scrub uninteresting data from the strings in `strlist`.
-
+
`scrubs is a list of (find, replace) pairs of regexes that are used on
each string in `strlist`. A list of scrubbed strings is returned.
-
+
"""
scrubbed = []
for s in strlist:
@@ -267,10 +267,10 @@ class FarmTestCase(object):
def contains(self, filename, *strlist):
"""Check that the file contains all of a list of strings.
-
+
An assert will be raised if one of the arguments in `strlist` is
missing in `filename`.
-
+
"""
text = open(filename, "r").read()
for s in strlist:
@@ -278,10 +278,10 @@ class FarmTestCase(object):
def doesnt_contain(self, filename, *strlist):
"""Check that the file contains none of a list of strings.
-
+
An assert will be raised if any of the strings in strlist appears in
`filename`.
-
+
"""
text = open(filename, "r").read()
for s in strlist:
@@ -294,13 +294,13 @@ class FarmTestCase(object):
def main(): # pragma: no cover
"""Command-line access to test_farm.
-
+
Commands:
-
+
run testcase - Run a single test case.
out testcase - Run a test case, but don't clean up, to see the output.
clean - Clean all the output for all tests.
-
+
"""
op = sys.argv[1]
if op == 'run':
@@ -317,7 +317,7 @@ def main(): # pragma: no cover
test[0].run_fully()
else:
print("Need an operation: run, out, clean")
-
+
# So that we can run just one farm run.py at a time.
if __name__ == '__main__':
main()
diff --git a/test/test_oddball.py b/test/test_oddball.py
index 6c97272d..05252ef8 100644
--- a/test/test_oddball.py
+++ b/test/test_oddball.py
@@ -16,13 +16,13 @@ class ThreadingTest(CoverageTest):
def fromMainThread():
return "called from main thread"
-
+
def fromOtherThread():
return "called from other thread"
-
+
def neverCalled():
return "no one calls me"
-
+
other = threading.Thread(target=fromOtherThread)
other.start()
fromMainThread()
@@ -42,11 +42,11 @@ class RecursionTest(CoverageTest):
return 0
else:
return recur(n-1)+1
-
+
recur(495) # We can get at least this many stack frames.
""",
[1,2,3,5,7], "")
-
+
def testLongRecursion(self):
# We can't finish a very deep recursion, but we don't crash.
self.assertRaises(RuntimeError, self.check_coverage,
@@ -56,7 +56,7 @@ class RecursionTest(CoverageTest):
return 0
else:
return recur(n-1)+1
-
+
recur(100000) # This is definitely too many frames.
""",
[1,2,3,5,7], "")
@@ -135,7 +135,7 @@ class PyexpatTest(CoverageTest):
_, statements, missing, _ = cov.analysis("trydom.py")
self.assertEqual(statements, [1,3,8,9,10,11,13])
self.assertEqual(missing, [])
-
+
_, statements, missing, _ = cov.analysis("outer.py")
self.assertEqual(statements, [101,102])
self.assertEqual(missing, [])
@@ -145,7 +145,7 @@ class ExceptionTest(CoverageTest):
"""I suspect different versions of Python deal with exceptions differently
in the trace function.
"""
-
+
def testException(self):
# Python 2.3's trace function doesn't get called with "return" if the
# scope is exiting due to an exception. This confounds our trace
@@ -156,21 +156,21 @@ class ExceptionTest(CoverageTest):
# stack is in a different file, to try to trip up the tracer. Each
# file has active lines in a different range so we'll see if the lines
# get attributed to the wrong file.
-
+
self.make_file("oops.py", """\
def oops(args):
a = 2
raise Exception("oops")
a = 4
""")
-
+
self.make_file("fly.py", "\n"*100 + """\
def fly(calls):
a = 2
calls[0](calls[1:])
a = 4
""")
-
+
self.make_file("catch.py", "\n"*200 + """\
def catch(calls):
try:
@@ -180,7 +180,7 @@ class ExceptionTest(CoverageTest):
except:
a = 7
""")
-
+
self.make_file("doit.py", "\n"*300 + """\
def doit(calls):
try:
@@ -220,19 +220,19 @@ class ExceptionTest(CoverageTest):
'oops.py': [2,3],
}),
]
-
+
for callnames, lines_expected in runs:
-
+
# Make the list of functions we'll call for this test.
calls = [getattr(sys.modules[cn], cn) for cn in callnames.split()]
-
+
cov = coverage.coverage()
cov.start()
# Call our list of functions: invoke the first, with the rest as
# an argument.
calls[0](calls[1:])
cov.stop()
-
+
# Clean the line data and compare to expected results.
# The filenames are absolute, so keep just the base.
lines = cov.data.line_data()
@@ -248,10 +248,10 @@ class ExceptionTest(CoverageTest):
if sys.hexversion > 0x02050000:
class DoctestTest(CoverageTest):
"""Tests invoked with doctest should measure properly."""
-
+
def setUp(self):
super(DoctestTest, self).setUp()
-
+
# Oh, the irony! This test case exists because Python 2.4's
# doctest module doesn't play well with coverage. But nose fixes
# the problem by monkeypatching doctest. I want to undo the
@@ -260,12 +260,12 @@ if sys.hexversion > 0x02050000:
# enough: when the test imports doctest again, it will get a fresh
# copy without the monkeypatch.
del sys.modules['doctest']
-
+
def testDoctest(self):
self.check_coverage('''\
def return_arg_or_void(arg):
"""If <arg> is None, return "Void"; otherwise return <arg>
-
+
>>> return_arg_or_void(None)
'Void'
>>> return_arg_or_void("arg")
@@ -277,7 +277,7 @@ if sys.hexversion > 0x02050000:
return "Void"
else:
return arg
-
+
import doctest, sys
doctest.testmod(sys.modules[__name__]) # we're not __main__ :(
''',
diff --git a/test/test_parser.py b/test/test_parser.py
index 0dc7089c..b398044d 100644
--- a/test/test_parser.py
+++ b/test/test_parser.py
@@ -19,7 +19,7 @@ class ParserTest(CoverageTest):
cp = CodeParser(text, exclude="nocover")
cp.parse_source()
return cp
-
+
def test_exit_counts(self):
cp = self.parse_source("""\
# check some basic branch counting
@@ -29,7 +29,7 @@ class ParserTest(CoverageTest):
return 5
else:
return 7
-
+
class Bar:
pass
""")
@@ -52,13 +52,13 @@ class ParserTest(CoverageTest):
self.assertEqual(cp.exit_counts(), {
1: 1, 2:1, 3:1, 4:1, 5:1, 6:1, 7:1, 8:1, 9:1
})
-
+
def test_excluded_classes(self):
cp = self.parse_source("""\
class Foo:
def __init__(self):
pass
-
+
if 0: # nocover
class Bar:
pass
@@ -66,7 +66,7 @@ class ParserTest(CoverageTest):
self.assertEqual(cp.exit_counts(), {
1:0, 2:1, 3:1
})
-
+
def test_missing_branch_to_excluded_code(self):
cp = self.parse_source("""\
if fooey:
diff --git a/test/test_phystokens.py b/test/test_phystokens.py
index a01cc374..6b16d68e 100644
--- a/test/test_phystokens.py
+++ b/test/test_phystokens.py
@@ -77,5 +77,3 @@ class PhysTokensTest(CoverageTest):
# Check the tokenization of a stress-test file.
stress = os.path.join(HERE, "stress_phystoken.txt")
self.check_file_tokenization(stress)
-
- \ No newline at end of file
diff --git a/test/test_results.py b/test/test_results.py
index 33ebe4d7..ef15121c 100644
--- a/test/test_results.py
+++ b/test/test_results.py
@@ -10,7 +10,7 @@ from coveragetest import CoverageTest
class NumbersTest(CoverageTest):
"""Tests for Coverage.py's numeric measurement summaries."""
-
+
run_in_temp_dir = False
def test_basic(self):
@@ -19,7 +19,7 @@ class NumbersTest(CoverageTest):
self.assertEqual(n1.n_executed, 180)
self.assertEqual(n1.n_missing, 20)
self.assertEqual(n1.pc_covered, 90)
-
+
def test_addition(self):
n1 = Numbers(n_files=1, n_statements=200, n_missing=20)
n2 = Numbers(n_files=1, n_statements=10, n_missing=8)
diff --git a/test/test_summary.py b/test/test_summary.py
index 36db9969..0eec58ca 100644
--- a/test/test_summary.py
+++ b/test/test_summary.py
@@ -22,7 +22,7 @@ class SummaryTest(CoverageTest):
report = self.run_command(cmd).replace('\\', '/')
self.assert_("error" not in report.lower())
return report
-
+
def line_count(self, report):
"""How many lines are in `report`?"""
self.assertEqual(report.split('\n')[-1], "")
@@ -73,7 +73,7 @@ class SummaryTest(CoverageTest):
prefix = os.path.split(__file__)[0]
self.run_command("coverage -x mycode.py")
report = self.report_from_command("coverage -r -o %s" % prefix)
-
+
# Name Stmts Exec Cover
# ----------------------------
# mycode 4 4 100%
diff --git a/test/test_templite.py b/test/test_templite.py
index 35c1df55..57385cba 100644
--- a/test/test_templite.py
+++ b/test/test_templite.py
@@ -9,9 +9,9 @@ import unittest
class AnyOldObject(object):
"""Simple testing object.
-
+
Use keyword arguments in the constructor to set attributes on the object.
-
+
"""
def __init__(self, **attrs):
for n, v in attrs.items():
@@ -45,7 +45,7 @@ class TempliteTest(unittest.TestCase):
'second': lambda x: x[1],
}
self.try_render("Hello, {{name|upper}}!", data, "Hello, NED!")
-
+
# Pipes can be concatenated.
self.try_render("Hello, {{name|upper|second}}!", data, "Hello, E!")
@@ -55,7 +55,7 @@ class TempliteTest(unittest.TestCase):
'upper': lambda x: x.upper(),
'punct': '!',
}
-
+
template = Templite("This is {{name|upper}}{{punct}}", globs)
self.assertEqual(template.render({'name':'Ned'}), "This is NED!")
self.assertEqual(template.render({'name':'Ben'}), "This is BEN!")
@@ -67,7 +67,7 @@ class TempliteTest(unittest.TestCase):
obj2 = AnyOldObject(obj=obj, b="Bee")
self.try_render("{{obj2.obj.a}} {{obj2.b}}", locals(), "Ay Bee")
-
+
def test_member_function(self):
# Variables' member functions can be used, as long as they are nullary.
class WithMemberFns(AnyOldObject):
@@ -97,7 +97,7 @@ class TempliteTest(unittest.TestCase):
l = l[:]
l.reverse()
return l
-
+
self.try_render(
"Look: {% for n in nums|rev %}{{n}}, {% endfor %}done.",
locals(),
@@ -117,7 +117,7 @@ class TempliteTest(unittest.TestCase):
{'nums':[1,2,3]},
"Look: \n\n1, \n\n2, \n\n3, \ndone."
)
-
+
def test_multiple_loops(self):
self.try_render(
"{% for n in nums %}{{n}}{% endfor %} and "