Coverage for coverage / cmdline.py: 98.272%

333 statements  

« prev     ^ index     » next       coverage.py v7.12.1a0.dev1, created at 2025-11-30 17:57 +0000

1# Licensed under the Apache License: http://www.apache.org/licenses/LICENSE-2.0 

2# For details: https://github.com/coveragepy/coveragepy/blob/main/NOTICE.txt 

3 

4"""Command-line support for coverage.py.""" 

5 

6from __future__ import annotations 1PxQyjaRzSAkbTBUClcVDWEmdXFYGneZH90I!oft1J#2K$pgu3L%4M'qhv5N(6O)riw78s

7 

8import glob 1PxQyjaRzSAkbTBUClcVDWEmdXFYGneZH90I!oft1J#2K$pgu3L%4M'qhv5N(6O)riw78s

9import optparse 1PxQyjaRzSAkbTBUClcVDWEmdXFYGneZH90I!oft1J#2K$pgu3L%4M'qhv5N(6O)riw78s

10import os 1PxQyjaRzSAkbTBUClcVDWEmdXFYGneZH90I!oft1J#2K$pgu3L%4M'qhv5N(6O)riw78s

11import os.path 1PxQyjaRzSAkbTBUClcVDWEmdXFYGneZH90I!oft1J#2K$pgu3L%4M'qhv5N(6O)riw78s

12import shlex 1PxQyjaRzSAkbTBUClcVDWEmdXFYGneZH90I!oft1J#2K$pgu3L%4M'qhv5N(6O)riw78s

13import signal 1PxQyjaRzSAkbTBUClcVDWEmdXFYGneZH90I!oft1J#2K$pgu3L%4M'qhv5N(6O)riw78s

14import sys 1PxQyjaRzSAkbTBUClcVDWEmdXFYGneZH90I!oft1J#2K$pgu3L%4M'qhv5N(6O)riw78s

15import textwrap 1PxQyjaRzSAkbTBUClcVDWEmdXFYGneZH90I!oft1J#2K$pgu3L%4M'qhv5N(6O)riw78s

16import traceback 1PxQyjaRzSAkbTBUClcVDWEmdXFYGneZH90I!oft1J#2K$pgu3L%4M'qhv5N(6O)riw78s

17import types 1PxQyjaRzSAkbTBUClcVDWEmdXFYGneZH90I!oft1J#2K$pgu3L%4M'qhv5N(6O)riw78s

18from typing import Any, NoReturn, cast 1PxQyjaRzSAkbTBUClcVDWEmdXFYGneZH90I!oft1J#2K$pgu3L%4M'qhv5N(6O)riw78s

19 

20import coverage 1PxQyjaRzSAkbTBUClcVDWEmdXFYGneZH90I!oft1J#2K$pgu3L%4M'qhv5N(6O)riw78s

21from coverage import Coverage, env 1PxQyjaRzSAkbTBUClcVDWEmdXFYGneZH90I!oft1J#2K$pgu3L%4M'qhv5N(6O)riw78s

22from coverage.config import CoverageConfig 1PxQyjaRzSAkbTBUClcVDWEmdXFYGneZH90I!oft1J#2K$pgu3L%4M'qhv5N(6O)riw78s

23from coverage.control import DEFAULT_DATAFILE 1PxQyjaRzSAkbTBUClcVDWEmdXFYGneZH90I!oft1J#2K$pgu3L%4M'qhv5N(6O)riw78s

24from coverage.core import CTRACER_FILE 1PxQyjaRzSAkbTBUClcVDWEmdXFYGneZH90I!oft1J#2K$pgu3L%4M'qhv5N(6O)riw78s

25from coverage.data import CoverageData, combinable_files, debug_data_file 1PxQyjaRzSAkbTBUClcVDWEmdXFYGneZH90I!oft1J#2K$pgu3L%4M'qhv5N(6O)riw78s

26from coverage.debug import info_header, short_stack, write_formatted_info 1PxQyjaRzSAkbTBUClcVDWEmdXFYGneZH90I!oft1J#2K$pgu3L%4M'qhv5N(6O)riw78s

27from coverage.exceptions import NoSource, CoverageException, _ExceptionDuringRun 1PxQyjaRzSAkbTBUClcVDWEmdXFYGneZH90I!oft1J#2K$pgu3L%4M'qhv5N(6O)riw78s

28from coverage.execfile import PyRunner 1PxQyjaRzSAkbTBUClcVDWEmdXFYGneZH90I!oft1J#2K$pgu3L%4M'qhv5N(6O)riw78s

29from coverage.results import display_covered, should_fail_under 1PxQyjaRzSAkbTBUClcVDWEmdXFYGneZH90I!oft1J#2K$pgu3L%4M'qhv5N(6O)riw78s

30from coverage.version import __url__ 1PxQyjaRzSAkbTBUClcVDWEmdXFYGneZH90I!oft1J#2K$pgu3L%4M'qhv5N(6O)riw78s

31 

32# When adding to this file, alphabetization is important. Look for 

33# "alphabetize" comments throughout. 

34 

35 

36def oneline(text: str) -> str: 1PxQyjaRzSAkbTBUClcVDWEmdXFYGneZH90I!oft1J#2K$pgu3L%4M'qhv5N(6O)riw78s

37 """Turn a multi-line string into one line for help to reformat nicely.""" 

38 return " ".join(text.split()) 1PxQyjaRzSAkbTBUClcVDWEmdXFYGneZH90I!oft1J#2K$pgu3L%4M'qhv5N(6O)riw78s

39 

40 

41class Opts: 1PxQyjaRzSAkbTBUClcVDWEmdXFYGneZH90I!oft1J#2K$pgu3L%4M'qhv5N(6O)riw78s

42 """A namespace class for individual options we'll build parsers from.""" 

43 

44 # Keep these entries alphabetized (roughly) by the option name as it 

45 # appears on the command line. 

46 

47 append = optparse.make_option( 1PxQyjaRzSAkbTBUClcVDWEmdXFYGneZH90I!oft1J#2K$pgu3L%4M'qhv5N(6O)riw78s

48 "-a", 

49 "--append", 

50 action="store_true", 

51 help="Append data to the data file. Otherwise it starts clean each time.", 

52 ) 

53 branch = optparse.make_option( 1PxQyjaRzSAkbTBUClcVDWEmdXFYGneZH90I!oft1J#2K$pgu3L%4M'qhv5N(6O)riw78s

54 "", 

55 "--branch", 

56 action="store_true", 

57 help="Measure branch coverage in addition to statement coverage.", 

58 ) 

59 concurrency = optparse.make_option( 1PxQyjaRzSAkbTBUClcVDWEmdXFYGneZH90I!oft1J#2K$pgu3L%4M'qhv5N(6O)riw78s

60 "", 

61 "--concurrency", 

62 action="store", 

63 metavar="LIBS", 

64 help=oneline( 

65 """ 

66 Properly measure code using a concurrency library. 

67 Valid values are: {}, or a comma-list of them. 

68 """ 

69 ).format(", ".join(sorted(CoverageConfig.CONCURRENCY_CHOICES))), 

70 ) 

71 context = optparse.make_option( 1PxQyjaRzSAkbTBUClcVDWEmdXFYGneZH90I!oft1J#2K$pgu3L%4M'qhv5N(6O)riw78s

72 "", 

73 "--context", 

74 action="store", 

75 metavar="LABEL", 

76 help="The context label to record for this coverage run.", 

77 ) 

78 contexts = optparse.make_option( 1PxQyjaRzSAkbTBUClcVDWEmdXFYGneZH90I!oft1J#2K$pgu3L%4M'qhv5N(6O)riw78s

79 "", 

80 "--contexts", 

81 action="store", 

82 metavar="REGEX1,REGEX2,...", 

83 help=oneline( 

84 """ 

85 Only display data from lines covered in the given contexts. 

86 Accepts Python regexes, which must be quoted. 

87 """ 

88 ), 

89 ) 

90 datafile = optparse.make_option( 1PxQyjaRzSAkbTBUClcVDWEmdXFYGneZH90I!oft1J#2K$pgu3L%4M'qhv5N(6O)riw78s

91 "", 

92 "--data-file", 

93 action="store", 

94 metavar="DATAFILE", 

95 help=oneline( 

96 """ 

97 Base name of the data files to operate on. 

98 Defaults to '.coverage'. [env: COVERAGE_FILE] 

99 """ 

100 ), 

101 ) 

102 datafle_input = optparse.make_option( 1PxQyjaRzSAkbTBUClcVDWEmdXFYGneZH90I!oft1J#2K$pgu3L%4M'qhv5N(6O)riw78s

103 "", 

104 "--data-file", 

105 action="store", 

106 metavar="INFILE", 

107 help=oneline( 

108 """ 

109 Read coverage data for report generation from this file. 

110 Defaults to '.coverage'. [env: COVERAGE_FILE] 

111 """ 

112 ), 

113 ) 

114 datafile_output = optparse.make_option( 1PxQyjaRzSAkbTBUClcVDWEmdXFYGneZH90I!oft1J#2K$pgu3L%4M'qhv5N(6O)riw78s

115 "", 

116 "--data-file", 

117 action="store", 

118 metavar="OUTFILE", 

119 help=oneline( 

120 """ 

121 Write the recorded coverage data to this file. 

122 Defaults to '.coverage'. [env: COVERAGE_FILE] 

123 """ 

124 ), 

125 ) 

126 debug = optparse.make_option( 1PxQyjaRzSAkbTBUClcVDWEmdXFYGneZH90I!oft1J#2K$pgu3L%4M'qhv5N(6O)riw78s

127 "", 

128 "--debug", 

129 action="store", 

130 metavar="OPTS", 

131 help="Debug options, separated by commas. [env: COVERAGE_DEBUG]", 

132 ) 

133 directory = optparse.make_option( 1PxQyjaRzSAkbTBUClcVDWEmdXFYGneZH90I!oft1J#2K$pgu3L%4M'qhv5N(6O)riw78s

134 "-d", 

135 "--directory", 

136 action="store", 

137 metavar="DIR", 

138 help="Write the output files to DIR.", 

139 ) 

140 fail_under = optparse.make_option( 1PxQyjaRzSAkbTBUClcVDWEmdXFYGneZH90I!oft1J#2K$pgu3L%4M'qhv5N(6O)riw78s

141 "", 

142 "--fail-under", 

143 action="store", 

144 metavar="MIN", 

145 type="float", 

146 help="Exit with a status of 2 if the total coverage is less than MIN.", 

147 ) 

148 format = optparse.make_option( 1PxQyjaRzSAkbTBUClcVDWEmdXFYGneZH90I!oft1J#2K$pgu3L%4M'qhv5N(6O)riw78s

149 "", 

150 "--format", 

151 action="store", 

152 metavar="FORMAT", 

153 help="Output format, either text (default), markdown, or total.", 

154 ) 

155 help = optparse.make_option( 1PxQyjaRzSAkbTBUClcVDWEmdXFYGneZH90I!oft1J#2K$pgu3L%4M'qhv5N(6O)riw78s

156 "-h", 

157 "--help", 

158 action="store_true", 

159 help="Get help on this command.", 

160 ) 

161 ignore_errors = optparse.make_option( 1PxQyjaRzSAkbTBUClcVDWEmdXFYGneZH90I!oft1J#2K$pgu3L%4M'qhv5N(6O)riw78s

162 "-i", 

163 "--ignore-errors", 

164 action="store_true", 

165 help="Ignore errors while reading source files.", 

166 ) 

167 include = optparse.make_option( 1PxQyjaRzSAkbTBUClcVDWEmdXFYGneZH90I!oft1J#2K$pgu3L%4M'qhv5N(6O)riw78s

168 "", 

169 "--include", 

170 action="store", 

171 metavar="PAT1,PAT2,...", 

172 help=oneline( 

173 """ 

174 Include only files whose paths match one of these patterns. 

175 Accepts shell-style wildcards, which must be quoted. 

176 """ 

177 ), 

178 ) 

179 keep = optparse.make_option( 1PxQyjaRzSAkbTBUClcVDWEmdXFYGneZH90I!oft1J#2K$pgu3L%4M'qhv5N(6O)riw78s

180 "", 

181 "--keep", 

182 action="store_true", 

183 help="Keep original coverage files, otherwise they are deleted.", 

184 ) 

185 pylib = optparse.make_option( 1PxQyjaRzSAkbTBUClcVDWEmdXFYGneZH90I!oft1J#2K$pgu3L%4M'qhv5N(6O)riw78s

186 "-L", 

187 "--pylib", 

188 action="store_true", 

189 help=oneline( 

190 """ 

191 Measure coverage even inside the Python installed library, 

192 which isn't done by default. 

193 """ 

194 ), 

195 ) 

196 show_missing = optparse.make_option( 1PxQyjaRzSAkbTBUClcVDWEmdXFYGneZH90I!oft1J#2K$pgu3L%4M'qhv5N(6O)riw78s

197 "-m", 

198 "--show-missing", 

199 action="store_true", 

200 help="Show line numbers of statements in each module that weren't executed.", 

201 ) 

202 module = optparse.make_option( 1PxQyjaRzSAkbTBUClcVDWEmdXFYGneZH90I!oft1J#2K$pgu3L%4M'qhv5N(6O)riw78s

203 "-m", 

204 "--module", 

205 action="store_true", 

206 help=oneline( 

207 """ 

208 <pyfile> is an importable Python module, not a script path, 

209 to be run as 'python -m' would run it. 

210 """ 

211 ), 

212 ) 

213 omit = optparse.make_option( 1PxQyjaRzSAkbTBUClcVDWEmdXFYGneZH90I!oft1J#2K$pgu3L%4M'qhv5N(6O)riw78s

214 "", 

215 "--omit", 

216 action="store", 

217 metavar="PAT1,PAT2,...", 

218 help=oneline( 

219 """ 

220 Omit files whose paths match one of these patterns. 

221 Accepts shell-style wildcards, which must be quoted. 

222 """ 

223 ), 

224 ) 

225 output_xml = optparse.make_option( 1PxQyjaRzSAkbTBUClcVDWEmdXFYGneZH90I!oft1J#2K$pgu3L%4M'qhv5N(6O)riw78s

226 "-o", 

227 "", 

228 action="store", 

229 dest="outfile", 

230 metavar="OUTFILE", 

231 help="Write the XML report to this file. Defaults to 'coverage.xml'", 

232 ) 

233 output_json = optparse.make_option( 1PxQyjaRzSAkbTBUClcVDWEmdXFYGneZH90I!oft1J#2K$pgu3L%4M'qhv5N(6O)riw78s

234 "-o", 

235 "", 

236 action="store", 

237 dest="outfile", 

238 metavar="OUTFILE", 

239 help="Write the JSON report to this file. Defaults to 'coverage.json'", 

240 ) 

241 output_lcov = optparse.make_option( 1PxQyjaRzSAkbTBUClcVDWEmdXFYGneZH90I!oft1J#2K$pgu3L%4M'qhv5N(6O)riw78s

242 "-o", 

243 "", 

244 action="store", 

245 dest="outfile", 

246 metavar="OUTFILE", 

247 help="Write the LCOV report to this file. Defaults to 'coverage.lcov'", 

248 ) 

249 json_pretty_print = optparse.make_option( 1PxQyjaRzSAkbTBUClcVDWEmdXFYGneZH90I!oft1J#2K$pgu3L%4M'qhv5N(6O)riw78s

250 "", 

251 "--pretty-print", 

252 action="store_true", 

253 help="Format the JSON for human readers.", 

254 ) 

255 parallel_mode = optparse.make_option( 1PxQyjaRzSAkbTBUClcVDWEmdXFYGneZH90I!oft1J#2K$pgu3L%4M'qhv5N(6O)riw78s

256 "-p", 

257 "--parallel-mode", 

258 action="store_true", 

259 help=oneline( 

260 """ 

261 Append a unique suffix to the data file name to collect separate 

262 data from multiple processes. 

263 """ 

264 ), 

265 ) 

266 precision = optparse.make_option( 1PxQyjaRzSAkbTBUClcVDWEmdXFYGneZH90I!oft1J#2K$pgu3L%4M'qhv5N(6O)riw78s

267 "", 

268 "--precision", 

269 action="store", 

270 metavar="N", 

271 type=int, 

272 help=oneline( 

273 """ 

274 Number of digits after the decimal point to display for 

275 reported coverage percentages. 

276 """ 

277 ), 

278 ) 

279 quiet = optparse.make_option( 1PxQyjaRzSAkbTBUClcVDWEmdXFYGneZH90I!oft1J#2K$pgu3L%4M'qhv5N(6O)riw78s

280 "-q", 

281 "--quiet", 

282 action="store_true", 

283 help="Don't print messages about what is happening.", 

284 ) 

285 rcfile = optparse.make_option( 1PxQyjaRzSAkbTBUClcVDWEmdXFYGneZH90I!oft1J#2K$pgu3L%4M'qhv5N(6O)riw78s

286 "", 

287 "--rcfile", 

288 action="store", 

289 help=oneline( 

290 """ 

291 Specify configuration file. 

292 By default '.coveragerc', 'setup.cfg', 'tox.ini', and 

293 'pyproject.toml' are tried. [env: COVERAGE_RCFILE] 

294 """ 

295 ), 

296 ) 

297 save_signal = optparse.make_option( 1PxQyjaRzSAkbTBUClcVDWEmdXFYGneZH90I!oft1J#2K$pgu3L%4M'qhv5N(6O)riw78s

298 "", 

299 "--save-signal", 

300 action="store", 

301 metavar="SIGNAL", 

302 choices=["USR1", "USR2"], 

303 help=oneline( 

304 """ 

305 Specify a signal that will trigger coverage to write its collected data. 

306 Supported values are: USR1, USR2. Not available on Windows. 

307 """ 

308 ), 

309 ) 

310 show_contexts = optparse.make_option( 1PxQyjaRzSAkbTBUClcVDWEmdXFYGneZH90I!oft1J#2K$pgu3L%4M'qhv5N(6O)riw78s

311 "--show-contexts", 

312 action="store_true", 

313 help="Show contexts for covered lines.", 

314 ) 

315 skip_covered = optparse.make_option( 1PxQyjaRzSAkbTBUClcVDWEmdXFYGneZH90I!oft1J#2K$pgu3L%4M'qhv5N(6O)riw78s

316 "--skip-covered", 

317 action="store_true", 

318 help="Skip files with 100% coverage.", 

319 ) 

320 no_skip_covered = optparse.make_option( 1PxQyjaRzSAkbTBUClcVDWEmdXFYGneZH90I!oft1J#2K$pgu3L%4M'qhv5N(6O)riw78s

321 "--no-skip-covered", 

322 action="store_false", 

323 dest="skip_covered", 

324 help="Disable --skip-covered.", 

325 ) 

326 skip_empty = optparse.make_option( 1PxQyjaRzSAkbTBUClcVDWEmdXFYGneZH90I!oft1J#2K$pgu3L%4M'qhv5N(6O)riw78s

327 "--skip-empty", 

328 action="store_true", 

329 help="Skip files with no code.", 

330 ) 

331 sort = optparse.make_option( 1PxQyjaRzSAkbTBUClcVDWEmdXFYGneZH90I!oft1J#2K$pgu3L%4M'qhv5N(6O)riw78s

332 "--sort", 

333 action="store", 

334 metavar="COLUMN", 

335 help=oneline( 

336 """ 

337 Sort the report by the named column: name, stmts, miss, branch, brpart, or cover. 

338 Default is name. 

339 """ 

340 ), 

341 ) 

342 source = optparse.make_option( 1PxQyjaRzSAkbTBUClcVDWEmdXFYGneZH90I!oft1J#2K$pgu3L%4M'qhv5N(6O)riw78s

343 "", 

344 "--source", 

345 action="store", 

346 metavar="SRC1,SRC2,...", 

347 help="A list of directories or importable names of code to measure.", 

348 ) 

349 timid = optparse.make_option( 1PxQyjaRzSAkbTBUClcVDWEmdXFYGneZH90I!oft1J#2K$pgu3L%4M'qhv5N(6O)riw78s

350 "", 

351 "--timid", 

352 action="store_true", 

353 help="Use the slower Python trace function core.", 

354 ) 

355 title = optparse.make_option( 1PxQyjaRzSAkbTBUClcVDWEmdXFYGneZH90I!oft1J#2K$pgu3L%4M'qhv5N(6O)riw78s

356 "", 

357 "--title", 

358 action="store", 

359 metavar="TITLE", 

360 help="A text string to use as the title on the HTML.", 

361 ) 

362 version = optparse.make_option( 1PxQyjaRzSAkbTBUClcVDWEmdXFYGneZH90I!oft1J#2K$pgu3L%4M'qhv5N(6O)riw78s

363 "", 

364 "--version", 

365 action="store_true", 

366 help="Display version information and exit.", 

367 ) 

368 

369 

370class CoverageOptionParser(optparse.OptionParser): 1PxQyjaRzSAkbTBUClcVDWEmdXFYGneZH90I!oft1J#2K$pgu3L%4M'qhv5N(6O)riw78s

371 """Base OptionParser for coverage.py. 

372 

373 Problems don't exit the program. 

374 Defaults are initialized for all options. 

375 

376 """ 

377 

378 def __init__(self, *args: Any, **kwargs: Any) -> None: 1PxQyjaRzSAkbTBUClcVDWEmdXFYGneZH90I!oft1J#2K$pgu3L%4M'qhv5N(6O)riw78s

379 kwargs["add_help_option"] = False 1PxQyjaRzSAkbTBUClcVDWEmdXFYGneZH90I!oft1J#2K$pgu3L%4M'qhv5N(6O)riw78s

380 super().__init__(*args, **kwargs) 1PxQyjaRzSAkbTBUClcVDWEmdXFYGneZH90I!oft1J#2K$pgu3L%4M'qhv5N(6O)riw78s

381 self.set_defaults( 1PxQyjaRzSAkbTBUClcVDWEmdXFYGneZH90I!oft1J#2K$pgu3L%4M'qhv5N(6O)riw78s

382 # Keep these arguments alphabetized by their names. 

383 action=None, 

384 append=None, 

385 branch=None, 

386 concurrency=None, 

387 context=None, 

388 contexts=None, 

389 data_file=None, 

390 debug=None, 

391 directory=None, 

392 fail_under=None, 

393 format=None, 

394 help=None, 

395 ignore_errors=None, 

396 include=None, 

397 keep=None, 

398 module=None, 

399 omit=None, 

400 parallel_mode=None, 

401 precision=None, 

402 pylib=None, 

403 quiet=None, 

404 rcfile=True, 

405 save_signal=None, 

406 show_contexts=None, 

407 show_missing=None, 

408 skip_covered=None, 

409 skip_empty=None, 

410 sort=None, 

411 source=None, 

412 timid=None, 

413 title=None, 

414 version=None, 

415 ) 

416 

417 self.disable_interspersed_args() 1PxQyjaRzSAkbTBUClcVDWEmdXFYGneZH90I!oft1J#2K$pgu3L%4M'qhv5N(6O)riw78s

418 

419 class OptionParserError(Exception): 1PxQyjaRzSAkbTBUClcVDWEmdXFYGneZH90I!oft1J#2K$pgu3L%4M'qhv5N(6O)riw78s

420 """Used to stop the optparse error handler ending the process.""" 

421 

422 pass 1PxQyjaRzSAkbTBUClcVDWEmdXFYGneZH90I!oft1J#2K$pgu3L%4M'qhv5N(6O)riw78s

423 

424 def parse_args_ok(self, args: list[str]) -> tuple[bool, optparse.Values | None, list[str]]: 1PxQyjaRzSAkbTBUClcVDWEmdXFYGneZH90I!oft1J#2K$pgu3L%4M'qhv5N(6O)riw78s

425 """Call optparse.parse_args, but return a triple: 

426 

427 (ok, options, args) 

428 

429 """ 

430 try: 1PxQyjaRzSAkbTBUClcVDWEmdXFYGneZH90I!oft1J#2K$pgu3L%4M'qhv5N(6O)riw78s

431 options, args = super().parse_args(args) 1PxQyjaRzSAkbTBUClcVDWEmdXFYGneZH90I!oft1J#2K$pgu3L%4M'qhv5N(6O)riw78s

432 except self.OptionParserError: 1PxQyjaRzSAkbTBUClcVDWEmdXFYGneZH90I!oft1J#2K$pgu3L%4M'qhv5N(6O)riw78s

433 return False, None, [] 1PxQyjaRzSAkbTBUClcVDWEmdXFYGneZH90I!oft1J#2K$pgu3L%4M'qhv5N(6O)riw78s

434 return True, options, args 1PxQyjaRzSAkbTBUClcVDWEmdXFYGneZH90I!oft1J#2K$pgu3L%4M'qhv5N(6O)riw78s

435 

436 def error(self, msg: str) -> NoReturn: 1PxQyjaRzSAkbTBUClcVDWEmdXFYGneZH90I!oft1J#2K$pgu3L%4M'qhv5N(6O)riw78s

437 """Override optparse.error so sys.exit doesn't get called.""" 

438 show_help(msg) 1PxQyjaRzSAkbTBUClcVDWEmdXFYGneZH90I!oft1J#2K$pgu3L%4M'qhv5N(6O)riw78s

439 raise self.OptionParserError 1PxQyjaRzSAkbTBUClcVDWEmdXFYGneZH90I!oft1J#2K$pgu3L%4M'qhv5N(6O)riw78s

440 

441 

442class GlobalOptionParser(CoverageOptionParser): 1PxQyjaRzSAkbTBUClcVDWEmdXFYGneZH90I!oft1J#2K$pgu3L%4M'qhv5N(6O)riw78s

443 """Command-line parser for coverage.py global option arguments.""" 

444 

445 def __init__(self) -> None: 1PxQyjaRzSAkbTBUClcVDWEmdXFYGneZH90I!oft1J#2K$pgu3L%4M'qhv5N(6O)riw78s

446 super().__init__() 1PxQyjaRzSAkbTBUClcVDWEmdXFYGneZH90I!oft1J#2K$pgu3L%4M'qhv5N(6O)riw78s

447 

448 self.add_options( 1PxQyjaRzSAkbTBUClcVDWEmdXFYGneZH90I!oft1J#2K$pgu3L%4M'qhv5N(6O)riw78s

449 [ 

450 Opts.help, 

451 Opts.version, 

452 ] 

453 ) 

454 

455 

456class CmdOptionParser(CoverageOptionParser): 1PxQyjaRzSAkbTBUClcVDWEmdXFYGneZH90I!oft1J#2K$pgu3L%4M'qhv5N(6O)riw78s

457 """Parse one of the new-style commands for coverage.py.""" 

458 

459 def __init__( 1PxQyjaRzSAkbTBUClcVDWEmdXFYGneZH90I!oft1J#2K$pgu3L%4M'qhv5N(6O)riw

460 self, 

461 action: str, 

462 options: list[optparse.Option], 

463 description: str, 

464 usage: str | None = None, 

465 ): 

466 """Create an OptionParser for a coverage.py command. 

467 

468 `action` is the slug to put into `options.action`. 

469 `options` is a list of Option's for the command. 

470 `description` is the description of the command, for the help text. 

471 `usage` is the usage string to display in help. 

472 

473 """ 

474 if usage: 1PxQyjaRzSAkbTBUClcVDWEmdXFYGneZH90I!oft1J#2K$pgu3L%4M'qhv5N(6O)riw78s

475 usage = "%prog " + usage 1PxQyjaRzSAkbTBUClcVDWEmdXFYGneZH90I!oft1J#2K$pgu3L%4M'qhv5N(6O)riw78s

476 super().__init__( 1PxQyjaRzSAkbTBUClcVDWEmdXFYGneZH90I!oft1J#2K$pgu3L%4M'qhv5N(6O)riw78s

477 usage=usage, 

478 description=description, 

479 ) 

480 self.set_defaults(action=action) 1PxQyjaRzSAkbTBUClcVDWEmdXFYGneZH90I!oft1J#2K$pgu3L%4M'qhv5N(6O)riw78s

481 self.add_options(options) 1PxQyjaRzSAkbTBUClcVDWEmdXFYGneZH90I!oft1J#2K$pgu3L%4M'qhv5N(6O)riw78s

482 self.cmd = action 1PxQyjaRzSAkbTBUClcVDWEmdXFYGneZH90I!oft1J#2K$pgu3L%4M'qhv5N(6O)riw78s

483 

484 def __eq__(self, other: str) -> bool: # type: ignore[override] 1PxQyjaRzSAkbTBUClcVDWEmdXFYGneZH90I!oft1J#2K$pgu3L%4M'qhv5N(6O)riw78s

485 # A convenience equality, so that I can put strings in unit test 

486 # results, and they will compare equal to objects. 

487 return other == f"<CmdOptionParser:{self.cmd}>" 1PxQyjaRzSAkbTBUClcVDWEmdXFYGneZH90I!oft1J#2K$pgu3L%4M'qhv5N(6O)riw78s

488 

489 __hash__ = None # type: ignore[assignment] 1PxQyjaRzSAkbTBUClcVDWEmdXFYGneZH90I!oft1J#2K$pgu3L%4M'qhv5N(6O)riw78s

490 

491 def get_prog_name(self) -> str: 1PxQyjaRzSAkbTBUClcVDWEmdXFYGneZH90I!oft1J#2K$pgu3L%4M'qhv5N(6O)riw78s

492 """Override of an undocumented function in optparse.OptionParser.""" 

493 program_name = super().get_prog_name() 1PxQyjaRzSAkbTBUClcVDWEmdXFYGneZH90I!oft1J#2K$pgu3L%4M'qhv5N(6O)riw78s

494 

495 # Include the sub-command for this parser as part of the command. 

496 return f"{program_name} {self.cmd}" 1PxQyjaRzSAkbTBUClcVDWEmdXFYGneZH90I!oft1J#2K$pgu3L%4M'qhv5N(6O)riw78s

497 

498 

499# In lists of Opts, keep them alphabetized by the option names as they appear 

500# on the command line, since these lists determine the order of the options in 

501# the help output. 

502# 

503# In COMMANDS, keep the keys (command names) alphabetized. 

504 

505GLOBAL_ARGS = [ 1PxQyjaRzSAkbTBUClcVDWEmdXFYGneZH90I!oft1J#2K$pgu3L%4M'qhv5N(6O)riw78s

506 Opts.debug, 

507 Opts.help, 

508 Opts.rcfile, 

509] 

510 

511COMMANDS = { 1PxQyjaRzSAkbTBUClcVDWEmdXFYGneZH90I!oft1J#2K$pgu3L%4M'qhv5N(6O)riw78s

512 "annotate": CmdOptionParser( 

513 "annotate", 

514 [ 

515 Opts.directory, 

516 Opts.datafle_input, 

517 Opts.ignore_errors, 

518 Opts.include, 

519 Opts.omit, 

520 ] 

521 + GLOBAL_ARGS, 

522 usage="[options] [modules]", 

523 description=oneline( 

524 """ 

525 Make annotated copies of the given files, marking statements that are executed 

526 with > and statements that are missed with !. 

527 """ 

528 ), 

529 ), 

530 "combine": CmdOptionParser( 

531 "combine", 

532 [ 

533 Opts.append, 

534 Opts.datafile, 

535 Opts.keep, 

536 Opts.quiet, 

537 ] 

538 + GLOBAL_ARGS, 

539 usage="[options] <path1> <path2> ... <pathN>", 

540 description=oneline( 

541 """ 

542 Combine data from multiple coverage files. 

543 The combined results are written to a single 

544 file representing the union of the data. The positional 

545 arguments are data files or directories containing data files. 

546 If no paths are provided, data files in the default data file's 

547 directory are combined. 

548 """ 

549 ), 

550 ), 

551 "debug": CmdOptionParser( 

552 "debug", 

553 GLOBAL_ARGS, 

554 usage="<topic>", 

555 description=oneline( 

556 """ 

557 Display information about the internals of coverage.py, 

558 for diagnosing problems. 

559 Topics are: 

560 'data' to show a summary of the collected data; 

561 'sys' to show installation information; 

562 'config' to show the configuration; 

563 'premain' to show what is calling coverage; 

564 'pybehave' to show internal flags describing Python behavior; 

565 'sqlite' to show SQLite compilation options. 

566 """ 

567 ), 

568 ), 

569 "erase": CmdOptionParser( 

570 "erase", 

571 [ 

572 Opts.datafile, 

573 ] 

574 + GLOBAL_ARGS, 

575 description="Erase previously collected coverage data.", 

576 ), 

577 "help": CmdOptionParser( 

578 "help", 

579 GLOBAL_ARGS, 

580 usage="[command]", 

581 description="Describe how to use coverage.py", 

582 ), 

583 "html": CmdOptionParser( 

584 "html", 

585 [ 

586 Opts.contexts, 

587 Opts.directory, 

588 Opts.datafle_input, 

589 Opts.fail_under, 

590 Opts.ignore_errors, 

591 Opts.include, 

592 Opts.omit, 

593 Opts.precision, 

594 Opts.quiet, 

595 Opts.show_contexts, 

596 Opts.skip_covered, 

597 Opts.no_skip_covered, 

598 Opts.skip_empty, 

599 Opts.title, 

600 ] 

601 + GLOBAL_ARGS, 

602 usage="[options] [modules]", 

603 description=oneline( 

604 """ 

605 Create an HTML report of the coverage of the files. 

606 Each file gets its own page, with the source decorated to show 

607 executed, excluded, and missed lines. 

608 """ 

609 ), 

610 ), 

611 "json": CmdOptionParser( 

612 "json", 

613 [ 

614 Opts.contexts, 

615 Opts.datafle_input, 

616 Opts.fail_under, 

617 Opts.ignore_errors, 

618 Opts.include, 

619 Opts.omit, 

620 Opts.output_json, 

621 Opts.json_pretty_print, 

622 Opts.quiet, 

623 Opts.show_contexts, 

624 ] 

625 + GLOBAL_ARGS, 

626 usage="[options] [modules]", 

627 description="Generate a JSON report of coverage results.", 

628 ), 

629 "lcov": CmdOptionParser( 

630 "lcov", 

631 [ 

632 Opts.datafle_input, 

633 Opts.fail_under, 

634 Opts.ignore_errors, 

635 Opts.include, 

636 Opts.output_lcov, 

637 Opts.omit, 

638 Opts.quiet, 

639 ] 

640 + GLOBAL_ARGS, 

641 usage="[options] [modules]", 

642 description="Generate an LCOV report of coverage results.", 

643 ), 

644 "report": CmdOptionParser( 

645 "report", 

646 [ 

647 Opts.contexts, 

648 Opts.datafle_input, 

649 Opts.fail_under, 

650 Opts.format, 

651 Opts.ignore_errors, 

652 Opts.include, 

653 Opts.omit, 

654 Opts.precision, 

655 Opts.sort, 

656 Opts.show_missing, 

657 Opts.skip_covered, 

658 Opts.no_skip_covered, 

659 Opts.skip_empty, 

660 ] 

661 + GLOBAL_ARGS, 

662 usage="[options] [modules]", 

663 description="Report coverage statistics on modules.", 

664 ), 

665 "run": CmdOptionParser( 

666 "run", 

667 [ 

668 Opts.append, 

669 Opts.branch, 

670 Opts.concurrency, 

671 Opts.context, 

672 Opts.datafile_output, 

673 Opts.include, 

674 Opts.module, 

675 Opts.omit, 

676 Opts.pylib, 

677 Opts.parallel_mode, 

678 Opts.save_signal, 

679 Opts.source, 

680 Opts.timid, 

681 ] 

682 + GLOBAL_ARGS, 

683 usage="[options] <pyfile> [program options]", 

684 description="Run a Python program, measuring code execution.", 

685 ), 

686 "xml": CmdOptionParser( 

687 "xml", 

688 [ 

689 Opts.datafle_input, 

690 Opts.fail_under, 

691 Opts.ignore_errors, 

692 Opts.include, 

693 Opts.omit, 

694 Opts.output_xml, 

695 Opts.quiet, 

696 Opts.skip_empty, 

697 ] 

698 + GLOBAL_ARGS, 

699 usage="[options] [modules]", 

700 description="Generate an XML report of coverage results.", 

701 ), 

702} 

703 

704 

705def show_help( 1PxQyjaRzSAkbTBUClcVDWEmdXFYGneZH90I!oft1J#2K$pgu3L%4M'qhv5N(6O)riw

706 error: str | None = None, 

707 topic: str | None = None, 

708 parser: optparse.OptionParser | None = None, 

709) -> None: 

710 """Display an error message, or the named topic.""" 

711 assert error or topic or parser 1PxQyjaRzSAkbTBUClcVDWEmdXFYGneZH90I!oft1J#2K$pgu3L%4M'qhv5N(6O)riw78s

712 

713 program_path = sys.argv[0] 1PxQyjaRzSAkbTBUClcVDWEmdXFYGneZH90I!oft1J#2K$pgu3L%4M'qhv5N(6O)riw78s

714 if program_path.endswith(os.path.sep + "__main__.py"): 1PxQyjaRzSAkbTBUClcVDWEmdXFYGneZH90I!oft1J#2K$pgu3L%4M'qhv5N(6O)riw78s

715 # The path is the main module of a package; get that path instead. 

716 program_path = os.path.dirname(program_path) 1PxQyjaRzSAkbTBUClcVDWEmdXFYGneZH90I!oft1J#2K$pgu3L%4M'qhv5N(6O)riw78s

717 program_name = os.path.basename(program_path) 1PxQyjaRzSAkbTBUClcVDWEmdXFYGneZH90I!oft1J#2K$pgu3L%4M'qhv5N(6O)riw78s

718 if env.WINDOWS: 1PxQyjaRzSAkbTBUClcVDWEmdXFYGneZH90I!oft1J#2K$pgu3L%4M'qhv5N(6O)riw78s

719 # entry_points={"console_scripts":...} on Windows makes files 

720 # called coverage.exe, coverage3.exe, and coverage-3.5.exe. These 

721 # invoke coverage-script.py, coverage3-script.py, and 

722 # coverage-3.5-script.py. argv[0] is the .py file, but we want to 

723 # get back to the original form. 

724 auto_suffix = "-script.py" 1jakblcmdneoftpguqhvriws

725 if program_name.endswith(auto_suffix): 725 ↛ 726line 725 didn't jump to line 726 because the condition on line 725 was never true1jakblcmdneoftpguqhvriws

726 program_name = program_name[: -len(auto_suffix)] 

727 

728 help_params = dict(coverage.__dict__) 1PxQyjaRzSAkbTBUClcVDWEmdXFYGneZH90I!oft1J#2K$pgu3L%4M'qhv5N(6O)riw78s

729 help_params["__url__"] = __url__ 1PxQyjaRzSAkbTBUClcVDWEmdXFYGneZH90I!oft1J#2K$pgu3L%4M'qhv5N(6O)riw78s

730 help_params["program_name"] = program_name 1PxQyjaRzSAkbTBUClcVDWEmdXFYGneZH90I!oft1J#2K$pgu3L%4M'qhv5N(6O)riw78s

731 if CTRACER_FILE: 1PxQyjaRzSAkbTBUClcVDWEmdXFYGneZH90I!oft1J#2K$pgu3L%4M'qhv5N(6O)riw78s

732 help_params["extension_modifier"] = "with C extension" 1PQjRSkTUlVWmXYnZ0o12p34q56r

733 else: 

734 help_params["extension_modifier"] = "without C extension" 1xyazAbBCcDEdFGeH9I!ftJ#K$guL%M'hvN(O)iw78s

735 

736 if error: 1PxQyjaRzSAkbTBUClcVDWEmdXFYGneZH90I!oft1J#2K$pgu3L%4M'qhv5N(6O)riw78s

737 print(error, file=sys.stderr) 1PxQyjaRzSAkbTBUClcVDWEmdXFYGneZH90I!oft1J#2K$pgu3L%4M'qhv5N(6O)riw78s

738 print(f"Use '{program_name} help' for help.", file=sys.stderr) 1PxQyjaRzSAkbTBUClcVDWEmdXFYGneZH90I!oft1J#2K$pgu3L%4M'qhv5N(6O)riw78s

739 elif parser: 1PxQyjaRzSAkbTBUClcVDWEmdXFYGneZH90I!oft1J#2K$pgu3L%4M'qhv5N(6O)riw78s

740 print(parser.format_help().strip()) 1PxQyjaRzSAkbTBUClcVDWEmdXFYGneZH90I!oft1J#2K$pgu3L%4M'qhv5N(6O)riw78s

741 print() 1PxQyjaRzSAkbTBUClcVDWEmdXFYGneZH90I!oft1J#2K$pgu3L%4M'qhv5N(6O)riw78s

742 else: 

743 assert topic is not None 1PxQyjaRzSAkbTBUClcVDWEmdXFYGneZH90I!oft1J#2K$pgu3L%4M'qhv5N(6O)riw78s

744 help_msg = textwrap.dedent(HELP_TOPICS.get(topic, "")).strip() 1PxQyjaRzSAkbTBUClcVDWEmdXFYGneZH90I!oft1J#2K$pgu3L%4M'qhv5N(6O)riw78s

745 if help_msg: 1PxQyjaRzSAkbTBUClcVDWEmdXFYGneZH90I!oft1J#2K$pgu3L%4M'qhv5N(6O)riw78s

746 print(help_msg.format(**help_params)) 1PxQyjaRzSAkbTBUClcVDWEmdXFYGneZH90I!oft1J#2K$pgu3L%4M'qhv5N(6O)riw78s

747 else: 

748 print(f"Don't know topic {topic!r}") 1PxQyjaRzSAkbTBUClcVDWEmdXFYGneZH90I!oft1J#2K$pgu3L%4M'qhv5N(6O)riw78s

749 print("Full documentation is at {__url__}".format(**help_params)) 1PxQyjaRzSAkbTBUClcVDWEmdXFYGneZH90I!oft1J#2K$pgu3L%4M'qhv5N(6O)riw78s

750 

751 

752OK, ERR, FAIL_UNDER = 0, 1, 2 1PxQyjaRzSAkbTBUClcVDWEmdXFYGneZH90I!oft1J#2K$pgu3L%4M'qhv5N(6O)riw78s

753 

754 

755class CoverageScript: 1PxQyjaRzSAkbTBUClcVDWEmdXFYGneZH90I!oft1J#2K$pgu3L%4M'qhv5N(6O)riw78s

756 """The command-line interface to coverage.py.""" 

757 

758 def __init__(self) -> None: 1PxQyjaRzSAkbTBUClcVDWEmdXFYGneZH90I!oft1J#2K$pgu3L%4M'qhv5N(6O)riw78s

759 self.global_option = False 1PxQyjaRzSAkbTBUClcVDWEmdXFYGneZH90I!oft1J#2K$pgu3L%4M'qhv5N(6O)riw78s

760 self.coverage: Coverage 1PxQyjaRzSAkbTBUClcVDWEmdXFYGneZH90I!oft1J#2K$pgu3L%4M'qhv5N(6O)riw78s

761 

762 def command_line(self, argv: list[str]) -> int: 1PxQyjaRzSAkbTBUClcVDWEmdXFYGneZH90I!oft1J#2K$pgu3L%4M'qhv5N(6O)riw78s

763 """The bulk of the command line interface to coverage.py. 

764 

765 `argv` is the argument list to process. 

766 

767 Returns 0 if all is well, 1 if something went wrong. 

768 

769 """ 

770 # Collect the command-line options. 

771 if not argv: 1PxQyjaRzSAkbTBUClcVDWEmdXFYGneZH90I!oft1J#2K$pgu3L%4M'qhv5N(6O)riw78s

772 show_help(topic="minimum_help") 1PxQyjaRzSAkbTBUClcVDWEmdXFYGneZH90I!oft1J#2K$pgu3L%4M'qhv5N(6O)riw78s

773 return OK 1PxQyjaRzSAkbTBUClcVDWEmdXFYGneZH90I!oft1J#2K$pgu3L%4M'qhv5N(6O)riw78s

774 

775 # The command syntax we parse depends on the first argument. Global 

776 # switch syntax always starts with an option. 

777 parser: optparse.OptionParser | None 

778 self.global_option = argv[0].startswith("-") 1PxQyjaRzSAkbTBUClcVDWEmdXFYGneZH90I!oft1J#2K$pgu3L%4M'qhv5N(6O)riw78s

779 if self.global_option: 1PxQyjaRzSAkbTBUClcVDWEmdXFYGneZH90I!oft1J#2K$pgu3L%4M'qhv5N(6O)riw78s

780 parser = GlobalOptionParser() 1PxQyjaRzSAkbTBUClcVDWEmdXFYGneZH90I!oft1J#2K$pgu3L%4M'qhv5N(6O)riw78s

781 else: 

782 parser = COMMANDS.get(argv[0]) 1PxQyjaRzSAkbTBUClcVDWEmdXFYGneZH90I!oft1J#2K$pgu3L%4M'qhv5N(6O)riw78s

783 if not parser: 1PxQyjaRzSAkbTBUClcVDWEmdXFYGneZH90I!oft1J#2K$pgu3L%4M'qhv5N(6O)riw78s

784 show_help(f"Unknown command: {argv[0]!r}") 1PxQyjaRzSAkbTBUClcVDWEmdXFYGneZH90I!oft1J#2K$pgu3L%4M'qhv5N(6O)riw78s

785 return ERR 1PxQyjaRzSAkbTBUClcVDWEmdXFYGneZH90I!oft1J#2K$pgu3L%4M'qhv5N(6O)riw78s

786 argv = argv[1:] 1PxQyjaRzSAkbTBUClcVDWEmdXFYGneZH90I!oft1J#2K$pgu3L%4M'qhv5N(6O)riw78s

787 

788 ok, options, args = parser.parse_args_ok(argv) 1PxQyjaRzSAkbTBUClcVDWEmdXFYGneZH90I!oft1J#2K$pgu3L%4M'qhv5N(6O)riw78s

789 if not ok: 1PxQyjaRzSAkbTBUClcVDWEmdXFYGneZH90I!oft1J#2K$pgu3L%4M'qhv5N(6O)riw78s

790 return ERR 1PxQyjaRzSAkbTBUClcVDWEmdXFYGneZH90I!oft1J#2K$pgu3L%4M'qhv5N(6O)riw78s

791 assert options is not None 1PxQyjaRzSAkbTBUClcVDWEmdXFYGneZH90I!oft1J#2K$pgu3L%4M'qhv5N(6O)riw78s

792 

793 # Handle help and version. 

794 if self.do_help(options, args, parser): 1PxQyjaRzSAkbTBUClcVDWEmdXFYGneZH90I!oft1J#2K$pgu3L%4M'qhv5N(6O)riw78s

795 return OK 1PxQyjaRzSAkbTBUClcVDWEmdXFYGneZH90I!oft1J#2K$pgu3L%4M'qhv5N(6O)riw78s

796 

797 # Listify the list options. 

798 source = unshell_list(options.source) 1PxQyjaRzSAkbTBUClcVDWEmdXFYGneZH90I!oft1J#2K$pgu3L%4M'qhv5N(6O)riw78s

799 omit = unshell_list(options.omit) 1PxQyjaRzSAkbTBUClcVDWEmdXFYGneZH90I!oft1J#2K$pgu3L%4M'qhv5N(6O)riw78s

800 include = unshell_list(options.include) 1PxQyjaRzSAkbTBUClcVDWEmdXFYGneZH90I!oft1J#2K$pgu3L%4M'qhv5N(6O)riw78s

801 debug = unshell_list(options.debug) 1PxQyjaRzSAkbTBUClcVDWEmdXFYGneZH90I!oft1J#2K$pgu3L%4M'qhv5N(6O)riw78s

802 contexts = unshell_list(options.contexts) 1PxQyjaRzSAkbTBUClcVDWEmdXFYGneZH90I!oft1J#2K$pgu3L%4M'qhv5N(6O)riw78s

803 

804 if options.concurrency is not None: 1PxQyjaRzSAkbTBUClcVDWEmdXFYGneZH90I!oft1J#2K$pgu3L%4M'qhv5N(6O)riw78s

805 concurrency = options.concurrency.split(",") 1PxQyjaRzSAkbTBUClcVDWEmdXFYGneZH90I!oft1J#2K$pgu3L%4M'qhv5N(6O)riw78s

806 else: 

807 concurrency = None 1PxQyjaRzSAkbTBUClcVDWEmdXFYGneZH90I!oft1J#2K$pgu3L%4M'qhv5N(6O)riw78s

808 

809 # Do something. 

810 self.coverage = Coverage( 1PxQyjaRzSAkbTBUClcVDWEmdXFYGneZH90I!oft1J#2K$pgu3L%4M'qhv5N(6O)riw78s

811 data_file=options.data_file or DEFAULT_DATAFILE, 

812 data_suffix=options.parallel_mode, 

813 cover_pylib=options.pylib, 

814 timid=options.timid, 

815 branch=options.branch, 

816 config_file=options.rcfile, 

817 source=source, 

818 omit=omit, 

819 include=include, 

820 debug=debug, 

821 concurrency=concurrency, 

822 check_preimported=True, 

823 context=options.context, 

824 messages=not options.quiet, 

825 ) 

826 

827 if options.action == "debug": 1PxQyjaRzSAkbTBUClcVDWEmdXFYGneZH90I!oft1J#2K$pgu3L%4M'qhv5N(6O)riw78s

828 return self.do_debug(args) 1PxQyjaRzSAkbTBUClcVDWEmdXFYGneZH90I!oft1J#2K$pgu3L%4M'qhv5N(6O)riw78s

829 

830 elif options.action == "erase": 1PxQyjaRzSAkbTBUClcVDWEmdXFYGneZH90I!oft1J#2K$pgu3L%4M'qhv5N(6O)riw78s

831 self.coverage.erase() 1PxQyjaRzSAkbTBUClcVDWEmdXFYGneZH90I!oft1J#2K$pgu3L%4M'qhv5N(6O)riw78s

832 return OK 1PxQyjaRzSAkbTBUClcVDWEmdXFYGneZH90I!oft1J#2K$pgu3L%4M'qhv5N(6O)riw78s

833 

834 elif options.action == "run": 1PxQyjaRzSAkbTBUClcVDWEmdXFYGneZH90I!oft1J#2K$pgu3L%4M'qhv5N(6O)riw78s

835 return self.do_run(options, args) 1PxQyjaRzSAkbTBUClcVDWEmdXFYGneZH90I!oft1J#2K$pgu3L%4M'qhv5N(6O)riw78s

836 

837 elif options.action == "combine": 1PxQyjaRzSAkbTBUClcVDWEmdXFYGneZH90I!oft1J#2K$pgu3L%4M'qhv5N(6O)riw78s

838 if options.append: 1PxQyjaRzSAkbTBUClcVDWEmdXFYGneZH90I!oft1J#2K$pgu3L%4M'qhv5N(6O)riw78s

839 self.coverage.load() 1PxQyjaRzSAkbTBUClcVDWEmdXFYGneZH90I!oft1J#2K$pgu3L%4M'qhv5N(6O)riw78s

840 data_paths = args or None 1PxQyjaRzSAkbTBUClcVDWEmdXFYGneZH90I!oft1J#2K$pgu3L%4M'qhv5N(6O)riw78s

841 self.coverage.combine(data_paths, strict=True, keep=bool(options.keep)) 1PxQyjaRzSAkbTBUClcVDWEmdXFYGneZH90I!oft1J#2K$pgu3L%4M'qhv5N(6O)riw78s

842 self.coverage.save() 1PxQyjaRzSAkbTBUClcVDWEmdXFYGneZH90I!oft1J#2K$pgu3L%4M'qhv5N(6O)riw78s

843 return OK 1PxQyjaRzSAkbTBUClcVDWEmdXFYGneZH90I!oft1J#2K$pgu3L%4M'qhv5N(6O)riw78s

844 

845 # Remaining actions are reporting, with some common options. 

846 report_args = dict( 1PxQyjaRzSAkbTBUClcVDWEmdXFYGneZH90I!oft1J#2K$pgu3L%4M'qhv5N(6O)riw78s

847 morfs=unglob_args(args), 

848 ignore_errors=options.ignore_errors, 

849 omit=omit, 

850 include=include, 

851 contexts=contexts, 

852 ) 

853 

854 # We need to be able to import from the current directory, because 

855 # plugins may try to, for example, to read Django settings. 

856 sys.path.insert(0, "") 1PxQyjaRzSAkbTBUClcVDWEmdXFYGneZH90I!oft1J#2K$pgu3L%4M'qhv5N(6O)riw78s

857 

858 self.coverage.load() 1PxQyjaRzSAkbTBUClcVDWEmdXFYGneZH90I!oft1J#2K$pgu3L%4M'qhv5N(6O)riw78s

859 

860 total = None 1PxQyjaRzSAkbTBUClcVDWEmdXFYGneZH90I!oft1J#2K$pgu3L%4M'qhv5N(6O)riw78s

861 if options.action == "report": 1PxQyjaRzSAkbTBUClcVDWEmdXFYGneZH90I!oft1J#2K$pgu3L%4M'qhv5N(6O)riw78s

862 total = self.coverage.report( 1PxQyjaRzSAkbTBUClcVDWEmdXFYGneZH90I!oft1J#2K$pgu3L%4M'qhv5N(6O)riw78s

863 precision=options.precision, 

864 show_missing=options.show_missing, 

865 skip_covered=options.skip_covered, 

866 skip_empty=options.skip_empty, 

867 sort=options.sort, 

868 output_format=options.format, 

869 **report_args, 

870 ) 

871 elif options.action == "annotate": 1PxQyjaRzSAkbTBUClcVDWEmdXFYGneZH90I!oft1J#2K$pgu3L%4M'qhv5N(6O)riw78s

872 self.coverage.annotate(directory=options.directory, **report_args) 1PxQyjaRzSAkbTBUClcVDWEmdXFYGneZH90I!oft1J#2K$pgu3L%4M'qhv5N(6O)riw78s

873 elif options.action == "html": 1PxQyjaRzSAkbTBUClcVDWEmdXFYGneZH90I!oft1J#2K$pgu3L%4M'qhv5N(6O)riw78s

874 total = self.coverage.html_report( 1PxQyjaRzSAkbTBUClcVDWEmdXFYGneZH90I!oft1J#2K$pgu3L%4M'qhv5N(6O)riw78s

875 directory=options.directory, 

876 precision=options.precision, 

877 skip_covered=options.skip_covered, 

878 skip_empty=options.skip_empty, 

879 show_contexts=options.show_contexts, 

880 title=options.title, 

881 **report_args, 

882 ) 

883 elif options.action == "xml": 1PxQyjaRzSAkbTBUClcVDWEmdXFYGneZH90I!oft1J#2K$pgu3L%4M'qhv5N(6O)riw78s

884 total = self.coverage.xml_report( 1PxQyjaRzSAkbTBUClcVDWEmdXFYGneZH90I!oft1J#2K$pgu3L%4M'qhv5N(6O)riw78s

885 outfile=options.outfile, 

886 skip_empty=options.skip_empty, 

887 **report_args, 

888 ) 

889 elif options.action == "json": 1PxQyjaRzSAkbTBUClcVDWEmdXFYGneZH90I!oft1J#2K$pgu3L%4M'qhv5N(6O)riw78s

890 total = self.coverage.json_report( 1PxQyjaRzSAkbTBUClcVDWEmdXFYGneZH90I!oft1J#2K$pgu3L%4M'qhv5N(6O)riw78s

891 outfile=options.outfile, 

892 pretty_print=options.pretty_print, 

893 show_contexts=options.show_contexts, 

894 **report_args, 

895 ) 

896 elif options.action == "lcov": 1PxQyjaRzSAkbTBUClcVDWEmdXFYGneZH90I!oft1J#2K$pgu3L%4M'qhv5N(6O)riw78s

897 total = self.coverage.lcov_report( 1PxQyjaRzSAkbTBUClcVDWEmdXFYGneZH90I!oft1J#2K$pgu3L%4M'qhv5N(6O)riw78s

898 outfile=options.outfile, 

899 **report_args, 

900 ) 

901 else: 

902 # There are no other possible actions. 

903 raise AssertionError 

904 

905 if total is not None: 1PxQyjaRzSAkbTBUClcVDWEmdXFYGneZH90I!oft1J#2K$pgu3L%4M'qhv5N(6O)riw78s

906 # Apply the command line fail-under options, and then use the config 

907 # value, so we can get fail_under from the config file. 

908 if options.fail_under is not None: 1PxQyjaRzSAkbTBUClcVDWEmdXFYGneZH90I!oft1J#2K$pgu3L%4M'qhv5N(6O)riw78s

909 self.coverage.set_option("report:fail_under", options.fail_under) 1PxQyjaRzSAkbTBUClcVDWEmdXFYGneZH90I!oft1J#2K$pgu3L%4M'qhv5N(6O)riw78s

910 if options.precision is not None: 1PxQyjaRzSAkbTBUClcVDWEmdXFYGneZH90I!oft1J#2K$pgu3L%4M'qhv5N(6O)riw78s

911 self.coverage.set_option("report:precision", options.precision) 1PxQyjaRzSAkbTBUClcVDWEmdXFYGneZH90I!oft1J#2K$pgu3L%4M'qhv5N(6O)riw78s

912 

913 fail_under = cast(float, self.coverage.get_option("report:fail_under")) 1PxQyjaRzSAkbTBUClcVDWEmdXFYGneZH90I!oft1J#2K$pgu3L%4M'qhv5N(6O)riw78s

914 precision = cast(int, self.coverage.get_option("report:precision")) 1PxQyjaRzSAkbTBUClcVDWEmdXFYGneZH90I!oft1J#2K$pgu3L%4M'qhv5N(6O)riw78s

915 if should_fail_under(total, fail_under, precision): 1PxQyjaRzSAkbTBUClcVDWEmdXFYGneZH90I!oft1J#2K$pgu3L%4M'qhv5N(6O)riw78s

916 msg = "total of {total} is less than fail-under={fail_under:.{p}f}".format( 1PxQyjaRzSAkbTBUClcVDWEmdXFYGneZH90I!oft1J#2K$pgu3L%4M'qhv5N(6O)riw78s

917 total=display_covered(total, precision), 

918 fail_under=fail_under, 

919 p=precision, 

920 ) 

921 print("Coverage failure:", msg) 1PxQyjaRzSAkbTBUClcVDWEmdXFYGneZH90I!oft1J#2K$pgu3L%4M'qhv5N(6O)riw78s

922 return FAIL_UNDER 1PxQyjaRzSAkbTBUClcVDWEmdXFYGneZH90I!oft1J#2K$pgu3L%4M'qhv5N(6O)riw78s

923 

924 return OK 1PxQyjaRzSAkbTBUClcVDWEmdXFYGneZH90I!oft1J#2K$pgu3L%4M'qhv5N(6O)riw78s

925 

926 def do_help( 1PxQyjaRzSAkbTBUClcVDWEmdXFYGneZH90I!oft1J#2K$pgu3L%4M'qhv5N(6O)riw78s

927 self, 

928 options: optparse.Values, 

929 args: list[str], 

930 parser: optparse.OptionParser, 

931 ) -> bool: 

932 """Deal with help requests. 

933 

934 Return True if it handled the request, False if not. 

935 

936 """ 

937 # Handle help. 

938 if options.help: 1PxQyjaRzSAkbTBUClcVDWEmdXFYGneZH90I!oft1J#2K$pgu3L%4M'qhv5N(6O)riw78s

939 if self.global_option: 1PxQyjaRzSAkbTBUClcVDWEmdXFYGneZH90I!oft1J#2K$pgu3L%4M'qhv5N(6O)riw78s

940 show_help(topic="help") 1PxQyjaRzSAkbTBUClcVDWEmdXFYGneZH90I!oft1J#2K$pgu3L%4M'qhv5N(6O)riw78s

941 else: 

942 show_help(parser=parser) 1PxQyjaRzSAkbTBUClcVDWEmdXFYGneZH90I!oft1J#2K$pgu3L%4M'qhv5N(6O)riw78s

943 return True 1PxQyjaRzSAkbTBUClcVDWEmdXFYGneZH90I!oft1J#2K$pgu3L%4M'qhv5N(6O)riw78s

944 

945 if options.action == "help": 1PxQyjaRzSAkbTBUClcVDWEmdXFYGneZH90I!oft1J#2K$pgu3L%4M'qhv5N(6O)riw78s

946 if args: 1PxQyjaRzSAkbTBUClcVDWEmdXFYGneZH90I!oft1J#2K$pgu3L%4M'qhv5N(6O)riw78s

947 for a in args: 1PxQyjaRzSAkbTBUClcVDWEmdXFYGneZH90I!oft1J#2K$pgu3L%4M'qhv5N(6O)riw78s

948 parser_maybe = COMMANDS.get(a) 1PxQyjaRzSAkbTBUClcVDWEmdXFYGneZH90I!oft1J#2K$pgu3L%4M'qhv5N(6O)riw78s

949 if parser_maybe is not None: 1PxQyjaRzSAkbTBUClcVDWEmdXFYGneZH90I!oft1J#2K$pgu3L%4M'qhv5N(6O)riw78s

950 show_help(parser=parser_maybe) 1PxQyjaRzSAkbTBUClcVDWEmdXFYGneZH90I!oft1J#2K$pgu3L%4M'qhv5N(6O)riw78s

951 else: 

952 show_help(topic=a) 1PxQyjaRzSAkbTBUClcVDWEmdXFYGneZH90I!oft1J#2K$pgu3L%4M'qhv5N(6O)riw78s

953 else: 

954 show_help(topic="help") 1PxQyjaRzSAkbTBUClcVDWEmdXFYGneZH90I!oft1J#2K$pgu3L%4M'qhv5N(6O)riw78s

955 return True 1PxQyjaRzSAkbTBUClcVDWEmdXFYGneZH90I!oft1J#2K$pgu3L%4M'qhv5N(6O)riw78s

956 

957 # Handle version. 

958 if options.version: 1PxQyjaRzSAkbTBUClcVDWEmdXFYGneZH90I!oft1J#2K$pgu3L%4M'qhv5N(6O)riw78s

959 show_help(topic="version") 1PxQyjaRzSAkbTBUClcVDWEmdXFYGneZH90I!oft1J#2K$pgu3L%4M'qhv5N(6O)riw78s

960 return True 1PxQyjaRzSAkbTBUClcVDWEmdXFYGneZH90I!oft1J#2K$pgu3L%4M'qhv5N(6O)riw78s

961 

962 return False 1PxQyjaRzSAkbTBUClcVDWEmdXFYGneZH90I!oft1J#2K$pgu3L%4M'qhv5N(6O)riw78s

963 

964 def do_signal_save(self, _signum: int, _frame: types.FrameType | None) -> None: 1PxQyjaRzSAkbTBUClcVDWEmdXFYGneZH90I!oft1J#2K$pgu3L%4M'qhv5N(6O)riw78s

965 """Signal handler to save coverage report""" 

966 print("Saving coverage data...", flush=True) 

967 self.coverage.save() 

968 

969 def do_run(self, options: optparse.Values, args: list[str]) -> int: 1PxQyjaRzSAkbTBUClcVDWEmdXFYGneZH90I!oft1J#2K$pgu3L%4M'qhv5N(6O)riw78s

970 """Implementation of 'coverage run'.""" 

971 

972 if not args: 1PxQyjaRzSAkbTBUClcVDWEmdXFYGneZH90I!oft1J#2K$pgu3L%4M'qhv5N(6O)riw78s

973 if options.module: 1PxQyjaRzSAkbTBUClcVDWEmdXFYGneZH90I!oft1J#2K$pgu3L%4M'qhv5N(6O)riw78s

974 # Specified -m with nothing else. 

975 show_help("No module specified for -m") 1PxQyjaRzSAkbTBUClcVDWEmdXFYGneZH90I!oft1J#2K$pgu3L%4M'qhv5N(6O)riw78s

976 return ERR 1PxQyjaRzSAkbTBUClcVDWEmdXFYGneZH90I!oft1J#2K$pgu3L%4M'qhv5N(6O)riw78s

977 command_line = cast(str, self.coverage.get_option("run:command_line")) 1PxQyjaRzSAkbTBUClcVDWEmdXFYGneZH90I!oft1J#2K$pgu3L%4M'qhv5N(6O)riw78s

978 if command_line is not None: 1PxQyjaRzSAkbTBUClcVDWEmdXFYGneZH90I!oft1J#2K$pgu3L%4M'qhv5N(6O)riw78s

979 args = shlex.split(command_line) 1PxQyjaRzSAkbTBUClcVDWEmdXFYGneZH90I!oft1J#2K$pgu3L%4M'qhv5N(6O)riw78s

980 if args and args[0] in {"-m", "--module"}: 1PxQyjaRzSAkbTBUClcVDWEmdXFYGneZH90I!oft1J#2K$pgu3L%4M'qhv5N(6O)riw78s

981 options.module = True 1PxQyjaRzSAkbTBUClcVDWEmdXFYGneZH90I!oft1J#2K$pgu3L%4M'qhv5N(6O)riw78s

982 args = args[1:] 1PxQyjaRzSAkbTBUClcVDWEmdXFYGneZH90I!oft1J#2K$pgu3L%4M'qhv5N(6O)riw78s

983 if not args: 1PxQyjaRzSAkbTBUClcVDWEmdXFYGneZH90I!oft1J#2K$pgu3L%4M'qhv5N(6O)riw78s

984 show_help("Nothing to do.") 1PxQyjaRzSAkbTBUClcVDWEmdXFYGneZH90I!oft1J#2K$pgu3L%4M'qhv5N(6O)riw78s

985 return ERR 1PxQyjaRzSAkbTBUClcVDWEmdXFYGneZH90I!oft1J#2K$pgu3L%4M'qhv5N(6O)riw78s

986 

987 if options.append and self.coverage.get_option("run:parallel"): 1PxQyjaRzSAkbTBUClcVDWEmdXFYGneZH90I!oft1J#2K$pgu3L%4M'qhv5N(6O)riw78s

988 show_help("Can't append to data files in parallel mode.") 1PxQyjaRzSAkbTBUClcVDWEmdXFYGneZH90I!oft1J#2K$pgu3L%4M'qhv5N(6O)riw78s

989 return ERR 1PxQyjaRzSAkbTBUClcVDWEmdXFYGneZH90I!oft1J#2K$pgu3L%4M'qhv5N(6O)riw78s

990 

991 if options.concurrency == "multiprocessing": 1PxQyjaRzSAkbTBUClcVDWEmdXFYGneZH90I!oft1J#2K$pgu3L%4M'qhv5N(6O)riw78s

992 # Can't set other run-affecting command line options with 

993 # multiprocessing. 

994 for opt_name in ["branch", "include", "omit", "pylib", "source", "timid"]: 1PxQyjaRzSAkbTBUClcVDWEmdXFYGneZH90I!oft1J#2K$pgu3L%4M'qhv5N(6O)riw78s

995 # As it happens, all of these options have no default, meaning 

996 # they will be None if they have not been specified. 

997 if getattr(options, opt_name) is not None: 1PxQyjaRzSAkbTBUClcVDWEmdXFYGneZH90I!oft1J#2K$pgu3L%4M'qhv5N(6O)riw78s

998 show_help( 1PxQyjaRzSAkbTBUClcVDWEmdXFYGneZH90I!oft1J#2K$pgu3L%4M'qhv5N(6O)riw78s

999 "Options affecting multiprocessing must only be specified " 

1000 + "in a configuration file.\n" 

1001 + f"Remove --{opt_name} from the command line.", 

1002 ) 

1003 return ERR 1PxQyjaRzSAkbTBUClcVDWEmdXFYGneZH90I!oft1J#2K$pgu3L%4M'qhv5N(6O)riw78s

1004 

1005 os.environ["COVERAGE_RUN"] = "true" 1PxQyjaRzSAkbTBUClcVDWEmdXFYGneZH90I!oft1J#2K$pgu3L%4M'qhv5N(6O)riw78s

1006 

1007 runner = PyRunner(args, as_module=bool(options.module)) 1PxQyjaRzSAkbTBUClcVDWEmdXFYGneZH90I!oft1J#2K$pgu3L%4M'qhv5N(6O)riw78s

1008 runner.prepare() 1PxQyjaRzSAkbTBUClcVDWEmdXFYGneZH90I!oft1J#2K$pgu3L%4M'qhv5N(6O)riw78s

1009 

1010 if options.append: 1PxQyjaRzSAkbTBUClcVDWEmdXFYGneZH90I!oft1J#2K$pgu3L%4M'qhv5N(6O)riw78s

1011 self.coverage.load() 1PxQyjaRzSAkbTBUClcVDWEmdXFYGneZH90I!oft1J#2K$pgu3L%4M'qhv5N(6O)riw78s

1012 

1013 if options.save_signal: 1PxQyjaRzSAkbTBUClcVDWEmdXFYGneZH90I!oft1J#2K$pgu3L%4M'qhv5N(6O)riw78s

1014 if env.WINDOWS: 1014 ↛ 1017line 1014 didn't jump to line 1017 because the condition on line 1014 was always true1jakblcmdneoftpguqhvriws

1015 show_help("--save-signal is not supported on Windows.") 1jakblcmdneoftpguqhvriws

1016 return ERR 1jakblcmdneoftpguqhvriws

1017 sig = getattr(signal, f"SIG{options.save_signal}") 

1018 signal.signal(sig, self.do_signal_save) 

1019 

1020 # Run the script. 

1021 self.coverage.start() 1PxQyjaRzSAkbTBUClcVDWEmdXFYGneZH90I!oft1J#2K$pgu3L%4M'qhv5N(6O)riw78s

1022 code_ran = True 1PxQyjaRzSAkbTBUClcVDWEmdXFYGneZH90I!oft1J#2K$pgu3L%4M'qhv5N(6O)riw78s

1023 try: 1PxQyjaRzSAkbTBUClcVDWEmdXFYGneZH90I!oft1J#2K$pgu3L%4M'qhv5N(6O)riw78s

1024 runner.run() 1PxQyjaRzSAkbTBUClcVDWEmdXFYGneZH90I!oft1J#2K$pgu3L%4M'qhv5N(6O)riw78s

1025 except NoSource: 1xyazAbBCcDEdFGeHIfJKgLMhNOi78s

1026 code_ran = False 1xyazAbBCcDEdFGeHIfJKgLMhNOi78s

1027 raise 1xyazAbBCcDEdFGeHIfJKgLMhNOi78s

1028 finally: 

1029 self.coverage.stop() 1PxQyjaRzSAkbTBUClcVDWEmdXFYGneZH90I!oft1J#2K$pgu3L%4M'qhv5N(6O)riw78s

1030 if code_ran: 1030 ↛ 1033line 1030 didn't jump to line 1033 because the condition on line 1030 was always true1PxQyjaRzSAkbTBUClcVDWEmdXFYGneZH90I!oft1J#2K$pgu3L%4M'qhv5N(6O)riw78s

1031 self.coverage.save() 1PxQyjaRzSAkbTBUClcVDWEmdXFYGneZH90I!oft1J#2K$pgu3L%4M'qhv5N(6O)riw78s

1032 

1033 return OK 1PxQyjaRzSAkbTBUClcVDWEmdXFYGneZH90I!oft1J#2K$pgu3L%4M'qhv5N(6O)riw78s

1034 

1035 def do_debug(self, args: list[str]) -> int: 1PxQyjaRzSAkbTBUClcVDWEmdXFYGneZH90I!oft1J#2K$pgu3L%4M'qhv5N(6O)riw78s

1036 """Implementation of 'coverage debug'.""" 

1037 

1038 if not args: 1PxQyjaRzSAkbTBUClcVDWEmdXFYGneZH90I!oft1J#2K$pgu3L%4M'qhv5N(6O)riw78s

1039 show_help( 1PxQyjaRzSAkbTBUClcVDWEmdXFYGneZH90I!oft1J#2K$pgu3L%4M'qhv5N(6O)riw78s

1040 "What information would you like: " 

1041 + "config, data, sys, premain, pybehave, sqlite?" 

1042 ) 

1043 return ERR 1PxQyjaRzSAkbTBUClcVDWEmdXFYGneZH90I!oft1J#2K$pgu3L%4M'qhv5N(6O)riw78s

1044 if args[1:]: 1PxQyjaRzSAkbTBUClcVDWEmdXFYGneZH90I!oft1J#2K$pgu3L%4M'qhv5N(6O)riw78s

1045 show_help("Only one topic at a time, please") 1PxQyjaRzSAkbTBUClcVDWEmdXFYGneZH90I!oft1J#2K$pgu3L%4M'qhv5N(6O)riw78s

1046 return ERR 1PxQyjaRzSAkbTBUClcVDWEmdXFYGneZH90I!oft1J#2K$pgu3L%4M'qhv5N(6O)riw78s

1047 

1048 if args[0] == "sys": 1PxQyjaRzSAkbTBUClcVDWEmdXFYGneZH90I!oft1J#2K$pgu3L%4M'qhv5N(6O)riw78s

1049 write_formatted_info(print, "sys", self.coverage.sys_info()) 1PxQyjaRzSAkbTBUClcVDWEmdXFYGneZH90I!oft1J#2K$pgu3L%4M'qhv5N(6O)riw78s

1050 elif args[0] == "data": 1PxQyjaRzSAkbTBUClcVDWEmdXFYGneZH90I!oft1J#2K$pgu3L%4M'qhv5N(6O)riw78s

1051 print(info_header("data")) 1PxQyjaRzSAkbTBUClcVDWEmdXFYGneZH90I!oft1J#2K$pgu3L%4M'qhv5N(6O)riw78s

1052 data_file = self.coverage.config.data_file 1PxQyjaRzSAkbTBUClcVDWEmdXFYGneZH90I!oft1J#2K$pgu3L%4M'qhv5N(6O)riw78s

1053 debug_data_file(data_file) 1PxQyjaRzSAkbTBUClcVDWEmdXFYGneZH90I!oft1J#2K$pgu3L%4M'qhv5N(6O)riw78s

1054 for filename in combinable_files(data_file): 1PxQyjaRzSAkbTBUClcVDWEmdXFYGneZH90I!oft1J#2K$pgu3L%4M'qhv5N(6O)riw78s

1055 print("-----") 1PxQyjaRzSAkbTBUClcVDWEmdXFYGneZH90I!oft1J#2K$pgu3L%4M'qhv5N(6O)riw78s

1056 debug_data_file(filename) 1PxQyjaRzSAkbTBUClcVDWEmdXFYGneZH90I!oft1J#2K$pgu3L%4M'qhv5N(6O)riw78s

1057 elif args[0] == "config": 1PxQyjaRzSAkbTBUClcVDWEmdXFYGneZH90I!oft1J#2K$pgu3L%4M'qhv5N(6O)riw78s

1058 write_formatted_info(print, "config", self.coverage.config.debug_info()) 1PxQyjaRzSAkbTBUClcVDWEmdXFYGneZH90I!oft1J#2K$pgu3L%4M'qhv5N(6O)riw78s

1059 elif args[0] == "premain": 1PxQyjaRzSAkbTBUClcVDWEmdXFYGneZH90I!oft1J#2K$pgu3L%4M'qhv5N(6O)riw78s

1060 print(info_header("premain")) 1PxQyjaRzSAkbTBUClcVDWEmdXFYGneZH90I!oft1J#2K$pgu3L%4M'qhv5N(6O)riw78s

1061 print(short_stack(full=True)) 1PxQyjaRzSAkbTBUClcVDWEmdXFYGneZH90I!oft1J#2K$pgu3L%4M'qhv5N(6O)riw78s

1062 elif args[0] == "pybehave": 1PxQyjaRzSAkbTBUClcVDWEmdXFYGneZH90I!oft1J#2K$pgu3L%4M'qhv5N(6O)riw78s

1063 write_formatted_info(print, "pybehave", env.debug_info()) 1PxQyjaRzSAkbTBUClcVDWEmdXFYGneZH90I!oft1J#2K$pgu3L%4M'qhv5N(6O)riw78s

1064 elif args[0] == "sqlite": 1PxQyjaRzSAkbTBUClcVDWEmdXFYGneZH90I!oft1J#2K$pgu3L%4M'qhv5N(6O)riw78s

1065 write_formatted_info(print, "sqlite", CoverageData.sys_info()) 1PxQyjaRzSAkbTBUClcVDWEmdXFYGneZH90I!oft1J#2K$pgu3L%4M'qhv5N(6O)riw78s

1066 else: 

1067 show_help(f"Don't know what you mean by {args[0]!r}") 1PxQyjaRzSAkbTBUClcVDWEmdXFYGneZH90I!oft1J#2K$pgu3L%4M'qhv5N(6O)riw78s

1068 return ERR 1PxQyjaRzSAkbTBUClcVDWEmdXFYGneZH90I!oft1J#2K$pgu3L%4M'qhv5N(6O)riw78s

1069 

1070 return OK 1PxQyjaRzSAkbTBUClcVDWEmdXFYGneZH90I!oft1J#2K$pgu3L%4M'qhv5N(6O)riw78s

1071 

1072 

1073def unshell_list(s: str) -> list[str] | None: 1PxQyjaRzSAkbTBUClcVDWEmdXFYGneZH90I!oft1J#2K$pgu3L%4M'qhv5N(6O)riw78s

1074 """Turn a command-line argument into a list.""" 

1075 if not s: 1PxQyjaRzSAkbTBUClcVDWEmdXFYGneZH90I!oft1J#2K$pgu3L%4M'qhv5N(6O)riw78s

1076 return None 1PxQyjaRzSAkbTBUClcVDWEmdXFYGneZH90I!oft1J#2K$pgu3L%4M'qhv5N(6O)riw78s

1077 if env.WINDOWS: 1PxQyjaRzSAkbTBUClcVDWEmdXFYGneZH90I!oft1J#2K$pgu3L%4M'qhv5N(6O)riw78s

1078 # When running coverage.py as coverage.exe, some of the behavior 

1079 # of the shell is emulated: wildcards are expanded into a list of 

1080 # file names. So you have to single-quote patterns on the command 

1081 # line, but (not) helpfully, the single quotes are included in the 

1082 # argument, so we have to strip them off here. 

1083 s = s.strip("'") 1jakblcmdneoftpguqhvriws

1084 return s.split(",") 1PxQyjaRzSAkbTBUClcVDWEmdXFYGneZH90I!oft1J#2K$pgu3L%4M'qhv5N(6O)riw78s

1085 

1086 

1087def unglob_args(args: list[str]) -> list[str]: 1PxQyjaRzSAkbTBUClcVDWEmdXFYGneZH90I!oft1J#2K$pgu3L%4M'qhv5N(6O)riw78s

1088 """Interpret shell wildcards for platforms that need it.""" 

1089 if env.WINDOWS: 1PxQyjaRzSAkbTBUClcVDWEmdXFYGneZH90I!oft1J#2K$pgu3L%4M'qhv5N(6O)riw78s

1090 globbed = [] 1jakblcmdneoftpguqhvriws

1091 for arg in args: 1jakblcmdneoftpguqhvriws

1092 if "?" in arg or "*" in arg: 1jakblcmdneoftpguqhvriws

1093 globbed.extend(glob.glob(arg)) 1jakblcmdneoftpguqhvriws

1094 else: 

1095 globbed.append(arg) 1jakblcmdneoftpguqhvriws

1096 args = globbed 1jakblcmdneoftpguqhvriws

1097 return args 1PxQyjaRzSAkbTBUClcVDWEmdXFYGneZH90I!oft1J#2K$pgu3L%4M'qhv5N(6O)riw78s

1098 

1099 

1100HELP_TOPICS = { 1PxQyjaRzSAkbTBUClcVDWEmdXFYGneZH90I!oft1J#2K$pgu3L%4M'qhv5N(6O)riw78s

1101 "help": """\ 

1102 Coverage.py, version {__version__} {extension_modifier} 

1103 Measure, collect, and report on code coverage in Python programs. 

1104 

1105 usage: {program_name} <command> [options] [args] 

1106 

1107 Commands: 

1108 annotate Annotate source files with execution information. 

1109 combine Combine a number of data files. 

1110 debug Display information about the internals of coverage.py 

1111 erase Erase previously collected coverage data. 

1112 help Get help on using coverage.py. 

1113 html Create an HTML report. 

1114 json Create a JSON report of coverage results. 

1115 lcov Create an LCOV report of coverage results. 

1116 report Report coverage stats on modules. 

1117 run Run a Python program and measure code execution. 

1118 xml Create an XML report of coverage results. 

1119 

1120 Use "{program_name} help <command>" for detailed help on any command. 

1121 """, 

1122 "minimum_help": oneline( 

1123 """ 

1124 Code coverage for Python, version {__version__} {extension_modifier}. 

1125 Use '{program_name} help' for help. 

1126 """ 

1127 ), 

1128 "version": "Coverage.py, version {__version__} {extension_modifier}", 

1129} 

1130 

1131 

1132def main(argv: list[str] | None = None) -> int | None: 1PxQyjaRzSAkbTBUClcVDWEmdXFYGneZH90I!oft1J#2K$pgu3L%4M'qhv5N(6O)riw78s

1133 """The main entry point to coverage.py. 

1134 

1135 This is installed as the script entry point. 

1136 

1137 """ 

1138 if argv is None: 1PxQyjaRzSAkbTBUClcVDWEmdXFYGneZH90I!oft1J#2K$pgu3L%4M'qhv5N(6O)riw78s

1139 argv = sys.argv[1:] 1PxQyjaRzSAkbTBUClcVDWEmdXFYGneZH90I!oft1J#2K$pgu3L%4M'qhv5N(6O)riw78s

1140 try: 1PxQyjaRzSAkbTBUClcVDWEmdXFYGneZH90I!oft1J#2K$pgu3L%4M'qhv5N(6O)riw78s

1141 status = CoverageScript().command_line(argv) 1PxQyjaRzSAkbTBUClcVDWEmdXFYGneZH90I!oft1J#2K$pgu3L%4M'qhv5N(6O)riw78s

1142 except _ExceptionDuringRun as err: 1PxQyjaRzSAkbTBUClcVDWEmdXFYGneZH90I!oft1J#2K$pgu3L%4M'qhv5N(6O)riw78s

1143 # An exception was caught while running the product code. The 

1144 # sys.exc_info() return tuple is packed into an _ExceptionDuringRun 

1145 # exception. 

1146 traceback.print_exception(*err.args) # pylint: disable=no-value-for-parameter 1PxQyjaRzSAkbTBUClcVDWEmdXFYGneZH90I!oft1J#2K$pgu3L%4M'qhv5N(6O)riw78s

1147 status = ERR 1PxQyjaRzSAkbTBUClcVDWEmdXFYGneZH90I!oft1J#2K$pgu3L%4M'qhv5N(6O)riw78s

1148 except CoverageException as err: 1PxQyjaRzSAkbTBUClcVDWEmdXFYGneZH90I!oft1J#2K$pgu3L%4M'qhv5N(6O)riw78s

1149 # A controlled error inside coverage.py: print the message to the user. 

1150 msg = err.args[0] 1PxQyjaRzSAkbTBUClcVDWEmdXFYGneZH90I!oft1J#2K$pgu3L%4M'qhv5N(6O)riw78s

1151 if err.slug: 1PxQyjaRzSAkbTBUClcVDWEmdXFYGneZH90I!oft1J#2K$pgu3L%4M'qhv5N(6O)riw78s

1152 msg = f"{msg.rstrip('.')}; see {__url__}/messages.html#error-{err.slug}" 1PxQyjaRzSAkbTBUClcVDWEmdXFYGneZH90I!oft1J#2K$pgu3L%4M'qhv5N(6O)riw78s

1153 print(msg) 1PxQyjaRzSAkbTBUClcVDWEmdXFYGneZH90I!oft1J#2K$pgu3L%4M'qhv5N(6O)riw78s

1154 status = ERR 1PxQyjaRzSAkbTBUClcVDWEmdXFYGneZH90I!oft1J#2K$pgu3L%4M'qhv5N(6O)riw78s

1155 except SystemExit as err: 1PxQyjaRzSAkbTBUClcVDWEmdXFYGneZH90I!oft1J#2K$pgu3L%4M'qhv5N(6O)riw78s

1156 # The user called `sys.exit()`. Exit with their argument, if any. 

1157 if err.args: 1PxQyjaRzSAkbTBUClcVDWEmdXFYGneZH90I!oft1J#2K$pgu3L%4M'qhv5N(6O)riw78s

1158 status = err.args[0] 1PxQyjaRzSAkbTBUClcVDWEmdXFYGneZH90I!oft1J#2K$pgu3L%4M'qhv5N(6O)riw78s

1159 else: 

1160 status = None 1PxQyjaRzSAkbTBUClcVDWEmdXFYGneZH0Iof1J2Kpg3L4Mqh5N6Ori

1161 return status 1PxQyjaRzSAkbTBUClcVDWEmdXFYGneZH90I!oft1J#2K$pgu3L%4M'qhv5N(6O)riw78s

1162 

1163 

1164# Profiling using ox_profile. Install it from GitHub: 

1165# pip install git+https://github.com/emin63/ox_profile.git 

1166# 

1167# $set_env.py: COVERAGE_PROFILE - Set to use ox_profile. 

1168_profile = os.getenv("COVERAGE_PROFILE") 1PxQyjaRzSAkbTBUClcVDWEmdXFYGneZH90I!oft1J#2K$pgu3L%4M'qhv5N(6O)riw78s

1169if _profile: # pragma: debugging 1PxQyjaRzSAkbTBUClcVDWEmdXFYGneZH90I!oft1J#2K$pgu3L%4M'qhv5N(6O)riw78s

1170 from ox_profile.core.launchers import SimpleLauncher # pylint: disable=import-error 

1171 

1172 original_main = main 

1173 

1174 def main( # pylint: disable=function-redefined 

1175 argv: list[str] | None = None, 

1176 ) -> int | None: 

1177 """A wrapper around main that profiles.""" 

1178 profiler = SimpleLauncher.launch() 

1179 try: 

1180 return original_main(argv) 

1181 finally: 

1182 data, _ = profiler.query(re_filter="coverage", max_records=100) 

1183 print(profiler.show(query=data, limit=100, sep="", col="")) 

1184 profiler.cancel()