cython
1# mode: run
2
3from __future__ import print_function
4
5cimport cython
6
7import gc
8
9cdef class nontrivial_del:
10def __init__(self):
11print("init")
12
13def __del__(self):
14print("del")
15
16def test_del():
17"""
18>>> test_del()
19start
20init
21del
22finish
23"""
24print("start")
25d = nontrivial_del()
26d = None
27gc.collect()
28print("finish")
29
30
31cdef class del_and_dealloc:
32def __init__(self):
33print("init")
34
35def __del__(self):
36print("del")
37
38def __dealloc__(self):
39print("dealloc")
40
41def test_del_and_dealloc():
42"""
43>>> test_del_and_dealloc()
44start
45init
46del
47dealloc
48finish
49"""
50print("start")
51d = del_and_dealloc()
52d = None
53gc.collect()
54print("finish")
55
56@cython.final
57cdef class FinalClass:
58def __init__(self):
59print("init")
60def __del__(self):
61print("del")
62
63def test_final_class():
64"""
65>>> test_final_class()
66start
67init
68del
69finish
70"""
71print("start")
72d = FinalClass()
73d = None
74gc.collect()
75print("finish")
76
77@cython.final
78cdef class FinalInherits(nontrivial_del):
79def __init__(self):
80super().__init__()
81print("FinalInherits init")
82# no __del__ but nontrivial_del should still be called
83def __dealloc__(self):
84pass # define __dealloc__ so as not to fall back on base __dealloc__
85
86def test_final_inherited():
87"""
88>>> test_final_inherited()
89start
90init
91FinalInherits init
92del
93finish
94"""
95print("start")
96d = FinalInherits()
97d = None
98gc.collect()
99print("finish")
100
101cdef class DummyBase:
102pass
103
104class RegularClass:
105__slots__ = ()
106def __del__(self):
107print("del")
108
109@cython.final
110cdef class FinalMultipleInheritance(DummyBase, RegularClass):
111def __init__(self):
112super().__init__()
113print("init")
114def __dealloc__(self):
115pass
116
117def test_final_multiple_inheritance():
118"""
119>>> test_final_multiple_inheritance()
120start
121init
122del
123finish
124"""
125print("start")
126d = FinalMultipleInheritance()
127d = None
128gc.collect()
129print("finish")
130
131cdef class del_with_exception:
132def __init__(self):
133print("init")
134
135def __del__(self):
136print("del")
137raise Exception("Error")
138
139def test_del_with_exception():
140"""
141>>> test_del_with_exception()
142start
143init
144del
145finish
146"""
147print("start")
148d = nontrivial_del()
149d = None
150gc.collect()
151print("finish")
152
153
154def test_nontrivial_del_with_exception():
155"""
156>>> test_nontrivial_del_with_exception()
157start
158init
159del
160end
161"""
162print("start")
163def inner():
164c = nontrivial_del()
165raise RuntimeError()
166
167try:
168inner()
169except RuntimeError:
170pass
171
172print("end")
173
174
175cdef class parent:
176def __del__(self):
177print("del parent")
178
179class child(parent):
180def __del__(self):
181print("del child")
182
183def test_del_inheritance():
184"""
185>>> test_del_inheritance()
186start
187del child
188finish
189"""
190print("start")
191c = child()
192c = None
193gc.collect()
194print("finish")
195
196
197cdef class cy_parent:
198def __del__(self):
199print("del cy_parent")
200
201def __dealloc__(self):
202print("dealloc cy_parent")
203
204class py_parent:
205def __del__(self):
206print("del py_parent")
207
208class multi_child(cy_parent, py_parent):
209def __del__(self):
210print("del child")
211
212def test_multiple_inheritance():
213"""
214>>> test_multiple_inheritance()
215start
216del child
217dealloc cy_parent
218finish
219"""
220print("start")
221c = multi_child()
222c = None
223gc.collect()
224print("finish")
225
226
227cdef class zombie_object:
228def __del__(self):
229global global_zombie_object
230print("del")
231global_zombie_object = self
232
233def __dealloc__(self):
234print("dealloc")
235
236def test_zombie_object():
237"""
238>>> test_zombie_object()
239start
240del
241del global
242del
243finish
244"""
245global global_zombie_object
246print("start")
247i = zombie_object()
248i = None
249print("del global")
250del global_zombie_object
251gc.collect()
252print("finish")
253
254
255# Same as above, but the member
256# makes the class GC, so it
257# is deallocated
258cdef class gc_zombie_object:
259cdef object x
260
261def __del__(self):
262global global_gc_zombie_object
263print("del")
264global_gc_zombie_object = self
265
266def __dealloc__(self):
267print("dealloc")
268
269def test_gc_zombie_object():
270"""
271>>> test_gc_zombie_object()
272start
273del
274del global
275dealloc
276finish
277"""
278global global_gc_zombie_object
279print("start")
280i = gc_zombie_object()
281i = None
282print("del global")
283del global_gc_zombie_object
284gc.collect()
285print("finish")
286
287
288cdef class cdef_parent:
289pass
290
291cdef class cdef_child(cdef_parent):
292def __del__(self):
293print("del")
294def __dealloc__(self):
295print("dealloc")
296
297def test_cdef_parent_object():
298"""
299>>> test_cdef_parent_object()
300start
301del
302dealloc
303finish
304"""
305print("start")
306i = cdef_child()
307i = None
308gc.collect()
309print("finish")
310
311
312cdef class cdef_nontrivial_parent:
313def __del__(self):
314print("del parent")
315def __dealloc__(self):
316print("dealloc parent")
317
318cdef class cdef_nontrivial_child(cdef_nontrivial_parent):
319def __del__(self):
320print("del child")
321def __dealloc__(self):
322print("dealloc child")
323
324def test_cdef_nontrivial_parent_object():
325"""
326>>> test_cdef_nontrivial_parent_object()
327start
328del child
329dealloc child
330dealloc parent
331finish
332"""
333print("start")
334i = cdef_nontrivial_child()
335i = None
336gc.collect()
337print("finish")
338
339
340class python_child(cdef_nontrivial_parent):
341def __del__(self):
342print("del python child")
343super().__del__()
344
345def test_python_child_object():
346"""
347>>> test_python_child_object()
348Traceback (most recent call last):
349...
350RuntimeError: End function
351"""
352
353def func(tp):
354inst = tp()
355raise RuntimeError("End function")
356
357func(python_child)
358
359def test_python_child_fancy_inherit():
360"""
361>>> test_python_child_fancy_inherit()
362Traceback (most recent call last):
363...
364RuntimeError: End function
365"""
366
367# inherit using "true python" rather than Cython
368globs = { 'cdef_nontrivial_parent': cdef_nontrivial_parent }
369
370exec("""
371class derived_python_child(cdef_nontrivial_parent):
372pass
373""", globs)
374
375derived_python_child = globs['derived_python_child']
376
377def func(tp):
378inst = tp()
379raise RuntimeError("End function")
380
381func(derived_python_child)
382
383