DebugClients/Python/coverage/data.py

changeset 5051
3586ebd9fac8
parent 4491
0d8612e24fef
--- 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:])
 
 #

eric ide

mercurial