eric7/DebugClients/Python/coverage/cmdline.py

branch
eric7
changeset 8312
800c432b34c8
parent 7702
f8b97639deb5
child 8527
2bd1325d727e
equal deleted inserted replaced
8311:4e8b98454baa 8312:800c432b34c8
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
3
4 """Command-line support for coverage.py."""
5
6 from __future__ import print_function
7
8 import glob
9 import optparse
10 import os.path
11 import shlex
12 import sys
13 import textwrap
14 import traceback
15
16 import coverage
17 from coverage import Coverage
18 from coverage import env
19 from coverage.collector import CTracer
20 from coverage.data import line_counts
21 from coverage.debug import info_formatter, info_header, short_stack
22 from coverage.execfile import PyRunner
23 from coverage.misc import BaseCoverageException, ExceptionDuringRun, NoSource, output_encoding
24 from coverage.results import should_fail_under
25
26
27 class Opts(object):
28 """A namespace class for individual options we'll build parsers from."""
29
30 append = optparse.make_option(
31 '-a', '--append', action='store_true',
32 help="Append coverage data to .coverage, otherwise it starts clean each time.",
33 )
34 branch = optparse.make_option(
35 '', '--branch', action='store_true',
36 help="Measure branch coverage in addition to statement coverage.",
37 )
38 CONCURRENCY_CHOICES = [
39 "thread", "gevent", "greenlet", "eventlet", "multiprocessing",
40 ]
41 concurrency = optparse.make_option(
42 '', '--concurrency', action='store', metavar="LIB",
43 choices=CONCURRENCY_CHOICES,
44 help=(
45 "Properly measure code using a concurrency library. "
46 "Valid values are: %s."
47 ) % ", ".join(CONCURRENCY_CHOICES),
48 )
49 context = optparse.make_option(
50 '', '--context', action='store', metavar="LABEL",
51 help="The context label to record for this coverage run.",
52 )
53 debug = optparse.make_option(
54 '', '--debug', action='store', metavar="OPTS",
55 help="Debug options, separated by commas. [env: COVERAGE_DEBUG]",
56 )
57 directory = optparse.make_option(
58 '-d', '--directory', action='store', metavar="DIR",
59 help="Write the output files to DIR.",
60 )
61 fail_under = optparse.make_option(
62 '', '--fail-under', action='store', metavar="MIN", type="float",
63 help="Exit with a status of 2 if the total coverage is less than MIN.",
64 )
65 help = optparse.make_option(
66 '-h', '--help', action='store_true',
67 help="Get help on this command.",
68 )
69 ignore_errors = optparse.make_option(
70 '-i', '--ignore-errors', action='store_true',
71 help="Ignore errors while reading source files.",
72 )
73 include = optparse.make_option(
74 '', '--include', action='store',
75 metavar="PAT1,PAT2,...",
76 help=(
77 "Include only files whose paths match one of these patterns. "
78 "Accepts shell-style wildcards, which must be quoted."
79 ),
80 )
81 pylib = optparse.make_option(
82 '-L', '--pylib', action='store_true',
83 help=(
84 "Measure coverage even inside the Python installed library, "
85 "which isn't done by default."
86 ),
87 )
88 sort = optparse.make_option(
89 '--sort', action='store', metavar='COLUMN',
90 help="Sort the report by the named column: name, stmts, miss, branch, brpart, or cover. "
91 "Default is name."
92 )
93 show_missing = optparse.make_option(
94 '-m', '--show-missing', action='store_true',
95 help="Show line numbers of statements in each module that weren't executed.",
96 )
97 skip_covered = optparse.make_option(
98 '--skip-covered', action='store_true',
99 help="Skip files with 100% coverage.",
100 )
101 no_skip_covered = optparse.make_option(
102 '--no-skip-covered', action='store_false', dest='skip_covered',
103 help="Disable --skip-covered.",
104 )
105 skip_empty = optparse.make_option(
106 '--skip-empty', action='store_true',
107 help="Skip files with no code.",
108 )
109 show_contexts = optparse.make_option(
110 '--show-contexts', action='store_true',
111 help="Show contexts for covered lines.",
112 )
113 omit = optparse.make_option(
114 '', '--omit', action='store',
115 metavar="PAT1,PAT2,...",
116 help=(
117 "Omit files whose paths match one of these patterns. "
118 "Accepts shell-style wildcards, which must be quoted."
119 ),
120 )
121 contexts = optparse.make_option(
122 '', '--contexts', action='store',
123 metavar="REGEX1,REGEX2,...",
124 help=(
125 "Only display data from lines covered in the given contexts. "
126 "Accepts Python regexes, which must be quoted."
127 ),
128 )
129 output_xml = optparse.make_option(
130 '-o', '', action='store', dest="outfile",
131 metavar="OUTFILE",
132 help="Write the XML report to this file. Defaults to 'coverage.xml'",
133 )
134 output_json = optparse.make_option(
135 '-o', '', action='store', dest="outfile",
136 metavar="OUTFILE",
137 help="Write the JSON report to this file. Defaults to 'coverage.json'",
138 )
139 json_pretty_print = optparse.make_option(
140 '', '--pretty-print', action='store_true',
141 help="Format the JSON for human readers.",
142 )
143 parallel_mode = optparse.make_option(
144 '-p', '--parallel-mode', action='store_true',
145 help=(
146 "Append the machine name, process id and random number to the "
147 ".coverage data file name to simplify collecting data from "
148 "many processes."
149 ),
150 )
151 module = optparse.make_option(
152 '-m', '--module', action='store_true',
153 help=(
154 "<pyfile> is an importable Python module, not a script path, "
155 "to be run as 'python -m' would run it."
156 ),
157 )
158 precision = optparse.make_option(
159 '', '--precision', action='store', metavar='N', type=int,
160 help=(
161 "Number of digits after the decimal point to display for "
162 "reported coverage percentages."
163 ),
164 )
165 rcfile = optparse.make_option(
166 '', '--rcfile', action='store',
167 help=(
168 "Specify configuration file. "
169 "By default '.coveragerc', 'setup.cfg', 'tox.ini', and "
170 "'pyproject.toml' are tried. [env: COVERAGE_RCFILE]"
171 ),
172 )
173 source = optparse.make_option(
174 '', '--source', action='store', metavar="SRC1,SRC2,...",
175 help="A list of packages or directories of code to be measured.",
176 )
177 timid = optparse.make_option(
178 '', '--timid', action='store_true',
179 help=(
180 "Use a simpler but slower trace method. Try this if you get "
181 "seemingly impossible results!"
182 ),
183 )
184 title = optparse.make_option(
185 '', '--title', action='store', metavar="TITLE",
186 help="A text string to use as the title on the HTML.",
187 )
188 version = optparse.make_option(
189 '', '--version', action='store_true',
190 help="Display version information and exit.",
191 )
192
193
194 class CoverageOptionParser(optparse.OptionParser, object):
195 """Base OptionParser for coverage.py.
196
197 Problems don't exit the program.
198 Defaults are initialized for all options.
199
200 """
201
202 def __init__(self, *args, **kwargs):
203 super(CoverageOptionParser, self).__init__(
204 add_help_option=False, *args, **kwargs
205 )
206 self.set_defaults(
207 action=None,
208 append=None,
209 branch=None,
210 concurrency=None,
211 context=None,
212 debug=None,
213 directory=None,
214 fail_under=None,
215 help=None,
216 ignore_errors=None,
217 include=None,
218 module=None,
219 omit=None,
220 contexts=None,
221 parallel_mode=None,
222 precision=None,
223 pylib=None,
224 rcfile=True,
225 show_missing=None,
226 skip_covered=None,
227 skip_empty=None,
228 show_contexts=None,
229 sort=None,
230 source=None,
231 timid=None,
232 title=None,
233 version=None,
234 )
235
236 self.disable_interspersed_args()
237
238 class OptionParserError(Exception):
239 """Used to stop the optparse error handler ending the process."""
240 pass
241
242 def parse_args_ok(self, args=None, options=None):
243 """Call optparse.parse_args, but return a triple:
244
245 (ok, options, args)
246
247 """
248 try:
249 options, args = super(CoverageOptionParser, self).parse_args(args, options)
250 except self.OptionParserError:
251 return False, None, None
252 return True, options, args
253
254 def error(self, msg):
255 """Override optparse.error so sys.exit doesn't get called."""
256 show_help(msg)
257 raise self.OptionParserError
258
259
260 class GlobalOptionParser(CoverageOptionParser):
261 """Command-line parser for coverage.py global option arguments."""
262
263 def __init__(self):
264 super(GlobalOptionParser, self).__init__()
265
266 self.add_options([
267 Opts.help,
268 Opts.version,
269 ])
270
271
272 class CmdOptionParser(CoverageOptionParser):
273 """Parse one of the new-style commands for coverage.py."""
274
275 def __init__(self, action, options, defaults=None, usage=None, description=None):
276 """Create an OptionParser for a coverage.py command.
277
278 `action` is the slug to put into `options.action`.
279 `options` is a list of Option's for the command.
280 `defaults` is a dict of default value for options.
281 `usage` is the usage string to display in help.
282 `description` is the description of the command, for the help text.
283
284 """
285 if usage:
286 usage = "%prog " + usage
287 super(CmdOptionParser, self).__init__(
288 usage=usage,
289 description=description,
290 )
291 self.set_defaults(action=action, **(defaults or {}))
292 self.add_options(options)
293 self.cmd = action
294
295 def __eq__(self, other):
296 # A convenience equality, so that I can put strings in unit test
297 # results, and they will compare equal to objects.
298 return (other == "<CmdOptionParser:%s>" % self.cmd)
299
300 __hash__ = None # This object doesn't need to be hashed.
301
302 def get_prog_name(self):
303 """Override of an undocumented function in optparse.OptionParser."""
304 program_name = super(CmdOptionParser, self).get_prog_name()
305
306 # Include the sub-command for this parser as part of the command.
307 return "{command} {subcommand}".format(command=program_name, subcommand=self.cmd)
308
309
310 GLOBAL_ARGS = [
311 Opts.debug,
312 Opts.help,
313 Opts.rcfile,
314 ]
315
316 CMDS = {
317 'annotate': CmdOptionParser(
318 "annotate",
319 [
320 Opts.directory,
321 Opts.ignore_errors,
322 Opts.include,
323 Opts.omit,
324 ] + GLOBAL_ARGS,
325 usage="[options] [modules]",
326 description=(
327 "Make annotated copies of the given files, marking statements that are executed "
328 "with > and statements that are missed with !."
329 ),
330 ),
331
332 'combine': CmdOptionParser(
333 "combine",
334 [
335 Opts.append,
336 ] + GLOBAL_ARGS,
337 usage="[options] <path1> <path2> ... <pathN>",
338 description=(
339 "Combine data from multiple coverage files collected "
340 "with 'run -p'. The combined results are written to a single "
341 "file representing the union of the data. The positional "
342 "arguments are data files or directories containing data files. "
343 "If no paths are provided, data files in the default data file's "
344 "directory are combined."
345 ),
346 ),
347
348 'debug': CmdOptionParser(
349 "debug", GLOBAL_ARGS,
350 usage="<topic>",
351 description=(
352 "Display information about the internals of coverage.py, "
353 "for diagnosing problems. "
354 "Topics are: "
355 "'data' to show a summary of the collected data; "
356 "'sys' to show installation information; "
357 "'config' to show the configuration; "
358 "'premain' to show what is calling coverage."
359 ),
360 ),
361
362 'erase': CmdOptionParser(
363 "erase", GLOBAL_ARGS,
364 description="Erase previously collected coverage data.",
365 ),
366
367 'help': CmdOptionParser(
368 "help", GLOBAL_ARGS,
369 usage="[command]",
370 description="Describe how to use coverage.py",
371 ),
372
373 'html': CmdOptionParser(
374 "html",
375 [
376 Opts.contexts,
377 Opts.directory,
378 Opts.fail_under,
379 Opts.ignore_errors,
380 Opts.include,
381 Opts.omit,
382 Opts.precision,
383 Opts.show_contexts,
384 Opts.skip_covered,
385 Opts.no_skip_covered,
386 Opts.skip_empty,
387 Opts.title,
388 ] + GLOBAL_ARGS,
389 usage="[options] [modules]",
390 description=(
391 "Create an HTML report of the coverage of the files. "
392 "Each file gets its own page, with the source decorated to show "
393 "executed, excluded, and missed lines."
394 ),
395 ),
396
397 'json': CmdOptionParser(
398 "json",
399 [
400 Opts.contexts,
401 Opts.fail_under,
402 Opts.ignore_errors,
403 Opts.include,
404 Opts.omit,
405 Opts.output_json,
406 Opts.json_pretty_print,
407 Opts.show_contexts,
408 ] + GLOBAL_ARGS,
409 usage="[options] [modules]",
410 description="Generate a JSON report of coverage results."
411 ),
412
413 'report': CmdOptionParser(
414 "report",
415 [
416 Opts.contexts,
417 Opts.fail_under,
418 Opts.ignore_errors,
419 Opts.include,
420 Opts.omit,
421 Opts.precision,
422 Opts.sort,
423 Opts.show_missing,
424 Opts.skip_covered,
425 Opts.no_skip_covered,
426 Opts.skip_empty,
427 ] + GLOBAL_ARGS,
428 usage="[options] [modules]",
429 description="Report coverage statistics on modules."
430 ),
431
432 'run': CmdOptionParser(
433 "run",
434 [
435 Opts.append,
436 Opts.branch,
437 Opts.concurrency,
438 Opts.context,
439 Opts.include,
440 Opts.module,
441 Opts.omit,
442 Opts.pylib,
443 Opts.parallel_mode,
444 Opts.source,
445 Opts.timid,
446 ] + GLOBAL_ARGS,
447 usage="[options] <pyfile> [program options]",
448 description="Run a Python program, measuring code execution."
449 ),
450
451 'xml': CmdOptionParser(
452 "xml",
453 [
454 Opts.fail_under,
455 Opts.ignore_errors,
456 Opts.include,
457 Opts.omit,
458 Opts.output_xml,
459 Opts.skip_empty,
460 ] + GLOBAL_ARGS,
461 usage="[options] [modules]",
462 description="Generate an XML report of coverage results."
463 ),
464 }
465
466
467 def show_help(error=None, topic=None, parser=None):
468 """Display an error message, or the named topic."""
469 assert error or topic or parser
470
471 program_path = sys.argv[0]
472 if program_path.endswith(os.path.sep + '__main__.py'):
473 # The path is the main module of a package; get that path instead.
474 program_path = os.path.dirname(program_path)
475 program_name = os.path.basename(program_path)
476 if env.WINDOWS:
477 # entry_points={'console_scripts':...} on Windows makes files
478 # called coverage.exe, coverage3.exe, and coverage-3.5.exe. These
479 # invoke coverage-script.py, coverage3-script.py, and
480 # coverage-3.5-script.py. argv[0] is the .py file, but we want to
481 # get back to the original form.
482 auto_suffix = "-script.py"
483 if program_name.endswith(auto_suffix):
484 program_name = program_name[:-len(auto_suffix)]
485
486 help_params = dict(coverage.__dict__)
487 help_params['program_name'] = program_name
488 if CTracer is not None:
489 help_params['extension_modifier'] = 'with C extension'
490 else:
491 help_params['extension_modifier'] = 'without C extension'
492
493 if error:
494 print(error, file=sys.stderr)
495 print("Use '%s help' for help." % (program_name,), file=sys.stderr)
496 elif parser:
497 print(parser.format_help().strip())
498 print()
499 else:
500 help_msg = textwrap.dedent(HELP_TOPICS.get(topic, '')).strip()
501 if help_msg:
502 print(help_msg.format(**help_params))
503 else:
504 print("Don't know topic %r" % topic)
505 print("Full documentation is at {__url__}".format(**help_params))
506
507
508 OK, ERR, FAIL_UNDER = 0, 1, 2
509
510
511 class CoverageScript(object):
512 """The command-line interface to coverage.py."""
513
514 def __init__(self):
515 self.global_option = False
516 self.coverage = None
517
518 def command_line(self, argv):
519 """The bulk of the command line interface to coverage.py.
520
521 `argv` is the argument list to process.
522
523 Returns 0 if all is well, 1 if something went wrong.
524
525 """
526 # Collect the command-line options.
527 if not argv:
528 show_help(topic='minimum_help')
529 return OK
530
531 # The command syntax we parse depends on the first argument. Global
532 # switch syntax always starts with an option.
533 self.global_option = argv[0].startswith('-')
534 if self.global_option:
535 parser = GlobalOptionParser()
536 else:
537 parser = CMDS.get(argv[0])
538 if not parser:
539 show_help("Unknown command: '%s'" % argv[0])
540 return ERR
541 argv = argv[1:]
542
543 ok, options, args = parser.parse_args_ok(argv)
544 if not ok:
545 return ERR
546
547 # Handle help and version.
548 if self.do_help(options, args, parser):
549 return OK
550
551 # Listify the list options.
552 source = unshell_list(options.source)
553 omit = unshell_list(options.omit)
554 include = unshell_list(options.include)
555 debug = unshell_list(options.debug)
556 contexts = unshell_list(options.contexts)
557
558 # Do something.
559 self.coverage = Coverage(
560 data_suffix=options.parallel_mode,
561 cover_pylib=options.pylib,
562 timid=options.timid,
563 branch=options.branch,
564 config_file=options.rcfile,
565 source=source,
566 omit=omit,
567 include=include,
568 debug=debug,
569 concurrency=options.concurrency,
570 check_preimported=True,
571 context=options.context,
572 )
573
574 if options.action == "debug":
575 return self.do_debug(args)
576
577 elif options.action == "erase":
578 self.coverage.erase()
579 return OK
580
581 elif options.action == "run":
582 return self.do_run(options, args)
583
584 elif options.action == "combine":
585 if options.append:
586 self.coverage.load()
587 data_dirs = args or None
588 self.coverage.combine(data_dirs, strict=True)
589 self.coverage.save()
590 return OK
591
592 # Remaining actions are reporting, with some common options.
593 report_args = dict(
594 morfs=unglob_args(args),
595 ignore_errors=options.ignore_errors,
596 omit=omit,
597 include=include,
598 contexts=contexts,
599 )
600
601 # We need to be able to import from the current directory, because
602 # plugins may try to, for example, to read Django settings.
603 sys.path.insert(0, '')
604
605 self.coverage.load()
606
607 total = None
608 if options.action == "report":
609 total = self.coverage.report(
610 show_missing=options.show_missing,
611 skip_covered=options.skip_covered,
612 skip_empty=options.skip_empty,
613 precision=options.precision,
614 sort=options.sort,
615 **report_args
616 )
617 elif options.action == "annotate":
618 self.coverage.annotate(directory=options.directory, **report_args)
619 elif options.action == "html":
620 total = self.coverage.html_report(
621 directory=options.directory,
622 title=options.title,
623 skip_covered=options.skip_covered,
624 skip_empty=options.skip_empty,
625 show_contexts=options.show_contexts,
626 precision=options.precision,
627 **report_args
628 )
629 elif options.action == "xml":
630 outfile = options.outfile
631 total = self.coverage.xml_report(
632 outfile=outfile, skip_empty=options.skip_empty,
633 **report_args
634 )
635 elif options.action == "json":
636 outfile = options.outfile
637 total = self.coverage.json_report(
638 outfile=outfile,
639 pretty_print=options.pretty_print,
640 show_contexts=options.show_contexts,
641 **report_args
642 )
643
644 if total is not None:
645 # Apply the command line fail-under options, and then use the config
646 # value, so we can get fail_under from the config file.
647 if options.fail_under is not None:
648 self.coverage.set_option("report:fail_under", options.fail_under)
649
650 fail_under = self.coverage.get_option("report:fail_under")
651 precision = self.coverage.get_option("report:precision")
652 if should_fail_under(total, fail_under, precision):
653 msg = "total of {total:.{p}f} is less than fail-under={fail_under:.{p}f}".format(
654 total=total, fail_under=fail_under, p=precision,
655 )
656 print("Coverage failure:", msg)
657 return FAIL_UNDER
658
659 return OK
660
661 def do_help(self, options, args, parser):
662 """Deal with help requests.
663
664 Return True if it handled the request, False if not.
665
666 """
667 # Handle help.
668 if options.help:
669 if self.global_option:
670 show_help(topic='help')
671 else:
672 show_help(parser=parser)
673 return True
674
675 if options.action == "help":
676 if args:
677 for a in args:
678 parser = CMDS.get(a)
679 if parser:
680 show_help(parser=parser)
681 else:
682 show_help(topic=a)
683 else:
684 show_help(topic='help')
685 return True
686
687 # Handle version.
688 if options.version:
689 show_help(topic='version')
690 return True
691
692 return False
693
694 def do_run(self, options, args):
695 """Implementation of 'coverage run'."""
696
697 if not args:
698 if options.module:
699 # Specified -m with nothing else.
700 show_help("No module specified for -m")
701 return ERR
702 command_line = self.coverage.get_option("run:command_line")
703 if command_line is not None:
704 args = shlex.split(command_line)
705 if args and args[0] == "-m":
706 options.module = True
707 args = args[1:]
708 if not args:
709 show_help("Nothing to do.")
710 return ERR
711
712 if options.append and self.coverage.get_option("run:parallel"):
713 show_help("Can't append to data files in parallel mode.")
714 return ERR
715
716 if options.concurrency == "multiprocessing":
717 # Can't set other run-affecting command line options with
718 # multiprocessing.
719 for opt_name in ['branch', 'include', 'omit', 'pylib', 'source', 'timid']:
720 # As it happens, all of these options have no default, meaning
721 # they will be None if they have not been specified.
722 if getattr(options, opt_name) is not None:
723 show_help(
724 "Options affecting multiprocessing must only be specified "
725 "in a configuration file.\n"
726 "Remove --{} from the command line.".format(opt_name)
727 )
728 return ERR
729
730 runner = PyRunner(args, as_module=bool(options.module))
731 runner.prepare()
732
733 if options.append:
734 self.coverage.load()
735
736 # Run the script.
737 self.coverage.start()
738 code_ran = True
739 try:
740 runner.run()
741 except NoSource:
742 code_ran = False
743 raise
744 finally:
745 self.coverage.stop()
746 if code_ran:
747 self.coverage.save()
748
749 return OK
750
751 def do_debug(self, args):
752 """Implementation of 'coverage debug'."""
753
754 if not args:
755 show_help("What information would you like: config, data, sys, premain?")
756 return ERR
757
758 for info in args:
759 if info == 'sys':
760 sys_info = self.coverage.sys_info()
761 print(info_header("sys"))
762 for line in info_formatter(sys_info):
763 print(" %s" % line)
764 elif info == 'data':
765 self.coverage.load()
766 data = self.coverage.get_data()
767 print(info_header("data"))
768 print("path: %s" % self.coverage.get_data().data_filename())
769 if data:
770 print("has_arcs: %r" % data.has_arcs())
771 summary = line_counts(data, fullpath=True)
772 filenames = sorted(summary.keys())
773 print("\n%d files:" % len(filenames))
774 for f in filenames:
775 line = "%s: %d lines" % (f, summary[f])
776 plugin = data.file_tracer(f)
777 if plugin:
778 line += " [%s]" % plugin
779 print(line)
780 else:
781 print("No data collected")
782 elif info == 'config':
783 print(info_header("config"))
784 config_info = self.coverage.config.__dict__.items()
785 for line in info_formatter(config_info):
786 print(" %s" % line)
787 elif info == "premain":
788 print(info_header("premain"))
789 print(short_stack())
790 else:
791 show_help("Don't know what you mean by %r" % info)
792 return ERR
793
794 return OK
795
796
797 def unshell_list(s):
798 """Turn a command-line argument into a list."""
799 if not s:
800 return None
801 if env.WINDOWS:
802 # When running coverage.py as coverage.exe, some of the behavior
803 # of the shell is emulated: wildcards are expanded into a list of
804 # file names. So you have to single-quote patterns on the command
805 # line, but (not) helpfully, the single quotes are included in the
806 # argument, so we have to strip them off here.
807 s = s.strip("'")
808 return s.split(',')
809
810
811 def unglob_args(args):
812 """Interpret shell wildcards for platforms that need it."""
813 if env.WINDOWS:
814 globbed = []
815 for arg in args:
816 if '?' in arg or '*' in arg:
817 globbed.extend(glob.glob(arg))
818 else:
819 globbed.append(arg)
820 args = globbed
821 return args
822
823
824 HELP_TOPICS = {
825 'help': """\
826 Coverage.py, version {__version__} {extension_modifier}
827 Measure, collect, and report on code coverage in Python programs.
828
829 usage: {program_name} <command> [options] [args]
830
831 Commands:
832 annotate Annotate source files with execution information.
833 combine Combine a number of data files.
834 debug Display information about the internals of coverage.py
835 erase Erase previously collected coverage data.
836 help Get help on using coverage.py.
837 html Create an HTML report.
838 json Create a JSON report of coverage results.
839 report Report coverage stats on modules.
840 run Run a Python program and measure code execution.
841 xml Create an XML report of coverage results.
842
843 Use "{program_name} help <command>" for detailed help on any command.
844 """,
845
846 'minimum_help': """\
847 Code coverage for Python, version {__version__} {extension_modifier}. Use '{program_name} help' for help.
848 """,
849
850 'version': """\
851 Coverage.py, version {__version__} {extension_modifier}
852 """,
853 }
854
855
856 def main(argv=None):
857 """The main entry point to coverage.py.
858
859 This is installed as the script entry point.
860
861 """
862 if argv is None:
863 argv = sys.argv[1:]
864 try:
865 status = CoverageScript().command_line(argv)
866 except ExceptionDuringRun as err:
867 # An exception was caught while running the product code. The
868 # sys.exc_info() return tuple is packed into an ExceptionDuringRun
869 # exception.
870 traceback.print_exception(*err.args) # pylint: disable=no-value-for-parameter
871 status = ERR
872 except BaseCoverageException as err:
873 # A controlled error inside coverage.py: print the message to the user.
874 msg = err.args[0]
875 if env.PY2:
876 msg = msg.encode(output_encoding())
877 print(msg)
878 status = ERR
879 except SystemExit as err:
880 # The user called `sys.exit()`. Exit with their argument, if any.
881 if err.args:
882 status = err.args[0]
883 else:
884 status = None
885 return status
886
887 # Profiling using ox_profile. Install it from GitHub:
888 # pip install git+https://github.com/emin63/ox_profile.git
889 #
890 # $set_env.py: COVERAGE_PROFILE - Set to use ox_profile.
891 _profile = os.environ.get("COVERAGE_PROFILE", "")
892 if _profile: # pragma: debugging
893 from ox_profile.core.launchers import SimpleLauncher # pylint: disable=import-error
894 original_main = main
895
896 def main(argv=None): # pylint: disable=function-redefined
897 """A wrapper around main that profiles."""
898 profiler = SimpleLauncher.launch()
899 try:
900 return original_main(argv)
901 finally:
902 data, _ = profiler.query(re_filter='coverage', max_records=100)
903 print(profiler.show(query=data, limit=100, sep='', col=''))
904 profiler.cancel()

eric ide

mercurial