Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
C
cython
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Labels
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Commits
Open sidebar
nexedi
cython
Commits
5ba68b7c
Commit
5ba68b7c
authored
5 years ago
by
Antonio Valentino
Committed by
Stefan Behnel
5 years ago
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Fix coverage analysis for code in separate source directory (see GH-1985) (GH-3088)
* Fix coverage path search * Add testcase
parent
993f2f72
Changes
2
Show whitespace changes
Inline
Side-by-side
Showing
2 changed files
with
171 additions
and
7 deletions
+171
-7
Cython/Coverage.py
Cython/Coverage.py
+9
-7
tests/run/coverage_cmd_src_layout.srctree
tests/run/coverage_cmd_src_layout.srctree
+162
-0
No files found.
Cython/Coverage.py
View file @
5ba68b7c
...
...
@@ -33,13 +33,14 @@ def _find_c_source(base_path):
return
None
def
_find_dep_file_path
(
main_file
,
file_path
):
def
_find_dep_file_path
(
main_file
,
file_path
,
relative_path_search
=
False
):
abs_path
=
os
.
path
.
abspath
(
file_path
)
if
file_path
.
endswith
(
'.pxi'
)
and
not
os
.
path
.
exists
(
abs_path
):
# include files are looked up relative to the main source file
pxi_file_path
=
os
.
path
.
join
(
os
.
path
.
dirname
(
main_file
),
file_path
)
if
os
.
path
.
exists
(
pxi_file_path
):
abs_path
=
os
.
path
.
abspath
(
pxi_file_path
)
if
not
os
.
path
.
exists
(
abs_path
)
and
(
file_path
.
endswith
(
'.pxi'
)
or
relative_path_search
):
# files are looked up relative to the main source file
rel_file_path
=
os
.
path
.
join
(
os
.
path
.
dirname
(
main_file
),
file_path
)
if
os
.
path
.
exists
(
rel_file_path
):
abs_path
=
os
.
path
.
abspath
(
rel_file_path
)
# search sys.path for external locations if a valid file hasn't been found
if
not
os
.
path
.
exists
(
abs_path
):
for
sys_path
in
sys
.
path
:
...
...
@@ -195,7 +196,8 @@ class Plugin(CoveragePlugin):
self
.
_c_files_map
=
{}
for
filename
,
code
in
code_lines
.
items
():
abs_path
=
_find_dep_file_path
(
c_file
,
filename
)
abs_path
=
_find_dep_file_path
(
c_file
,
filename
,
relative_path_search
=
True
)
self
.
_c_files_map
[
abs_path
]
=
(
c_file
,
filename
,
code
)
if
sourcefile
not
in
self
.
_c_files_map
:
...
...
This diff is collapsed.
Click to expand it.
tests/run/coverage_cmd_src_layout.srctree
0 → 100644
View file @
5ba68b7c
# mode: run
# tag: coverage,trace
"""
PYTHON setup.py build_ext -i
PYTHON -m coverage run --source=src coverage_test.py
PYTHON collect_coverage.py
"""
######## setup.py ########
from distutils.core import setup
from Cython.Build import cythonize
setup(ext_modules = cythonize([
'src/trivial_module.pyx',
]))
######## .coveragerc ########
[run]
plugins = Cython.Coverage
######## src/trivial_module.pyx ########
# cython: linetrace=True
# distutils: define_macros=CYTHON_TRACE=1
def func1(int a, int b):
cdef int x = 1 # 5
c = func2(a) + b # 6
return x + c # 7
def func2(int a):
return a * 2 # 11
######## coverage_test.py ########
import os.path
import trivial_module
assert not any(
trivial_module.__file__.endswith(ext)
for ext in '.py .pyc .pyo .pyw .pyx .pxi'.split()
), module.__file__
def run_coverage(module):
assert module.func1(1, 2) == (1 * 2) + 2 + 1
assert module.func2(2) == 2 * 2
if __name__ == '__main__':
run_coverage(trivial_module)
######## collect_coverage.py ########
import re
import sys
import os
import os.path
import subprocess
from glob import iglob
def run_coverage_command(*command):
env = dict(os.environ, LANG='', LC_ALL='C')
process = subprocess.Popen(
[sys.executable, '-m', 'coverage'] + list(command),
stdout=subprocess.PIPE, env=env)
stdout, _ = process.communicate()
return stdout
def run_report():
stdout = run_coverage_command('report', '--show-missing')
stdout = stdout.decode('iso8859-1') # 'safe' decoding
lines = stdout.splitlines()
print(stdout)
module_path = 'trivial_module.pyx'
assert any(module_path in line for line in lines), (
"'%s' not found in coverage report:\n\n%s" % (module_path, stdout))
files = {}
line_iter = iter(lines)
for line in line_iter:
if line.startswith('---'):
break
extend = [''] * 2
for line in line_iter:
if not line or line.startswith('---'):
continue
name, statements, missed, covered, _missing = (line.split(None, 4) + extend)[:5]
missing = []
for start, end in re.findall('([0-9]+)(?:-([0-9]+))?', _missing):
if end:
missing.extend(range(int(start), int(end)+1))
else:
missing.append(int(start))
files[os.path.basename(name)] = (statements, missed, covered, missing)
assert 5 not in files[module_path][-1], files[module_path]
assert 6 not in files[module_path][-1], files[module_path]
assert 7 not in files[module_path][-1], files[module_path]
assert 11 not in files[module_path][-1], files[module_path]
def run_xml_report():
stdout = run_coverage_command('xml', '-o', '-')
print(stdout)
import xml.etree.ElementTree as etree
data = etree.fromstring(stdout)
files = {}
for module in data.iterfind('.//class'):
files[module.get('filename').replace('\\', '/')] = dict(
(int(line.get('number')), int(line.get('hits')))
for line in module.findall('lines/line')
)
module_path = 'src/trivial_module.pyx'
assert files[module_path][5] > 0, files[module_path]
assert files[module_path][6] > 0, files[module_path]
assert files[module_path][7] > 0, files[module_path]
assert files[module_path][11] > 0, files[module_path]
def run_html_report():
stdout = run_coverage_command('html', '-d', 'html')
_parse_lines = re.compile(
r'<p[^>]* id=["\'][^0-9"\']*(?P<id>[0-9]+)[^0-9"\']*["\'][^>]*'
r' class=["\'][^"\']*(?P<run>mis|run)[^"\']*["\']').findall
files = {}
for file_path in iglob('html/*.html'):
with open(file_path) as f:
page = f.read()
executed = set()
missing = set()
for line, has_run in _parse_lines(page):
(executed if has_run == 'run' else missing).add(int(line))
files[file_path] = (executed, missing)
executed, missing = [data for path, data in files.items() if 'trivial_module' in path][0]
assert executed
assert 5 in executed, executed
assert 6 in executed, executed
assert 7 in executed, executed
assert 11 in executed, executed
if __name__ == '__main__':
run_report()
run_xml_report()
run_html_report()
This diff is collapsed.
Click to expand it.
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment