DebugClients/Python3/coverage/python.py

changeset 5051
3586ebd9fac8
parent 4489
d0d6e4ad31bd
diff -r 04e5dfbd3f3d -r 3586ebd9fac8 DebugClients/Python3/coverage/python.py
--- a/DebugClients/Python3/coverage/python.py	Sat Jul 23 13:33:54 2016 +0200
+++ b/DebugClients/Python3/coverage/python.py	Sun Jul 24 12:01:01 2016 +0200
@@ -4,14 +4,19 @@
 """Python source expertise for coverage.py"""
 
 import os.path
+import types
 import zipimport
 
 from coverage import env, files
-from coverage.misc import contract, expensive, NoSource, join_regex
+from coverage.misc import (
+    contract, CoverageException, expensive, NoSource, join_regex, isolate_module,
+)
 from coverage.parser import PythonParser
 from coverage.phystokens import source_token_lines, source_encoding
 from coverage.plugin import FileReporter
 
+os = isolate_module(os)
+
 
 @contract(returns='bytes')
 def read_python_source(filename):
@@ -48,6 +53,8 @@
         # Couldn't find source.
         raise NoSource("No source for code: '%s'." % filename)
 
+    # Replace \f because of http://bugs.python.org/issue19035
+    source = source.replace(b'\f', b' ')
     source = source.decode(source_encoding(source), "replace")
 
     # Python code should always end with a line with a newline.
@@ -90,9 +97,15 @@
 
         if hasattr(morf, '__file__'):
             filename = morf.__file__
+        elif isinstance(morf, types.ModuleType):
+            # A module should have had .__file__, otherwise we can't use it.
+            # This could be a PEP-420 namespace package.
+            raise CoverageException("Module {0} has no file".format(morf))
         else:
             filename = morf
 
+        filename = files.unicode_filename(filename)
+
         # .pyc files should always refer to a .py instead.
         if filename.endswith(('.pyc', '.pyo')):
             filename = filename[:-1]
@@ -104,6 +117,7 @@
         if hasattr(morf, '__name__'):
             name = morf.__name__
             name = name.replace(".", os.sep) + ".py"
+            name = files.unicode_filename(name)
         else:
             name = files.relative_filename(filename)
         self.relname = name
@@ -113,6 +127,7 @@
         self._statements = None
         self._excluded = None
 
+    @contract(returns='unicode')
     def relative_filename(self):
         return self.relname
 
@@ -124,21 +139,16 @@
                 filename=self.filename,
                 exclude=self.coverage._exclude_regex('exclude'),
             )
+            self._parser.parse_source()
         return self._parser
 
-    @expensive
     def lines(self):
         """Return the line numbers of statements in the file."""
-        if self._statements is None:
-            self._statements, self._excluded = self.parser.parse_source()
-        return self._statements
+        return self.parser.statements
 
-    @expensive
     def excluded_lines(self):
         """Return the line numbers of statements in the file."""
-        if self._excluded is None:
-            self._statements, self._excluded = self.parser.parse_source()
-        return self._excluded
+        return self.parser.excluded
 
     def translate_lines(self, lines):
         return self.parser.translate_lines(lines)
@@ -162,6 +172,9 @@
     def exit_counts(self):
         return self.parser.exit_counts()
 
+    def missing_arc_description(self, start, end, executed_arcs=None):
+        return self.parser.missing_arc_description(start, end, executed_arcs)
+
     @contract(returns='unicode')
     def source(self):
         if self._source is None:

eric ide

mercurial