summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNed Batchelder <nedbat@gmail.com>2015-04-24 20:17:09 -0400
committerNed Batchelder <nedbat@gmail.com>2015-04-24 20:17:09 -0400
commitf178835e323d5abbfb0f249326bbde24cecb15b7 (patch)
tree59f6c1ca04077b35bb9ceabdeff9e63297a537d5
parentb61d05fa1f80f375d49aefe59a4c46d083f0fe08 (diff)
parente114efc35ad2c2134f7d4c24a7a4fac286f9e50a (diff)
downloadpython-coveragepy-f178835e323d5abbfb0f249326bbde24cecb15b7.tar.gz
Merged in clytwynec/coverage.py/combine-from-multiple-dirs (pull request #51)
Added ability to combine coverage data files from multiple directories into one file via command line args.
-rw-r--r--AUTHORS.txt1
-rw-r--r--coverage/cmdline.py10
-rw-r--r--coverage/control.py8
-rw-r--r--coverage/data.py38
-rw-r--r--tests/test_cmdline.py11
-rw-r--r--tests/test_data.py30
6 files changed, 76 insertions, 22 deletions
diff --git a/AUTHORS.txt b/AUTHORS.txt
index 6b38f9c..b0ea69f 100644
--- a/AUTHORS.txt
+++ b/AUTHORS.txt
@@ -16,6 +16,7 @@ Catherine Proulx
Chris Adams
Chris Rose
Christian Heimes
+Christine Lytwynec
Christoph Zwerschke
Conrad Ho
Danek Duvall
diff --git a/coverage/cmdline.py b/coverage/cmdline.py
index 2be3294..66a76fa 100644
--- a/coverage/cmdline.py
+++ b/coverage/cmdline.py
@@ -249,10 +249,13 @@ CMDS = {
),
'combine': CmdOptionParser("combine", GLOBAL_ARGS,
- usage = " ",
+ usage = "<dir1> <dir2> ... <dirN>",
description = "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."
+ "file representing the union of the data. The positional "
+ "arguments are directories from which the data files should be "
+ "combined. By default, only data files in the current directory "
+ "are combined."
),
'debug': CmdOptionParser("debug", GLOBAL_ARGS,
@@ -430,7 +433,8 @@ class CoverageScript(object):
self.do_run(options, args)
if options.action == "combine":
- self.coverage.combine()
+ data_dirs = argv if argv else None
+ self.coverage.combine(data_dirs)
self.coverage.save()
# Remaining actions are reporting, with some common options.
diff --git a/coverage/control.py b/coverage/control.py
index 563925e..2c8d384 100644
--- a/coverage/control.py
+++ b/coverage/control.py
@@ -717,13 +717,17 @@ class Coverage(object):
self._harvest_data()
self.data.write(suffix=data_suffix)
- def combine(self):
+ def combine(self, data_dirs=None):
"""Combine together a number of similarly-named coverage data files.
All coverage data files whose name starts with `data_file` (from the
coverage() constructor) will be read, and combined together into the
current measurements.
+ `data_dirs` is a list of directories from which data files should be
+ combined. If no list is passed, then the data files from the current
+ directory will be combined.
+
"""
self._init()
aliases = None
@@ -733,7 +737,7 @@ class Coverage(object):
result = paths[0]
for pattern in paths[1:]:
aliases.add(pattern, result)
- self.data.combine_parallel_data(aliases=aliases)
+ self.data.combine_parallel_data(aliases=aliases, data_dirs=data_dirs)
def _harvest_data(self):
"""Get the collected data and reset the collector.
diff --git a/coverage/data.py b/coverage/data.py
index 2c5d351..8a699b5 100644
--- a/coverage/data.py
+++ b/coverage/data.py
@@ -1,5 +1,6 @@
"""Coverage data for Coverage."""
+import glob
import os
from coverage.backward import iitems, pickle
@@ -190,7 +191,7 @@ class CoverageData(object):
pass
return lines, arcs, plugins
- def combine_parallel_data(self, aliases=None):
+ def combine_parallel_data(self, aliases=None, data_dirs=None):
"""Combine a number of data files together.
Treat `self.filename` as a file prefix, and combine the data from all
@@ -199,23 +200,30 @@ class CoverageData(object):
If `aliases` is provided, it's a `PathAliases` object that is used to
re-map paths to match the local machine's.
+ If `data_dirs` is provided, then it combines the data files from each
+ directory into a single file.
+
"""
aliases = aliases or PathAliases()
data_dir, local = os.path.split(self.filename)
- localdot = local + '.'
- for f in os.listdir(data_dir or '.'):
- if f.startswith(localdot):
- full_path = os.path.join(data_dir, f)
- new_lines, new_arcs, new_plugins = self._read_file(full_path)
- for filename, file_data in iitems(new_lines):
- filename = aliases.map(filename)
- self.lines.setdefault(filename, {}).update(file_data)
- for filename, file_data in iitems(new_arcs):
- filename = aliases.map(filename)
- self.arcs.setdefault(filename, {}).update(file_data)
- self.plugins.update(new_plugins)
- if f != local:
- os.remove(full_path)
+ localdot = local + '.*'
+
+ data_dirs = data_dirs or [data_dir]
+ files_to_combine = []
+ for d in data_dirs:
+ pattern = os.path.join(os.path.abspath(d), localdot)
+ files_to_combine.extend(glob.glob(pattern))
+
+ for f in files_to_combine:
+ new_lines, new_arcs, new_plugins = self._read_file(f)
+ for filename, file_data in iitems(new_lines):
+ filename = aliases.map(filename)
+ self.lines.setdefault(filename, {}).update(file_data)
+ for filename, file_data in iitems(new_arcs):
+ filename = aliases.map(filename)
+ self.arcs.setdefault(filename, {}).update(file_data)
+ self.plugins.update(new_plugins)
+ os.remove(f)
def add_line_data(self, line_data):
"""Add executed line data.
diff --git a/tests/test_cmdline.py b/tests/test_cmdline.py
index 775e003..b616ed5 100644
--- a/tests/test_cmdline.py
+++ b/tests/test_cmdline.py
@@ -213,11 +213,18 @@ class CmdLineTest(BaseCmdLineTest):
""")
def test_combine(self):
- # coverage combine
+ # coverage combine with args
+ self.cmd_executes("combine datadir1", """\
+ .coverage()
+ .load()
+ .combine(["datadir1"])
+ .save()
+ """)
+ # coverage combine without args
self.cmd_executes("combine", """\
.coverage()
.load()
- .combine()
+ .combine(None)
.save()
""")
diff --git a/tests/test_data.py b/tests/test_data.py
index 0549a3c..ef57f0c 100644
--- a/tests/test_data.py
+++ b/tests/test_data.py
@@ -1,5 +1,8 @@
"""Tests for coverage.data"""
+import os
+import shutil
+
from coverage.backward import pickle
from coverage.data import CoverageData
from coverage.files import PathAliases
@@ -154,3 +157,30 @@ class DataTest(CoverageTest):
covdata3, {'./a.py': 4, './sub/b.py': 2}, fullpath=True
)
self.assert_measured_files(covdata3, ['./a.py', './sub/b.py'])
+
+
+class DataTestInTempDir(DataTest):
+ """Test cases for coverage.data."""
+
+ run_in_temp_dir = True
+
+ def test_combining_from_different_directories(self):
+ covdata1 = CoverageData()
+ covdata1.add_line_data(DATA_1)
+ os.makedirs('cov1')
+ covdata1.write_file('cov1/.coverage.1')
+
+ covdata2 = CoverageData()
+ covdata2.add_line_data(DATA_2)
+ os.makedirs('cov2')
+ covdata2.write_file('cov2/.coverage.2')
+
+ covdata3 = CoverageData()
+ covdata3.combine_parallel_data(data_dirs=[
+ 'cov1/',
+ 'cov2/',
+ ])
+
+ self.assert_summary(covdata3, SUMMARY_1_2)
+ self.assert_measured_files(covdata3, MEASURED_FILES_1_2)
+