1PYTHON setup.py build_ext --inplace
2PYTHON test_profile.py
3
4######## setup.py ###########
5
6from distutils.extension import Extension
7from distutils.core import setup
8from Cython.Build import cythonize
9
10extensions = [
11    Extension("collatz", ["collatz.pyx"], define_macros=[('CYTHON_TRACE', '1')])
12]
13
14setup(
15    ext_modules = cythonize(extensions)
16)
17
18######## test_profile.py ###########
19
20try:
21    import line_profiler
22except ImportError:
23    print("No line profiler, skipping test.")
24    import sys
25    sys.exit(0)
26
27
28def assert_stats(profile, name):
29    profile.print_stats()
30    stats = profile.get_stats()
31    assert len(stats.timings) > 0, "No profile stats."
32    for key, timings in stats.timings.items():
33        if key[-1] == name:
34            assert len(timings) > 0
35            break
36    else:
37        raise ValueError("No stats for %s." % name)
38
39
40from collatz import collatz
41func = collatz
42profile = line_profiler.LineProfiler(func)
43profile.runcall(func, 19)
44assert_stats(profile, func.__name__)
45
46from collatz import cp_collatz
47func = cp_collatz
48profile = line_profiler.LineProfiler(func)
49profile.runcall(func, 19)
50assert_stats(profile, func.__name__)
51
52from collatz import run_generator, cy_generator
53func = cy_generator
54profile = line_profiler.LineProfiler(func)
55profile.runcall(run_generator, 19)
56assert_stats(profile, func.__name__)
57
58from collatz import run_coro, cy_coro
59func = cy_coro
60profile = line_profiler.LineProfiler(func)
61profile.runcall(run_coro, 19)
62assert_stats(profile, func.__name__)
63
64from collatz import PyClass
65obj = PyClass()
66func = obj.py_pymethod
67profile = line_profiler.LineProfiler(func)
68profile.runcall(func)
69assert_stats(profile, func.__name__)
70
71from collatz import CClass
72obj = CClass()
73func = obj.c_pymethod
74profile = line_profiler.LineProfiler(func)
75profile.runcall(func)
76assert_stats(profile, func.__name__)
77
78func = obj.cp_pymethod
79profile = line_profiler.LineProfiler(func)
80profile.runcall(func, 19)
81assert_stats(profile, func.__name__)
82
83
84######## collatz.pyx ###########
85# cython: linetrace=True
86
87cimport cython
88
89@cython.binding(True)
90def collatz(n):
91    while n > 1:
92        if n % 2 == 0:
93            n //= 2
94        else:
95            n = 3*n+1
96
97
98@cython.binding(True)
99cpdef cp_collatz(n):
100    while n > 1:
101        if n % 2 == 0:
102            n //= 2
103        else:
104            n = 3*n+1
105
106
107@cython.binding(True)
108def cy_generator(int n):
109   x = 1
110   for i in range(n):
111       yield x + 2
112
113
114@cython.binding(True)
115def run_generator(n):
116    assert len(list(cy_generator(n))) == n
117
118
119@cython.binding(True)
120async def cy_coro(int n):
121    while n > 1:
122        if n % 2 == 0:
123            n //= 2
124        else:
125            n = 3*n+1
126
127
128@cython.binding(True)
129def run_coro(n):
130    coro = cy_coro(n)
131    try:
132        coro.send(None)
133    except StopIteration:
134        assert True
135    else:
136        assert False, "Coroutine did not raise"
137
138
139@cython.binding(True)
140class PyClass(object):
141    def py_pymethod(self):
142        x = 1
143        for i in range(10):
144            a = x + 2
145        return a * 3
146
147
148@cython.binding(True)
149cdef class CClass:
150    def c_pymethod(self, c=2):
151        for i in range(10):
152            a = c + 1
153        y = self.cmethod(c + a)
154        return y * 4
155
156    cpdef cp_pymethod(self, r):
157        for i in range(10):
158            a = r + 1
159        z = self.c_pymethod(a) + self.cmethod(r)
160        return z * 2
161
162    cdef cmethod(self, s):
163        for i in range(10):
164            p = s + 3
165        return p * 5
166