1 """Command-line support for Coverage.""" |
1 """Command-line support for Coverage.""" |
2 |
2 |
3 import getopt, sys |
3 import optparse, re, sys |
4 |
4 |
5 from execfile import run_python_file |
5 from coverage.execfile import run_python_file |
6 |
6 from coverage.misc import CoverageException |
7 USAGE = r""" |
7 |
8 Coverage version %(__version__)s |
8 |
|
9 class Opts(object): |
|
10 """A namespace class for individual options we'll build parsers from.""" |
|
11 |
|
12 append = optparse.Option( |
|
13 '-a', '--append', action='store_false', dest="erase_first", |
|
14 help="Append coverage data to .coverage, otherwise it is started " |
|
15 "clean with each run." |
|
16 ) |
|
17 branch = optparse.Option( |
|
18 '', '--branch', action='store_true', |
|
19 help="Measure branch coverage in addition to statement coverage." |
|
20 ) |
|
21 directory = optparse.Option( |
|
22 '-d', '--directory', action='store', |
|
23 metavar="DIR", |
|
24 help="Write the output files to DIR." |
|
25 ) |
|
26 help = optparse.Option( |
|
27 '-h', '--help', action='store_true', |
|
28 help="Get help on this command." |
|
29 ) |
|
30 ignore_errors = optparse.Option( |
|
31 '-i', '--ignore-errors', action='store_true', |
|
32 help="Ignore errors while reading source files." |
|
33 ) |
|
34 pylib = optparse.Option( |
|
35 '-L', '--pylib', action='store_true', |
|
36 help="Measure coverage even inside the Python installed library, " |
|
37 "which isn't done by default." |
|
38 ) |
|
39 show_missing = optparse.Option( |
|
40 '-m', '--show-missing', action='store_true', |
|
41 help="Show line numbers of statements in each module that weren't " |
|
42 "executed." |
|
43 ) |
|
44 old_omit = optparse.Option( |
|
45 '-o', '--omit', action='store', |
|
46 metavar="PRE1,PRE2,...", |
|
47 help="Omit files when their filename path starts with one of these " |
|
48 "prefixes." |
|
49 ) |
|
50 omit = optparse.Option( |
|
51 '', '--omit', action='store', |
|
52 metavar="PRE1,PRE2,...", |
|
53 help="Omit files when their filename path starts with one of these " |
|
54 "prefixes." |
|
55 ) |
|
56 output_xml = optparse.Option( |
|
57 '-o', '', action='store', dest="outfile", |
|
58 metavar="OUTFILE", |
|
59 help="Write the XML report to this file. Defaults to 'coverage.xml'" |
|
60 ) |
|
61 parallel_mode = optparse.Option( |
|
62 '-p', '--parallel-mode', action='store_true', |
|
63 help="Include the machine name and process id in the .coverage " |
|
64 "data file name." |
|
65 ) |
|
66 timid = optparse.Option( |
|
67 '', '--timid', action='store_true', |
|
68 help="Use a simpler but slower trace method. Try this if you get " |
|
69 "seemingly impossible results!" |
|
70 ) |
|
71 version = optparse.Option( |
|
72 '', '--version', action='store_true', |
|
73 help="Display version information and exit." |
|
74 ) |
|
75 |
|
76 |
|
77 class CoverageOptionParser(optparse.OptionParser, object): |
|
78 """Base OptionParser for coverage. |
|
79 |
|
80 Problems don't exit the program. |
|
81 Defaults are initialized for all options. |
|
82 |
|
83 """ |
|
84 |
|
85 def __init__(self, *args, **kwargs): |
|
86 super(CoverageOptionParser, self).__init__( |
|
87 add_help_option=False, *args, **kwargs |
|
88 ) |
|
89 self.set_defaults( |
|
90 actions=[], |
|
91 branch=None, |
|
92 directory=None, |
|
93 help=None, |
|
94 ignore_errors=None, |
|
95 omit=None, |
|
96 parallel_mode=None, |
|
97 pylib=None, |
|
98 show_missing=None, |
|
99 timid=None, |
|
100 erase_first=None, |
|
101 version=None, |
|
102 ) |
|
103 |
|
104 self.disable_interspersed_args() |
|
105 self.help_fn = lambda: None |
|
106 |
|
107 class OptionParserError(Exception): |
|
108 """Used to stop the optparse error handler ending the process.""" |
|
109 pass |
|
110 |
|
111 def parse_args(self, args=None, options=None): |
|
112 """Call optparse.parse_args, but return a triple: |
|
113 |
|
114 (ok, options, args) |
|
115 |
|
116 """ |
|
117 try: |
|
118 options, args = \ |
|
119 super(CoverageOptionParser, self).parse_args(args, options) |
|
120 except self.OptionParserError: |
|
121 return False, None, None |
|
122 return True, options, args |
|
123 |
|
124 def error(self, msg): |
|
125 """Override optparse.error so sys.exit doesn't get called.""" |
|
126 self.help_fn(msg) |
|
127 raise self.OptionParserError |
|
128 |
|
129 |
|
130 class ClassicOptionParser(CoverageOptionParser): |
|
131 """Command-line parser for coverage.py classic arguments.""" |
|
132 |
|
133 def __init__(self): |
|
134 super(ClassicOptionParser, self).__init__() |
|
135 |
|
136 self.add_action('-a', '--annotate', 'annotate') |
|
137 self.add_action('-b', '--html', 'html') |
|
138 self.add_action('-c', '--combine', 'combine') |
|
139 self.add_action('-e', '--erase', 'erase') |
|
140 self.add_action('-r', '--report', 'report') |
|
141 self.add_action('-x', '--execute', 'execute') |
|
142 |
|
143 self.add_options([ |
|
144 Opts.directory, |
|
145 Opts.help, |
|
146 Opts.ignore_errors, |
|
147 Opts.pylib, |
|
148 Opts.show_missing, |
|
149 Opts.old_omit, |
|
150 Opts.parallel_mode, |
|
151 Opts.timid, |
|
152 Opts.version, |
|
153 ]) |
|
154 |
|
155 def add_action(self, dash, dashdash, action_code): |
|
156 """Add a specialized option that is the action to execute.""" |
|
157 option = self.add_option(dash, dashdash, action='callback', |
|
158 callback=self._append_action |
|
159 ) |
|
160 option.action_code = action_code |
|
161 |
|
162 def _append_action(self, option, opt_unused, value_unused, parser): |
|
163 """Callback for an option that adds to the `actions` list.""" |
|
164 parser.values.actions.append(option.action_code) |
|
165 |
|
166 |
|
167 class CmdOptionParser(CoverageOptionParser): |
|
168 """Parse one of the new-style commands for coverage.py.""" |
|
169 |
|
170 def __init__(self, action, options=None, defaults=None, usage=None, |
|
171 cmd=None, description=None |
|
172 ): |
|
173 """Create an OptionParser for a coverage command. |
|
174 |
|
175 `action` is the slug to put into `options.actions`. |
|
176 `options` is a list of Option's for the command. |
|
177 `defaults` is a dict of default value for options. |
|
178 `usage` is the usage string to display in help. |
|
179 `cmd` is the command name, if different than `action`. |
|
180 `description` is the description of the command, for the help text. |
|
181 |
|
182 """ |
|
183 if usage: |
|
184 usage = "%prog " + usage |
|
185 super(CmdOptionParser, self).__init__( |
|
186 prog="coverage %s" % (cmd or action), |
|
187 usage=usage, |
|
188 description=description, |
|
189 ) |
|
190 self.set_defaults(actions=[action], **(defaults or {})) |
|
191 if options: |
|
192 self.add_options(options) |
|
193 self.cmd = cmd or action |
|
194 |
|
195 def __eq__(self, other): |
|
196 # A convenience equality, so that I can put strings in unit test |
|
197 # results, and they will compare equal to objects. |
|
198 return (other == "<CmdOptionParser:%s>" % self.cmd) |
|
199 |
|
200 |
|
201 CMDS = { |
|
202 'annotate': CmdOptionParser("annotate", |
|
203 [ |
|
204 Opts.directory, |
|
205 Opts.ignore_errors, |
|
206 Opts.omit, |
|
207 Opts.help, |
|
208 ], |
|
209 usage = "[options] [modules]", |
|
210 description = "Make annotated copies of the given files, marking " |
|
211 "statements that are executed with > and statements that are " |
|
212 "missed with !." |
|
213 ), |
|
214 |
|
215 'help': CmdOptionParser("help", [Opts.help], |
|
216 usage = "[command]", |
|
217 description = "Describe how to use coverage.py" |
|
218 ), |
|
219 |
|
220 'html': CmdOptionParser("html", |
|
221 [ |
|
222 Opts.directory, |
|
223 Opts.ignore_errors, |
|
224 Opts.omit, |
|
225 Opts.help, |
|
226 ], |
|
227 usage = "[options] [modules]", |
|
228 description = "Create an HTML report of the coverage of the files. " |
|
229 "Each file gets its own page, with the source decorated to show " |
|
230 "executed, excluded, and missed lines." |
|
231 ), |
|
232 |
|
233 'combine': CmdOptionParser("combine", [Opts.help], |
|
234 usage = " ", |
|
235 description = "Combine data from multiple coverage files collected " |
|
236 "with 'run -p'. The combined results are written to a single " |
|
237 "file representing the union of the data." |
|
238 ), |
|
239 |
|
240 'debug': CmdOptionParser("debug", [Opts.help], |
|
241 usage = "<topic>", |
|
242 description = "Display information on the internals of coverage.py, " |
|
243 "for diagnosing problems. " |
|
244 "Topics are 'data' to show a summary of the collected data, " |
|
245 "or 'sys' to show installation information." |
|
246 ), |
|
247 |
|
248 'erase': CmdOptionParser("erase", [Opts.help], |
|
249 usage = " ", |
|
250 description = "Erase previously collected coverage data." |
|
251 ), |
|
252 |
|
253 'report': CmdOptionParser("report", |
|
254 [ |
|
255 Opts.ignore_errors, |
|
256 Opts.omit, |
|
257 Opts.show_missing, |
|
258 Opts.help, |
|
259 ], |
|
260 usage = "[options] [modules]", |
|
261 description = "Report coverage statistics on modules." |
|
262 ), |
|
263 |
|
264 'run': CmdOptionParser("execute", |
|
265 [ |
|
266 Opts.append, |
|
267 Opts.branch, |
|
268 Opts.pylib, |
|
269 Opts.parallel_mode, |
|
270 Opts.timid, |
|
271 Opts.help, |
|
272 ], |
|
273 defaults = {'erase_first': True}, |
|
274 cmd = "run", |
|
275 usage = "[options] <pyfile> [program options]", |
|
276 description = "Run a Python program, measuring code execution." |
|
277 ), |
|
278 |
|
279 'xml': CmdOptionParser("xml", |
|
280 [ |
|
281 Opts.ignore_errors, |
|
282 Opts.omit, |
|
283 Opts.output_xml, |
|
284 Opts.help, |
|
285 ], |
|
286 cmd = "xml", |
|
287 defaults = {'outfile': 'coverage.xml'}, |
|
288 usage = "[options] [modules]", |
|
289 description = "Generate an XML report of coverage results." |
|
290 ), |
|
291 } |
|
292 |
|
293 |
|
294 OK, ERR = 0, 1 |
|
295 |
|
296 |
|
297 class CoverageScript(object): |
|
298 """The command-line interface to Coverage.""" |
|
299 |
|
300 def __init__(self, _covpkg=None, _run_python_file=None, _help_fn=None): |
|
301 # _covpkg is for dependency injection, so we can test this code. |
|
302 if _covpkg: |
|
303 self.covpkg = _covpkg |
|
304 else: |
|
305 import coverage |
|
306 self.covpkg = coverage |
|
307 |
|
308 # _run_python_file is for dependency injection also. |
|
309 self.run_python_file = _run_python_file or run_python_file |
|
310 |
|
311 # _help_fn is for dependency injection. |
|
312 self.help_fn = _help_fn or self.help |
|
313 |
|
314 self.coverage = None |
|
315 |
|
316 def help(self, error=None, topic=None, parser=None): |
|
317 """Display an error message, or the named topic.""" |
|
318 assert error or topic or parser |
|
319 if error: |
|
320 print(error) |
|
321 print("Use 'coverage help' for help.") |
|
322 elif parser: |
|
323 print(parser.format_help().strip()) |
|
324 else: |
|
325 # Parse out the topic we want from HELP_TOPICS |
|
326 topic_list = re.split("(?m)^=+ (\w+) =+$", HELP_TOPICS) |
|
327 topics = dict(zip(topic_list[1::2], topic_list[2::2])) |
|
328 help_msg = topics.get(topic, '').strip() |
|
329 if help_msg: |
|
330 print(help_msg % self.covpkg.__dict__) |
|
331 else: |
|
332 print("Don't know topic %r" % topic) |
|
333 |
|
334 def command_line(self, argv): |
|
335 """The bulk of the command line interface to Coverage. |
|
336 |
|
337 `argv` is the argument list to process. |
|
338 |
|
339 Returns 0 if all is well, 1 if something went wrong. |
|
340 |
|
341 """ |
|
342 # Collect the command-line options. |
|
343 |
|
344 if not argv: |
|
345 self.help_fn(topic='minimum_help') |
|
346 return OK |
|
347 |
|
348 # The command syntax we parse depends on the first argument. Classic |
|
349 # syntax always starts with an option. |
|
350 classic = argv[0].startswith('-') |
|
351 if classic: |
|
352 parser = ClassicOptionParser() |
|
353 else: |
|
354 parser = CMDS.get(argv[0]) |
|
355 if not parser: |
|
356 self.help_fn("Unknown command: '%s'" % argv[0]) |
|
357 return ERR |
|
358 argv = argv[1:] |
|
359 |
|
360 parser.help_fn = self.help_fn |
|
361 ok, options, args = parser.parse_args(argv) |
|
362 if not ok: |
|
363 return ERR |
|
364 |
|
365 # Handle help. |
|
366 if options.help: |
|
367 if classic: |
|
368 self.help_fn(topic='help') |
|
369 else: |
|
370 self.help_fn(parser=parser) |
|
371 return OK |
|
372 |
|
373 if "help" in options.actions: |
|
374 if args: |
|
375 for a in args: |
|
376 parser = CMDS.get(a) |
|
377 if parser: |
|
378 self.help_fn(parser=parser) |
|
379 else: |
|
380 self.help_fn(topic=a) |
|
381 else: |
|
382 self.help_fn(topic='help') |
|
383 return OK |
|
384 |
|
385 # Handle version. |
|
386 if options.version: |
|
387 self.help_fn(topic='version') |
|
388 return OK |
|
389 |
|
390 # Check for conflicts and problems in the options. |
|
391 for i in ['erase', 'execute']: |
|
392 for j in ['annotate', 'html', 'report', 'combine']: |
|
393 if (i in options.actions) and (j in options.actions): |
|
394 self.help_fn("You can't specify the '%s' and '%s' " |
|
395 "options at the same time." % (i, j)) |
|
396 return ERR |
|
397 |
|
398 if not options.actions: |
|
399 self.help_fn( |
|
400 "You must specify at least one of -e, -x, -c, -r, -a, or -b." |
|
401 ) |
|
402 return ERR |
|
403 args_allowed = ( |
|
404 'execute' in options.actions or |
|
405 'annotate' in options.actions or |
|
406 'html' in options.actions or |
|
407 'debug' in options.actions or |
|
408 'report' in options.actions or |
|
409 'xml' in options.actions |
|
410 ) |
|
411 if not args_allowed and args: |
|
412 self.help_fn("Unexpected arguments: %s" % " ".join(args)) |
|
413 return ERR |
|
414 |
|
415 if 'execute' in options.actions and not args: |
|
416 self.help_fn("Nothing to do.") |
|
417 return ERR |
|
418 |
|
419 # Do something. |
|
420 self.coverage = self.covpkg.coverage( |
|
421 data_suffix = bool(options.parallel_mode), |
|
422 cover_pylib = options.pylib, |
|
423 timid = options.timid, |
|
424 branch = options.branch, |
|
425 ) |
|
426 |
|
427 if 'debug' in options.actions: |
|
428 if not args: |
|
429 self.help_fn("What information would you like: data, sys?") |
|
430 return ERR |
|
431 for info in args: |
|
432 if info == 'sys': |
|
433 print("-- sys ----------------------------------------") |
|
434 for label, info in self.coverage.sysinfo(): |
|
435 if isinstance(info, list): |
|
436 print("%15s:" % label) |
|
437 for e in info: |
|
438 print("%15s %s" % ("", e)) |
|
439 else: |
|
440 print("%15s: %s" % (label, info)) |
|
441 elif info == 'data': |
|
442 print("-- data ---------------------------------------") |
|
443 self.coverage.load() |
|
444 print("path: %s" % self.coverage.data.filename) |
|
445 print("has_arcs: %r" % self.coverage.data.has_arcs()) |
|
446 summary = self.coverage.data.summary(fullpath=True) |
|
447 if summary: |
|
448 filenames = sorted(summary.keys()) |
|
449 print("\n%d files:" % len(filenames)) |
|
450 for f in filenames: |
|
451 print("%s: %d lines" % (f, summary[f])) |
|
452 else: |
|
453 print("No data collected") |
|
454 else: |
|
455 self.help_fn("Don't know what you mean by %r" % info) |
|
456 return ERR |
|
457 return OK |
|
458 |
|
459 if 'erase' in options.actions or options.erase_first: |
|
460 self.coverage.erase() |
|
461 else: |
|
462 self.coverage.load() |
|
463 |
|
464 if 'execute' in options.actions: |
|
465 # Run the script. |
|
466 self.coverage.start() |
|
467 try: |
|
468 self.run_python_file(args[0], args) |
|
469 finally: |
|
470 self.coverage.stop() |
|
471 self.coverage.save() |
|
472 |
|
473 if 'combine' in options.actions: |
|
474 self.coverage.combine() |
|
475 self.coverage.save() |
|
476 |
|
477 # Remaining actions are reporting, with some common options. |
|
478 report_args = { |
|
479 'morfs': args, |
|
480 'ignore_errors': options.ignore_errors, |
|
481 } |
|
482 |
|
483 omit = None |
|
484 if options.omit: |
|
485 omit = options.omit.split(',') |
|
486 report_args['omit_prefixes'] = omit |
|
487 |
|
488 if 'report' in options.actions: |
|
489 self.coverage.report( |
|
490 show_missing=options.show_missing, **report_args) |
|
491 if 'annotate' in options.actions: |
|
492 self.coverage.annotate( |
|
493 directory=options.directory, **report_args) |
|
494 if 'html' in options.actions: |
|
495 self.coverage.html_report( |
|
496 directory=options.directory, **report_args) |
|
497 if 'xml' in options.actions: |
|
498 outfile = options.outfile |
|
499 if outfile == '-': |
|
500 outfile = None |
|
501 self.coverage.xml_report(outfile=outfile, **report_args) |
|
502 |
|
503 return OK |
|
504 |
|
505 |
|
506 HELP_TOPICS = r""" |
|
507 |
|
508 == classic ==================================================================== |
|
509 Coverage.py version %(__version__)s |
9 Measure, collect, and report on code coverage in Python programs. |
510 Measure, collect, and report on code coverage in Python programs. |
10 |
511 |
11 Usage: |
512 Usage: |
12 |
513 |
13 coverage -x [-p] [-L] MODULE.py [ARG1 ARG2 ...] |
514 coverage -x [-p] [-L] [--timid] MODULE.py [ARG1 ARG2 ...] |
14 Execute the module, passing the given command-line arguments, collecting |
515 Execute the module, passing the given command-line arguments, collecting |
15 coverage data. With the -p option, include the machine name and process |
516 coverage data. With the -p option, include the machine name and process |
16 ID in the .coverage file name. With -L, measure coverage even inside the |
517 id in the .coverage file name. With -L, measure coverage even inside the |
17 Python installed library, which isn't done by default. |
518 Python installed library, which isn't done by default. With --timid, use a |
|
519 simpler but slower trace method. |
18 |
520 |
19 coverage -e |
521 coverage -e |
20 Erase collected coverage data. |
522 Erase collected coverage data. |
21 |
523 |
22 coverage -c |
524 coverage -c |
44 -o DIR,... |
546 -o DIR,... |
45 Omit reporting or annotating files when their filename path starts with |
547 Omit reporting or annotating files when their filename path starts with |
46 a directory listed in the omit list. |
548 a directory listed in the omit list. |
47 e.g. coverage -i -r -o c:\python25,lib\enthought\traits |
549 e.g. coverage -i -r -o c:\python25,lib\enthought\traits |
48 |
550 |
49 -h Print this help. |
|
50 |
|
51 Coverage data is saved in the file .coverage by default. Set the |
551 Coverage data is saved in the file .coverage by default. Set the |
52 COVERAGE_FILE environment variable to save it somewhere else. |
552 COVERAGE_FILE environment variable to save it somewhere else. |
53 """.strip() |
553 |
54 |
554 == help ======================================================================= |
55 |
555 Coverage.py, version %(__version__)s |
56 class CoverageScript: |
556 Measure, collect, and report on code coverage in Python programs. |
57 """The command-line interface to Coverage.""" |
557 |
58 |
558 usage: coverage <command> [options] [args] |
59 def __init__(self): |
559 |
60 import coverage |
560 Commands: |
61 self.covpkg = coverage |
561 annotate Annotate source files with execution information. |
62 self.coverage = None |
562 combine Combine a number of data files. |
63 |
563 erase Erase previously collected coverage data. |
64 def help(self, error=None): |
564 help Get help on using coverage.py. |
65 """Display an error message, or the usage for Coverage.""" |
565 html Create an HTML report. |
66 if error: |
566 report Report coverage stats on modules. |
67 print error |
567 run Run a Python program and measure code execution. |
68 print "Use -h for help." |
568 xml Create an XML report of coverage results. |
69 else: |
569 |
70 print USAGE % self.covpkg.__dict__ |
570 Use "coverage help <command>" for detailed help on any command. |
71 |
571 Use "coverage help classic" for help on older command syntax. |
72 def command_line(self, argv, help_fn=None): |
572 For more information, see %(__url__)s |
73 """The bulk of the command line interface to Coverage. |
573 |
74 |
574 == minimum_help =============================================================== |
75 `argv` is the argument list to process. |
575 Code coverage for Python. Use 'coverage help' for help. |
76 `help_fn` is the help function to use when something goes wrong. |
576 |
77 |
577 == version ==================================================================== |
78 """ |
578 Coverage.py, version %(__version__)s. %(__url__)s |
79 # Collect the command-line options. |
579 |
80 help_fn = help_fn or self.help |
580 """ |
81 OK, ERR = 0, 1 |
581 |
82 settings = {} |
|
83 optmap = { |
|
84 '-a': 'annotate', |
|
85 '-b': 'html', |
|
86 '-c': 'combine', |
|
87 '-d:': 'directory=', |
|
88 '-e': 'erase', |
|
89 '-h': 'help', |
|
90 '-i': 'ignore-errors', |
|
91 '-L': 'pylib', |
|
92 '-m': 'show-missing', |
|
93 '-p': 'parallel-mode', |
|
94 '-r': 'report', |
|
95 '-x': 'execute', |
|
96 '-o:': 'omit=', |
|
97 } |
|
98 short_opts = ''.join([o[1:] for o in optmap.keys()]) |
|
99 long_opts = optmap.values() |
|
100 options, args = getopt.getopt(argv, short_opts, long_opts) |
|
101 for o, a in options: |
|
102 if optmap.has_key(o): |
|
103 settings[optmap[o]] = True |
|
104 elif optmap.has_key(o + ':'): |
|
105 settings[optmap[o + ':']] = a |
|
106 elif o[2:] in long_opts: |
|
107 settings[o[2:]] = True |
|
108 elif o[2:] + '=' in long_opts: |
|
109 settings[o[2:]+'='] = a |
|
110 |
|
111 if settings.get('help'): |
|
112 help_fn() |
|
113 return OK |
|
114 |
|
115 # Check for conflicts and problems in the options. |
|
116 for i in ['erase', 'execute']: |
|
117 for j in ['annotate', 'html', 'report', 'combine']: |
|
118 if settings.get(i) and settings.get(j): |
|
119 help_fn("You can't specify the '%s' and '%s' " |
|
120 "options at the same time." % (i, j)) |
|
121 return ERR |
|
122 |
|
123 args_needed = (settings.get('execute') |
|
124 or settings.get('annotate') |
|
125 or settings.get('html') |
|
126 or settings.get('report')) |
|
127 action = (settings.get('erase') |
|
128 or settings.get('combine') |
|
129 or args_needed) |
|
130 if not action: |
|
131 help_fn( |
|
132 "You must specify at least one of -e, -x, -c, -r, -a, or -b." |
|
133 ) |
|
134 return ERR |
|
135 if not args_needed and args: |
|
136 help_fn("Unexpected arguments: %s" % " ".join(args)) |
|
137 return ERR |
|
138 |
|
139 # Do something. |
|
140 self.coverage = self.covpkg.coverage( |
|
141 data_suffix = bool(settings.get('parallel-mode')), |
|
142 cover_pylib = settings.get('pylib') |
|
143 ) |
|
144 |
|
145 if settings.get('erase'): |
|
146 self.coverage.erase() |
|
147 else: |
|
148 self.coverage.load() |
|
149 |
|
150 if settings.get('execute'): |
|
151 if not args: |
|
152 help_fn("Nothing to do.") |
|
153 return ERR |
|
154 |
|
155 # Run the script. |
|
156 self.coverage.start() |
|
157 try: |
|
158 run_python_file(args[0], args) |
|
159 finally: |
|
160 self.coverage.stop() |
|
161 self.coverage.save() |
|
162 |
|
163 if settings.get('combine'): |
|
164 self.coverage.combine() |
|
165 self.coverage.save() |
|
166 |
|
167 # Remaining actions are reporting, with some common options. |
|
168 show_missing = settings.get('show-missing') |
|
169 directory = settings.get('directory=') |
|
170 report_args = { |
|
171 'morfs': args, |
|
172 'ignore_errors': settings.get('ignore-errors'), |
|
173 } |
|
174 |
|
175 omit = settings.get('omit=') |
|
176 if omit: |
|
177 omit = omit.split(',') |
|
178 report_args['omit_prefixes'] = omit |
|
179 |
|
180 if settings.get('report'): |
|
181 self.coverage.report(show_missing=show_missing, **report_args) |
|
182 if settings.get('annotate'): |
|
183 self.coverage.annotate(directory=directory, **report_args) |
|
184 if settings.get('html'): |
|
185 self.coverage.html_report(directory=directory, **report_args) |
|
186 |
|
187 return OK |
|
188 |
|
189 |
582 |
190 def main(): |
583 def main(): |
191 """The main entrypoint to Coverage. |
584 """The main entrypoint to Coverage. |
192 |
585 |
193 This is installed as the script entrypoint. |
586 This is installed as the script entrypoint. |
194 |
587 |
195 """ |
588 """ |
196 return CoverageScript().command_line(sys.argv[1:]) |
589 try: |
|
590 status = CoverageScript().command_line(sys.argv[1:]) |
|
591 except CoverageException: |
|
592 _, err, _ = sys.exc_info() |
|
593 print(err) |
|
594 status = ERR |
|
595 return status |