16 import coverage |
15 import coverage |
17 from coverage import Coverage |
16 from coverage import Coverage |
18 from coverage import env |
17 from coverage import env |
19 from coverage.collector import CTracer |
18 from coverage.collector import CTracer |
20 from coverage.config import CoverageConfig |
19 from coverage.config import CoverageConfig |
|
20 from coverage.control import DEFAULT_DATAFILE |
21 from coverage.data import combinable_files, debug_data_file |
21 from coverage.data import combinable_files, debug_data_file |
22 from coverage.debug import info_formatter, info_header, short_stack |
22 from coverage.debug import info_header, short_stack, write_formatted_info |
23 from coverage.exceptions import _BaseCoverageException, _ExceptionDuringRun, NoSource |
23 from coverage.exceptions import _BaseCoverageException, _ExceptionDuringRun, NoSource |
24 from coverage.execfile import PyRunner |
24 from coverage.execfile import PyRunner |
25 from coverage.results import Numbers, should_fail_under |
25 from coverage.results import Numbers, should_fail_under |
26 |
26 |
|
27 # When adding to this file, alphabetization is important. Look for |
|
28 # "alphabetize" comments throughout. |
27 |
29 |
28 class Opts: |
30 class Opts: |
29 """A namespace class for individual options we'll build parsers from.""" |
31 """A namespace class for individual options we'll build parsers from.""" |
|
32 |
|
33 # Keep these entries alphabetized (roughly) by the option name as it |
|
34 # appears on the command line. |
30 |
35 |
31 append = optparse.make_option( |
36 append = optparse.make_option( |
32 '-a', '--append', action='store_true', |
37 '-a', '--append', action='store_true', |
33 help="Append coverage data to .coverage, otherwise it starts clean each time.", |
38 help="Append coverage data to .coverage, otherwise it starts clean each time.", |
34 ) |
39 ) |
50 context = optparse.make_option( |
55 context = optparse.make_option( |
51 '', '--context', action='store', metavar="LABEL", |
56 '', '--context', action='store', metavar="LABEL", |
52 help="The context label to record for this coverage run.", |
57 help="The context label to record for this coverage run.", |
53 ) |
58 ) |
54 contexts = optparse.make_option( |
59 contexts = optparse.make_option( |
55 '', '--contexts', action='store', |
60 '', '--contexts', action='store', metavar="REGEX1,REGEX2,...", |
56 metavar="REGEX1,REGEX2,...", |
|
57 help=( |
61 help=( |
58 "Only display data from lines covered in the given contexts. " + |
62 "Only display data from lines covered in the given contexts. " + |
59 "Accepts Python regexes, which must be quoted." |
63 "Accepts Python regexes, which must be quoted." |
|
64 ), |
|
65 ) |
|
66 combine_datafile = optparse.make_option( |
|
67 '', '--data-file', action='store', metavar="DATAFILE", |
|
68 help=( |
|
69 "Base name of the data files to operate on. " + |
|
70 "Defaults to '.coverage'. [env: COVERAGE_FILE]" |
|
71 ), |
|
72 ) |
|
73 input_datafile = optparse.make_option( |
|
74 '', '--data-file', action='store', metavar="INFILE", |
|
75 help=( |
|
76 "Read coverage data for report generation from this file. " + |
|
77 "Defaults to '.coverage'. [env: COVERAGE_FILE]" |
|
78 ), |
|
79 ) |
|
80 output_datafile = optparse.make_option( |
|
81 '', '--data-file', action='store', metavar="OUTFILE", |
|
82 help=( |
|
83 "Write the recorded coverage data to this file. " + |
|
84 "Defaults to '.coverage'. [env: COVERAGE_FILE]" |
60 ), |
85 ), |
61 ) |
86 ) |
62 debug = optparse.make_option( |
87 debug = optparse.make_option( |
63 '', '--debug', action='store', metavar="OPTS", |
88 '', '--debug', action='store', metavar="OPTS", |
64 help="Debug options, separated by commas. [env: COVERAGE_DEBUG]", |
89 help="Debug options, separated by commas. [env: COVERAGE_DEBUG]", |
78 ignore_errors = optparse.make_option( |
103 ignore_errors = optparse.make_option( |
79 '-i', '--ignore-errors', action='store_true', |
104 '-i', '--ignore-errors', action='store_true', |
80 help="Ignore errors while reading source files.", |
105 help="Ignore errors while reading source files.", |
81 ) |
106 ) |
82 include = optparse.make_option( |
107 include = optparse.make_option( |
83 '', '--include', action='store', |
108 '', '--include', action='store', metavar="PAT1,PAT2,...", |
84 metavar="PAT1,PAT2,...", |
|
85 help=( |
109 help=( |
86 "Include only files whose paths match one of these patterns. " + |
110 "Include only files whose paths match one of these patterns. " + |
87 "Accepts shell-style wildcards, which must be quoted." |
111 "Accepts shell-style wildcards, which must be quoted." |
88 ), |
112 ), |
89 ) |
113 ) |
104 "<pyfile> is an importable Python module, not a script path, " + |
128 "<pyfile> is an importable Python module, not a script path, " + |
105 "to be run as 'python -m' would run it." |
129 "to be run as 'python -m' would run it." |
106 ), |
130 ), |
107 ) |
131 ) |
108 omit = optparse.make_option( |
132 omit = optparse.make_option( |
109 '', '--omit', action='store', |
133 '', '--omit', action='store', metavar="PAT1,PAT2,...", |
110 metavar="PAT1,PAT2,...", |
|
111 help=( |
134 help=( |
112 "Omit files whose paths match one of these patterns. " + |
135 "Omit files whose paths match one of these patterns. " + |
113 "Accepts shell-style wildcards, which must be quoted." |
136 "Accepts shell-style wildcards, which must be quoted." |
114 ), |
137 ), |
115 ) |
138 ) |
116 output_xml = optparse.make_option( |
139 output_xml = optparse.make_option( |
117 '-o', '', action='store', dest="outfile", |
140 '-o', '', action='store', dest="outfile", metavar="OUTFILE", |
118 metavar="OUTFILE", |
|
119 help="Write the XML report to this file. Defaults to 'coverage.xml'", |
141 help="Write the XML report to this file. Defaults to 'coverage.xml'", |
120 ) |
142 ) |
121 output_json = optparse.make_option( |
143 output_json = optparse.make_option( |
122 '-o', '', action='store', dest="outfile", |
144 '-o', '', action='store', dest="outfile", metavar="OUTFILE", |
123 metavar="OUTFILE", |
|
124 help="Write the JSON report to this file. Defaults to 'coverage.json'", |
145 help="Write the JSON report to this file. Defaults to 'coverage.json'", |
|
146 ) |
|
147 output_lcov = optparse.make_option( |
|
148 '-o', '', action='store', dest='outfile', metavar="OUTFILE", |
|
149 help="Write the LCOV report to this file. Defaults to 'coverage.lcov'", |
125 ) |
150 ) |
126 json_pretty_print = optparse.make_option( |
151 json_pretty_print = optparse.make_option( |
127 '', '--pretty-print', action='store_true', |
152 '', '--pretty-print', action='store_true', |
128 help="Format the JSON for human readers.", |
153 help="Format the JSON for human readers.", |
129 ) |
154 ) |
130 parallel_mode = optparse.make_option( |
155 parallel_mode = optparse.make_option( |
131 '-p', '--parallel-mode', action='store_true', |
156 '-p', '--parallel-mode', action='store_true', |
132 help=( |
157 help=( |
133 "Append the machine name, process id and random number to the " + |
158 "Append the machine name, process id and random number to the " + |
134 ".coverage data file name to simplify collecting data from " + |
159 "data file name to simplify collecting data from " + |
135 "many processes." |
160 "many processes." |
136 ), |
161 ), |
137 ) |
162 ) |
138 precision = optparse.make_option( |
163 precision = optparse.make_option( |
139 '', '--precision', action='store', metavar='N', type=int, |
164 '', '--precision', action='store', metavar='N', type=int, |
170 '--skip-empty', action='store_true', |
195 '--skip-empty', action='store_true', |
171 help="Skip files with no code.", |
196 help="Skip files with no code.", |
172 ) |
197 ) |
173 sort = optparse.make_option( |
198 sort = optparse.make_option( |
174 '--sort', action='store', metavar='COLUMN', |
199 '--sort', action='store', metavar='COLUMN', |
175 help="Sort the report by the named column: name, stmts, miss, branch, brpart, or cover. " + |
200 help=( |
|
201 "Sort the report by the named column: name, stmts, miss, branch, brpart, or cover. " + |
176 "Default is name." |
202 "Default is name." |
|
203 ), |
177 ) |
204 ) |
178 source = optparse.make_option( |
205 source = optparse.make_option( |
179 '', '--source', action='store', metavar="SRC1,SRC2,...", |
206 '', '--source', action='store', metavar="SRC1,SRC2,...", |
180 help="A list of directories or importable names of code to measure.", |
207 help="A list of directories or importable names of code to measure.", |
181 ) |
208 ) |
362 "for diagnosing problems. " + |
398 "for diagnosing problems. " + |
363 "Topics are: " + |
399 "Topics are: " + |
364 "'data' to show a summary of the collected data; " + |
400 "'data' to show a summary of the collected data; " + |
365 "'sys' to show installation information; " + |
401 "'sys' to show installation information; " + |
366 "'config' to show the configuration; " + |
402 "'config' to show the configuration; " + |
367 "'premain' to show what is calling coverage." |
403 "'premain' to show what is calling coverage; " + |
|
404 "'pybehave' to show internal flags describing Python behavior." |
368 ), |
405 ), |
369 ), |
406 ), |
370 |
407 |
371 'erase': CmdOptionParser( |
408 'erase': CmdOptionParser( |
372 "erase", GLOBAL_ARGS, |
409 "erase", |
|
410 [ |
|
411 Opts.combine_datafile |
|
412 ] + GLOBAL_ARGS, |
373 description="Erase previously collected coverage data.", |
413 description="Erase previously collected coverage data.", |
374 ), |
414 ), |
375 |
415 |
376 'help': CmdOptionParser( |
416 'help': CmdOptionParser( |
377 "help", GLOBAL_ARGS, |
417 "help", GLOBAL_ARGS, |
435 Opts.skip_covered, |
493 Opts.skip_covered, |
436 Opts.no_skip_covered, |
494 Opts.no_skip_covered, |
437 Opts.skip_empty, |
495 Opts.skip_empty, |
438 ] + GLOBAL_ARGS, |
496 ] + GLOBAL_ARGS, |
439 usage="[options] [modules]", |
497 usage="[options] [modules]", |
440 description="Report coverage statistics on modules." |
498 description="Report coverage statistics on modules.", |
441 ), |
499 ), |
442 |
500 |
443 'run': CmdOptionParser( |
501 'run': CmdOptionParser( |
444 "run", |
502 "run", |
445 [ |
503 [ |
446 Opts.append, |
504 Opts.append, |
447 Opts.branch, |
505 Opts.branch, |
448 Opts.concurrency, |
506 Opts.concurrency, |
449 Opts.context, |
507 Opts.context, |
|
508 Opts.output_datafile, |
450 Opts.include, |
509 Opts.include, |
451 Opts.module, |
510 Opts.module, |
452 Opts.omit, |
511 Opts.omit, |
453 Opts.pylib, |
512 Opts.pylib, |
454 Opts.parallel_mode, |
513 Opts.parallel_mode, |
455 Opts.source, |
514 Opts.source, |
456 Opts.timid, |
515 Opts.timid, |
457 ] + GLOBAL_ARGS, |
516 ] + GLOBAL_ARGS, |
458 usage="[options] <pyfile> [program options]", |
517 usage="[options] <pyfile> [program options]", |
459 description="Run a Python program, measuring code execution." |
518 description="Run a Python program, measuring code execution.", |
460 ), |
519 ), |
461 |
520 |
462 'xml': CmdOptionParser( |
521 'xml': CmdOptionParser( |
463 "xml", |
522 "xml", |
464 [ |
523 [ |
|
524 Opts.input_datafile, |
465 Opts.fail_under, |
525 Opts.fail_under, |
466 Opts.ignore_errors, |
526 Opts.ignore_errors, |
467 Opts.include, |
527 Opts.include, |
468 Opts.omit, |
528 Opts.omit, |
469 Opts.output_xml, |
529 Opts.output_xml, |
470 Opts.quiet, |
530 Opts.quiet, |
471 Opts.skip_empty, |
531 Opts.skip_empty, |
472 ] + GLOBAL_ARGS, |
532 ] + GLOBAL_ARGS, |
473 usage="[options] [modules]", |
533 usage="[options] [modules]", |
474 description="Generate an XML report of coverage results." |
534 description="Generate an XML report of coverage results.", |
475 ), |
535 ), |
476 } |
536 } |
477 |
537 |
478 |
538 |
479 def show_help(error=None, topic=None, parser=None): |
539 def show_help(error=None, topic=None, parser=None): |
623 self.coverage.load() |
684 self.coverage.load() |
624 |
685 |
625 total = None |
686 total = None |
626 if options.action == "report": |
687 if options.action == "report": |
627 total = self.coverage.report( |
688 total = self.coverage.report( |
|
689 precision=options.precision, |
628 show_missing=options.show_missing, |
690 show_missing=options.show_missing, |
629 skip_covered=options.skip_covered, |
691 skip_covered=options.skip_covered, |
630 skip_empty=options.skip_empty, |
692 skip_empty=options.skip_empty, |
631 precision=options.precision, |
|
632 sort=options.sort, |
693 sort=options.sort, |
633 **report_args |
694 **report_args |
634 ) |
695 ) |
635 elif options.action == "annotate": |
696 elif options.action == "annotate": |
636 self.coverage.annotate(directory=options.directory, **report_args) |
697 self.coverage.annotate(directory=options.directory, **report_args) |
637 elif options.action == "html": |
698 elif options.action == "html": |
638 total = self.coverage.html_report( |
699 total = self.coverage.html_report( |
639 directory=options.directory, |
700 directory=options.directory, |
640 title=options.title, |
701 precision=options.precision, |
641 skip_covered=options.skip_covered, |
702 skip_covered=options.skip_covered, |
642 skip_empty=options.skip_empty, |
703 skip_empty=options.skip_empty, |
643 show_contexts=options.show_contexts, |
704 show_contexts=options.show_contexts, |
644 precision=options.precision, |
705 title=options.title, |
645 **report_args |
706 **report_args |
646 ) |
707 ) |
647 elif options.action == "xml": |
708 elif options.action == "xml": |
648 outfile = options.outfile |
|
649 total = self.coverage.xml_report( |
709 total = self.coverage.xml_report( |
650 outfile=outfile, skip_empty=options.skip_empty, |
710 outfile=options.outfile, |
|
711 skip_empty=options.skip_empty, |
651 **report_args |
712 **report_args |
652 ) |
713 ) |
653 elif options.action == "json": |
714 elif options.action == "json": |
654 outfile = options.outfile |
|
655 total = self.coverage.json_report( |
715 total = self.coverage.json_report( |
656 outfile=outfile, |
716 outfile=options.outfile, |
657 pretty_print=options.pretty_print, |
717 pretty_print=options.pretty_print, |
658 show_contexts=options.show_contexts, |
718 show_contexts=options.show_contexts, |
659 **report_args |
719 **report_args |
660 ) |
720 ) |
|
721 elif options.action == "lcov": |
|
722 total = self.coverage.lcov_report( |
|
723 outfile=options.outfile, |
|
724 **report_args |
|
725 ) |
661 else: |
726 else: |
662 # There are no other possible actions. |
727 # There are no other possible actions. |
663 raise AssertionError |
728 raise AssertionError |
664 |
729 |
665 if total is not None: |
730 if total is not None: |
666 # Apply the command line fail-under options, and then use the config |
731 # Apply the command line fail-under options, and then use the config |
667 # value, so we can get fail_under from the config file. |
732 # value, so we can get fail_under from the config file. |
668 if options.fail_under is not None: |
733 if options.fail_under is not None: |
669 self.coverage.set_option("report:fail_under", options.fail_under) |
734 self.coverage.set_option("report:fail_under", options.fail_under) |
|
735 if options.precision is not None: |
|
736 self.coverage.set_option("report:precision", options.precision) |
670 |
737 |
671 fail_under = self.coverage.get_option("report:fail_under") |
738 fail_under = self.coverage.get_option("report:fail_under") |
672 precision = self.coverage.get_option("report:precision") |
739 precision = self.coverage.get_option("report:precision") |
673 if should_fail_under(total, fail_under, precision): |
740 if should_fail_under(total, fail_under, precision): |
674 msg = "total of {total} is less than fail-under={fail_under:.{p}f}".format( |
741 msg = "total of {total} is less than fail-under={fail_under:.{p}f}".format( |
775 |
842 |
776 def do_debug(self, args): |
843 def do_debug(self, args): |
777 """Implementation of 'coverage debug'.""" |
844 """Implementation of 'coverage debug'.""" |
778 |
845 |
779 if not args: |
846 if not args: |
780 show_help("What information would you like: config, data, sys, premain?") |
847 show_help("What information would you like: config, data, sys, premain, pybehave?") |
781 return ERR |
848 return ERR |
782 if args[1:]: |
849 if args[1:]: |
783 show_help("Only one topic at a time, please") |
850 show_help("Only one topic at a time, please") |
784 return ERR |
851 return ERR |
785 |
852 |
786 if args[0] == 'sys': |
853 if args[0] == "sys": |
787 sys_info = self.coverage.sys_info() |
854 write_formatted_info(print, "sys", self.coverage.sys_info()) |
788 print(info_header("sys")) |
855 elif args[0] == "data": |
789 for line in info_formatter(sys_info): |
|
790 print(f" {line}") |
|
791 elif args[0] == 'data': |
|
792 print(info_header("data")) |
856 print(info_header("data")) |
793 data_file = self.coverage.config.data_file |
857 data_file = self.coverage.config.data_file |
794 debug_data_file(data_file) |
858 debug_data_file(data_file) |
795 for filename in combinable_files(data_file): |
859 for filename in combinable_files(data_file): |
796 print("-----") |
860 print("-----") |
797 debug_data_file(filename) |
861 debug_data_file(filename) |
798 elif args[0] == 'config': |
862 elif args[0] == "config": |
799 print(info_header("config")) |
863 write_formatted_info(print, "config", self.coverage.config.debug_info()) |
800 config_info = sorted(self.coverage.config.__dict__.items()) |
|
801 for line in info_formatter(config_info): |
|
802 print(f" {line}") |
|
803 elif args[0] == "premain": |
864 elif args[0] == "premain": |
804 print(info_header("premain")) |
865 print(info_header("premain")) |
805 print(short_stack()) |
866 print(short_stack()) |
|
867 elif args[0] == "pybehave": |
|
868 write_formatted_info(print, "pybehave", env.debug_info()) |
806 else: |
869 else: |
807 show_help(f"Don't know what you mean by {args[0]!r}") |
870 show_help(f"Don't know what you mean by {args[0]!r}") |
808 return ERR |
871 return ERR |
809 |
872 |
810 return OK |
873 return OK |
850 debug Display information about the internals of coverage.py |
913 debug Display information about the internals of coverage.py |
851 erase Erase previously collected coverage data. |
914 erase Erase previously collected coverage data. |
852 help Get help on using coverage.py. |
915 help Get help on using coverage.py. |
853 html Create an HTML report. |
916 html Create an HTML report. |
854 json Create a JSON report of coverage results. |
917 json Create a JSON report of coverage results. |
|
918 lcov Create an LCOV report of coverage results. |
855 report Report coverage stats on modules. |
919 report Report coverage stats on modules. |
856 run Run a Python program and measure code execution. |
920 run Run a Python program and measure code execution. |
857 xml Create an XML report of coverage results. |
921 xml Create an XML report of coverage results. |
858 |
922 |
859 Use "{program_name} help <command>" for detailed help on any command. |
923 Use "{program_name} help <command>" for detailed help on any command. |