summaryrefslogtreecommitdiff
path: root/coverage/data.py
diff options
context:
space:
mode:
Diffstat (limited to 'coverage/data.py')
-rw-r--r--coverage/data.py63
1 files changed, 36 insertions, 27 deletions
diff --git a/coverage/data.py b/coverage/data.py
index db205811..adacaecc 100644
--- a/coverage/data.py
+++ b/coverage/data.py
@@ -8,7 +8,7 @@ import socket
from coverage.backward import iitems, pickle
from coverage.debug import _TEST_NAME_FILE
from coverage.files import PathAliases
-from coverage.misc import file_be_gone
+from coverage.misc import CoverageException, file_be_gone
class CoverageData(object):
@@ -18,12 +18,12 @@ class CoverageData(object):
* collector: a string identifying the collecting software
- * lines: a dict mapping filenames to sorted lists of line numbers
+ * lines: a dict mapping filenames to lists of line numbers
executed::
{ 'file1': [17,23,45], 'file2': [1,2,3], ... }
- * arcs: a dict mapping filenames to sorted lists of line number pairs::
+ * arcs: a dict mapping filenames to lists of line number pairs::
{ 'file1': [(17,23), (17,25), (25,26)], ... }
@@ -31,6 +31,11 @@ class CoverageData(object):
{ 'file1': "django.coverage", ... }
+ Only one of `lines` or `arcs` will be present: with branch coverage, data
+ is stored as arcs. Without branch coverage, it is stored as lines. The
+ line data is easily recovered from the arcs: it is all the first elements
+ of the pairs that are greater than zero.
+
"""
def __init__(self, collector=None, debug=None):
@@ -82,7 +87,12 @@ class CoverageData(object):
def lines(self, filename):
"""Get the list of lines executed for a file."""
- return list((self._lines.get(filename) or {}).keys())
+ if self._arcs:
+ arcs = self._arcs.get(filename) or {}
+ return [s for s, __ in arcs if s > 0]
+ else:
+ lines = self._lines.get(filename) or {}
+ return list(lines)
def arcs(self, filename):
"""Get the list of arcs executed for a file."""
@@ -107,30 +117,29 @@ class CoverageData(object):
Should only be used on an empty CoverageData object.
"""
- try:
- data = pickle.load(file_obj)
- if isinstance(data, dict):
- # Unpack the 'lines' item.
- self._lines = dict([
- (f, dict.fromkeys(linenos, None))
- for f, linenos in iitems(data.get('lines', {}))
- ])
- # Unpack the 'arcs' item.
- self._arcs = dict([
- (f, dict.fromkeys(arcpairs, None))
- for f, arcpairs in iitems(data.get('arcs', {}))
- ])
- self._plugins = data.get('plugins', {})
- except Exception:
- # TODO: this used to handle file-doesnt-exist problems. Do we still need it?
- pass
+ data = pickle.load(file_obj)
+
+ # Unpack the 'lines' item.
+ self._lines = dict([
+ (f, dict.fromkeys(linenos, None))
+ for f, linenos in iitems(data.get('lines', {}))
+ ])
+ # Unpack the 'arcs' item.
+ self._arcs = dict([
+ (f, dict.fromkeys(arcpairs, None))
+ for f, arcpairs in iitems(data.get('arcs', {}))
+ ])
+ self._plugins = data.get('plugins', {})
def read_file(self, filename):
"""Read the coverage data from `filename`."""
if self._debug and self._debug.should('dataio'):
self._debug.write("Reading data from %r" % (filename,))
- with open(filename, "rb") as f:
- self.read(f)
+ try:
+ with open(filename, "rb") as f:
+ self.read(f)
+ except Exception as exc:
+ raise CoverageException("Couldn't read data from '%s': %s" % (filename, exc))
def write(self, file_obj):
"""Write the coverage data to `file_obj`."""
@@ -202,11 +211,11 @@ class CoverageData(object):
def touch_file(self, filename):
"""Ensure that `filename` appears in the data, empty if needed."""
- self._lines.setdefault(filename, {})
+ (self._arcs or self._lines).setdefault(filename, {})
def measured_files(self):
"""A list of all files that had been measured."""
- return list(self._lines.keys())
+ return list(self._arcs or self._lines)
def add_to_hash(self, filename, hasher):
"""Contribute `filename`'s data to the Md5Hash `hasher`."""
@@ -231,8 +240,8 @@ class CoverageData(object):
filename_fn = lambda f: f
else:
filename_fn = os.path.basename
- for filename, lines in iitems(self._lines):
- summ[filename_fn(filename)] = len(lines)
+ for filename in self.measured_files():
+ summ[filename_fn(filename)] = len(self.lines(filename))
return summ
def __nonzero__(self):