summaryrefslogtreecommitdiff
path: root/coverage/python.py
diff options
context:
space:
mode:
authorNed Batchelder <ned@nedbatchelder.com>2015-05-17 20:15:42 -0400
committerNed Batchelder <ned@nedbatchelder.com>2015-05-17 20:15:42 -0400
commitd0d1f4ad6f0190309be76ee486253995a547bf34 (patch)
treec2e70991179e837975ef1290b768ecf78ad554c3 /coverage/python.py
parent1435fb6b43a84229bff0a1b83347a22a19259abe (diff)
downloadpython-coveragepy-d0d1f4ad6f0190309be76ee486253995a547bf34.tar.gz
All Python source is Unicode internally.
Unfortunately, this meant hacking around a silly Python 2 restriction (can't compile a Unicode string containing an encoding declaration).
Diffstat (limited to 'coverage/python.py')
-rw-r--r--coverage/python.py16
1 files changed, 10 insertions, 6 deletions
diff --git a/coverage/python.py b/coverage/python.py
index 19212a5..f335f16 100644
--- a/coverage/python.py
+++ b/coverage/python.py
@@ -8,12 +8,13 @@ import zipimport
from coverage import env
from coverage.backward import unicode_class
from coverage.files import FileLocator
-from coverage.misc import NoSource, join_regex
+from coverage.misc import contract, NoSource, join_regex
from coverage.parser import PythonParser
from coverage.phystokens import source_token_lines, source_encoding
from coverage.plugin import FileReporter
+@contract(returns='str')
def read_python_source(filename):
"""Read the Python source text from `filename`.
@@ -30,8 +31,9 @@ def read_python_source(filename):
return f.read()
+@contract(returns='unicode')
def get_python_source(filename):
- """Return the source code, as a str."""
+ """Return the source code, as unicode."""
base, ext = os.path.splitext(filename)
if ext == ".py" and env.WINDOWS:
exts = [".py", ".pyw"]
@@ -49,12 +51,15 @@ def get_python_source(filename):
source = get_zip_bytes(try_filename)
if source is not None:
if env.PY3:
- source = source.decode(source_encoding(source))
+ source = source.decode(source_encoding(source), "replace")
break
else:
# Couldn't find source.
raise NoSource("No source for code: '%s'." % filename)
+ if env.PY2:
+ source = source.decode(source_encoding(source), "replace")
+
# Python code should always end with a line with a newline.
if source and source[-1] != '\n':
source += '\n'
@@ -62,6 +67,7 @@ def get_python_source(filename):
return source
+@contract(returns='bytes|None')
def get_zip_bytes(filename):
"""Get data from `filename` if it is a zip file path.
@@ -161,12 +167,10 @@ class PythonFileReporter(FileReporter):
def exit_counts(self):
return self.parser.exit_counts()
+ @contract(returns='unicode')
def source(self):
if self._source is None:
self._source = get_python_source(self.filename)
- if env.PY2:
- encoding = source_encoding(self._source)
- self._source = self._source.decode(encoding, "replace")
assert isinstance(self._source, unicode_class)
return self._source