eric7/DebugClients/Python/coverage/cmdline.py

branch
eric7
changeset 8775
0802ae193343
parent 8527
2bd1325d727e
child 8929
fcca2fa618bf
equal deleted inserted replaced
8774:d728227e8ebb 8775:0802ae193343
1 # Licensed under the Apache License: http://www.apache.org/licenses/LICENSE-2.0 1 # Licensed under the Apache License: http://www.apache.org/licenses/LICENSE-2.0
2 # For details: https://github.com/nedbat/coveragepy/blob/master/NOTICE.txt 2 # For details: https://github.com/nedbat/coveragepy/blob/master/NOTICE.txt
3 3
4 """Command-line support for coverage.py.""" 4 """Command-line support for coverage.py."""
5 5
6 from __future__ import print_function
7 6
8 import glob 7 import glob
9 import optparse 8 import optparse # pylint: disable=deprecated-module
9 import os
10 import os.path 10 import os.path
11 import shlex 11 import shlex
12 import sys 12 import sys
13 import textwrap 13 import textwrap
14 import traceback 14 import traceback
17 from coverage import Coverage 17 from coverage import Coverage
18 from coverage import env 18 from coverage import env
19 from coverage.collector import CTracer 19 from coverage.collector import CTracer
20 from coverage.data import line_counts 20 from coverage.data import line_counts
21 from coverage.debug import info_formatter, info_header, short_stack 21 from coverage.debug import info_formatter, info_header, short_stack
22 from coverage.exceptions import BaseCoverageException, ExceptionDuringRun, NoSource
22 from coverage.execfile import PyRunner 23 from coverage.execfile import PyRunner
23 from coverage.misc import BaseCoverageException, ExceptionDuringRun, NoSource, output_encoding 24 from coverage.misc import human_sorted
24 from coverage.results import should_fail_under 25 from coverage.results import Numbers, should_fail_under
25 26
26 27
27 class Opts(object): 28 class Opts:
28 """A namespace class for individual options we'll build parsers from.""" 29 """A namespace class for individual options we'll build parsers from."""
29 30
30 append = optparse.make_option( 31 append = optparse.make_option(
31 '-a', '--append', action='store_true', 32 '-a', '--append', action='store_true',
32 help="Append coverage data to .coverage, otherwise it starts clean each time.", 33 help="Append coverage data to .coverage, otherwise it starts clean each time.",
44 ] 45 ]
45 concurrency = optparse.make_option( 46 concurrency = optparse.make_option(
46 '', '--concurrency', action='store', metavar="LIB", 47 '', '--concurrency', action='store', metavar="LIB",
47 choices=CONCURRENCY_CHOICES, 48 choices=CONCURRENCY_CHOICES,
48 help=( 49 help=(
49 "Properly measure code using a concurrency library. " 50 "Properly measure code using a concurrency library. " +
50 "Valid values are: %s." 51 "Valid values are: {}."
51 ) % ", ".join(CONCURRENCY_CHOICES), 52 ).format(", ".join(CONCURRENCY_CHOICES)),
52 ) 53 )
53 context = optparse.make_option( 54 context = optparse.make_option(
54 '', '--context', action='store', metavar="LABEL", 55 '', '--context', action='store', metavar="LABEL",
55 help="The context label to record for this coverage run.", 56 help="The context label to record for this coverage run.",
57 )
58 contexts = optparse.make_option(
59 '', '--contexts', action='store',
60 metavar="REGEX1,REGEX2,...",
61 help=(
62 "Only display data from lines covered in the given contexts. " +
63 "Accepts Python regexes, which must be quoted."
64 ),
56 ) 65 )
57 debug = optparse.make_option( 66 debug = optparse.make_option(
58 '', '--debug', action='store', metavar="OPTS", 67 '', '--debug', action='store', metavar="OPTS",
59 help="Debug options, separated by commas. [env: COVERAGE_DEBUG]", 68 help="Debug options, separated by commas. [env: COVERAGE_DEBUG]",
60 ) 69 )
76 ) 85 )
77 include = optparse.make_option( 86 include = optparse.make_option(
78 '', '--include', action='store', 87 '', '--include', action='store',
79 metavar="PAT1,PAT2,...", 88 metavar="PAT1,PAT2,...",
80 help=( 89 help=(
81 "Include only files whose paths match one of these patterns. " 90 "Include only files whose paths match one of these patterns. " +
82 "Accepts shell-style wildcards, which must be quoted." 91 "Accepts shell-style wildcards, which must be quoted."
83 ), 92 ),
84 ) 93 )
85 pylib = optparse.make_option( 94 pylib = optparse.make_option(
86 '-L', '--pylib', action='store_true', 95 '-L', '--pylib', action='store_true',
87 help=( 96 help=(
88 "Measure coverage even inside the Python installed library, " 97 "Measure coverage even inside the Python installed library, " +
89 "which isn't done by default." 98 "which isn't done by default."
90 ), 99 ),
91 )
92 sort = optparse.make_option(
93 '--sort', action='store', metavar='COLUMN',
94 help="Sort the report by the named column: name, stmts, miss, branch, brpart, or cover. "
95 "Default is name."
96 ) 100 )
97 show_missing = optparse.make_option( 101 show_missing = optparse.make_option(
98 '-m', '--show-missing', action='store_true', 102 '-m', '--show-missing', action='store_true',
99 help="Show line numbers of statements in each module that weren't executed.", 103 help="Show line numbers of statements in each module that weren't executed.",
100 ) 104 )
101 skip_covered = optparse.make_option( 105 module = optparse.make_option(
102 '--skip-covered', action='store_true', 106 '-m', '--module', action='store_true',
103 help="Skip files with 100% coverage.", 107 help=(
104 ) 108 "<pyfile> is an importable Python module, not a script path, " +
105 no_skip_covered = optparse.make_option( 109 "to be run as 'python -m' would run it."
106 '--no-skip-covered', action='store_false', dest='skip_covered', 110 ),
107 help="Disable --skip-covered.",
108 )
109 skip_empty = optparse.make_option(
110 '--skip-empty', action='store_true',
111 help="Skip files with no code.",
112 )
113 show_contexts = optparse.make_option(
114 '--show-contexts', action='store_true',
115 help="Show contexts for covered lines.",
116 ) 111 )
117 omit = optparse.make_option( 112 omit = optparse.make_option(
118 '', '--omit', action='store', 113 '', '--omit', action='store',
119 metavar="PAT1,PAT2,...", 114 metavar="PAT1,PAT2,...",
120 help=( 115 help=(
121 "Omit files whose paths match one of these patterns. " 116 "Omit files whose paths match one of these patterns. " +
122 "Accepts shell-style wildcards, which must be quoted." 117 "Accepts shell-style wildcards, which must be quoted."
123 ),
124 )
125 contexts = optparse.make_option(
126 '', '--contexts', action='store',
127 metavar="REGEX1,REGEX2,...",
128 help=(
129 "Only display data from lines covered in the given contexts. "
130 "Accepts Python regexes, which must be quoted."
131 ), 118 ),
132 ) 119 )
133 output_xml = optparse.make_option( 120 output_xml = optparse.make_option(
134 '-o', '', action='store', dest="outfile", 121 '-o', '', action='store', dest="outfile",
135 metavar="OUTFILE", 122 metavar="OUTFILE",
145 help="Format the JSON for human readers.", 132 help="Format the JSON for human readers.",
146 ) 133 )
147 parallel_mode = optparse.make_option( 134 parallel_mode = optparse.make_option(
148 '-p', '--parallel-mode', action='store_true', 135 '-p', '--parallel-mode', action='store_true',
149 help=( 136 help=(
150 "Append the machine name, process id and random number to the " 137 "Append the machine name, process id and random number to the " +
151 ".coverage data file name to simplify collecting data from " 138 ".coverage data file name to simplify collecting data from " +
152 "many processes." 139 "many processes."
153 ),
154 )
155 module = optparse.make_option(
156 '-m', '--module', action='store_true',
157 help=(
158 "<pyfile> is an importable Python module, not a script path, "
159 "to be run as 'python -m' would run it."
160 ), 140 ),
161 ) 141 )
162 precision = optparse.make_option( 142 precision = optparse.make_option(
163 '', '--precision', action='store', metavar='N', type=int, 143 '', '--precision', action='store', metavar='N', type=int,
164 help=( 144 help=(
165 "Number of digits after the decimal point to display for " 145 "Number of digits after the decimal point to display for " +
166 "reported coverage percentages." 146 "reported coverage percentages."
167 ), 147 ),
148 )
149 quiet = optparse.make_option(
150 '-q', '--quiet', action='store_true',
151 help="Don't print messages about what is happening.",
168 ) 152 )
169 rcfile = optparse.make_option( 153 rcfile = optparse.make_option(
170 '', '--rcfile', action='store', 154 '', '--rcfile', action='store',
171 help=( 155 help=(
172 "Specify configuration file. " 156 "Specify configuration file. " +
173 "By default '.coveragerc', 'setup.cfg', 'tox.ini', and " 157 "By default '.coveragerc', 'setup.cfg', 'tox.ini', and " +
174 "'pyproject.toml' are tried. [env: COVERAGE_RCFILE]" 158 "'pyproject.toml' are tried. [env: COVERAGE_RCFILE]"
175 ), 159 ),
160 )
161 show_contexts = optparse.make_option(
162 '--show-contexts', action='store_true',
163 help="Show contexts for covered lines.",
164 )
165 skip_covered = optparse.make_option(
166 '--skip-covered', action='store_true',
167 help="Skip files with 100% coverage.",
168 )
169 no_skip_covered = optparse.make_option(
170 '--no-skip-covered', action='store_false', dest='skip_covered',
171 help="Disable --skip-covered.",
172 )
173 skip_empty = optparse.make_option(
174 '--skip-empty', action='store_true',
175 help="Skip files with no code.",
176 )
177 sort = optparse.make_option(
178 '--sort', action='store', metavar='COLUMN',
179 help="Sort the report by the named column: name, stmts, miss, branch, brpart, or cover. " +
180 "Default is name."
176 ) 181 )
177 source = optparse.make_option( 182 source = optparse.make_option(
178 '', '--source', action='store', metavar="SRC1,SRC2,...", 183 '', '--source', action='store', metavar="SRC1,SRC2,...",
179 help="A list of packages or directories of code to be measured.", 184 help="A list of directories or importable names of code to measure.",
180 ) 185 )
181 timid = optparse.make_option( 186 timid = optparse.make_option(
182 '', '--timid', action='store_true', 187 '', '--timid', action='store_true',
183 help=( 188 help=(
184 "Use a simpler but slower trace method. Try this if you get " 189 "Use a simpler but slower trace method. Try this if you get " +
185 "seemingly impossible results!" 190 "seemingly impossible results!"
186 ), 191 ),
187 ) 192 )
188 title = optparse.make_option( 193 title = optparse.make_option(
189 '', '--title', action='store', metavar="TITLE", 194 '', '--title', action='store', metavar="TITLE",
193 '', '--version', action='store_true', 198 '', '--version', action='store_true',
194 help="Display version information and exit.", 199 help="Display version information and exit.",
195 ) 200 )
196 201
197 202
198 class CoverageOptionParser(optparse.OptionParser, object): 203 class CoverageOptionParser(optparse.OptionParser):
199 """Base OptionParser for coverage.py. 204 """Base OptionParser for coverage.py.
200 205
201 Problems don't exit the program. 206 Problems don't exit the program.
202 Defaults are initialized for all options. 207 Defaults are initialized for all options.
203 208
204 """ 209 """
205 210
206 def __init__(self, *args, **kwargs): 211 def __init__(self, *args, **kwargs):
207 super(CoverageOptionParser, self).__init__( 212 super().__init__(
208 add_help_option=False, *args, **kwargs 213 add_help_option=False, *args, **kwargs
209 ) 214 )
210 self.set_defaults( 215 self.set_defaults(
211 action=None, 216 action=None,
212 append=None, 217 append=None,
213 branch=None, 218 branch=None,
214 concurrency=None, 219 concurrency=None,
215 context=None, 220 context=None,
221 contexts=None,
216 debug=None, 222 debug=None,
217 directory=None, 223 directory=None,
218 fail_under=None, 224 fail_under=None,
219 help=None, 225 help=None,
220 ignore_errors=None, 226 ignore_errors=None,
221 include=None, 227 include=None,
222 keep=None, 228 keep=None,
223 module=None, 229 module=None,
224 omit=None, 230 omit=None,
225 contexts=None,
226 parallel_mode=None, 231 parallel_mode=None,
227 precision=None, 232 precision=None,
228 pylib=None, 233 pylib=None,
234 quiet=None,
229 rcfile=True, 235 rcfile=True,
236 show_contexts=None,
230 show_missing=None, 237 show_missing=None,
231 skip_covered=None, 238 skip_covered=None,
232 skip_empty=None, 239 skip_empty=None,
233 show_contexts=None,
234 sort=None, 240 sort=None,
235 source=None, 241 source=None,
236 timid=None, 242 timid=None,
237 title=None, 243 title=None,
238 version=None, 244 version=None,
249 255
250 (ok, options, args) 256 (ok, options, args)
251 257
252 """ 258 """
253 try: 259 try:
254 options, args = super(CoverageOptionParser, self).parse_args(args, options) 260 options, args = super().parse_args(args, options)
255 except self.OptionParserError: 261 except self.OptionParserError:
256 return False, None, None 262 return False, None, None
257 return True, options, args 263 return True, options, args
258 264
259 def error(self, msg): 265 def error(self, msg):
264 270
265 class GlobalOptionParser(CoverageOptionParser): 271 class GlobalOptionParser(CoverageOptionParser):
266 """Command-line parser for coverage.py global option arguments.""" 272 """Command-line parser for coverage.py global option arguments."""
267 273
268 def __init__(self): 274 def __init__(self):
269 super(GlobalOptionParser, self).__init__() 275 super().__init__()
270 276
271 self.add_options([ 277 self.add_options([
272 Opts.help, 278 Opts.help,
273 Opts.version, 279 Opts.version,
274 ]) 280 ])
287 `description` is the description of the command, for the help text. 293 `description` is the description of the command, for the help text.
288 294
289 """ 295 """
290 if usage: 296 if usage:
291 usage = "%prog " + usage 297 usage = "%prog " + usage
292 super(CmdOptionParser, self).__init__( 298 super().__init__(
293 usage=usage, 299 usage=usage,
294 description=description, 300 description=description,
295 ) 301 )
296 self.set_defaults(action=action, **(defaults or {})) 302 self.set_defaults(action=action, **(defaults or {}))
297 self.add_options(options) 303 self.add_options(options)
298 self.cmd = action 304 self.cmd = action
299 305
300 def __eq__(self, other): 306 def __eq__(self, other):
301 # A convenience equality, so that I can put strings in unit test 307 # A convenience equality, so that I can put strings in unit test
302 # results, and they will compare equal to objects. 308 # results, and they will compare equal to objects.
303 return (other == "<CmdOptionParser:%s>" % self.cmd) 309 return (other == f"<CmdOptionParser:{self.cmd}>")
304 310
305 __hash__ = None # This object doesn't need to be hashed. 311 __hash__ = None # This object doesn't need to be hashed.
306 312
307 def get_prog_name(self): 313 def get_prog_name(self):
308 """Override of an undocumented function in optparse.OptionParser.""" 314 """Override of an undocumented function in optparse.OptionParser."""
309 program_name = super(CmdOptionParser, self).get_prog_name() 315 program_name = super().get_prog_name()
310 316
311 # Include the sub-command for this parser as part of the command. 317 # Include the sub-command for this parser as part of the command.
312 return "{command} {subcommand}".format(command=program_name, subcommand=self.cmd) 318 return f"{program_name} {self.cmd}"
313 319
314 320
315 GLOBAL_ARGS = [ 321 GLOBAL_ARGS = [
316 Opts.debug, 322 Opts.debug,
317 Opts.help, 323 Opts.help,
327 Opts.include, 333 Opts.include,
328 Opts.omit, 334 Opts.omit,
329 ] + GLOBAL_ARGS, 335 ] + GLOBAL_ARGS,
330 usage="[options] [modules]", 336 usage="[options] [modules]",
331 description=( 337 description=(
332 "Make annotated copies of the given files, marking statements that are executed " 338 "Make annotated copies of the given files, marking statements that are executed " +
333 "with > and statements that are missed with !." 339 "with > and statements that are missed with !."
334 ), 340 ),
335 ), 341 ),
336 342
337 'combine': CmdOptionParser( 343 'combine': CmdOptionParser(
338 "combine", 344 "combine",
339 [ 345 [
340 Opts.append, 346 Opts.append,
341 Opts.keep, 347 Opts.keep,
348 Opts.quiet,
342 ] + GLOBAL_ARGS, 349 ] + GLOBAL_ARGS,
343 usage="[options] <path1> <path2> ... <pathN>", 350 usage="[options] <path1> <path2> ... <pathN>",
344 description=( 351 description=(
345 "Combine data from multiple coverage files collected " 352 "Combine data from multiple coverage files collected " +
346 "with 'run -p'. The combined results are written to a single " 353 "with 'run -p'. The combined results are written to a single " +
347 "file representing the union of the data. The positional " 354 "file representing the union of the data. The positional " +
348 "arguments are data files or directories containing data files. " 355 "arguments are data files or directories containing data files. " +
349 "If no paths are provided, data files in the default data file's " 356 "If no paths are provided, data files in the default data file's " +
350 "directory are combined." 357 "directory are combined."
351 ), 358 ),
352 ), 359 ),
353 360
354 'debug': CmdOptionParser( 361 'debug': CmdOptionParser(
355 "debug", GLOBAL_ARGS, 362 "debug", GLOBAL_ARGS,
356 usage="<topic>", 363 usage="<topic>",
357 description=( 364 description=(
358 "Display information about the internals of coverage.py, " 365 "Display information about the internals of coverage.py, " +
359 "for diagnosing problems. " 366 "for diagnosing problems. " +
360 "Topics are: " 367 "Topics are: " +
361 "'data' to show a summary of the collected data; " 368 "'data' to show a summary of the collected data; " +
362 "'sys' to show installation information; " 369 "'sys' to show installation information; " +
363 "'config' to show the configuration; " 370 "'config' to show the configuration; " +
364 "'premain' to show what is calling coverage." 371 "'premain' to show what is calling coverage."
365 ), 372 ),
366 ), 373 ),
367 374
368 'erase': CmdOptionParser( 375 'erase': CmdOptionParser(
384 Opts.fail_under, 391 Opts.fail_under,
385 Opts.ignore_errors, 392 Opts.ignore_errors,
386 Opts.include, 393 Opts.include,
387 Opts.omit, 394 Opts.omit,
388 Opts.precision, 395 Opts.precision,
396 Opts.quiet,
389 Opts.show_contexts, 397 Opts.show_contexts,
390 Opts.skip_covered, 398 Opts.skip_covered,
391 Opts.no_skip_covered, 399 Opts.no_skip_covered,
392 Opts.skip_empty, 400 Opts.skip_empty,
393 Opts.title, 401 Opts.title,
394 ] + GLOBAL_ARGS, 402 ] + GLOBAL_ARGS,
395 usage="[options] [modules]", 403 usage="[options] [modules]",
396 description=( 404 description=(
397 "Create an HTML report of the coverage of the files. " 405 "Create an HTML report of the coverage of the files. " +
398 "Each file gets its own page, with the source decorated to show " 406 "Each file gets its own page, with the source decorated to show " +
399 "executed, excluded, and missed lines." 407 "executed, excluded, and missed lines."
400 ), 408 ),
401 ), 409 ),
402 410
403 'json': CmdOptionParser( 411 'json': CmdOptionParser(
408 Opts.ignore_errors, 416 Opts.ignore_errors,
409 Opts.include, 417 Opts.include,
410 Opts.omit, 418 Opts.omit,
411 Opts.output_json, 419 Opts.output_json,
412 Opts.json_pretty_print, 420 Opts.json_pretty_print,
421 Opts.quiet,
413 Opts.show_contexts, 422 Opts.show_contexts,
414 ] + GLOBAL_ARGS, 423 ] + GLOBAL_ARGS,
415 usage="[options] [modules]", 424 usage="[options] [modules]",
416 description="Generate a JSON report of coverage results." 425 description="Generate a JSON report of coverage results."
417 ), 426 ),
460 Opts.fail_under, 469 Opts.fail_under,
461 Opts.ignore_errors, 470 Opts.ignore_errors,
462 Opts.include, 471 Opts.include,
463 Opts.omit, 472 Opts.omit,
464 Opts.output_xml, 473 Opts.output_xml,
474 Opts.quiet,
465 Opts.skip_empty, 475 Opts.skip_empty,
466 ] + GLOBAL_ARGS, 476 ] + GLOBAL_ARGS,
467 usage="[options] [modules]", 477 usage="[options] [modules]",
468 description="Generate an XML report of coverage results." 478 description="Generate an XML report of coverage results."
469 ), 479 ),
496 else: 506 else:
497 help_params['extension_modifier'] = 'without C extension' 507 help_params['extension_modifier'] = 'without C extension'
498 508
499 if error: 509 if error:
500 print(error, file=sys.stderr) 510 print(error, file=sys.stderr)
501 print("Use '%s help' for help." % (program_name,), file=sys.stderr) 511 print(f"Use '{program_name} help' for help.", file=sys.stderr)
502 elif parser: 512 elif parser:
503 print(parser.format_help().strip()) 513 print(parser.format_help().strip())
504 print() 514 print()
505 else: 515 else:
506 help_msg = textwrap.dedent(HELP_TOPICS.get(topic, '')).strip() 516 help_msg = textwrap.dedent(HELP_TOPICS.get(topic, '')).strip()
507 if help_msg: 517 if help_msg:
508 print(help_msg.format(**help_params)) 518 print(help_msg.format(**help_params))
509 else: 519 else:
510 print("Don't know topic %r" % topic) 520 print(f"Don't know topic {topic!r}")
511 print("Full documentation is at {__url__}".format(**help_params)) 521 print("Full documentation is at {__url__}".format(**help_params))
512 522
513 523
514 OK, ERR, FAIL_UNDER = 0, 1, 2 524 OK, ERR, FAIL_UNDER = 0, 1, 2
515 525
516 526
517 class CoverageScript(object): 527 class CoverageScript:
518 """The command-line interface to coverage.py.""" 528 """The command-line interface to coverage.py."""
519 529
520 def __init__(self): 530 def __init__(self):
521 self.global_option = False 531 self.global_option = False
522 self.coverage = None 532 self.coverage = None
540 if self.global_option: 550 if self.global_option:
541 parser = GlobalOptionParser() 551 parser = GlobalOptionParser()
542 else: 552 else:
543 parser = CMDS.get(argv[0]) 553 parser = CMDS.get(argv[0])
544 if not parser: 554 if not parser:
545 show_help("Unknown command: '%s'" % argv[0]) 555 show_help(f"Unknown command: {argv[0]!r}")
546 return ERR 556 return ERR
547 argv = argv[1:] 557 argv = argv[1:]
548 558
549 ok, options, args = parser.parse_args_ok(argv) 559 ok, options, args = parser.parse_args_ok(argv)
550 if not ok: 560 if not ok:
573 include=include, 583 include=include,
574 debug=debug, 584 debug=debug,
575 concurrency=options.concurrency, 585 concurrency=options.concurrency,
576 check_preimported=True, 586 check_preimported=True,
577 context=options.context, 587 context=options.context,
588 messages=not options.quiet,
578 ) 589 )
579 590
580 if options.action == "debug": 591 if options.action == "debug":
581 return self.do_debug(args) 592 return self.do_debug(args)
582 593
644 outfile=outfile, 655 outfile=outfile,
645 pretty_print=options.pretty_print, 656 pretty_print=options.pretty_print,
646 show_contexts=options.show_contexts, 657 show_contexts=options.show_contexts,
647 **report_args 658 **report_args
648 ) 659 )
660 else:
661 # There are no other possible actions.
662 raise AssertionError
649 663
650 if total is not None: 664 if total is not None:
651 # Apply the command line fail-under options, and then use the config 665 # Apply the command line fail-under options, and then use the config
652 # value, so we can get fail_under from the config file. 666 # value, so we can get fail_under from the config file.
653 if options.fail_under is not None: 667 if options.fail_under is not None:
654 self.coverage.set_option("report:fail_under", options.fail_under) 668 self.coverage.set_option("report:fail_under", options.fail_under)
655 669
656 fail_under = self.coverage.get_option("report:fail_under") 670 fail_under = self.coverage.get_option("report:fail_under")
657 precision = self.coverage.get_option("report:precision") 671 precision = self.coverage.get_option("report:precision")
658 if should_fail_under(total, fail_under, precision): 672 if should_fail_under(total, fail_under, precision):
659 msg = "total of {total:.{p}f} is less than fail-under={fail_under:.{p}f}".format( 673 msg = "total of {total} is less than fail-under={fail_under:.{p}f}".format(
660 total=total, fail_under=fail_under, p=precision, 674 total=Numbers(precision=precision).display_covered(total),
675 fail_under=fail_under,
676 p=precision,
661 ) 677 )
662 print("Coverage failure:", msg) 678 print("Coverage failure:", msg)
663 return FAIL_UNDER 679 return FAIL_UNDER
664 680
665 return OK 681 return OK
706 show_help("No module specified for -m") 722 show_help("No module specified for -m")
707 return ERR 723 return ERR
708 command_line = self.coverage.get_option("run:command_line") 724 command_line = self.coverage.get_option("run:command_line")
709 if command_line is not None: 725 if command_line is not None:
710 args = shlex.split(command_line) 726 args = shlex.split(command_line)
711 if args and args[0] == "-m": 727 if args and args[0] in {"-m", "--module"}:
712 options.module = True 728 options.module = True
713 args = args[1:] 729 args = args[1:]
714 if not args: 730 if not args:
715 show_help("Nothing to do.") 731 show_help("Nothing to do.")
716 return ERR 732 return ERR
725 for opt_name in ['branch', 'include', 'omit', 'pylib', 'source', 'timid']: 741 for opt_name in ['branch', 'include', 'omit', 'pylib', 'source', 'timid']:
726 # As it happens, all of these options have no default, meaning 742 # As it happens, all of these options have no default, meaning
727 # they will be None if they have not been specified. 743 # they will be None if they have not been specified.
728 if getattr(options, opt_name) is not None: 744 if getattr(options, opt_name) is not None:
729 show_help( 745 show_help(
730 "Options affecting multiprocessing must only be specified " 746 "Options affecting multiprocessing must only be specified " +
731 "in a configuration file.\n" 747 "in a configuration file.\n" +
732 "Remove --{} from the command line.".format(opt_name) 748 f"Remove --{opt_name} from the command line."
733 ) 749 )
734 return ERR 750 return ERR
751
752 os.environ["COVERAGE_RUN"] = "true"
735 753
736 runner = PyRunner(args, as_module=bool(options.module)) 754 runner = PyRunner(args, as_module=bool(options.module))
737 runner.prepare() 755 runner.prepare()
738 756
739 if options.append: 757 if options.append:
764 for info in args: 782 for info in args:
765 if info == 'sys': 783 if info == 'sys':
766 sys_info = self.coverage.sys_info() 784 sys_info = self.coverage.sys_info()
767 print(info_header("sys")) 785 print(info_header("sys"))
768 for line in info_formatter(sys_info): 786 for line in info_formatter(sys_info):
769 print(" %s" % line) 787 print(f" {line}")
770 elif info == 'data': 788 elif info == 'data':
771 self.coverage.load() 789 self.coverage.load()
772 data = self.coverage.get_data() 790 data = self.coverage.get_data()
773 print(info_header("data")) 791 print(info_header("data"))
774 print("path: %s" % data.data_filename()) 792 print(f"path: {data.data_filename()}")
775 if data: 793 if data:
776 print("has_arcs: %r" % data.has_arcs()) 794 print(f"has_arcs: {data.has_arcs()!r}")
777 summary = line_counts(data, fullpath=True) 795 summary = line_counts(data, fullpath=True)
778 filenames = sorted(summary.keys()) 796 filenames = human_sorted(summary.keys())
779 print("\n%d files:" % len(filenames)) 797 print(f"\n{len(filenames)} files:")
780 for f in filenames: 798 for f in filenames:
781 line = "%s: %d lines" % (f, summary[f]) 799 line = f"{f}: {summary[f]} lines"
782 plugin = data.file_tracer(f) 800 plugin = data.file_tracer(f)
783 if plugin: 801 if plugin:
784 line += " [%s]" % plugin 802 line += f" [{plugin}]"
785 print(line) 803 print(line)
786 else: 804 else:
787 print("No data collected") 805 print("No data collected")
788 elif info == 'config': 806 elif info == 'config':
789 print(info_header("config")) 807 print(info_header("config"))
790 config_info = self.coverage.config.__dict__.items() 808 config_info = self.coverage.config.__dict__.items()
791 for line in info_formatter(config_info): 809 for line in info_formatter(config_info):
792 print(" %s" % line) 810 print(f" {line}")
793 elif info == "premain": 811 elif info == "premain":
794 print(info_header("premain")) 812 print(info_header("premain"))
795 print(short_stack()) 813 print(short_stack())
796 else: 814 else:
797 show_help("Don't know what you mean by %r" % info) 815 show_help(f"Don't know what you mean by {info!r}")
798 return ERR 816 return ERR
799 817
800 return OK 818 return OK
801 819
802 820
876 traceback.print_exception(*err.args) # pylint: disable=no-value-for-parameter 894 traceback.print_exception(*err.args) # pylint: disable=no-value-for-parameter
877 status = ERR 895 status = ERR
878 except BaseCoverageException as err: 896 except BaseCoverageException as err:
879 # A controlled error inside coverage.py: print the message to the user. 897 # A controlled error inside coverage.py: print the message to the user.
880 msg = err.args[0] 898 msg = err.args[0]
881 if env.PY2:
882 msg = msg.encode(output_encoding())
883 print(msg) 899 print(msg)
884 status = ERR 900 status = ERR
885 except SystemExit as err: 901 except SystemExit as err:
886 # The user called `sys.exit()`. Exit with their argument, if any. 902 # The user called `sys.exit()`. Exit with their argument, if any.
887 if err.args: 903 if err.args:

eric ide

mercurial