1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
|
"""Command-line support for Coverage."""
import optparse, sys
from coverage.execfile import run_python_file
USAGE = r"""
Coverage version %(__version__)s
Measure, collect, and report on code coverage in Python programs.
Usage:
coverage -x [-p] [-L] [--timid] MODULE.py [ARG1 ARG2 ...]
Execute the module, passing the given command-line arguments, collecting
coverage data. With the -p option, include the machine name and process
id in the .coverage file name. With -L, measure coverage even inside the
Python installed library, which isn't done by default. With --timid, use a
simpler but slower trace method.
coverage -e
Erase collected coverage data.
coverage -c
Combine data from multiple coverage files (as created by -p option above)
and store it into a single file representing the union of the coverage.
coverage -r [-m] [-i] [-o DIR,...] [FILE1 FILE2 ...]
Report on the statement coverage for the given files. With the -m
option, show line numbers of the statements that weren't executed.
coverage -b -d DIR [-i] [-o DIR,...] [FILE1 FILE2 ...]
Create an HTML report of the coverage of the given files. Each file gets
its own page, with the file listing decorated to show executed, excluded,
and missed lines.
coverage -a [-d DIR] [-i] [-o DIR,...] [FILE1 FILE2 ...]
Make annotated copies of the given files, marking statements that
are executed with > and statements that are missed with !.
-d DIR
Write output files for -b or -a to this directory.
-i Ignore errors while reporting or annotating.
-o DIR,...
Omit reporting or annotating files when their filename path starts with
a directory listed in the omit list.
e.g. coverage -i -r -o c:\python25,lib\enthought\traits
-h Print this help.
Coverage data is saved in the file .coverage by default. Set the
COVERAGE_FILE environment variable to save it somewhere else.
""".strip()
class OptionParser(optparse.OptionParser, object):
"""Command-line parser for this coverage.py."""
def __init__(self, help_fn, *args, **kwargs):
super(OptionParser, self).__init__(
add_help_option=False,
*args, **kwargs)
self.help_fn = help_fn
self.set_defaults(actions=[])
self.disable_interspersed_args()
self.add_option(
'-a', '--annotate',
action='callback', callback=self.append_action, callback_args=('annotate',),
)
self.add_option(
'-b', '--html',
action='callback', callback=self.append_action, callback_args=('html',),
)
self.add_option(
'-c', '--combine',
action='callback', callback=self.append_action, callback_args=('combine',),
)
self.add_option(
'-d', '--directory',
action='store', dest='directory',
)
self.add_option(
'-e', '--erase',
action='callback', callback=self.append_action, callback_args=('erase',),
)
self.add_option(
'-h', '--help',
action='store_true', dest='help',
)
self.add_option(
'-i', '--ignore-errors',
action='store_true',
)
self.add_option(
'-L', '--pylib',
action='store_true',
)
self.add_option(
'-m', '--show-missing',
action='store_true',
)
self.add_option(
'-p', '--parallel-mode',
action='store_true',
)
self.add_option(
'-r', '--report',
action='callback', callback=self.append_action, callback_args=('report',),
)
self.add_option(
'-x', '--execute',
action='callback', callback=self.append_action, callback_args=('execute',),
)
self.add_option(
'-o', '--omit',
action='store',
)
self.add_option(
'', '--timid',
action='store_true',
)
def append_action(self, option_unused, opt_unused, value_unused, parser, arg1):
"""Callback for an option that adds to the `actions` list."""
parser.values.actions.append(arg1)
class OptionParserError(Exception):
"""Used to stop the optparse error handler ending the process."""
pass
def parse_args(self, args=None, options=None):
"""Call optparse.parse_args, but return a triple:
(ok, options, args)
"""
try:
options, args = super(OptionParser, self).parse_args(args, options)
except self.OptionParserError:
return False, None, None
return True, options, args
def error(self, msg):
"""Override optparse.error so sys.exit doesn't get called."""
self.help_fn(msg)
raise self.OptionParserError
class CoverageScript:
"""The command-line interface to Coverage."""
def __init__(self, _covpkg=None, _run_python_file=None):
# _covpkg is for dependency injection, so we can test this code.
if _covpkg:
self.covpkg = _covpkg
else:
import coverage
self.covpkg = coverage
# _run_python_file is for dependency injection also.
self.run_python_file = _run_python_file or run_python_file
self.coverage = None
def help(self, error=None):
"""Display an error message, or the usage for Coverage."""
if error:
print error
print "Use -h for help."
else:
print USAGE % self.covpkg.__dict__
def command_line(self, argv, help_fn=None):
"""The bulk of the command line interface to Coverage.
`argv` is the argument list to process.
`help_fn` is the help function to use when something goes wrong.
"""
# Collect the command-line options.
help_fn = help_fn or self.help
OK, ERR = 0, 1
parser = OptionParser(help_fn)
ok, options, args = parser.parse_args(argv)
if not ok:
return ERR
if options.help:
help_fn()
return OK
# Check for conflicts and problems in the options.
for i in ['erase', 'execute']:
for j in ['annotate', 'html', 'report', 'combine']:
if (i in options.actions) and (j in options.actions):
help_fn("You can't specify the '%s' and '%s' "
"options at the same time." % (i, j))
return ERR
args_needed = (
'execute' in options.actions or
'annotate' in options.actions or
'html' in options.actions or
'report' in options.actions
)
if not options.actions:
help_fn(
"You must specify at least one of -e, -x, -c, -r, -a, or -b."
)
return ERR
if not args_needed and args:
help_fn("Unexpected arguments: %s" % " ".join(args))
return ERR
# Do something.
self.coverage = self.covpkg.coverage(
data_suffix = bool(options.parallel_mode),
cover_pylib = options.pylib,
timid = options.timid,
)
if 'erase' in options.actions:
self.coverage.erase()
else:
self.coverage.load()
if 'execute' in options.actions:
if not args:
help_fn("Nothing to do.")
return ERR
# Run the script.
self.coverage.start()
try:
self.run_python_file(args[0], args)
finally:
self.coverage.stop()
self.coverage.save()
if 'combine' in options.actions:
self.coverage.combine()
self.coverage.save()
# Remaining actions are reporting, with some common options.
report_args = {
'morfs': args,
'ignore_errors': options.ignore_errors,
}
omit = None
if options.omit:
omit = options.omit.split(',')
report_args['omit_prefixes'] = omit
if 'report' in options.actions:
self.coverage.report(
show_missing=options.show_missing, **report_args)
if 'annotate' in options.actions:
self.coverage.annotate(
directory=options.directory, **report_args)
if 'html' in options.actions:
self.coverage.html_report(
directory=options.directory, **report_args)
return OK
def main():
"""The main entrypoint to Coverage.
This is installed as the script entrypoint.
"""
return CoverageScript().command_line(sys.argv[1:])
|