--- a/DebugClients/Python/coverage/data.py Sat Jul 23 13:33:54 2016 +0200 +++ b/DebugClients/Python/coverage/data.py Sun Jul 24 12:01:01 2016 +0200 @@ -4,6 +4,7 @@ """Coverage data for coverage.py.""" import glob +import itertools import json import optparse import os @@ -11,13 +12,14 @@ import random import re import socket -import sys from coverage import env from coverage.backward import iitems, string_class from coverage.debug import _TEST_NAME_FILE from coverage.files import PathAliases -from coverage.misc import CoverageException, file_be_gone +from coverage.misc import CoverageException, file_be_gone, isolate_module + +os = isolate_module(os) class CoverageData(object): @@ -177,11 +179,12 @@ """ if self._arcs is not None: - if filename in self._arcs: - return [s for s, __ in self._arcs[filename] if s > 0] + arcs = self._arcs.get(filename) + if arcs is not None: + all_lines = itertools.chain.from_iterable(arcs) + return list(set(l for l in all_lines if l > 0)) elif self._lines is not None: - if filename in self._lines: - return self._lines[filename] + return self._lines.get(filename) return None def arcs(self, filename): @@ -270,15 +273,10 @@ self._lines = self._arcs = None if 'lines' in data: - self._lines = dict( - (fname.encode(sys.getfilesystemencoding()), linenos) - for fname, linenos in iitems(data['lines']) - ) - + self._lines = data['lines'] if 'arcs' in data: self._arcs = dict( - (fname.encode(sys.getfilesystemencoding()), - [tuple(pair) for pair in arcs]) + (fname, [tuple(pair) for pair in arcs]) for fname, arcs in iitems(data['arcs']) ) self._file_tracers = data.get('file_tracers', {}) @@ -290,8 +288,15 @@ """Read the coverage data from `filename` into this object.""" if self._debug and self._debug.should('dataio'): self._debug.write("Reading data from %r" % (filename,)) - with self._open_for_reading(filename) as f: - self.read_fileobj(f) + try: + with self._open_for_reading(filename) as f: + self.read_fileobj(f) + except Exception as exc: + raise CoverageException( + "Couldn't read data from '%s': %s: %s" % ( + filename, exc.__class__.__name__, exc, + ) + ) _GO_AWAY = "!coverage.py: This is a private format, don't read it directly!" @@ -433,17 +438,10 @@ file_data = {} if self._has_arcs(): - file_data['arcs'] = dict( - (fname.decode(sys.getfilesystemencoding()), - [tuple(pair) for pair in self._arcs]) - for fname, arcs in iitems(data['arcs']) - ) + file_data['arcs'] = self._arcs if self._has_lines(): - file_data['lines'] = dict( - (fname.decode(sys.getfilesystemencoding()), linenos) - for fname, linenos in iitems(self._lines) - ) + file_data['lines'] = self._lines if self._file_tracers: file_data['file_tracers'] = self._file_tracers @@ -580,7 +578,7 @@ def add_to_hash(self, filename, hasher): """Contribute `filename`'s data to the `hasher`. - `hasher` is a :class:`coverage.misc.Hasher` instance to be updated with + `hasher` is a `coverage.misc.Hasher` instance to be updated with the file's data. It should only get the results data, not the run data. @@ -607,12 +605,15 @@ class CoverageDataFiles(object): """Manage the use of coverage data files.""" - def __init__(self, basename=None): + def __init__(self, basename=None, warn=None): """Create a CoverageDataFiles to manage data files. + `warn` is the warning function to use. + `basename` is the name of the file to use for storing data. """ + self.warn = warn # Construct the file name that will be used for data storage. self.filename = os.path.abspath(basename or ".coverage") @@ -681,7 +682,9 @@ If `data_paths` is not provided, then the directory portion of `self.filename` is used as the directory to search for data files. - Every data file found and combined is then deleted from disk. + 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. """ # Because of the os.path.abspath in the constructor, data_dir will @@ -702,9 +705,16 @@ for f in files_to_combine: new_data = CoverageData() - new_data.read_file(f) - data.update(new_data, aliases=aliases) - file_be_gone(f) + try: + new_data.read_file(f) + except CoverageException as exc: + if self.warn: + # The CoverageException has the file name in it, so just + # use the message as the warning. + self.warn(str(exc)) + else: + data.update(new_data, aliases=aliases) + file_be_gone(f) def canonicalize_json_data(data): @@ -754,6 +764,7 @@ if __name__ == '__main__': + import sys debug_main(sys.argv[1:]) #