diff options
author | Ned Batchelder <ned@nedbatchelder.com> | 2015-05-17 20:15:42 -0400 |
---|---|---|
committer | Ned Batchelder <ned@nedbatchelder.com> | 2015-05-17 20:15:42 -0400 |
commit | d0d1f4ad6f0190309be76ee486253995a547bf34 (patch) | |
tree | c2e70991179e837975ef1290b768ecf78ad554c3 /coverage/python.py | |
parent | 1435fb6b43a84229bff0a1b83347a22a19259abe (diff) | |
download | python-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.py | 16 |
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 |