Skip to content

Commit ba884e4

Browse files
nbfalconnedbat
authored andcommitted
feat: use --data-file to configure the coverage database
1 parent cfe14c2 commit ba884e4

File tree

3 files changed

+54
-9
lines changed

3 files changed

+54
-9
lines changed

coverage/cmdline.py

+25-6
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
from coverage import env
1919
from coverage.collector import CTracer
2020
from coverage.config import CoverageConfig
21+
from coverage.control import DEFAULT_DATAFILE
2122
from coverage.data import combinable_files, debug_data_file
2223
from coverage.debug import info_formatter, info_header, short_stack
2324
from coverage.exceptions import _BaseCoverageException, _ExceptionDuringRun, NoSource
@@ -128,6 +129,17 @@ class Opts:
128129
metavar="OUTFILE",
129130
help="Write the LCOV report to this file. Defaults to 'coverage.lcov'",
130131
)
132+
output_coverage = optparse.make_option(
133+
'', '--data-file', action='store', dest="output_coverage",
134+
metavar="OUTFILE",
135+
help="Write the recorded coverage information to this file. Defaults to '.coverage'"
136+
)
137+
input_coverage = optparse.make_option(
138+
'', '--data-file', action='store', dest="input_coverage",
139+
metavar="INPUT",
140+
help="Read coverage data for report generation from this file (needed if you have "
141+
"specified -o previously). Defaults to '.coverage'"
142+
)
131143
json_pretty_print = optparse.make_option(
132144
'', '--pretty-print', action='store_true',
133145
help="Format the JSON for human readers.",
@@ -325,6 +337,8 @@ def get_prog_name(self):
325337
Opts.rcfile,
326338
]
327339

340+
REPORT_ARGS = [Opts.input_coverage]
341+
328342
CMDS = {
329343
'annotate': CmdOptionParser(
330344
"annotate",
@@ -333,7 +347,7 @@ def get_prog_name(self):
333347
Opts.ignore_errors,
334348
Opts.include,
335349
Opts.omit,
336-
] + GLOBAL_ARGS,
350+
] + REPORT_ARGS + GLOBAL_ARGS,
337351
usage="[options] [modules]",
338352
description=(
339353
"Make annotated copies of the given files, marking statements that are executed " +
@@ -347,6 +361,7 @@ def get_prog_name(self):
347361
Opts.append,
348362
Opts.keep,
349363
Opts.quiet,
364+
Opts.output_coverage
350365
] + GLOBAL_ARGS,
351366
usage="[options] <path1> <path2> ... <pathN>",
352367
description=(
@@ -374,7 +389,7 @@ def get_prog_name(self):
374389
),
375390

376391
'erase': CmdOptionParser(
377-
"erase", GLOBAL_ARGS,
392+
"erase", [Opts.input_coverage] + GLOBAL_ARGS,
378393
description="Erase previously collected coverage data.",
379394
),
380395

@@ -400,7 +415,7 @@ def get_prog_name(self):
400415
Opts.no_skip_covered,
401416
Opts.skip_empty,
402417
Opts.title,
403-
] + GLOBAL_ARGS,
418+
] + REPORT_ARGS + GLOBAL_ARGS,
404419
usage="[options] [modules]",
405420
description=(
406421
"Create an HTML report of the coverage of the files. " +
@@ -421,7 +436,7 @@ def get_prog_name(self):
421436
Opts.json_pretty_print,
422437
Opts.quiet,
423438
Opts.show_contexts,
424-
] + GLOBAL_ARGS,
439+
] + REPORT_ARGS + GLOBAL_ARGS,
425440
usage="[options] [modules]",
426441
description="Generate a JSON report of coverage results.",
427442
),
@@ -454,7 +469,7 @@ def get_prog_name(self):
454469
Opts.skip_covered,
455470
Opts.no_skip_covered,
456471
Opts.skip_empty,
457-
] + GLOBAL_ARGS,
472+
] + REPORT_ARGS + GLOBAL_ARGS,
458473
usage="[options] [modules]",
459474
description="Report coverage statistics on modules.",
460475
),
@@ -469,6 +484,7 @@ def get_prog_name(self):
469484
Opts.include,
470485
Opts.module,
471486
Opts.omit,
487+
Opts.output_coverage,
472488
Opts.pylib,
473489
Opts.parallel_mode,
474490
Opts.source,
@@ -488,7 +504,7 @@ def get_prog_name(self):
488504
Opts.output_xml,
489505
Opts.quiet,
490506
Opts.skip_empty,
491-
] + GLOBAL_ARGS,
507+
] + REPORT_ARGS + GLOBAL_ARGS,
492508
usage="[options] [modules]",
493509
description="Generate an XML report of coverage results.",
494510
),
@@ -591,8 +607,11 @@ def command_line(self, argv):
591607
else:
592608
concurrency = None
593609

610+
data_file = getattr(options, "output_coverage", None) \
611+
or getattr(options, "input_coverage", None)
594612
# Do something.
595613
self.coverage = Coverage(
614+
data_file=data_file or DEFAULT_DATAFILE,
596615
data_suffix=options.parallel_mode,
597616
cover_pylib=options.pylib,
598617
timid=options.timid,

coverage/control.py

+4-3
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,8 @@ def override_config(cov, **kwargs):
6262
cov.config = original_config
6363

6464

65-
_DEFAULT_DATAFILE = DefaultValue("MISSING")
65+
DEFAULT_DATAFILE = DefaultValue("MISSING")
66+
_DEFAULT_DATAFILE = DEFAULT_DATAFILE # Just in case, for backwards compatibility
6667

6768
class Coverage:
6869
"""Programmatic access to coverage.py.
@@ -103,7 +104,7 @@ def current(cls):
103104
return None
104105

105106
def __init__(
106-
self, data_file=_DEFAULT_DATAFILE, data_suffix=None, cover_pylib=None,
107+
self, data_file=DEFAULT_DATAFILE, data_suffix=None, cover_pylib=None,
107108
auto_data=False, timid=None, branch=None, config_file=True,
108109
source=None, source_pkgs=None, omit=None, include=None, debug=None,
109110
concurrency=None, check_preimported=False, context=None,
@@ -200,7 +201,7 @@ def __init__(
200201
# data_file=None means no disk file at all. data_file missing means
201202
# use the value from the config file.
202203
self._no_disk = data_file is None
203-
if data_file is _DEFAULT_DATAFILE:
204+
if data_file is DEFAULT_DATAFILE:
204205
data_file = None
205206

206207
self.config = None

tests/test_cmdline.py

+25
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
import coverage
1515
import coverage.cmdline
1616
from coverage import env
17+
from coverage.control import DEFAULT_DATAFILE
1718
from coverage.config import CoverageConfig
1819
from coverage.exceptions import _ExceptionDuringRun
1920
from coverage.version import __url__
@@ -57,6 +58,7 @@ class BaseCmdLineTest(CoverageTest):
5758
contexts=None,
5859
)
5960
_defaults.Coverage(
61+
data_file=DEFAULT_DATAFILE,
6062
cover_pylib=None, data_suffix=None, timid=None, branch=None,
6163
config_file=True, source=None, include=None, omit=None, debug=None,
6264
concurrency=None, check_preimported=True, context=None, messages=True,
@@ -250,6 +252,11 @@ def test_combine(self):
250252
cov.combine(None, strict=True, keep=False)
251253
cov.save()
252254
""")
255+
self.cmd_executes("combine --data-file=foo.cov", """\
256+
cov = Coverage(data_file="foo.cov")
257+
cov.combine(None, strict=True, keep=False)
258+
cov.save()
259+
""")
253260

254261
def test_combine_doesnt_confuse_options_with_args(self):
255262
# https://github.com/nedbat/coveragepy/issues/385
@@ -305,6 +312,10 @@ def test_erase(self):
305312
cov = Coverage()
306313
cov.erase()
307314
""")
315+
self.cmd_executes("erase --data-file=foo.cov", """\
316+
cov = Coverage(data_file="foo.cov")
317+
cov.erase()
318+
""")
308319

309320
def test_version(self):
310321
# coverage --version
@@ -558,6 +569,11 @@ def test_report(self):
558569
cov.load()
559570
cov.report(sort='-foo')
560571
""")
572+
self.cmd_executes("report --data-file=foo.cov.2", """\
573+
cov = Coverage(data_file="foo.cov.2")
574+
cov.load()
575+
cov.report(show_missing=None)
576+
""")
561577

562578
def test_run(self):
563579
# coverage run [-p] [-L] [--timid] MODULE.py [ARG1 ARG2 ...]
@@ -684,6 +700,15 @@ def test_run(self):
684700
cov.stop()
685701
cov.save()
686702
""")
703+
self.cmd_executes("run --data-file=output.coverage foo.py", """\
704+
cov = Coverage(data_file="output.coverage")
705+
runner = PyRunner(['foo.py'], as_module=False)
706+
runner.prepare()
707+
cov.start()
708+
runner.run()
709+
cov.stop()
710+
cov.save()
711+
""")
687712

688713
def test_multiprocessing_needs_config_file(self):
689714
# You can't use command-line args to add options to multiprocessing

0 commit comments

Comments
 (0)