8
8
import pytest
9
9
import pickle
10
10
11
+ # begin code from https://utcc.utoronto.ca/~cks/space/blog/python/GetAllObjects
12
+ import gc
13
+ # Recursively expand slist's objects
14
+ # into olist, using seen to track
15
+ # already processed objects.
16
+
17
+ def _getr (slist , olist , seen ):
18
+ for e in slist :
19
+ if id (e ) in seen :
20
+ continue
21
+ seen [id (e )] = None
22
+ olist .append (e )
23
+ tl = gc .get_referents (e )
24
+ if tl :
25
+ _getr (tl , olist , seen )
26
+
27
+ # The public function.
28
+ def get_all_objects ():
29
+ gcl = gc .get_objects ()
30
+ olist = []
31
+ seen = {}
32
+ # Just in case:
33
+ seen [id (gcl )] = None
34
+ seen [id (olist )] = None
35
+ seen [id (seen )] = None
36
+ # _getr does the real work.
37
+ _getr (gcl , olist , seen )
38
+ return olist
39
+ # end code from https://utcc.utoronto.ca/~cks/space/blog/python/GetAllObjects
40
+
41
+ def leak_check (func ):
42
+ def do_leak_check ():
43
+ func ()
44
+ gc .collect ()
45
+ exc = {x for x in get_all_objects () if isinstance (x , Exception ) and not isinstance (x , pytest .PytestDeprecationWarning )}
46
+ print (len (exc ))
47
+ if len (exc ):
48
+ for x in exc :
49
+ print ('-------' )
50
+ print (repr (x ))
51
+ print (gc .get_referrers (x ))
52
+ print (len (gc .get_referrers (x )))
53
+ assert False
54
+ gc .collect ()
55
+ return do_leak_check
11
56
12
57
def test_unified_exception_semantics ():
13
58
"""Test unified exception semantics."""
@@ -375,3 +420,33 @@ def test_iteration_innerexception():
375
420
# after exception is thrown iterator is no longer valid
376
421
with pytest .raises (StopIteration ):
377
422
next (val )
423
+
424
+ def leak_test (func ):
425
+ def do_test_leak ():
426
+ # PyTest leaks things, gather the current state
427
+ orig_exc = {x for x in get_all_objects () if isinstance (x , Exception )}
428
+ func ()
429
+ exc = {x for x in get_all_objects () if isinstance (x , Exception )}
430
+ possibly_leaked = exc - orig_exc
431
+ assert not possibly_leaked
432
+
433
+ return do_test_leak
434
+
435
+ @leak_test
436
+ def test_dont_leak_exceptions_simple ():
437
+ from Python .Test import ExceptionTest
438
+
439
+ try :
440
+ ExceptionTest .DoThrowSimple ()
441
+ except System .ArgumentException :
442
+ print ('type error, as expected' )
443
+
444
+ @leak_test
445
+ def test_dont_leak_exceptions_inner ():
446
+ from Python .Test import ExceptionTest
447
+ try :
448
+ ExceptionTest .DoThrowWithInner ()
449
+ except TypeError :
450
+ print ('type error, as expected' )
451
+ except System .ArgumentException :
452
+ print ('type error, also expected' )
0 commit comments