summaryrefslogtreecommitdiff
path: root/coverage/cmdline.py
diff options
context:
space:
mode:
Diffstat (limited to 'coverage/cmdline.py')
-rw-r--r--coverage/cmdline.py101
1 files changed, 62 insertions, 39 deletions
diff --git a/coverage/cmdline.py b/coverage/cmdline.py
index 2be32947..fc40e619 100644
--- a/coverage/cmdline.py
+++ b/coverage/cmdline.py
@@ -1,4 +1,7 @@
-"""Command-line support for Coverage."""
+# Licensed under the Apache License: http://www.apache.org/licenses/LICENSE-2.0
+# For details: https://bitbucket.org/ned/coveragepy/src/default/NOTICE.txt
+
+"""Command-line support for coverage.py."""
import glob
import optparse
@@ -16,7 +19,7 @@ class Opts(object):
"""A namespace class for individual options we'll build parsers from."""
append = optparse.make_option(
- '-a', '--append', action='store_false', dest="erase_first",
+ '-a', '--append', action='store_true',
help="Append coverage data to .coverage, otherwise it is started "
"clean with each run."
)
@@ -56,7 +59,7 @@ class Opts(object):
include = optparse.make_option(
'', '--include', action='store',
metavar="PAT1,PAT2,...",
- help="Include only files whose paths match one of these patterns."
+ help="Include only files whose paths match one of these patterns. "
"Accepts shell-style wildcards, which must be quoted."
)
pylib = optparse.make_option(
@@ -119,7 +122,7 @@ class Opts(object):
class CoverageOptionParser(optparse.OptionParser, object):
- """Base OptionParser for coverage.
+ """Base OptionParser for coverage.py.
Problems don't exit the program.
Defaults are initialized for all options.
@@ -132,6 +135,7 @@ class CoverageOptionParser(optparse.OptionParser, object):
)
self.set_defaults(
action=None,
+ append=None,
branch=None,
concurrency=None,
debug=None,
@@ -140,9 +144,9 @@ class CoverageOptionParser(optparse.OptionParser, object):
help=None,
ignore_errors=None,
include=None,
+ module=None,
omit=None,
parallel_mode=None,
- module=None,
pylib=None,
rcfile=True,
show_missing=None,
@@ -150,7 +154,6 @@ class CoverageOptionParser(optparse.OptionParser, object):
source=None,
timid=None,
title=None,
- erase_first=None,
version=None,
)
@@ -202,7 +205,7 @@ class CmdOptionParser(CoverageOptionParser):
def __init__(self, action, options=None, defaults=None, usage=None,
description=None
):
- """Create an OptionParser for a coverage command.
+ """Create an OptionParser for a coverage.py command.
`action` is the slug to put into `options.action`.
`options` is a list of Option's for the command.
@@ -239,8 +242,8 @@ CMDS = {
[
Opts.directory,
Opts.ignore_errors,
- Opts.omit,
Opts.include,
+ Opts.omit,
] + GLOBAL_ARGS,
usage = "[options] [modules]",
description = "Make annotated copies of the given files, marking "
@@ -249,10 +252,13 @@ CMDS = {
),
'combine': CmdOptionParser("combine", GLOBAL_ARGS,
- usage = " ",
+ usage = "<path1> <path2> ... <pathN>",
description = "Combine data from multiple coverage files collected "
"with 'run -p'. The combined results are written to a single "
- "file representing the union of the data."
+ "file representing the union of the data. The positional "
+ "arguments are data files or directories containing data files. "
+ "If no paths are provided, data files in the default data file's "
+ "directory are combined."
),
'debug': CmdOptionParser("debug", GLOBAL_ARGS,
@@ -278,8 +284,8 @@ CMDS = {
Opts.directory,
Opts.fail_under,
Opts.ignore_errors,
- Opts.omit,
Opts.include,
+ Opts.omit,
Opts.title,
] + GLOBAL_ARGS,
usage = "[options] [modules]",
@@ -292,10 +298,10 @@ CMDS = {
[
Opts.fail_under,
Opts.ignore_errors,
- Opts.omit,
Opts.include,
+ Opts.omit,
Opts.show_missing,
- Opts.skip_covered
+ Opts.skip_covered,
] + GLOBAL_ARGS,
usage = "[options] [modules]",
description = "Report coverage statistics on modules."
@@ -306,15 +312,14 @@ CMDS = {
Opts.append,
Opts.branch,
Opts.concurrency,
+ Opts.include,
+ Opts.module,
+ Opts.omit,
Opts.pylib,
Opts.parallel_mode,
- Opts.module,
- Opts.timid,
Opts.source,
- Opts.omit,
- Opts.include,
+ Opts.timid,
] + GLOBAL_ARGS,
- defaults = {'erase_first': True},
usage = "[options] <pyfile> [program options]",
description = "Run a Python program, measuring code execution."
),
@@ -323,8 +328,8 @@ CMDS = {
[
Opts.fail_under,
Opts.ignore_errors,
- Opts.omit,
Opts.include,
+ Opts.omit,
Opts.output_xml,
] + GLOBAL_ARGS,
usage = "[options] [modules]",
@@ -337,7 +342,7 @@ OK, ERR, FAIL_UNDER = 0, 1, 2
class CoverageScript(object):
- """The command-line interface to Coverage."""
+ """The command-line interface to coverage.py."""
def __init__(self, _covpkg=None, _run_python_file=None,
_run_python_module=None, _help_fn=None):
@@ -357,7 +362,7 @@ class CoverageScript(object):
self.coverage = None
def command_line(self, argv):
- """The bulk of the command line interface to Coverage.
+ """The bulk of the command line interface to coverage.py.
`argv` is the argument list to process.
@@ -421,17 +426,19 @@ class CoverageScript(object):
if options.action == "debug":
return self.do_debug(args)
- if options.action == "erase" or options.erase_first:
+ elif options.action == "erase":
self.coverage.erase()
- else:
- self.coverage.load()
+ return OK
- if options.action == "run":
- self.do_run(options, args)
+ elif options.action == "run":
+ return self.do_run(options, args)
- if options.action == "combine":
- self.coverage.combine()
+ elif options.action == "combine":
+ self.coverage.load()
+ data_dirs = args or None
+ self.coverage.combine(data_dirs)
self.coverage.save()
+ return OK
# Remaining actions are reporting, with some common options.
report_args = dict(
@@ -441,19 +448,21 @@ class CoverageScript(object):
include = include,
)
+ self.coverage.load()
+
total = None
if options.action == "report":
total = self.coverage.report(
show_missing=options.show_missing,
skip_covered=options.skip_covered, **report_args)
- if options.action == "annotate":
+ elif options.action == "annotate":
self.coverage.annotate(
directory=options.directory, **report_args)
- if options.action == "html":
+ elif options.action == "html":
total = self.coverage.html_report(
directory=options.directory, title=options.title,
**report_args)
- if options.action == "xml":
+ elif options.action == "xml":
outfile = options.outfile
total = self.coverage.xml_report(outfile=outfile, **report_args)
@@ -538,11 +547,19 @@ class CoverageScript(object):
self.help_fn("Nothing to do.")
return False
+ if options.append and options.parallel_mode:
+ self.help_fn("Can't append to data files in parallel mode.")
+ return False
+
return True
def do_run(self, options, args):
"""Implementation of 'coverage run'."""
+ if not self.coverage.config.parallel:
+ if not options.append:
+ self.coverage.erase()
+
# Set the first path element properly.
old_path0 = sys.path[0]
@@ -563,17 +580,22 @@ class CoverageScript(object):
finally:
self.coverage.stop()
if code_ran:
+ if options.append:
+ self.coverage.combine(data_paths=[self.coverage.config.data_file])
self.coverage.save()
# Restore the old path
sys.path[0] = old_path0
+ return OK
+
def do_debug(self, args):
"""Implementation of 'coverage debug'."""
if not args:
self.help_fn("What information would you like: data, sys?")
return ERR
+
for info in args:
if info == 'sys':
sys_info = self.coverage.sys_info()
@@ -582,17 +604,17 @@ class CoverageScript(object):
print(" %s" % line)
elif info == 'data':
self.coverage.load()
+ data = self.coverage.data
print(info_header("data"))
- print("path: %s" % self.coverage.data.filename)
- print("has_arcs: %r" % self.coverage.data.has_arcs())
- summary = self.coverage.data.summary(fullpath=True)
- if summary:
- plugins = self.coverage.data.plugin_data()
+ print("path: %s" % self.coverage.data_files.filename)
+ if data:
+ print("has_arcs: %r" % data.has_arcs())
+ summary = data.line_counts(fullpath=True)
filenames = sorted(summary.keys())
print("\n%d files:" % len(filenames))
for f in filenames:
line = "%s: %d lines" % (f, summary[f])
- plugin = plugins.get(f)
+ plugin = data.file_tracer(f)
if plugin:
line += " [%s]" % plugin
print(line)
@@ -601,6 +623,7 @@ class CoverageScript(object):
else:
self.help_fn("Don't know what you mean by %r" % info)
return ERR
+
return OK
@@ -609,7 +632,7 @@ def unshell_list(s):
if not s:
return None
if env.WINDOWS:
- # When running coverage as coverage.exe, some of the behavior
+ # When running coverage.py as coverage.exe, some of the behavior
# of the shell is emulated: wildcards are expanded into a list of
# filenames. So you have to single-quote patterns on the command
# line, but (not) helpfully, the single quotes are included in the
@@ -665,7 +688,7 @@ Documentation at %(__url__)s
def main(argv=None):
- """The main entry point to Coverage.
+ """The main entry point to coverage.py.
This is installed as the script entry point.