Commit d6341966 authored by Stefan Behnel's avatar Stefan Behnel

Refactor parsing function in code coverage plugin to split the actual parsing...

Refactor parsing function in code coverage plugin to split the actual parsing code from the lookup code.
parent 86904478
...@@ -82,7 +82,7 @@ class Plugin(CoveragePlugin): ...@@ -82,7 +82,7 @@ class Plugin(CoveragePlugin):
# is not from the main .pyx file but a file with a different # is not from the main .pyx file but a file with a different
# name than the .c file (which prevents us from finding the # name than the .c file (which prevents us from finding the
# .c file) # .c file)
_, code = self._parse_lines(c_file, filename) _, code = self._read_source_lines(c_file, filename)
if code is None: if code is None:
return None # no source found return None # no source found
...@@ -104,7 +104,7 @@ class Plugin(CoveragePlugin): ...@@ -104,7 +104,7 @@ class Plugin(CoveragePlugin):
c_file, _ = self._find_source_files(filename) c_file, _ = self._find_source_files(filename)
if not c_file: if not c_file:
return None # unknown file return None # unknown file
rel_file_path, code = self._parse_lines(c_file, filename) rel_file_path, code = self._read_source_lines(c_file, filename)
if code is None: if code is None:
return None # no source found return None # no source found
return CythonModuleReporter(c_file, filename, rel_file_path, code) return CythonModuleReporter(c_file, filename, rel_file_path, code)
...@@ -170,14 +170,14 @@ class Plugin(CoveragePlugin): ...@@ -170,14 +170,14 @@ class Plugin(CoveragePlugin):
for filename in os.listdir(dir_path): for filename in os.listdir(dir_path):
ext = splitext(filename)[1].lower() ext = splitext(filename)[1].lower()
if ext in C_FILE_EXTENSIONS: if ext in C_FILE_EXTENSIONS:
self._parse_lines(os.path.join(dir_path, filename), source_file) self._read_source_lines(os.path.join(dir_path, filename), source_file)
if source_file in self._c_files_map: if source_file in self._c_files_map:
return return
# not found? then try one package up # not found? then try one package up
if is_package_dir(dir_path): if is_package_dir(dir_path):
self._find_c_source_files(os.path.dirname(dir_path), source_file) self._find_c_source_files(os.path.dirname(dir_path), source_file)
def _parse_lines(self, c_file, sourcefile): def _read_source_lines(self, c_file, sourcefile):
""" """
Parse a Cython generated C/C++ source file and find the executable lines. Parse a Cython generated C/C++ source file and find the executable lines.
Each executable line starts with a comment header that states source file Each executable line starts with a comment header that states source file
...@@ -188,6 +188,24 @@ class Plugin(CoveragePlugin): ...@@ -188,6 +188,24 @@ class Plugin(CoveragePlugin):
if c_file in self._parsed_c_files: if c_file in self._parsed_c_files:
code_lines = self._parsed_c_files[c_file] code_lines = self._parsed_c_files[c_file]
else: else:
code_lines = self._parse_cfile_lines(c_file)
self._parsed_c_files[c_file] = code_lines
if self._c_files_map is None:
self._c_files_map = {}
for filename, code in code_lines.items():
abs_path = _find_dep_file_path(c_file, filename)
self._c_files_map[abs_path] = (c_file, filename, code)
if sourcefile not in self._c_files_map:
return (None,) * 2 # e.g. shared library file
return self._c_files_map[sourcefile][1:]
def _parse_cfile_lines(self, c_file):
"""
Parse a C file and extract all source file lines that generated executable code.
"""
match_source_path_line = re.compile(r' */[*] +"(.*)":([0-9]+)$').match match_source_path_line = re.compile(r' */[*] +"(.*)":([0-9]+)$').match
match_current_code_line = re.compile(r' *[*] (.*) # <<<<<<+$').match match_current_code_line = re.compile(r' *[*] (.*) # <<<<<<+$').match
match_comment_end = re.compile(r' *[*]/$').match match_comment_end = re.compile(r' *[*]/$').match
...@@ -202,6 +220,7 @@ class Plugin(CoveragePlugin): ...@@ -202,6 +220,7 @@ class Plugin(CoveragePlugin):
code_lines = defaultdict(dict) code_lines = defaultdict(dict)
executable_lines = defaultdict(set) executable_lines = defaultdict(set)
current_filename = None current_filename = None
with open(c_file) as lines: with open(c_file) as lines:
lines = iter(lines) lines = iter(lines)
for line in lines: for line in lines:
...@@ -232,19 +251,7 @@ class Plugin(CoveragePlugin): ...@@ -232,19 +251,7 @@ class Plugin(CoveragePlugin):
dead_lines = set(lines).difference(executable_lines.get(filename, ())) dead_lines = set(lines).difference(executable_lines.get(filename, ()))
for lineno in dead_lines: for lineno in dead_lines:
del lines[lineno] del lines[lineno]
return code_lines
self._parsed_c_files[c_file] = code_lines
if self._c_files_map is None:
self._c_files_map = {}
for filename, code in code_lines.items():
abs_path = _find_dep_file_path(c_file, filename)
self._c_files_map[abs_path] = (c_file, filename, code)
if sourcefile not in self._c_files_map:
return (None,) * 2 # e.g. shared library file
return self._c_files_map[sourcefile][1:]
class CythonModuleTracer(FileTracer): class CythonModuleTracer(FileTracer):
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment