Skip to content

Commit

Permalink
Add combine --keep (#1110)
Browse files Browse the repository at this point in the history
* Add combine --keep

Related to #1108

* Fix unit tests

* Fix line too long

* Fix line too long
  • Loading branch information
elarivie committed Jan 30, 2021
1 parent 0143891 commit a0f6692
Show file tree
Hide file tree
Showing 8 changed files with 51 additions and 14 deletions.
8 changes: 7 additions & 1 deletion coverage/cmdline.py
Expand Up @@ -31,6 +31,10 @@ class Opts(object):
'-a', '--append', action='store_true',
help="Append coverage data to .coverage, otherwise it starts clean each time.",
)
keep = optparse.make_option(
'', '--keep', action='store_true',
help="Keep combined coverage files, otherwise they are deleted.",
)
branch = optparse.make_option(
'', '--branch', action='store_true',
help="Measure branch coverage in addition to statement coverage.",
Expand Down Expand Up @@ -215,6 +219,7 @@ def __init__(self, *args, **kwargs):
help=None,
ignore_errors=None,
include=None,
keep=None,
module=None,
omit=None,
contexts=None,
Expand Down Expand Up @@ -333,6 +338,7 @@ def get_prog_name(self):
"combine",
[
Opts.append,
Opts.keep,
] + GLOBAL_ARGS,
usage="[options] <path1> <path2> ... <pathN>",
description=(
Expand Down Expand Up @@ -585,7 +591,7 @@ def command_line(self, argv):
if options.append:
self.coverage.load()
data_dirs = args or None
self.coverage.combine(data_dirs, strict=True)
self.coverage.combine(data_dirs, strict=True, keep=bool(options.keep))
self.coverage.save()
return OK

Expand Down
7 changes: 5 additions & 2 deletions coverage/control.py
Expand Up @@ -659,7 +659,7 @@ def save(self):
data = self.get_data()
data.write()

def combine(self, data_paths=None, strict=False):
def combine(self, data_paths=None, strict=False, keep=False):
"""Combine together a number of similarly-named coverage data files.
All coverage data files whose name starts with `data_file` (from the
Expand All @@ -674,6 +674,8 @@ def combine(self, data_paths=None, strict=False):
If `strict` is true, then it is an error to attempt to combine when
there are no data files to combine.
If `keep` is true, then combined data files won't be deleted.
.. versionadded:: 4.0
The `data_paths` parameter.
Expand All @@ -694,7 +696,8 @@ def combine(self, data_paths=None, strict=False):
for pattern in paths[1:]:
aliases.add(pattern, result)

combine_parallel_data(self._data, aliases=aliases, data_paths=data_paths, strict=strict)
combine_parallel_data(self._data,
aliases=aliases, data_paths=data_paths, strict=strict, keep=keep)

def get_data(self):
"""Get the collected data.
Expand Down
11 changes: 6 additions & 5 deletions coverage/data.py
Expand Up @@ -52,7 +52,7 @@ def add_data_to_hash(data, filename, hasher):
hasher.update(data.file_tracer(filename))


def combine_parallel_data(data, aliases=None, data_paths=None, strict=False):
def combine_parallel_data(data, aliases=None, data_paths=None, strict=False, keep=False):
"""Combine a number of data files together.
Treat `data.filename` as a file prefix, and combine the data from all
Expand All @@ -68,7 +68,7 @@ def combine_parallel_data(data, aliases=None, data_paths=None, strict=False):
If `data_paths` is not provided, then the directory portion of
`data.filename` is used as the directory to search for data files.
Every data file found and combined is then deleted from disk. If a file
Unless `keep` is True every data file found and combined is then deleted from disk. If a file
cannot be read, a warning will be issued, and the file will not be
deleted.
Expand Down Expand Up @@ -116,9 +116,10 @@ def combine_parallel_data(data, aliases=None, data_paths=None, strict=False):
else:
data.update(new_data, aliases=aliases)
files_combined += 1
if data._debug.should('dataio'):
data._debug.write("Deleting combined data file %r" % (f,))
file_be_gone(f)
if not keep:
if data._debug.should('dataio'):
data._debug.write("Deleting combined data file %r" % (f,))
file_be_gone(f)

if strict and not files_combined:
raise CoverageException("No usable data files")
1 change: 1 addition & 0 deletions doc/help/combine.rst
Expand Up @@ -13,6 +13,7 @@
Options:
-a, --append Append coverage data to .coverage, otherwise it starts
clean each time.
--keep Keep combined coverage files, otherwise they are deleted.
--debug=OPTS Debug options, separated by commas. [env: COVERAGE_DEBUG]
-h, --help Get help on this command.
--rcfile=RCFILE Specify configuration file. By default '.coveragerc',
Expand Down
4 changes: 4 additions & 0 deletions doc/python-coverage.1.txt
Expand Up @@ -109,6 +109,7 @@ COMMAND REFERENCE
Combine data from multiple coverage files collected with ``run -p``.
The combined results are written to a single file representing the
union of the data.
Unless --keep is provided the combined coverage files are deleted.

If `PATH` is specified, they are files or directories containing data to
be combined.
Expand All @@ -119,6 +120,9 @@ COMMAND REFERENCE
Append coverage data to .coverage, otherwise it starts clean each
time.

\--keep
Keep combined coverage file.

**debug** `TOPIC` ...

Display information about the internals of coverage.py, for diagnosing
Expand Down
2 changes: 1 addition & 1 deletion tests/test_api.py
Expand Up @@ -442,7 +442,7 @@ def test_combining_twice(self):

cov2 = coverage.Coverage()
with self.assertRaisesRegex(CoverageException, r"No data to combine"):
cov2.combine(strict=True)
cov2.combine(strict=True, keep=False)

cov3 = coverage.Coverage()
cov3.combine()
Expand Down
10 changes: 5 additions & 5 deletions tests/test_cmdline.py
Expand Up @@ -218,33 +218,33 @@ def test_combine(self):
# coverage combine with args
self.cmd_executes("combine datadir1", """\
cov = Coverage()
cov.combine(["datadir1"], strict=True)
cov.combine(["datadir1"], strict=True, keep=False)
cov.save()
""")
# coverage combine, appending
self.cmd_executes("combine --append datadir1", """\
cov = Coverage()
cov.load()
cov.combine(["datadir1"], strict=True)
cov.combine(["datadir1"], strict=True, keep=False)
cov.save()
""")
# coverage combine without args
self.cmd_executes("combine", """\
cov = Coverage()
cov.combine(None, strict=True)
cov.combine(None, strict=True, keep=False)
cov.save()
""")

def test_combine_doesnt_confuse_options_with_args(self):
# https://github.com/nedbat/coveragepy/issues/385
self.cmd_executes("combine --rcfile cov.ini", """\
cov = Coverage(config_file='cov.ini')
cov.combine(None, strict=True)
cov.combine(None, strict=True, keep=False)
cov.save()
""")
self.cmd_executes("combine --rcfile cov.ini data1 data2/more", """\
cov = Coverage(config_file='cov.ini')
cov.combine(["data1", "data2/more"], strict=True)
cov.combine(["data1", "data2/more"], strict=True, keep=False)
cov.save()
""")

Expand Down
22 changes: 22 additions & 0 deletions tests/test_process.py
Expand Up @@ -244,6 +244,28 @@ def test_combine_parallel_data_no_append(self):
data.read()
self.assertEqual(line_counts(data)['b_or_c.py'], 7)

def test_combine_parallel_data_keep(self):
self.make_b_or_c_py()
out = self.run_command("coverage run -p b_or_c.py b")
self.assertEqual(out, 'done\n')
self.assert_doesnt_exist(".coverage")
self.assert_file_count(".coverage.*", 1)

out = self.run_command("coverage run -p b_or_c.py c")
self.assertEqual(out, 'done\n')
self.assert_doesnt_exist(".coverage")

# After two -p runs, there should be two .coverage.machine.123 files.
self.assert_file_count(".coverage.*", 2)

# Combine the parallel coverage data files into .coverage with the keep flag.
self.run_command("coverage combine --keep")

# After combining, the .coverage file & the original combined file should still be there.
self.assert_exists(".coverage")
self.assert_file_count(".coverage.*", 2)


def test_append_data(self):
self.make_b_or_c_py()

Expand Down

0 comments on commit a0f6692

Please sign in to comment.