eric7/DebugClients/Python/coverage/cmdline.py

branch
eric7
changeset 8991
2fc945191992
parent 8929
fcca2fa618bf
child 9099
0e511e0e94a3
diff -r ca8e477c590c -r 2fc945191992 eric7/DebugClients/Python/coverage/cmdline.py
--- a/eric7/DebugClients/Python/coverage/cmdline.py	Sun Mar 20 17:26:35 2022 +0100
+++ b/eric7/DebugClients/Python/coverage/cmdline.py	Sun Mar 20 17:49:44 2022 +0100
@@ -3,7 +3,6 @@
 
 """Command-line support for coverage.py."""
 
-
 import glob
 import optparse     # pylint: disable=deprecated-module
 import os
@@ -18,16 +17,22 @@
 from coverage import env
 from coverage.collector import CTracer
 from coverage.config import CoverageConfig
+from coverage.control import DEFAULT_DATAFILE
 from coverage.data import combinable_files, debug_data_file
-from coverage.debug import info_formatter, info_header, short_stack
+from coverage.debug import info_header, short_stack, write_formatted_info
 from coverage.exceptions import _BaseCoverageException, _ExceptionDuringRun, NoSource
 from coverage.execfile import PyRunner
 from coverage.results import Numbers, should_fail_under
 
+# When adding to this file, alphabetization is important.  Look for
+# "alphabetize" comments throughout.
 
 class Opts:
     """A namespace class for individual options we'll build parsers from."""
 
+    # Keep these entries alphabetized (roughly) by the option name as it
+    # appears on the command line.
+
     append = optparse.make_option(
         '-a', '--append', action='store_true',
         help="Append coverage data to .coverage, otherwise it starts clean each time.",
@@ -52,13 +57,33 @@
         help="The context label to record for this coverage run.",
     )
     contexts = optparse.make_option(
-        '', '--contexts', action='store',
-        metavar="REGEX1,REGEX2,...",
+        '', '--contexts', action='store', metavar="REGEX1,REGEX2,...",
         help=(
             "Only display data from lines covered in the given contexts. " +
             "Accepts Python regexes, which must be quoted."
         ),
     )
+    combine_datafile = optparse.make_option(
+        '', '--data-file', action='store', metavar="DATAFILE",
+        help=(
+            "Base name of the data files to operate on. " +
+            "Defaults to '.coverage'. [env: COVERAGE_FILE]"
+        ),
+    )
+    input_datafile = optparse.make_option(
+        '', '--data-file', action='store', metavar="INFILE",
+        help=(
+            "Read coverage data for report generation from this file. " +
+            "Defaults to '.coverage'. [env: COVERAGE_FILE]"
+        ),
+    )
+    output_datafile = optparse.make_option(
+        '', '--data-file', action='store', metavar="OUTFILE",
+        help=(
+            "Write the recorded coverage data to this file. " +
+            "Defaults to '.coverage'. [env: COVERAGE_FILE]"
+        ),
+    )
     debug = optparse.make_option(
         '', '--debug', action='store', metavar="OPTS",
         help="Debug options, separated by commas. [env: COVERAGE_DEBUG]",
@@ -80,8 +105,7 @@
         help="Ignore errors while reading source files.",
     )
     include = optparse.make_option(
-        '', '--include', action='store',
-        metavar="PAT1,PAT2,...",
+        '', '--include', action='store', metavar="PAT1,PAT2,...",
         help=(
             "Include only files whose paths match one of these patterns. " +
             "Accepts shell-style wildcards, which must be quoted."
@@ -106,23 +130,24 @@
         ),
     )
     omit = optparse.make_option(
-        '', '--omit', action='store',
-        metavar="PAT1,PAT2,...",
+        '', '--omit', action='store', metavar="PAT1,PAT2,...",
         help=(
             "Omit files whose paths match one of these patterns. " +
             "Accepts shell-style wildcards, which must be quoted."
         ),
     )
     output_xml = optparse.make_option(
-        '-o', '', action='store', dest="outfile",
-        metavar="OUTFILE",
+        '-o', '', action='store', dest="outfile", metavar="OUTFILE",
         help="Write the XML report to this file. Defaults to 'coverage.xml'",
     )
     output_json = optparse.make_option(
-        '-o', '', action='store', dest="outfile",
-        metavar="OUTFILE",
+        '-o', '', action='store', dest="outfile", metavar="OUTFILE",
         help="Write the JSON report to this file. Defaults to 'coverage.json'",
     )
+    output_lcov = optparse.make_option(
+        '-o', '', action='store', dest='outfile', metavar="OUTFILE",
+        help="Write the LCOV report to this file. Defaults to 'coverage.lcov'",
+    )
     json_pretty_print = optparse.make_option(
         '', '--pretty-print', action='store_true',
         help="Format the JSON for human readers.",
@@ -131,7 +156,7 @@
         '-p', '--parallel-mode', action='store_true',
         help=(
             "Append the machine name, process id and random number to the " +
-            ".coverage data file name to simplify collecting data from " +
+            "data file name to simplify collecting data from " +
             "many processes."
         ),
     )
@@ -172,8 +197,10 @@
     )
     sort = optparse.make_option(
         '--sort', action='store', metavar='COLUMN',
-        help="Sort the report by the named column: name, stmts, miss, branch, brpart, or cover. " +
+        help=(
+            "Sort the report by the named column: name, stmts, miss, branch, brpart, or cover. " +
              "Default is name."
+        ),
     )
     source = optparse.make_option(
         '', '--source', action='store', metavar="SRC1,SRC2,...",
@@ -209,12 +236,14 @@
             add_help_option=False, *args, **kwargs
             )
         self.set_defaults(
+            # Keep these arguments alphabetized by their names.
             action=None,
             append=None,
             branch=None,
             concurrency=None,
             context=None,
             contexts=None,
+            data_file=None,
             debug=None,
             directory=None,
             fail_under=None,
@@ -313,6 +342,11 @@
         # Include the sub-command for this parser as part of the command.
         return f"{program_name} {self.cmd}"
 
+# In lists of Opts, keep them alphabetized by the option names as they appear
+# on the command line, since these lists determine the order of the options in
+# the help output.
+#
+# In COMMANDS, keep the keys (command names) alphabetized.
 
 GLOBAL_ARGS = [
     Opts.debug,
@@ -320,11 +354,12 @@
     Opts.rcfile,
     ]
 
-CMDS = {
+COMMANDS = {
     'annotate': CmdOptionParser(
         "annotate",
         [
             Opts.directory,
+            Opts.input_datafile,
             Opts.ignore_errors,
             Opts.include,
             Opts.omit,
@@ -340,6 +375,7 @@
         "combine",
         [
             Opts.append,
+            Opts.combine_datafile,
             Opts.keep,
             Opts.quiet,
             ] + GLOBAL_ARGS,
@@ -364,12 +400,16 @@
                 "'data' to show a summary of the collected data; " +
                 "'sys' to show installation information; " +
                 "'config' to show the configuration; " +
-                "'premain' to show what is calling coverage."
+                "'premain' to show what is calling coverage; " +
+                "'pybehave' to show internal flags describing Python behavior."
         ),
     ),
 
     'erase': CmdOptionParser(
-        "erase", GLOBAL_ARGS,
+        "erase",
+        [
+            Opts.combine_datafile
+            ] + GLOBAL_ARGS,
         description="Erase previously collected coverage data.",
     ),
 
@@ -384,6 +424,7 @@
         [
             Opts.contexts,
             Opts.directory,
+            Opts.input_datafile,
             Opts.fail_under,
             Opts.ignore_errors,
             Opts.include,
@@ -408,6 +449,7 @@
         "json",
         [
             Opts.contexts,
+            Opts.input_datafile,
             Opts.fail_under,
             Opts.ignore_errors,
             Opts.include,
@@ -418,13 +460,29 @@
             Opts.show_contexts,
             ] + GLOBAL_ARGS,
         usage="[options] [modules]",
-        description="Generate a JSON report of coverage results."
+        description="Generate a JSON report of coverage results.",
+    ),
+
+    'lcov': CmdOptionParser(
+        "lcov",
+        [
+            Opts.input_datafile,
+            Opts.fail_under,
+            Opts.ignore_errors,
+            Opts.include,
+            Opts.output_lcov,
+            Opts.omit,
+            Opts.quiet,
+        ] + GLOBAL_ARGS,
+        usage="[options] [modules]",
+        description="Generate an LCOV report of coverage results.",
     ),
 
     'report': CmdOptionParser(
         "report",
         [
             Opts.contexts,
+            Opts.input_datafile,
             Opts.fail_under,
             Opts.ignore_errors,
             Opts.include,
@@ -437,7 +495,7 @@
             Opts.skip_empty,
             ] + GLOBAL_ARGS,
         usage="[options] [modules]",
-        description="Report coverage statistics on modules."
+        description="Report coverage statistics on modules.",
     ),
 
     'run': CmdOptionParser(
@@ -447,6 +505,7 @@
             Opts.branch,
             Opts.concurrency,
             Opts.context,
+            Opts.output_datafile,
             Opts.include,
             Opts.module,
             Opts.omit,
@@ -456,12 +515,13 @@
             Opts.timid,
             ] + GLOBAL_ARGS,
         usage="[options] <pyfile> [program options]",
-        description="Run a Python program, measuring code execution."
+        description="Run a Python program, measuring code execution.",
     ),
 
     'xml': CmdOptionParser(
         "xml",
         [
+            Opts.input_datafile,
             Opts.fail_under,
             Opts.ignore_errors,
             Opts.include,
@@ -471,7 +531,7 @@
             Opts.skip_empty,
             ] + GLOBAL_ARGS,
         usage="[options] [modules]",
-        description="Generate an XML report of coverage results."
+        description="Generate an XML report of coverage results.",
     ),
 }
 
@@ -546,7 +606,7 @@
         if self.global_option:
             parser = GlobalOptionParser()
         else:
-            parser = CMDS.get(argv[0])
+            parser = COMMANDS.get(argv[0])
             if not parser:
                 show_help(f"Unknown command: {argv[0]!r}")
                 return ERR
@@ -574,6 +634,7 @@
 
         # Do something.
         self.coverage = Coverage(
+            data_file=options.data_file or DEFAULT_DATAFILE,
             data_suffix=options.parallel_mode,
             cover_pylib=options.pylib,
             timid=options.timid,
@@ -625,10 +686,10 @@
         total = None
         if options.action == "report":
             total = self.coverage.report(
+                precision=options.precision,
                 show_missing=options.show_missing,
                 skip_covered=options.skip_covered,
                 skip_empty=options.skip_empty,
-                precision=options.precision,
                 sort=options.sort,
                 **report_args
                 )
@@ -637,27 +698,31 @@
         elif options.action == "html":
             total = self.coverage.html_report(
                 directory=options.directory,
-                title=options.title,
+                precision=options.precision,
                 skip_covered=options.skip_covered,
                 skip_empty=options.skip_empty,
                 show_contexts=options.show_contexts,
-                precision=options.precision,
+                title=options.title,
                 **report_args
                 )
         elif options.action == "xml":
-            outfile = options.outfile
             total = self.coverage.xml_report(
-                outfile=outfile, skip_empty=options.skip_empty,
+                outfile=options.outfile,
+                skip_empty=options.skip_empty,
                 **report_args
                 )
         elif options.action == "json":
-            outfile = options.outfile
             total = self.coverage.json_report(
-                outfile=outfile,
+                outfile=options.outfile,
                 pretty_print=options.pretty_print,
                 show_contexts=options.show_contexts,
                 **report_args
-            )
+                )
+        elif options.action == "lcov":
+            total = self.coverage.lcov_report(
+                outfile=options.outfile,
+                **report_args
+                )
         else:
             # There are no other possible actions.
             raise AssertionError
@@ -667,6 +732,8 @@
             # value, so we can get fail_under from the config file.
             if options.fail_under is not None:
                 self.coverage.set_option("report:fail_under", options.fail_under)
+            if options.precision is not None:
+                self.coverage.set_option("report:precision", options.precision)
 
             fail_under = self.coverage.get_option("report:fail_under")
             precision = self.coverage.get_option("report:precision")
@@ -698,7 +765,7 @@
         if options.action == "help":
             if args:
                 for a in args:
-                    parser = CMDS.get(a)
+                    parser = COMMANDS.get(a)
                     if parser:
                         show_help(parser=parser)
                     else:
@@ -777,32 +844,28 @@
         """Implementation of 'coverage debug'."""
 
         if not args:
-            show_help("What information would you like: config, data, sys, premain?")
+            show_help("What information would you like: config, data, sys, premain, pybehave?")
             return ERR
         if args[1:]:
             show_help("Only one topic at a time, please")
             return ERR
 
-        if args[0] == 'sys':
-            sys_info = self.coverage.sys_info()
-            print(info_header("sys"))
-            for line in info_formatter(sys_info):
-                print(f" {line}")
-        elif args[0] == 'data':
+        if args[0] == "sys":
+            write_formatted_info(print, "sys", self.coverage.sys_info())
+        elif args[0] == "data":
             print(info_header("data"))
             data_file = self.coverage.config.data_file
             debug_data_file(data_file)
             for filename in combinable_files(data_file):
                 print("-----")
                 debug_data_file(filename)
-        elif args[0] == 'config':
-            print(info_header("config"))
-            config_info = sorted(self.coverage.config.__dict__.items())
-            for line in info_formatter(config_info):
-                print(f" {line}")
+        elif args[0] == "config":
+            write_formatted_info(print, "config", self.coverage.config.debug_info())
         elif args[0] == "premain":
             print(info_header("premain"))
             print(short_stack())
+        elif args[0] == "pybehave":
+            write_formatted_info(print, "pybehave", env.debug_info())
         else:
             show_help(f"Don't know what you mean by {args[0]!r}")
             return ERR
@@ -852,6 +915,7 @@
             help        Get help on using coverage.py.
             html        Create an HTML report.
             json        Create a JSON report of coverage results.
+            lcov        Create an LCOV report of coverage results.
             report      Report coverage stats on modules.
             run         Run a Python program and measure code execution.
             xml         Create an XML report of coverage results.

eric ide

mercurial