summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNed Batchelder <ned@nedbatchelder.com>2015-07-19 20:14:33 -0400
committerNed Batchelder <ned@nedbatchelder.com>2015-07-19 20:14:33 -0400
commita00a35bc146fafcaf8ead535075355631f838f8b (patch)
tree90d4e273a0b57a7e10950a5ab4d8af9b37e3fd0d
parent8eec054f2e2c7b3f3669f28d382ddcfec39d48f0 (diff)
downloadpython-coveragepy-git-a00a35bc146fafcaf8ead535075355631f838f8b.tar.gz
CoverageData.plugin_name() can now return None or '' to differentiate unmeasured, or measured but no plugin.
-rw-r--r--coverage/data.py43
-rw-r--r--tests/test_data.py45
2 files changed, 67 insertions, 21 deletions
diff --git a/coverage/data.py b/coverage/data.py
index 1c6a283a..f2e528d4 100644
--- a/coverage/data.py
+++ b/coverage/data.py
@@ -118,11 +118,17 @@ class CoverageData(object):
filename: the name of the file you're interested in.
Returns:
- str: the name of the plugin that handles this file. Can be None
- if no plugin was involved.
+ str: the name of the plugin that handles this file. If the file
+ was measured, but didn't use a plugin, then "" is returned.
+ If the file was not measured, then None is returned.
"""
- return self._plugins.get(filename)
+ # Because the vast majority of files involve no plugin, we don't store
+ # them explicitly in self._plugins. Check the measured data instead
+ # to see if it was a known file with no plugin.
+ if filename in (self._arcs or self._lines):
+ return self._plugins.get(filename, "")
+ return None
def read(self, file_obj):
"""Read the coverage data from the given file object.
@@ -226,6 +232,22 @@ class CoverageData(object):
aliases = aliases or PathAliases()
+ # _plugins: only have a string, so they have to agree.
+ # Have to do these first, so that our examination of self._arcs and
+ # self._lines won't be confused by data updated from other_data.
+ for filename in other_data.measured_files():
+ other_plugin = other_data.plugin_name(filename)
+ filename = aliases.map(filename)
+ this_plugin = self.plugin_name(filename)
+ if this_plugin is None:
+ self._plugins[filename] = other_plugin
+ elif this_plugin != other_plugin:
+ raise CoverageException(
+ "Conflicting plugin name for '%s': %r vs %r" % (
+ filename, this_plugin, other_plugin,
+ )
+ )
+
# _lines: merge dicts.
for filename, file_data in iitems(other_data._lines):
filename = aliases.map(filename)
@@ -236,21 +258,6 @@ class CoverageData(object):
filename = aliases.map(filename)
self._arcs.setdefault(filename, {}).update(file_data)
- # _plugins: only have a string, so they have to agree.
- for filename, plugin_name in iitems(other_data._plugins):
- filename = aliases.map(filename)
- this_plugin = self._plugins.get(filename)
- # TODO: plugin=None could mean no filename recorded, or it could
- # mean, handled by Python. Need to distinguish those cases.
- if this_plugin is None:
- self._plugins[filename] = plugin_name
- elif this_plugin != plugin_name:
- raise CoverageException(
- "Conflicting plugin name for '%s': %s vs %s" % (
- filename, this_plugin, plugin_name,
- )
- )
-
def touch_file(self, filename):
"""Ensure that `filename` appears in the data, empty if needed."""
(self._arcs or self._lines).setdefault(filename, {})
diff --git a/tests/test_data.py b/tests/test_data.py
index e48724da..08c3a8d5 100644
--- a/tests/test_data.py
+++ b/tests/test_data.py
@@ -152,8 +152,14 @@ class CoverageDataTest(DataTestHelpers, CoverageTest):
def test_plugin_name(self):
covdata = CoverageData()
+ covdata.add_lines({
+ "p1.foo": dict.fromkeys([1, 2, 3]),
+ "p2.html": dict.fromkeys([10, 11, 12]),
+ "main.py": dict.fromkeys([20]),
+ })
covdata.add_plugins({"p1.foo": "p1.plugin", "p2.html": "p2.plugin"})
self.assertEqual(covdata.plugin_name("p1.foo"), "p1.plugin")
+ self.assertEqual(covdata.plugin_name("main.py"), "")
self.assertIsNone(covdata.plugin_name("p3.not_here"))
def test_update_lines(self):
@@ -204,7 +210,10 @@ class CoverageDataTest(DataTestHelpers, CoverageTest):
"p2.html": dict.fromkeys([5, 6, 7]),
"main.py": dict.fromkeys([10, 11, 12]),
})
- covdata1.add_plugins({"p1.html": "html.plugin", "p2.html": "html.plugin2"})
+ covdata1.add_plugins({
+ "p1.html": "html.plugin",
+ "p2.html": "html.plugin2",
+ })
covdata2 = CoverageData()
covdata2.add_lines({
@@ -213,7 +222,11 @@ class CoverageDataTest(DataTestHelpers, CoverageTest):
"p3.foo": dict.fromkeys([1000, 1001]),
"main.py": dict.fromkeys([10, 11, 12]),
})
- covdata2.add_plugins({"p1.html": "html.plugin", "p3.foo": "foo_plugin"})
+ covdata2.add_plugins({
+ "p1.html": "html.plugin",
+ "p2.html": "html.plugin2",
+ "p3.foo": "foo_plugin",
+ })
covdata3 = CoverageData()
covdata3.update(covdata1)
@@ -221,7 +234,33 @@ class CoverageDataTest(DataTestHelpers, CoverageTest):
self.assertEqual(covdata3.plugin_name("p1.html"), "html.plugin")
self.assertEqual(covdata3.plugin_name("p2.html"), "html.plugin2")
self.assertEqual(covdata3.plugin_name("p3.foo"), "foo_plugin")
- self.assertIsNone(covdata3.plugin_name("main.py"))
+ self.assertEqual(covdata3.plugin_name("main.py"), "")
+
+ def test_update_conflicting_plugins(self):
+ covdata1 = CoverageData()
+ covdata1.add_lines({"p1.html": dict.fromkeys([1, 2, 3])})
+ covdata1.add_plugins({"p1.html": "html.plugin"})
+
+ covdata2 = CoverageData()
+ covdata2.add_lines({"p1.html": dict.fromkeys([1, 2, 3])})
+ covdata2.add_plugins({"p1.html": "html.other_plugin"})
+
+ with self.assertRaises(CoverageException):
+ covdata1.update(covdata2)
+
+ def test_update_plugin_vs_no_plugin(self):
+ covdata1 = CoverageData()
+ covdata1.add_lines({"p1.html": dict.fromkeys([1, 2, 3])})
+ covdata1.add_plugins({"p1.html": "html.plugin"})
+
+ covdata2 = CoverageData()
+ covdata2.add_lines({"p1.html": dict.fromkeys([1, 2, 3])})
+
+ with self.assertRaises(CoverageException):
+ covdata1.update(covdata2)
+
+ with self.assertRaises(CoverageException):
+ covdata2.update(covdata1)
class CoverageDataTestInTempDir(DataTestHelpers, CoverageTest):