88import pytest
99import pickle
1010
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
1156
1257def test_unified_exception_semantics ():
1358 """Test unified exception semantics."""
@@ -375,3 +420,33 @@ def test_iteration_innerexception():
375420 # after exception is thrown iterator is no longer valid
376421 with pytest .raises (StopIteration ):
377422 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