|
from __future__ import print_function |
|
from coverage.plugin import CoveragePlugin, FileReporter, FileTracer |
|
import inspect |
|
import os |
|
import re |
|
|
|
|
|
class ChameleonTemplatePlugin(CoveragePlugin, FileTracer): |
|
def __init__(self): |
|
self.source_filename_map = {} |
|
self.filename_line_map = {} |
|
|
|
def file_reporter(self, filename): |
|
return ChameleonFileReporter(filename) |
|
|
|
def file_tracer(self, filename): |
|
directory = os.environ.get('CHAMELEON_CACHE', None) or os.getcwd() |
|
if os.path.dirname(filename) == directory: |
|
return self |
|
return None |
|
|
|
def find_executable_files(self, src_dir): |
|
for (dirpath, dirnames, filenames) in os.walk(src_dir): |
|
for filename in filenames: |
|
# We're only interested in files that look like reasonable HTML |
|
# files: Must end with .pt, and must not have certain funny |
|
# characters that probably mean they are editor junk. |
|
if re.match(r"^[^.#~!$@%^&*()+=,]+\.pt$", filename): |
|
yield os.path.join(dirpath, filename) |
|
|
|
def has_dynamic_source_filename(self): |
|
return True |
|
|
|
def dynamic_source_filename(self, filename, frame): |
|
result = None |
|
# result = self.source_filename_map.get(frame.f_code.co_filename) |
|
if result is None: |
|
if frame.f_code.co_name.startswith('render'): |
|
if 'econtext' in frame.f_locals: |
|
econtext = frame.f_locals['econtext'] |
|
if 1: |
|
dump_frame(frame, label="dynamic_source_filename") |
|
if 'template' in econtext: |
|
template_fn = econtext['template'].filename |
|
basename = os.path.basename(frame.f_code.co_filename) |
|
template_basename = os.path.basename(template_fn) |
|
template_basename, ext = os.path.splitext(template_basename) |
|
print(basename, template_basename) |
|
if result is not None: |
|
self.source_filename_map[frame.f_code.co_filename] = result |
|
print(self.source_filename_map) |
|
return result |
|
|
|
def get_line_map(self, frame): |
|
filename = inspect.getfile(frame) |
|
name = frame.f_code.co_name |
|
key = (filename, name) |
|
if key in self.filename_line_map: |
|
return self.filename_line_map[key] |
|
matcher = re.compile(r'^.*#.*\((\d+):\d+\)') |
|
print() |
|
print(key) |
|
line_map = {} |
|
(source, start_line) = inspect.getsourcelines(frame) |
|
if name == 'render': |
|
end_line = len(source) + start_line |
|
template_lines = (1, 1) |
|
template = self.source_filename_map.get(filename) |
|
if template is not None: |
|
with open(template) as f: |
|
template_lines = (1, len(f.readlines()) + 1) |
|
print(template, template_lines) |
|
for i in range(start_line, end_line + 1): |
|
line_map[i] = template_lines |
|
lineno = None |
|
for index, line in enumerate(source, start=start_line): |
|
m = matcher.match(line) |
|
if m is None: |
|
continue |
|
lineno = int(m.group(1)) |
|
for i in range(start_line, index + 1): |
|
line_map[i] = (lineno, lineno) |
|
start_line = index + 1 |
|
if lineno is not None: |
|
for i in range(start_line, index + 1): |
|
line_map[i] = (lineno, lineno) |
|
# print(line_map) |
|
self.filename_line_map[key] = line_map |
|
return line_map |
|
|
|
def line_number_range(self, frame): |
|
if 0: |
|
dump_frame(frame, label="line_number_range") |
|
line_map = self.get_line_map(frame) |
|
result = line_map.get(frame.f_lineno, (-1, -1)) |
|
if result == (-1, -1): |
|
print(frame.f_code.co_filename, frame.f_code.co_name, frame.f_lineno) |
|
return result |
|
|
|
def sys_info(self): |
|
return [ |
|
("environment", sorted( |
|
("%s = %s" % (k, v)) |
|
for k, v in os.environ.items() |
|
if "CHAMELEON_" in k |
|
)), |
|
] |
|
|
|
|
|
class ChameleonFileReporter(FileReporter): |
|
def lines(self): |
|
# print(self.filename) |
|
lines = self.source().splitlines() |
|
source_lines = set(range(len(lines))) |
|
return source_lines |
|
|
|
|
|
def coverage_init(reg, options): |
|
reg.add_file_tracer(ChameleonTemplatePlugin()) |
|
|
|
|
|
def dump_frame(frame, label=""): |
|
"""Dump interesting information about this frame.""" |
|
locals = dict(frame.f_locals) |
|
econtext = locals.pop('econtext', None) |
|
rcontext = locals.pop('rcontext', None) |
|
if "__builtins__" in locals: |
|
del locals["__builtins__"] |
|
|
|
if label: |
|
label = " ( %s ) " % label |
|
print("-- frame --%s---------------------" % label) |
|
print("{}:{} {}".format( |
|
os.path.basename(frame.f_code.co_filename), |
|
frame.f_lineno, |
|
frame.f_code.co_name)) |
|
print("locals:", locals.keys()) |
|
if econtext: |
|
print("econtext:", econtext.keys()) |
|
if rcontext: |
|
print("rcontext:", rcontext.keys()) |
|
print("\\--") |