From e4d3d19a4192536d35e419468354bd8d14904098 Mon Sep 17 00:00:00 2001 From: Ned Batchelder Date: Sun, 18 May 2014 15:03:40 -0400 Subject: Move shell globbing into cmdline.py --- coverage/codeunit.py | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) (limited to 'coverage/codeunit.py') diff --git a/coverage/codeunit.py b/coverage/codeunit.py index 88858801..23f49e8b 100644 --- a/coverage/codeunit.py +++ b/coverage/codeunit.py @@ -1,6 +1,6 @@ """Code unit (module) handling for Coverage.""" -import glob, os, re +import os, re from coverage.backward import open_python_source, string_class, StringIO from coverage.misc import CoverageException, NoSource @@ -22,15 +22,6 @@ def code_unit_factory(morfs, file_locator): if not isinstance(morfs, (list, tuple)): morfs = [morfs] - # On Windows, the shell doesn't expand wildcards. Do it here. - globbed = [] - for morf in morfs: - if isinstance(morf, string_class) and ('?' in morf or '*' in morf): - globbed.extend(glob.glob(morf)) - else: - globbed.append(morf) - morfs = globbed - code_units = [] for morf in morfs: # Hacked-in Mako support. Disabled for going onto trunk. -- cgit v1.2.1 From a189b3bb1846d8e0c7b003a94af69822d3890f9e Mon Sep 17 00:00:00 2001 From: Ned Batchelder Date: Sun, 18 May 2014 21:26:57 -0400 Subject: Continued refactoring of CodeUnit --- coverage/codeunit.py | 33 ++++++++++++++++++--------------- 1 file changed, 18 insertions(+), 15 deletions(-) (limited to 'coverage/codeunit.py') diff --git a/coverage/codeunit.py b/coverage/codeunit.py index 23f49e8b..2ee19104 100644 --- a/coverage/codeunit.py +++ b/coverage/codeunit.py @@ -2,7 +2,7 @@ import os, re -from coverage.backward import open_python_source, string_class, StringIO +from coverage.backward import open_python_source, string_class from coverage.misc import CoverageException, NoSource from coverage.parser import CodeParser, PythonParser from coverage.phystokens import source_token_lines, source_encoding @@ -110,16 +110,16 @@ class CodeUnit(object): root = os.path.splitdrive(self.name)[1] return root.replace('\\', '_').replace('/', '_').replace('.', '_') - def source_file(self): - """Return an open file for reading the source of the code unit.""" + def source(self): + """Return the source code, as a string.""" if os.path.exists(self.filename): # A regular text file: open it. - return open_python_source(self.filename) + return open_python_source(self.filename).read() # Maybe it's in a zip file? source = self.file_locator.get_zip_data(self.filename) if source is not None: - return StringIO(source) + return source # Couldn't find source. raise CoverageException( @@ -139,8 +139,6 @@ class CodeUnit(object): class PythonCodeUnit(CodeUnit): """Represents a Python file.""" - parser_class = PythonParser - def _adjust_filename(self, fname): # .pyc files should always refer to a .py instead. if fname.endswith(('.pyc', '.pyo')): @@ -149,7 +147,13 @@ class PythonCodeUnit(CodeUnit): fname = fname[:-9] + ".py" return fname - def find_source(self, filename): + def get_parser(self, exclude=None): + actual_filename, source = self._find_source(self.filename) + return PythonParser( + text=source, filename=actual_filename, exclude=exclude, + ) + + def _find_source(self, filename): """Find the source for `filename`. Returns two values: the actual filename, and the source. @@ -227,10 +231,8 @@ def mako_template_name(py_filename): class MakoParser(CodeParser): - def __init__(self, cu, text, filename, exclude): + def __init__(self, cu, exclude): self.cu = cu - self.text = text - self.filename = filename self.exclude = exclude def parse_source(self): @@ -261,14 +263,15 @@ class MakoParser(CodeParser): class MakoCodeUnit(CodeUnit): - parser_class = MakoParser - def __init__(self, *args, **kwargs): super(MakoCodeUnit, self).__init__(*args, **kwargs) self.mako_filename = mako_template_name(self.filename) - def source_file(self): - return open(self.mako_filename) + def source(self): + return open(self.mako_filename).read() + + def get_parser(self, exclude=None): + return MakoParser(self, exclude) def find_source(self, filename): """Find the source for `filename`. -- cgit v1.2.1 From 8aead29863e1e6604eb15e9a463da747d38eb47f Mon Sep 17 00:00:00 2001 From: Ned Batchelder Date: Tue, 20 May 2014 07:08:34 -0400 Subject: Improved Mako support. Needs Mako tip --- coverage/codeunit.py | 75 ++++++++++++++++------------------------------------ 1 file changed, 23 insertions(+), 52 deletions(-) (limited to 'coverage/codeunit.py') diff --git a/coverage/codeunit.py b/coverage/codeunit.py index 2ee19104..4fa9cf8e 100644 --- a/coverage/codeunit.py +++ b/coverage/codeunit.py @@ -24,8 +24,11 @@ def code_unit_factory(morfs, file_locator): code_units = [] for morf in morfs: - # Hacked-in Mako support. Disabled for going onto trunk. - if 0 and isinstance(morf, string_class) and "/mako/" in morf: + # Hacked-in Mako support. Define COVERAGE_MAKO_PATH as a fragment of + # the path that indicates the Python file is actually a compiled Mako + # template. THIS IS TEMPORARY! + MAKO_PATH = os.environ.get('COVERAGE_MAKO_PATH') + if MAKO_PATH and isinstance(morf, string_class) and MAKO_PATH in morf: # Super hack! Do mako both ways! if 0: cu = PythonCodeUnit(morf, file_locator) @@ -78,6 +81,10 @@ class CodeUnit(object): def __repr__(self): return "" % (self.name, self.filename) + def _adjust_filename(self, f): + # TODO: This shouldn't be in the base class, right? + return f + # Annoying comparison operators. Py3k wants __lt__ etc, and Py2k needs all # of them defined. @@ -218,46 +225,18 @@ class PythonCodeUnit(CodeUnit): return source_encoding(source) -def mako_template_name(py_filename): - with open(py_filename) as f: - py_source = f.read() - - # Find the template filename. TODO: string escapes in the string. - m = re.search(r"^_template_filename = u?'([^']+)'", py_source, flags=re.MULTILINE) - if not m: - raise Exception("Couldn't find template filename in Mako file %r" % py_filename) - template_filename = m.group(1) - return template_filename - - class MakoParser(CodeParser): - def __init__(self, cu, exclude): - self.cu = cu - self.exclude = exclude + def __init__(self, metadata): + self.metadata = metadata def parse_source(self): """Returns executable_line_numbers, excluded_line_numbers""" - with open(self.cu.filename) as f: - py_source = f.read() - - # Get the line numbers. - self.py_to_html = {} - html_linenum = None - for linenum, line in enumerate(py_source.splitlines(), start=1): - m_source_line = re.search(r"^\s*# SOURCE LINE (\d+)$", line) - if m_source_line: - html_linenum = int(m_source_line.group(1)) - else: - m_boilerplate_line = re.search(r"^\s*# BOILERPLATE", line) - if m_boilerplate_line: - html_linenum = None - elif html_linenum: - self.py_to_html[linenum] = html_linenum - - return set(self.py_to_html.values()), set() + r = set(self.metadata['line_map'].values()) + print r + return r, set() def translate_lines(self, lines): - tlines = set(self.py_to_html.get(l, -1) for l in lines) + tlines = set(self.metadata['full_line_map'].get(l, -1) for l in lines) tlines.remove(-1) return tlines @@ -265,30 +244,22 @@ class MakoParser(CodeParser): class MakoCodeUnit(CodeUnit): def __init__(self, *args, **kwargs): super(MakoCodeUnit, self).__init__(*args, **kwargs) - self.mako_filename = mako_template_name(self.filename) + from mako.template import ModuleInfo + py_source = open(self.filename).read() + self.metadata = ModuleInfo.get_module_source_metadata(py_source, full_line_map=True) def source(self): - return open(self.mako_filename).read() + return open(self.metadata['filename']).read() def get_parser(self, exclude=None): - return MakoParser(self, exclude) - - def find_source(self, filename): - """Find the source for `filename`. - - Returns two values: the actual filename, and the source. - - """ - mako_filename = mako_template_name(filename) - with open(mako_filename) as f: - source = f.read() - - return mako_filename, source + return MakoParser(self.metadata) def source_token_lines(self, source): """Return the 'tokenized' text for the code.""" + # TODO: Taking source here is wrong, change it? for line in source.splitlines(): yield [('txt', line)] def source_encoding(self, source): - return "utf-8" + # TODO: Taking source here is wrong, change it! + return self.metadata['source_encoding'] -- cgit v1.2.1 From e8ae0fd9eab531a700fe00a0d8b8ce185f8f24c0 Mon Sep 17 00:00:00 2001 From: Ned Batchelder Date: Tue, 20 May 2014 07:23:56 -0400 Subject: Clean up codeunit, as usual --- coverage/codeunit.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'coverage/codeunit.py') diff --git a/coverage/codeunit.py b/coverage/codeunit.py index 4fa9cf8e..179de017 100644 --- a/coverage/codeunit.py +++ b/coverage/codeunit.py @@ -1,6 +1,6 @@ """Code unit (module) handling for Coverage.""" -import os, re +import os from coverage.backward import open_python_source, string_class from coverage.misc import CoverageException, NoSource @@ -121,7 +121,8 @@ class CodeUnit(object): """Return the source code, as a string.""" if os.path.exists(self.filename): # A regular text file: open it. - return open_python_source(self.filename).read() + with open_python_source(self.filename) as f: + return f.read() # Maybe it's in a zip file? source = self.file_locator.get_zip_data(self.filename) @@ -231,9 +232,8 @@ class MakoParser(CodeParser): def parse_source(self): """Returns executable_line_numbers, excluded_line_numbers""" - r = set(self.metadata['line_map'].values()) - print r - return r, set() + executable = set(self.metadata['line_map'].values()) + return executable, set() def translate_lines(self, lines): tlines = set(self.metadata['full_line_map'].get(l, -1) for l in lines) -- cgit v1.2.1 From 12e05dbdbedea2c668ce90cb19da34476dccaca8 Mon Sep 17 00:00:00 2001 From: Ned Batchelder Date: Tue, 27 May 2014 09:32:01 -0400 Subject: Adapt to the full_line_map change in Mako --- coverage/codeunit.py | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) (limited to 'coverage/codeunit.py') diff --git a/coverage/codeunit.py b/coverage/codeunit.py index 179de017..9282687d 100644 --- a/coverage/codeunit.py +++ b/coverage/codeunit.py @@ -236,8 +236,12 @@ class MakoParser(CodeParser): return executable, set() def translate_lines(self, lines): - tlines = set(self.metadata['full_line_map'].get(l, -1) for l in lines) - tlines.remove(-1) + tlines = set() + for l in lines: + try: + tlines.add(self.metadata['full_line_map'][l]) + except IndexError: + pass return tlines -- cgit v1.2.1 From 44527cc9db62aa3979c69abe4edb7070aafd6897 Mon Sep 17 00:00:00 2001 From: Ned Batchelder Date: Thu, 12 Jun 2014 17:17:38 -0400 Subject: Hacked-in django template support --HG-- branch : django --- coverage/codeunit.py | 41 +++++++++++++++++++++++++++++++++++------ 1 file changed, 35 insertions(+), 6 deletions(-) (limited to 'coverage/codeunit.py') diff --git a/coverage/codeunit.py b/coverage/codeunit.py index 9282687d..59382c23 100644 --- a/coverage/codeunit.py +++ b/coverage/codeunit.py @@ -7,6 +7,8 @@ from coverage.misc import CoverageException, NoSource from coverage.parser import CodeParser, PythonParser from coverage.phystokens import source_token_lines, source_encoding +from coverage.django import DjangoTracer + def code_unit_factory(morfs, file_locator): """Construct a list of CodeUnits from polymorphic inputs. @@ -22,6 +24,8 @@ def code_unit_factory(morfs, file_locator): if not isinstance(morfs, (list, tuple)): morfs = [morfs] + django_tracer = DjangoTracer() + code_units = [] for morf in morfs: # Hacked-in Mako support. Define COVERAGE_MAKO_PATH as a fragment of @@ -35,6 +39,8 @@ def code_unit_factory(morfs, file_locator): cu.name += '_fako' code_units.append(cu) klass = MakoCodeUnit + elif isinstance(morf, string_class) and morf.endswith(".html"): + klass = DjangoCodeUnit else: klass = PythonCodeUnit code_units.append(klass(morf, file_locator)) @@ -134,6 +140,12 @@ class CodeUnit(object): "No source for code '%s'." % self.filename ) + def source_token_lines(self, source): + """Return the 'tokenized' text for the code.""" + # TODO: Taking source here is wrong, change it? + for line in source.splitlines(): + yield [('txt', line)] + def should_be_python(self): """Does it seem like this file should contain Python? @@ -258,12 +270,29 @@ class MakoCodeUnit(CodeUnit): def get_parser(self, exclude=None): return MakoParser(self.metadata) - def source_token_lines(self, source): - """Return the 'tokenized' text for the code.""" - # TODO: Taking source here is wrong, change it? - for line in source.splitlines(): - yield [('txt', line)] - def source_encoding(self, source): # TODO: Taking source here is wrong, change it! return self.metadata['source_encoding'] + + +class DjangoCodeUnit(CodeUnit): + def source(self): + with open(self.filename) as f: + return f.read() + + def get_parser(self, exclude=None): + return DjangoParser(self.filename) + + def source_encoding(self, source): + return "utf8" + + +class DjangoParser(CodeParser): + def __init__(self, filename): + self.filename = filename + + def parse_source(self): + with open(self.filename) as f: + source = f.read() + executable = set(range(1, len(source.splitlines())+1)) + return executable, set() -- cgit v1.2.1 From f346f85e04e44294e4c26f876e8dc75b17c4f8d7 Mon Sep 17 00:00:00 2001 From: Ned Batchelder Date: Fri, 4 Jul 2014 22:15:20 -0400 Subject: Crazy-ugly start to extensions for Django and Mako --HG-- branch : django --- coverage/codeunit.py | 35 +++++++++++++++++++++-------------- 1 file changed, 21 insertions(+), 14 deletions(-) (limited to 'coverage/codeunit.py') diff --git a/coverage/codeunit.py b/coverage/codeunit.py index 59382c23..35167a72 100644 --- a/coverage/codeunit.py +++ b/coverage/codeunit.py @@ -10,13 +10,15 @@ from coverage.phystokens import source_token_lines, source_encoding from coverage.django import DjangoTracer -def code_unit_factory(morfs, file_locator): +def code_unit_factory(morfs, file_locator, get_ext=None): """Construct a list of CodeUnits from polymorphic inputs. `morfs` is a module or a filename, or a list of same. `file_locator` is a FileLocator that can help resolve filenames. + `get_ext` TODO + Returns a list of CodeUnit objects. """ @@ -28,19 +30,24 @@ def code_unit_factory(morfs, file_locator): code_units = [] for morf in morfs: - # Hacked-in Mako support. Define COVERAGE_MAKO_PATH as a fragment of - # the path that indicates the Python file is actually a compiled Mako - # template. THIS IS TEMPORARY! - MAKO_PATH = os.environ.get('COVERAGE_MAKO_PATH') - if MAKO_PATH and isinstance(morf, string_class) and MAKO_PATH in morf: - # Super hack! Do mako both ways! - if 0: - cu = PythonCodeUnit(morf, file_locator) - cu.name += '_fako' - code_units.append(cu) - klass = MakoCodeUnit - elif isinstance(morf, string_class) and morf.endswith(".html"): - klass = DjangoCodeUnit + ext = None + if isinstance(morf, string_class) and get_ext: + ext = get_ext(morf) + if ext: + klass = DjangoTracer # NOT REALLY! TODO + # Hacked-in Mako support. Define COVERAGE_MAKO_PATH as a fragment of + # the path that indicates the Python file is actually a compiled Mako + # template. THIS IS TEMPORARY! + #MAKO_PATH = os.environ.get('COVERAGE_MAKO_PATH') + #if MAKO_PATH and isinstance(morf, string_class) and MAKO_PATH in morf: + # # Super hack! Do mako both ways! + # if 0: + # cu = PythonCodeUnit(morf, file_locator) + # cu.name += '_fako' + # code_units.append(cu) + # klass = MakoCodeUnit + #elif isinstance(morf, string_class) and morf.endswith(".html"): + # klass = DjangoCodeUnit else: klass = PythonCodeUnit code_units.append(klass(morf, file_locator)) -- cgit v1.2.1