1# mode: run
2# tag: coverage,trace,nogil
3
4"""
5PYTHON setup.py build_ext -i
6PYTHON coverage_test.py
7"""
8
9######## setup.py ########
10
11from distutils.core import setup
12from Cython.Build import cythonize
13
14setup(ext_modules = cythonize([
15    'coverage_test_*.pyx',
16]))
17
18
19######## .coveragerc ########
20[run]
21plugins = Cython.Coverage
22
23
24######## coverage_test_nogil.pyx ########
25# cython: linetrace=True
26# distutils: define_macros=CYTHON_TRACE=1 CYTHON_TRACE_NOGIL=1
27
28cdef int func1(int a, int b) nogil:  #  4
29    cdef int x                       #  5
30    with gil:                        #  6
31        x = 1                        #  7
32    cdef int c = func2(a) + b        #  8
33    return x + c                     #  9
34
35
36cdef int func2(int a) with gil:  # 12
37    return a * 2                 # 13
38
39
40def call(int a, int b):          # 16
41    a, b = b, a                  # 17
42    with nogil:                  # 18
43        result = func1(b, a)     # 19
44    return result                # 20
45
46
47######## coverage_test.py ########
48
49import os.path
50try:
51    # io.StringIO in Py2.x cannot handle str ...
52    from StringIO import StringIO
53except ImportError:
54    from io import StringIO
55
56from coverage import coverage
57
58
59def run_coverage():
60    cov = coverage()
61    cov.start()
62
63    import coverage_test_nogil as module
64    module_name = module.__name__
65    module_path = module_name + '.pyx'
66    assert not any(module.__file__.endswith(ext)
67                   for ext in '.py .pyc .pyo .pyw .pyx .pxi'.split()), \
68        module.__file__
69    assert module.call(1, 2) == (1 * 2) + 2 + 1
70
71    cov.stop()
72
73    out = StringIO()
74    cov.report(file=out)
75    #cov.report([module], file=out)
76    lines = out.getvalue().splitlines()
77    assert any(module_path in line for line in lines), \
78        "'%s' not found in coverage report:\n\n%s" % (module_path, out.getvalue())
79
80    mod_file, exec_lines, excl_lines, missing_lines, _ = cov.analysis2(os.path.abspath(module_path))
81    assert module_path in mod_file
82
83    executed = set(exec_lines) - set(missing_lines)
84    # check that everything that runs with the gil owned was executed
85    assert all(line in executed for line in [12, 13, 16, 17, 18, 20]), '%s / %s' % (exec_lines, missing_lines)
86    # check that everything that runs in nogil sections was executed
87    assert all(line in executed for line in [4, 6, 7, 8, 9]), '%s / %s' % (exec_lines, missing_lines)
88
89
90if __name__ == '__main__':
91    run_coverage()
92