diff --git a/Lib/test/regrtest.py b/Lib/test/regrtest.py --- a/Lib/test/regrtest.py +++ b/Lib/test/regrtest.py @@ -1217,8 +1217,11 @@ # tests. If not, use normal unittest test loading. test_runner = getattr(the_module, "test_main", None) if test_runner is None: - tests = unittest.TestLoader().loadTestsFromModule(the_module) - test_runner = lambda: support.run_unittest(tests) + # Issue 16968: keeping an extra reference to the tests here + # can cause issues with garbage collection, particularly in + # threading._dangling + test_runner = lambda: support.run_unittest( + unittest.TestLoader().loadTestsFromModule(the_module)) test_runner() if huntrleaks: refleak = dash_R(the_module, test, test_runner, diff --git a/Lib/test/test_concurrent_futures.py b/Lib/test/test_concurrent_futures.py --- a/Lib/test/test_concurrent_futures.py +++ b/Lib/test/test_concurrent_futures.py @@ -83,12 +83,22 @@ class ThreadPoolMixin(ExecutorMixin): executor_type = futures.ThreadPoolExecutor + @test.support.reap_threads + def run(self, result): + return super().run(result) + class ProcessPoolMixin(ExecutorMixin): executor_type = futures.ProcessPoolExecutor + def run(self, result): + try: + return super().run(result) + finally: + test.support.reap_children() -class ExecutorShutdownTest(unittest.TestCase): + +class ExecutorShutdownTest: def test_run_after_shutdown(self): self.executor.shutdown() self.assertRaises(RuntimeError, @@ -116,7 +126,9 @@ f.result() -class ThreadPoolShutdownTest(ThreadPoolMixin, ExecutorShutdownTest): +class ThreadPoolShutdownTest(ThreadPoolMixin, + ExecutorShutdownTest, + unittest.TestCase): def _prime_executor(self): pass @@ -148,7 +160,9 @@ t.join() -class ProcessPoolShutdownTest(ProcessPoolMixin, ExecutorShutdownTest): +class ProcessPoolShutdownTest(ProcessPoolMixin, + ExecutorShutdownTest, + unittest.TestCase): def _prime_executor(self): pass @@ -184,8 +198,7 @@ p.join() -class WaitTests(unittest.TestCase): - +class WaitTests: def test_first_completed(self): future1 = self.executor.submit(mul, 21, 2) future2 = self.executor.submit(time.sleep, 1.5) @@ -285,8 +298,7 @@ self.assertEqual(set([future2]), pending) -class ThreadPoolWaitTests(ThreadPoolMixin, WaitTests): - +class ThreadPoolWaitTests(ThreadPoolMixin, WaitTests, unittest.TestCase): def test_pending_calls_race(self): # Issue #14406: multi-threaded race condition when waiting on all # futures. @@ -303,11 +315,11 @@ sys.setswitchinterval(oldswitchinterval) -class ProcessPoolWaitTests(ProcessPoolMixin, WaitTests): +class ProcessPoolWaitTests(ProcessPoolMixin, WaitTests, unittest.TestCase): pass -class AsCompletedTests(unittest.TestCase): +class AsCompletedTests: # TODO(brian@sweetapp.com): Should have a test with a non-zero timeout. def test_no_timeout(self): future1 = self.executor.submit(mul, 2, 21) @@ -345,15 +357,19 @@ completed_futures) -class ThreadPoolAsCompletedTests(ThreadPoolMixin, AsCompletedTests): +class ThreadPoolAsCompletedTests(ThreadPoolMixin, + AsCompletedTests, + unittest.TestCase): pass -class ProcessPoolAsCompletedTests(ProcessPoolMixin, AsCompletedTests): +class ProcessPoolAsCompletedTests(ProcessPoolMixin, + AsCompletedTests, + unittest.TestCase): pass -class ExecutorTest(unittest.TestCase): +class ExecutorTest: # Executor.shutdown() and context manager usage is tested by # ExecutorShutdownTest. def test_submit(self): @@ -397,7 +413,9 @@ self.executor.shutdown() -class ThreadPoolExecutorTest(ThreadPoolMixin, ExecutorTest): +class ThreadPoolExecutorTest(ThreadPoolMixin, + ExecutorTest, + unittest.TestCase): def test_map_submits_without_iteration(self): """Tests verifying issue 11777.""" finished = [] @@ -409,7 +427,9 @@ self.assertCountEqual(finished, range(10)) -class ProcessPoolExecutorTest(ProcessPoolMixin, ExecutorTest): +class ProcessPoolExecutorTest(ProcessPoolMixin, + ExecutorTest, + unittest.TestCase): def test_killed_child(self): # When a child process is abruptly terminated, the whole pool gets # "broken". @@ -645,21 +665,5 @@ self.assertTrue(isinstance(f1.exception(timeout=5), OSError)) -@test.support.reap_threads -def test_main(): - try: - test.support.run_unittest(ProcessPoolExecutorTest, - ThreadPoolExecutorTest, - ProcessPoolWaitTests, - ThreadPoolWaitTests, - ProcessPoolAsCompletedTests, - ThreadPoolAsCompletedTests, - FutureTests, - ProcessPoolShutdownTest, - ThreadPoolShutdownTest, - ) - finally: - test.support.reap_children() - if __name__ == "__main__": - test_main() + unittest.main()