@@ -19,6 +19,36 @@ def run_tests(testmod, verbose=True):
1919 print (flush = True )
2020
2121
22+ def run_refleak_tests (testmod ):
23+ # Run tests and check for reference leaks
24+ warmups = 3
25+ runs = 3
26+ repcount = warmups + runs
27+ refcount = array .array ('q' , [0 ] * repcount )
28+ rep_range = tuple (range (repcount ))
29+
30+ for i in rep_range :
31+ print (f"Run #{ i + 1 } " , flush = True )
32+ run_tests (testmod )
33+ gc .collect ()
34+ refcount [i ] = sys .gettotalrefcount ()
35+
36+ # Compute differences
37+ previous = None
38+ for i in rep_range :
39+ value = refcount [i ]
40+ if previous is not None :
41+ refcount [i ] = value - previous
42+ previous = value
43+
44+ deltas = list (refcount [warmups :])
45+ if all (delta >= 1 for delta in deltas ):
46+ print (f'ERROR: Tests leaked { deltas } references' )
47+ sys .exit (1 )
48+ elif any (deltas ):
49+ print (f'WARNING: Tests leaked { deltas } references (this is fine)' )
50+
51+
2252def main ():
2353 if len (sys .argv ) < 2 :
2454 print ("usage: python runtests.py TEST_MODULE_NAME" )
@@ -45,21 +75,7 @@ def main():
4575 print ()
4676
4777 if hasattr (sys , 'gettotalrefcount' ):
48- # First run to warm up Python. For example, test_datetime() imports
49- # the datetime module.
50- run_tests (testmod , verbose = False )
51-
52- refcount = array .array ('q' , [0 , 0 ])
53- gc .collect ()
54-
55- # Check for reference leak
56- refcount [0 ] = sys .gettotalrefcount ()
57- run_tests (testmod )
58- refcount [1 ] = sys .gettotalrefcount ()
59-
60- diff = refcount [1 ] - refcount [0 ]
61- if diff >= 1 :
62- raise AssertionError (f'Tests leaked { diff } references' )
78+ run_refleak_tests (testmod )
6379 else :
6480 run_tests (testmod )
6581
0 commit comments