diff options
Diffstat (limited to 'coverage/cmdline.py')
-rw-r--r-- | coverage/cmdline.py | 101 |
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. |