diff options
-rw-r--r-- | coverage/codeunit.py | 2 | ||||
-rw-r--r-- | coverage/execfile.py | 7 | ||||
-rw-r--r-- | coverage/files.py | 13 | ||||
-rw-r--r-- | coverage/parser.py | 15 | ||||
-rw-r--r-- | coverage/phystokens.py | 25 | ||||
-rw-r--r-- | coverage/summary.py | 2 | ||||
-rw-r--r-- | lab/parser.py | 4 |
7 files changed, 34 insertions, 34 deletions
diff --git a/coverage/codeunit.py b/coverage/codeunit.py index 09b86fe6..1182398d 100644 --- a/coverage/codeunit.py +++ b/coverage/codeunit.py @@ -169,6 +169,8 @@ class PythonCodeUnit(CodeUnit): return self._source def get_parser(self, exclude=None): + return PythonParser(filename=self.filename, exclude=exclude) + # TODO: REMOVE THIS USELESS CODE! actual_filename, source = self._find_source(self.filename) return PythonParser( text=source, filename=actual_filename, exclude=exclude, diff --git a/coverage/execfile.py b/coverage/execfile.py index 246d79a5..ecb03372 100644 --- a/coverage/execfile.py +++ b/coverage/execfile.py @@ -8,7 +8,7 @@ import types from coverage.backward import BUILTINS from coverage.backward import PYC_MAGIC_NUMBER, imp, importlib_util_find_spec from coverage.misc import ExceptionDuringRun, NoCode, NoSource -from coverage.phystokens import open_python_source +from coverage.phystokens import read_python_source class DummyLoader(object): @@ -178,13 +178,10 @@ def make_code_from_py(filename): """Get source from `filename` and make a code object of it.""" # Open the source file. try: - source_file = open_python_source(filename) + source = read_python_source(filename) except IOError: raise NoSource("No file to run: %r" % filename) - with source_file: - source = source_file.read() - # We have the source. `compile` still needs the last line to be clean, # so make sure it is, then compile a code object from it. if not source or source[-1] != '\n': diff --git a/coverage/files.py b/coverage/files.py index 6ba7983b..29450542 100644 --- a/coverage/files.py +++ b/coverage/files.py @@ -8,8 +8,8 @@ import sys import ntpath import posixpath -from coverage.misc import CoverageException, join_regex -from coverage.phystokens import open_python_source +from coverage.misc import CoverageException, NoSource, join_regex +from coverage.phystokens import read_python_source, source_encoding class FileLocator(object): @@ -56,19 +56,20 @@ class FileLocator(object): def get_python_source(filename): - """Return the source code, as a string.""" + """Return the source code, as a str.""" if os.path.exists(filename): # A regular text file: open it. - with open_python_source(filename) as f: - return f.read() + return read_python_source(filename) # Maybe it's in a zip file? source = get_zip_bytes(filename) if source is not None: + if sys.version_info >= (3, 0): + source = source.decode(source_encoding(source)) return source # Couldn't find source. - raise CoverageException( + raise NoSource( "No source for code: '%s'." % filename ) diff --git a/coverage/parser.py b/coverage/parser.py index 317f7ec7..b50bc578 100644 --- a/coverage/parser.py +++ b/coverage/parser.py @@ -54,6 +54,7 @@ class PythonParser(CodeParser): ) if self.text: + assert isinstance(self.text, str) # Scrap the BOM if it exists. if ord(self.text[0]) == 0xfeff: self.text = self.text[1:] @@ -90,8 +91,7 @@ class PythonParser(CodeParser): def byte_parser(self): """Create a ByteParser on demand.""" if not self._byte_parser: - self._byte_parser = \ - ByteParser(text=self.text, filename=self.filename) + self._byte_parser = ByteParser(self.text, filename=self.filename) return self._byte_parser def lines_matching(self, *regexes): @@ -343,16 +343,11 @@ OP_RETURN_VALUE = _opcode('RETURN_VALUE') class ByteParser(object): """Parse byte codes to understand the structure of code.""" - def __init__(self, code=None, text=None, filename=None): + def __init__(self, text, code=None, filename=None): + self.text = text if code: self.code = code - self.text = text else: - if not text: - assert filename, "If no code or text, need a filename" - text = get_python_source(filename) - self.text = text - try: self.code = compile(text, filename, "exec") except SyntaxError as synerr: @@ -378,7 +373,7 @@ class ByteParser(object): """ children = CodeObjects(self.code) - return (ByteParser(code=c, text=self.text) for c in children) + return (ByteParser(self.text, code=c) for c in children) def _bytes_lines(self): """Map byte offsets to line numbers in `code`. diff --git a/coverage/phystokens.py b/coverage/phystokens.py index 4faa3c3f..70deb800 100644 --- a/coverage/phystokens.py +++ b/coverage/phystokens.py @@ -153,17 +153,17 @@ def source_encoding(source): Returns a string, the name of the encoding. """ - # Note: this function should never be called on Python 3, since py3 has - # built-in tools to do this. - assert sys.version_info < (3, 0) + if sys.version_info >= (3, 0): + readline = iter(source.splitlines(True)).__next__ + return tokenize.detect_encoding(readline)[0] + + # Do this so the detect_encode code we copied will work. + readline = iter(source.splitlines(True)).next # This is mostly code adapted from Py3.2's tokenize module. cookie_re = re.compile(r"^\s*#.*coding[:=]\s*([-\w.]+)") - # Do this so the detect_encode code we copied will work. - readline = iter(source.splitlines(True)).next - def _get_normal_name(orig_enc): """Imitates get_normal_name in tokenizer.c.""" # Only care about the first 12 characters. @@ -246,9 +246,12 @@ def source_encoding(source): # Reading Python source and interpreting the coding comment is a big deal. if sys.version_info >= (3, 0): # Python 3.2 provides `tokenize.open`, the best way to open source files. - import tokenize - open_python_source = tokenize.open + def read_python_source(filename): + # Returns unicode on Py3, bytes on Py2 + with tokenize.open(filename) as f: + return f.read() else: - def open_python_source(fname): - """Open a source file the best way.""" - return open(fname, "rU") + def read_python_source(filename): + # Returns unicode on Py3, bytes on Py2 + with open(filename, "rU") as f: + return f.read() diff --git a/coverage/summary.py b/coverage/summary.py index 10ac7e2c..cfcdfcda 100644 --- a/coverage/summary.py +++ b/coverage/summary.py @@ -4,7 +4,7 @@ import sys from coverage.report import Reporter from coverage.results import Numbers -from coverage.misc import NotPython +from coverage.misc import CoverageException, NotPython class SummaryReporter(Reporter): diff --git a/lab/parser.py b/lab/parser.py index 932480df..1783468b 100644 --- a/lab/parser.py +++ b/lab/parser.py @@ -9,6 +9,7 @@ from optparse import OptionParser import disgen from coverage.misc import CoverageException +from coverage.files import get_python_source from coverage.parser import ByteParser, PythonParser opcode_counts = collections.Counter() @@ -70,7 +71,8 @@ class ParserMain(object): """Process just one file.""" try: - bp = ByteParser(filename=filename) + text = get_python_source(filename) + bp = ByteParser(text, filename=filename) except Exception as err: print("%s" % (err,)) return |