[Python-checkins] [3.10] bpo-25130: Add calls of gc.collect() in tests to support PyPy (GH-28005) (GH-28027)

ambv webhook-mailer at python.org
Wed Sep 8 11:09:07 EDT 2021


https://github.com/python/cpython/commit/462c1f0403324efc27c11435da12b8d16f5387de
commit: 462c1f0403324efc27c11435da12b8d16f5387de
branch: 3.10
author: Serhiy Storchaka <storchaka at gmail.com>
committer: ambv <lukasz at langa.pl>
date: 2021-09-08T17:08:57+02:00
summary:

[3.10] bpo-25130: Add calls of gc.collect() in tests to support PyPy (GH-28005) (GH-28027)

(cherry picked from commit 2a8127cafe1d196f858a3ecabf5f1df3eebf9a12)

Co-authored-by: Serhiy Storchaka <storchaka at gmail.com>

files:
A Misc/NEWS.d/next/Tests/2021-08-27-22-37-19.bpo-25130.ig4oJe.rst
M Lib/test/_test_multiprocessing.py
M Lib/test/lock_tests.py
M Lib/test/test_array.py
M Lib/test/test_asyncgen.py
M Lib/test/test_asyncio/test_tasks.py
M Lib/test/test_code.py
M Lib/test/test_concurrent_futures.py
M Lib/test/test_copy.py
M Lib/test/test_deque.py
M Lib/test/test_exceptions.py
M Lib/test/test_file.py
M Lib/test/test_fileio.py
M Lib/test/test_functools.py
M Lib/test/test_generators.py
M Lib/test/test_io.py
M Lib/test/test_itertools.py
M Lib/test/test_queue.py
M Lib/test/test_raise.py
M Lib/test/test_scope.py
M Lib/test/test_set.py
M Lib/test/test_socket.py
M Lib/test/test_subprocess.py
M Lib/test/test_tempfile.py
M Lib/test/test_thread.py
M Lib/test/test_threading_local.py
M Lib/test/test_weakref.py
M Lib/test/test_weakset.py
M Lib/test/test_xml_etree.py
M Lib/tkinter/test/test_tkinter/test_images.py
M Lib/tkinter/test/test_tkinter/test_variables.py
M Lib/tkinter/test/test_ttk/test_extensions.py
M Lib/tkinter/test/test_ttk/test_widgets.py
M Lib/unittest/test/test_assertions.py
M Lib/unittest/test/test_case.py

diff --git a/Lib/test/_test_multiprocessing.py b/Lib/test/_test_multiprocessing.py
index 087ab70f66d64..8ebcd0d64dfaa 100644
--- a/Lib/test/_test_multiprocessing.py
+++ b/Lib/test/_test_multiprocessing.py
@@ -611,6 +611,7 @@ def test_lose_target_ref(self):
         del c
         p.start()
         p.join()
+        gc.collect()  # For PyPy or other GCs.
         self.assertIs(wr(), None)
         self.assertEqual(q.get(), 5)
         close_queue(q)
@@ -2667,6 +2668,7 @@ def test_release_task_refs(self):
         self.pool.map(identity, objs)
 
         del objs
+        gc.collect()  # For PyPy or other GCs.
         time.sleep(DELTA)  # let threaded cleanup code run
         self.assertEqual(set(wr() for wr in refs), {None})
         # With a process pool, copies of the objects are returned, check
@@ -4197,6 +4199,7 @@ def setUp(self):
         util._finalizer_registry.clear()
 
     def tearDown(self):
+        gc.collect()  # For PyPy or other GCs.
         self.assertFalse(util._finalizer_registry)
         util._finalizer_registry.update(self.registry_backup)
 
@@ -4208,12 +4211,14 @@ class Foo(object):
         a = Foo()
         util.Finalize(a, conn.send, args=('a',))
         del a           # triggers callback for a
+        gc.collect()  # For PyPy or other GCs.
 
         b = Foo()
         close_b = util.Finalize(b, conn.send, args=('b',))
         close_b()       # triggers callback for b
         close_b()       # does nothing because callback has already been called
         del b           # does nothing because callback has already been called
+        gc.collect()  # For PyPy or other GCs.
 
         c = Foo()
         util.Finalize(c, conn.send, args=('c',))
diff --git a/Lib/test/lock_tests.py b/Lib/test/lock_tests.py
index d69bcc9496843..dffb7d4418dfe 100644
--- a/Lib/test/lock_tests.py
+++ b/Lib/test/lock_tests.py
@@ -3,6 +3,7 @@
 """
 
 import os
+import gc
 import sys
 import time
 from _thread import start_new_thread, TIMEOUT_MAX
@@ -221,6 +222,7 @@ def test_weakref_deleted(self):
         lock = self.locktype()
         ref = weakref.ref(lock)
         del lock
+        gc.collect()  # For PyPy or other GCs.
         self.assertIsNone(ref())
 
 
diff --git a/Lib/test/test_array.py b/Lib/test/test_array.py
old mode 100644
new mode 100755
index 18f78d52467e2..6a48c1cc97572
--- a/Lib/test/test_array.py
+++ b/Lib/test/test_array.py
@@ -1097,6 +1097,7 @@ def test_weakref(self):
         p = weakref.proxy(s)
         self.assertEqual(p.tobytes(), s.tobytes())
         s = None
+        support.gc_collect()  # For PyPy or other GCs.
         self.assertRaises(ReferenceError, len, p)
 
     @unittest.skipUnless(hasattr(sys, 'getrefcount'),
diff --git a/Lib/test/test_asyncgen.py b/Lib/test/test_asyncgen.py
index f448f8d53b632..473bce484b47b 100644
--- a/Lib/test/test_asyncgen.py
+++ b/Lib/test/test_asyncgen.py
@@ -1044,6 +1044,7 @@ async def run():
             await g.__anext__()
             await g.__anext__()
             del g
+            gc_collect()  # For PyPy or other GCs.
 
             await asyncio.sleep(0.1)
 
diff --git a/Lib/test/test_asyncio/test_tasks.py b/Lib/test/test_asyncio/test_tasks.py
index f7345c5c40688..9498c7251f6f6 100644
--- a/Lib/test/test_asyncio/test_tasks.py
+++ b/Lib/test/test_asyncio/test_tasks.py
@@ -2690,6 +2690,7 @@ def coro():
                 self.new_task(self.loop, gen)
             finally:
                 gen.close()
+        gc.collect()  # For PyPy or other GCs.
 
         self.assertTrue(m_log.error.called)
         message = m_log.error.call_args[0][0]
diff --git a/Lib/test/test_code.py b/Lib/test/test_code.py
index 74cd0458a5108..b9c4f8bdcb382 100644
--- a/Lib/test/test_code.py
+++ b/Lib/test/test_code.py
@@ -135,7 +135,7 @@
 except ImportError:
     ctypes = None
 from test.support import (run_doctest, run_unittest, cpython_only,
-                          check_impl_detail)
+                          check_impl_detail, gc_collect)
 
 
 def consts(t):
@@ -343,6 +343,7 @@ def callback(code):
         coderef = weakref.ref(f.__code__, callback)
         self.assertTrue(bool(coderef()))
         del f
+        gc_collect()  # For PyPy or other GCs.
         self.assertFalse(bool(coderef()))
         self.assertTrue(self.called)
 
diff --git a/Lib/test/test_concurrent_futures.py b/Lib/test/test_concurrent_futures.py
index 99651f5f4ed4d..eae98d690bd97 100644
--- a/Lib/test/test_concurrent_futures.py
+++ b/Lib/test/test_concurrent_futures.py
@@ -463,6 +463,7 @@ def test_thread_names_assigned(self):
         executor.map(abs, range(-5, 5))
         threads = executor._threads
         del executor
+        support.gc_collect()  # For PyPy or other GCs.
 
         for t in threads:
             self.assertRegex(t.name, r'^SpecialPool_[0-4]$')
@@ -473,6 +474,7 @@ def test_thread_names_default(self):
         executor.map(abs, range(-5, 5))
         threads = executor._threads
         del executor
+        support.gc_collect()  # For PyPy or other GCs.
 
         for t in threads:
             # Ensure that our default name is reasonably sane and unique when
@@ -535,6 +537,7 @@ def test_del_shutdown(self):
         call_queue = executor._call_queue
         executor_manager_thread = executor._executor_manager_thread
         del executor
+        support.gc_collect()  # For PyPy or other GCs.
 
         # Make sure that all the executor resources were properly cleaned by
         # the shutdown process
@@ -759,6 +762,7 @@ def test_free_reference_yielded_future(self):
                 futures_list.remove(future)
                 wr = weakref.ref(future)
                 del future
+                support.gc_collect()  # For PyPy or other GCs.
                 self.assertIsNone(wr())
 
         futures_list[0].set_result("test")
@@ -766,6 +770,7 @@ def test_free_reference_yielded_future(self):
             futures_list.remove(future)
             wr = weakref.ref(future)
             del future
+            support.gc_collect()  # For PyPy or other GCs.
             self.assertIsNone(wr())
             if futures_list:
                 futures_list[0].set_result("test")
@@ -865,6 +870,7 @@ def test_free_reference(self):
         for obj in self.executor.map(make_dummy_object, range(10)):
             wr = weakref.ref(obj)
             del obj
+            support.gc_collect()  # For PyPy or other GCs.
             self.assertIsNone(wr())
 
 
diff --git a/Lib/test/test_copy.py b/Lib/test/test_copy.py
index ba3d233f63d1c..f1ca8cb254d18 100644
--- a/Lib/test/test_copy.py
+++ b/Lib/test/test_copy.py
@@ -7,6 +7,7 @@
 from operator import le, lt, ge, gt, eq, ne
 
 import unittest
+from test import support
 
 order_comparisons = le, lt, ge, gt
 equality_comparisons = eq, ne
@@ -805,6 +806,7 @@ class C(object):
         self.assertEqual(v[c], d)
         self.assertEqual(len(v), 2)
         del c, d
+        support.gc_collect()  # For PyPy or other GCs.
         self.assertEqual(len(v), 1)
         x, y = C(), C()
         # The underlying containers are decoupled
@@ -834,6 +836,7 @@ def __init__(self, i):
         self.assertEqual(v[a].i, b.i)
         self.assertEqual(v[c].i, d.i)
         del c
+        support.gc_collect()  # For PyPy or other GCs.
         self.assertEqual(len(v), 1)
 
     def test_deepcopy_weakvaluedict(self):
@@ -857,6 +860,7 @@ def __init__(self, i):
         self.assertIs(t, d)
         del x, y, z, t
         del d
+        support.gc_collect()  # For PyPy or other GCs.
         self.assertEqual(len(v), 1)
 
     def test_deepcopy_bound_method(self):
diff --git a/Lib/test/test_deque.py b/Lib/test/test_deque.py
index 8bd6ebdbbadb5..7886bbfea1f0d 100644
--- a/Lib/test/test_deque.py
+++ b/Lib/test/test_deque.py
@@ -869,6 +869,7 @@ def test_weakref(self):
         p = weakref.proxy(d)
         self.assertEqual(str(p), str(d))
         d = None
+        support.gc_collect()  # For PyPy or other GCs.
         self.assertRaises(ReferenceError, str, p)
 
     def test_strange_subclass(self):
diff --git a/Lib/test/test_exceptions.py b/Lib/test/test_exceptions.py
index 520deb301ecf8..09a555a7f1643 100644
--- a/Lib/test/test_exceptions.py
+++ b/Lib/test/test_exceptions.py
@@ -656,6 +656,7 @@ def inner_raising_func():
         except MyException as e:
             pass
         obj = None
+        gc_collect()  # For PyPy or other GCs.
         obj = wr()
         self.assertIsNone(obj)
 
@@ -667,6 +668,7 @@ def inner_raising_func():
         except MyException:
             pass
         obj = None
+        gc_collect()  # For PyPy or other GCs.
         obj = wr()
         self.assertIsNone(obj)
 
@@ -678,6 +680,7 @@ def inner_raising_func():
         except:
             pass
         obj = None
+        gc_collect()  # For PyPy or other GCs.
         obj = wr()
         self.assertIsNone(obj)
 
@@ -690,6 +693,7 @@ def inner_raising_func():
             except:
                 break
         obj = None
+        gc_collect()  # For PyPy or other GCs.
         obj = wr()
         self.assertIsNone(obj)
 
@@ -708,6 +712,7 @@ def inner_raising_func():
             # must clear the latter manually for our test to succeed.
             e.__context__ = None
             obj = None
+            gc_collect()  # For PyPy or other GCs.
             obj = wr()
             # guarantee no ref cycles on CPython (don't gc_collect)
             if check_impl_detail(cpython=False):
@@ -898,6 +903,7 @@ def raising_gen():
         next(g)
         testfunc(g)
         g = obj = None
+        gc_collect()  # For PyPy or other GCs.
         obj = wr()
         self.assertIsNone(obj)
 
@@ -951,6 +957,7 @@ def __del__(self):
             raise Exception(MyObject())
         except:
             pass
+        gc_collect()  # For PyPy or other GCs.
         self.assertEqual(e, (None, None, None))
 
     def test_raise_does_not_create_context_chain_cycle(self):
@@ -1413,6 +1420,7 @@ def inner():
             self.assertNotEqual(wr(), None)
         else:
             self.fail("MemoryError not raised")
+        gc_collect()  # For PyPy or other GCs.
         self.assertEqual(wr(), None)
 
     @no_tracing
@@ -1433,6 +1441,7 @@ def inner():
             self.assertNotEqual(wr(), None)
         else:
             self.fail("RecursionError not raised")
+        gc_collect()  # For PyPy or other GCs.
         self.assertEqual(wr(), None)
 
     def test_errno_ENOTDIR(self):
@@ -1453,6 +1462,7 @@ def __del__(self):
         with support.catch_unraisable_exception() as cm:
             del obj
 
+            gc_collect()  # For PyPy or other GCs.
             self.assertEqual(cm.unraisable.object, BrokenDel.__del__)
             self.assertIsNotNone(cm.unraisable.exc_traceback)
 
diff --git a/Lib/test/test_file.py b/Lib/test/test_file.py
index 1ec756f334d28..1146a37323c9b 100644
--- a/Lib/test/test_file.py
+++ b/Lib/test/test_file.py
@@ -7,6 +7,7 @@
 import io
 import _pyio as pyio
 
+from test.support import gc_collect
 from test.support.os_helper import TESTFN
 from test.support import os_helper
 from test.support import warnings_helper
@@ -30,6 +31,7 @@ def testWeakRefs(self):
         self.assertEqual(self.f.tell(), p.tell())
         self.f.close()
         self.f = None
+        gc_collect()  # For PyPy or other GCs.
         self.assertRaises(ReferenceError, getattr, p, 'tell')
 
     def testAttributes(self):
diff --git a/Lib/test/test_fileio.py b/Lib/test/test_fileio.py
index ff611a90eede3..cdca5a8599655 100644
--- a/Lib/test/test_fileio.py
+++ b/Lib/test/test_fileio.py
@@ -9,7 +9,7 @@
 from weakref import proxy
 from functools import wraps
 
-from test.support import (run_unittest, cpython_only, swap_attr)
+from test.support import run_unittest, cpython_only, swap_attr, gc_collect
 from test.support.os_helper import (TESTFN, TESTFN_UNICODE, make_bad_fd)
 from test.support.warnings_helper import check_warnings
 from collections import UserList
@@ -36,6 +36,7 @@ def testWeakRefs(self):
         self.assertEqual(self.f.tell(), p.tell())
         self.f.close()
         self.f = None
+        gc_collect()  # For PyPy or other GCs.
         self.assertRaises(ReferenceError, getattr, p, 'tell')
 
     def testSeekTell(self):
diff --git a/Lib/test/test_functools.py b/Lib/test/test_functools.py
index fbf5578872e6b..fece8256a3e26 100644
--- a/Lib/test/test_functools.py
+++ b/Lib/test/test_functools.py
@@ -167,6 +167,7 @@ def test_weakref(self):
         p = proxy(f)
         self.assertEqual(f.func, p.func)
         f = None
+        support.gc_collect()  # For PyPy or other GCs.
         self.assertRaises(ReferenceError, getattr, p, 'func')
 
     def test_with_bound_and_unbound_methods(self):
diff --git a/Lib/test/test_generators.py b/Lib/test/test_generators.py
index 53d579e723c47..d14c757c7b6e4 100644
--- a/Lib/test/test_generators.py
+++ b/Lib/test/test_generators.py
@@ -1966,6 +1966,8 @@ def printsolution(self, x):
 """
 
 coroutine_tests = """\
+>>> from test.support import gc_collect
+
 Sending a value into a started generator:
 
 >>> def f():
@@ -2189,7 +2191,7 @@ def printsolution(self, x):
 
 >>> g = f()
 >>> next(g)
->>> del g
+>>> del g; gc_collect()  # For PyPy or other GCs.
 exiting
 
 
@@ -2204,7 +2206,7 @@ def printsolution(self, x):
 
 >>> g = f()
 >>> next(g)
->>> del g
+>>> del g; gc_collect()  # For PyPy or other GCs.
 finally
 
 
diff --git a/Lib/test/test_io.py b/Lib/test/test_io.py
index 32c29ea5dc4a7..273545a2a2cbb 100644
--- a/Lib/test/test_io.py
+++ b/Lib/test/test_io.py
@@ -4372,6 +4372,31 @@ def check_interrupted_write(self, item, bytes, **fdopen_kwargs):
         """Check that a partial write, when it gets interrupted, properly
         invokes the signal handler, and bubbles up the exception raised
         in the latter."""
+
+        # XXX This test has three flaws that appear when objects are
+        # XXX not reference counted.
+
+        # - if wio.write() happens to trigger a garbage collection,
+        #   the signal exception may be raised when some __del__
+        #   method is running; it will not reach the assertRaises()
+        #   call.
+
+        # - more subtle, if the wio object is not destroyed at once
+        #   and survives this function, the next opened file is likely
+        #   to have the same fileno (since the file descriptor was
+        #   actively closed).  When wio.__del__ is finally called, it
+        #   will close the other's test file...  To trigger this with
+        #   CPython, try adding "global wio" in this function.
+
+        # - This happens only for streams created by the _pyio module,
+        #   because a wio.close() that fails still consider that the
+        #   file needs to be closed again.  You can try adding an
+        #   "assert wio.closed" at the end of the function.
+
+        # Fortunately, a little gc.collect() seems to be enough to
+        # work around all these issues.
+        support.gc_collect()  # For PyPy or other GCs.
+
         read_results = []
         def _read():
             s = os.read(r, 1)
diff --git a/Lib/test/test_itertools.py b/Lib/test/test_itertools.py
index 6f8f87684e29c..aa81076f32d00 100644
--- a/Lib/test/test_itertools.py
+++ b/Lib/test/test_itertools.py
@@ -1442,6 +1442,7 @@ def test_tee(self):
         p = weakref.proxy(a)
         self.assertEqual(getattr(p, '__class__'), type(b))
         del a
+        support.gc_collect()  # For PyPy or other GCs.
         self.assertRaises(ReferenceError, getattr, p, '__class__')
 
         ans = list('abc')
diff --git a/Lib/test/test_queue.py b/Lib/test/test_queue.py
index 508b739019593..9bb5181377698 100644
--- a/Lib/test/test_queue.py
+++ b/Lib/test/test_queue.py
@@ -6,6 +6,7 @@
 import time
 import unittest
 import weakref
+from test.support import gc_collect
 from test.support import import_helper
 from test.support import threading_helper
 
@@ -590,6 +591,7 @@ class C:
             q.put(C())
         for i in range(N):
             wr = weakref.ref(q.get())
+            gc_collect()  # For PyPy or other GCs.
             self.assertIsNone(wr())
 
 
diff --git a/Lib/test/test_raise.py b/Lib/test/test_raise.py
index 57da0e15a756b..8dc62a933e872 100644
--- a/Lib/test/test_raise.py
+++ b/Lib/test/test_raise.py
@@ -438,6 +438,7 @@ def f():
         f()
 
     def test_3611(self):
+        import gc
         # A re-raised exception in a __del__ caused the __context__
         # to be cleared
         class C:
@@ -451,9 +452,11 @@ def f():
             x = C()
             try:
                 try:
-                    x.x
+                    f.x
                 except AttributeError:
+                    # make x.__del__ trigger
                     del x
+                    gc.collect()  # For PyPy or other GCs.
                     raise TypeError
             except Exception as e:
                 self.assertNotEqual(e.__context__, None)
diff --git a/Lib/test/test_scope.py b/Lib/test/test_scope.py
index 4239b26408ecd..59d59127982e3 100644
--- a/Lib/test/test_scope.py
+++ b/Lib/test/test_scope.py
@@ -2,6 +2,7 @@
 import weakref
 
 from test.support import check_syntax_error, cpython_only
+from test.support import gc_collect
 
 
 class ScopeTests(unittest.TestCase):
@@ -422,6 +423,7 @@ def f2():
         for i in range(100):
             f1()
 
+        gc_collect()  # For PyPy or other GCs.
         self.assertEqual(Foo.count, 0)
 
     def testClassAndGlobal(self):
@@ -754,6 +756,7 @@ def dig(self):
         tester.dig()
         ref = weakref.ref(tester)
         del tester
+        gc_collect()  # For PyPy or other GCs.
         self.assertIsNone(ref())
 
 
diff --git a/Lib/test/test_set.py b/Lib/test/test_set.py
index b1fab0f6207f4..29bb39df76c8a 100644
--- a/Lib/test/test_set.py
+++ b/Lib/test/test_set.py
@@ -593,6 +593,7 @@ def test_weakref(self):
         p = weakref.proxy(s)
         self.assertEqual(str(p), str(s))
         s = None
+        support.gc_collect()  # For PyPy or other GCs.
         self.assertRaises(ReferenceError, str, p)
 
     def test_rich_compare(self):
diff --git a/Lib/test/test_socket.py b/Lib/test/test_socket.py
index 12af22fa3ca91..6e4772df251ed 100755
--- a/Lib/test/test_socket.py
+++ b/Lib/test/test_socket.py
@@ -870,6 +870,7 @@ def test_weakref(self):
             p = proxy(s)
             self.assertEqual(p.fileno(), s.fileno())
         s = None
+        support.gc_collect()  # For PyPy or other GCs.
         try:
             p.fileno()
         except ReferenceError:
diff --git a/Lib/test/test_subprocess.py b/Lib/test/test_subprocess.py
index f0f0e6f6069da..7bb049296912b 100644
--- a/Lib/test/test_subprocess.py
+++ b/Lib/test/test_subprocess.py
@@ -3022,6 +3022,7 @@ def test_leak_fast_process_del_killed(self):
         pid = p.pid
         with warnings_helper.check_warnings(('', ResourceWarning)):
             p = None
+            support.gc_collect()  # For PyPy or other GCs.
 
         os.kill(pid, signal.SIGKILL)
         if mswindows:
diff --git a/Lib/test/test_tempfile.py b/Lib/test/test_tempfile.py
index 3a3f6a999ce0a..f1d483733e267 100644
--- a/Lib/test/test_tempfile.py
+++ b/Lib/test/test_tempfile.py
@@ -430,6 +430,7 @@ def test_choose_directory(self):
             self.do_create(dir=dir).write(b"blat")
             self.do_create(dir=pathlib.Path(dir)).write(b"blat")
         finally:
+            support.gc_collect()  # For PyPy or other GCs.
             os.rmdir(dir)
 
     def test_file_mode(self):
@@ -880,6 +881,8 @@ def test_many(self):
         extant = list(range(TEST_FILES))
         for i in extant:
             extant[i] = self.do_create(pre="aa")
+        del extant
+        support.gc_collect()  # For PyPy or other GCs.
 
 ##     def test_warning(self):
 ##         # mktemp issues a warning when used
diff --git a/Lib/test/test_thread.py b/Lib/test/test_thread.py
index 62b57fa338837..4ae8a833b990d 100644
--- a/Lib/test/test_thread.py
+++ b/Lib/test/test_thread.py
@@ -132,6 +132,7 @@ def task():
             del task
             while not done:
                 time.sleep(POLL_SLEEP)
+                support.gc_collect()  # For PyPy or other GCs.
             self.assertEqual(thread._count(), orig)
 
     def test_unraisable_exception(self):
diff --git a/Lib/test/test_threading_local.py b/Lib/test/test_threading_local.py
index 9862094eaccd8..13facb513367a 100644
--- a/Lib/test/test_threading_local.py
+++ b/Lib/test/test_threading_local.py
@@ -37,7 +37,7 @@ def _local_refs(self, n):
             t.join()
         del t
 
-        gc.collect()
+        support.gc_collect()  # For PyPy or other GCs.
         self.assertEqual(len(weaklist), n)
 
         # XXX _threading_local keeps the local of the last stopped thread alive.
@@ -46,7 +46,7 @@ def _local_refs(self, n):
 
         # Assignment to the same thread local frees it sometimes (!)
         local.someothervar = None
-        gc.collect()
+        support.gc_collect()  # For PyPy or other GCs.
         deadlist = [weak for weak in weaklist if weak() is None]
         self.assertIn(len(deadlist), (n-1, n), (n, len(deadlist)))
 
@@ -89,7 +89,7 @@ def f():
             # 2) GC the cycle (triggers threadmodule.c::local_clear
             # before local_dealloc)
             del cycle
-            gc.collect()
+            support.gc_collect()  # For PyPy or other GCs.
             e1.set()
             e2.wait()
 
@@ -190,7 +190,7 @@ class X:
         x.local.x = x
         wr = weakref.ref(x)
         del x
-        gc.collect()
+        support.gc_collect()  # For PyPy or other GCs.
         self.assertIsNone(wr())
 
 
diff --git a/Lib/test/test_weakref.py b/Lib/test/test_weakref.py
index 1a5314ccff315..5a3e59c3e9ef1 100644
--- a/Lib/test/test_weakref.py
+++ b/Lib/test/test_weakref.py
@@ -12,6 +12,7 @@
 
 from test import support
 from test.support import script_helper, ALWAYS_EQ
+from test.support import gc_collect
 
 # Used in ReferencesTestCase.test_ref_created_during_del() .
 ref_from_del = None
@@ -135,6 +136,7 @@ def test_multiple_callbacks(self):
         ref1 = weakref.ref(o, self.callback)
         ref2 = weakref.ref(o, self.callback)
         del o
+        gc_collect()  # For PyPy or other GCs.
         self.assertIsNone(ref1(), "expected reference to be invalidated")
         self.assertIsNone(ref2(), "expected reference to be invalidated")
         self.assertEqual(self.cbcalled, 2,
@@ -168,13 +170,16 @@ def test_proxy_ref(self):
         ref1 = weakref.proxy(o, self.callback)
         ref2 = weakref.proxy(o, self.callback)
         del o
+        gc_collect()  # For PyPy or other GCs.
 
         def check(proxy):
             proxy.bar
 
         self.assertRaises(ReferenceError, check, ref1)
         self.assertRaises(ReferenceError, check, ref2)
-        self.assertRaises(ReferenceError, bool, weakref.proxy(C()))
+        ref3 = weakref.proxy(C())
+        gc_collect()  # For PyPy or other GCs.
+        self.assertRaises(ReferenceError, bool, ref3)
         self.assertEqual(self.cbcalled, 2)
 
     def check_basic_ref(self, factory):
@@ -191,6 +196,7 @@ def check_basic_callback(self, factory):
         o = factory()
         ref = weakref.ref(o, self.callback)
         del o
+        gc_collect()  # For PyPy or other GCs.
         self.assertEqual(self.cbcalled, 1,
                      "callback did not properly set 'cbcalled'")
         self.assertIsNone(ref(),
@@ -215,6 +221,7 @@ def test_ref_reuse(self):
         self.assertEqual(weakref.getweakrefcount(o), 2,
                      "wrong weak ref count for object")
         del proxy
+        gc_collect()  # For PyPy or other GCs.
         self.assertEqual(weakref.getweakrefcount(o), 1,
                      "wrong weak ref count for object after deleting proxy")
 
@@ -480,6 +487,7 @@ def test_getweakrefcount(self):
                      "got wrong number of weak reference objects")
 
         del ref1, ref2, proxy1, proxy2
+        gc_collect()  # For PyPy or other GCs.
         self.assertEqual(weakref.getweakrefcount(o), 0,
                      "weak reference objects not unlinked from"
                      " referent when discarded.")
@@ -493,6 +501,7 @@ def test_getweakrefs(self):
         ref1 = weakref.ref(o, self.callback)
         ref2 = weakref.ref(o, self.callback)
         del ref1
+        gc_collect()  # For PyPy or other GCs.
         self.assertEqual(weakref.getweakrefs(o), [ref2],
                      "list of refs does not match")
 
@@ -500,10 +509,12 @@ def test_getweakrefs(self):
         ref1 = weakref.ref(o, self.callback)
         ref2 = weakref.ref(o, self.callback)
         del ref2
+        gc_collect()  # For PyPy or other GCs.
         self.assertEqual(weakref.getweakrefs(o), [ref1],
                      "list of refs does not match")
 
         del ref1
+        gc_collect()  # For PyPy or other GCs.
         self.assertEqual(weakref.getweakrefs(o), [],
                      "list of refs not cleared")
 
@@ -989,6 +1000,7 @@ def __call__(self):
         self.assertTrue(mr.called)
         self.assertEqual(mr.value, 24)
         del o
+        gc_collect()  # For PyPy or other GCs.
         self.assertIsNone(mr())
         self.assertTrue(mr.called)
 
@@ -1291,15 +1303,18 @@ def test_weak_values(self):
         del items1, items2
         self.assertEqual(len(dict), self.COUNT)
         del objects[0]
+        gc_collect()  # For PyPy or other GCs.
         self.assertEqual(len(dict), self.COUNT - 1,
                      "deleting object did not cause dictionary update")
         del objects, o
+        gc_collect()  # For PyPy or other GCs.
         self.assertEqual(len(dict), 0,
                      "deleting the values did not clear the dictionary")
         # regression on SF bug #447152:
         dict = weakref.WeakValueDictionary()
         self.assertRaises(KeyError, dict.__getitem__, 1)
         dict[2] = C()
+        gc_collect()  # For PyPy or other GCs.
         self.assertRaises(KeyError, dict.__getitem__, 2)
 
     def test_weak_keys(self):
@@ -1320,9 +1335,11 @@ def test_weak_keys(self):
         del items1, items2
         self.assertEqual(len(dict), self.COUNT)
         del objects[0]
+        gc_collect()  # For PyPy or other GCs.
         self.assertEqual(len(dict), (self.COUNT - 1),
                      "deleting object did not cause dictionary update")
         del objects, o
+        gc_collect()  # For PyPy or other GCs.
         self.assertEqual(len(dict), 0,
                      "deleting the keys did not clear the dictionary")
         o = Object(42)
@@ -1821,6 +1838,7 @@ def __eq__(self, other):
         for o in objs:
             count += 1
             del d[o]
+        gc_collect()  # For PyPy or other GCs.
         self.assertEqual(len(d), 0)
         self.assertEqual(count, 2)
 
@@ -2129,6 +2147,7 @@ def test_atexit(self):
 
 libreftest = """ Doctest for examples in the library reference: weakref.rst
 
+>>> from test.support import gc_collect
 >>> import weakref
 >>> class Dict(dict):
 ...     pass
@@ -2148,6 +2167,7 @@ def test_atexit(self):
 >>> o is o2
 True
 >>> del o, o2
+>>> gc_collect()  # For PyPy or other GCs.
 >>> print(r())
 None
 
@@ -2200,6 +2220,7 @@ def test_atexit(self):
 >>> id2obj(a_id) is a
 True
 >>> del a
+>>> gc_collect()  # For PyPy or other GCs.
 >>> try:
 ...     id2obj(a_id)
 ... except KeyError:
diff --git a/Lib/test/test_weakset.py b/Lib/test/test_weakset.py
index 49a9b5c3c658a..9b31d5fce3472 100644
--- a/Lib/test/test_weakset.py
+++ b/Lib/test/test_weakset.py
@@ -5,6 +5,7 @@
 from collections.abc import Set, MutableSet
 import gc
 import contextlib
+from test import support
 
 
 class Foo:
@@ -48,6 +49,7 @@ def test_len(self):
         self.assertEqual(len(self.s), len(self.d))
         self.assertEqual(len(self.fs), 1)
         del self.obj
+        support.gc_collect()  # For PyPy or other GCs.
         self.assertEqual(len(self.fs), 0)
 
     def test_contains(self):
@@ -57,6 +59,7 @@ def test_contains(self):
         self.assertNotIn(1, self.s)
         self.assertIn(self.obj, self.fs)
         del self.obj
+        support.gc_collect()  # For PyPy or other GCs.
         self.assertNotIn(ustr('F'), self.fs)
 
     def test_union(self):
@@ -215,6 +218,7 @@ def test_add(self):
         self.assertEqual(self.s, dup)
         self.assertRaises(TypeError, self.s.add, [])
         self.fs.add(Foo())
+        support.gc_collect()  # For PyPy or other GCs.
         self.assertTrue(len(self.fs) == 1)
         self.fs.add(self.obj)
         self.assertTrue(len(self.fs) == 1)
@@ -406,6 +410,7 @@ def test_len_cycles(self):
         n1 = len(s)
         del it
         gc.collect()
+        gc.collect()  # For PyPy or other GCs.
         n2 = len(s)
         # one item may be kept alive inside the iterator
         self.assertIn(n1, (0, 1))
diff --git a/Lib/test/test_xml_etree.py b/Lib/test/test_xml_etree.py
index 553529a300170..c79b5462b931d 100644
--- a/Lib/test/test_xml_etree.py
+++ b/Lib/test/test_xml_etree.py
@@ -2480,6 +2480,7 @@ def wref_cb(w):
         wref = weakref.ref(e, wref_cb)
         self.assertEqual(wref().tag, 'e')
         del e
+        gc_collect()  # For PyPy or other GCs.
         self.assertEqual(flag, True)
         self.assertEqual(wref(), None)
 
diff --git a/Lib/tkinter/test/test_tkinter/test_images.py b/Lib/tkinter/test/test_tkinter/test_images.py
index 2526e92200d90..c7b468044d55e 100644
--- a/Lib/tkinter/test/test_tkinter/test_images.py
+++ b/Lib/tkinter/test/test_tkinter/test_images.py
@@ -78,6 +78,7 @@ def test_create_from_file(self):
         self.assertEqual(image.height(), 16)
         self.assertIn('::img::test', self.root.image_names())
         del image
+        support.gc_collect()  # For PyPy or other GCs.
         self.assertNotIn('::img::test', self.root.image_names())
 
     def test_create_from_data(self):
@@ -92,6 +93,7 @@ def test_create_from_data(self):
         self.assertEqual(image.height(), 16)
         self.assertIn('::img::test', self.root.image_names())
         del image
+        support.gc_collect()  # For PyPy or other GCs.
         self.assertNotIn('::img::test', self.root.image_names())
 
     def assertEqualStrList(self, actual, expected):
@@ -172,6 +174,7 @@ def check_create_from_file(self, ext):
         self.assertEqual(image['file'], testfile)
         self.assertIn('::img::test', self.root.image_names())
         del image
+        support.gc_collect()  # For PyPy or other GCs.
         self.assertNotIn('::img::test', self.root.image_names())
 
     def check_create_from_data(self, ext):
@@ -189,6 +192,7 @@ def check_create_from_data(self, ext):
         self.assertEqual(image['file'], '')
         self.assertIn('::img::test', self.root.image_names())
         del image
+        support.gc_collect()  # For PyPy or other GCs.
         self.assertNotIn('::img::test', self.root.image_names())
 
     def test_create_from_ppm_file(self):
diff --git a/Lib/tkinter/test/test_tkinter/test_variables.py b/Lib/tkinter/test/test_tkinter/test_variables.py
index 6aebe8d16d556..0be5282a3a3b3 100644
--- a/Lib/tkinter/test/test_tkinter/test_variables.py
+++ b/Lib/tkinter/test/test_tkinter/test_variables.py
@@ -1,4 +1,6 @@
 import unittest
+from test import support
+
 import gc
 import tkinter
 from tkinter import (Variable, StringVar, IntVar, DoubleVar, BooleanVar, Tcl,
@@ -46,6 +48,7 @@ def test___del__(self):
         v = Variable(self.root, "sample string", "varname")
         self.assertTrue(self.info_exists("varname"))
         del v
+        support.gc_collect()  # For PyPy or other GCs.
         self.assertFalse(self.info_exists("varname"))
 
     def test_dont_unset_not_existing(self):
@@ -53,9 +56,11 @@ def test_dont_unset_not_existing(self):
         v1 = Variable(self.root, name="name")
         v2 = Variable(self.root, name="name")
         del v1
+        support.gc_collect()  # For PyPy or other GCs.
         self.assertFalse(self.info_exists("name"))
         # shouldn't raise exception
         del v2
+        support.gc_collect()  # For PyPy or other GCs.
         self.assertFalse(self.info_exists("name"))
 
     def test_equality(self):
diff --git a/Lib/tkinter/test/test_ttk/test_extensions.py b/Lib/tkinter/test/test_ttk/test_extensions.py
index 1a70e0befe623..e6b3eccf7afb8 100644
--- a/Lib/tkinter/test/test_ttk/test_extensions.py
+++ b/Lib/tkinter/test/test_ttk/test_extensions.py
@@ -2,7 +2,7 @@
 import unittest
 import tkinter
 from tkinter import ttk
-from test.support import requires, run_unittest
+from test.support import requires, run_unittest, gc_collect
 from tkinter.test.support import AbstractTkTest, AbstractDefaultRootTest
 
 requires('gui')
@@ -18,6 +18,7 @@ def test_widget_destroy(self):
         x = ttk.LabeledScale(self.root)
         var = x._variable._name
         x.destroy()
+        gc_collect()  # For PyPy or other GCs.
         self.assertRaises(tkinter.TclError, x.tk.globalgetvar, var)
 
         # manually created variable
@@ -30,6 +31,7 @@ def test_widget_destroy(self):
         else:
             self.assertEqual(float(x.tk.globalgetvar(name)), myvar.get())
         del myvar
+        gc_collect()  # For PyPy or other GCs.
         self.assertRaises(tkinter.TclError, x.tk.globalgetvar, name)
 
         # checking that the tracing callback is properly removed
@@ -171,6 +173,7 @@ def test_variable_change(self):
     def test_resize(self):
         x = ttk.LabeledScale(self.root)
         x.pack(expand=True, fill='both')
+        gc_collect()  # For PyPy or other GCs.
         x.update()
 
         width, height = x.master.winfo_width(), x.master.winfo_height()
@@ -206,6 +209,7 @@ def test_widget_destroy(self):
         optmenu.destroy()
         self.assertEqual(optmenu.tk.globalgetvar(name), var.get())
         del var
+        gc_collect()  # For PyPy or other GCs.
         self.assertRaises(tkinter.TclError, optmenu.tk.globalgetvar, name)
 
 
@@ -251,6 +255,7 @@ def test_menu(self):
 
         # check that variable is updated correctly
         optmenu.pack()
+        gc_collect()  # For PyPy or other GCs.
         optmenu['menu'].invoke(0)
         self.assertEqual(optmenu._variable.get(), items[0])
 
diff --git a/Lib/tkinter/test/test_ttk/test_widgets.py b/Lib/tkinter/test/test_ttk/test_widgets.py
index 1fac83a004a6d..ee5af82fd1b44 100644
--- a/Lib/tkinter/test/test_ttk/test_widgets.py
+++ b/Lib/tkinter/test/test_ttk/test_widgets.py
@@ -1,7 +1,7 @@
 import unittest
 import tkinter
 from tkinter import ttk, TclError
-from test.support import requires
+from test.support import requires, gc_collect
 import sys
 
 from tkinter.test.test_ttk.test_functions import MockTclObj
@@ -839,6 +839,7 @@ def test_set(self):
         self.assertEqual(conv(self.scale.get()), var.get())
         self.assertEqual(conv(self.scale.get()), max + 5)
         del var
+        gc_collect()  # For PyPy or other GCs.
 
         # the same happens with the value option
         self.scale['value'] = max + 10
diff --git a/Lib/unittest/test/test_assertions.py b/Lib/unittest/test/test_assertions.py
index f5e64d68e7b10..a0db3423b868a 100644
--- a/Lib/unittest/test/test_assertions.py
+++ b/Lib/unittest/test/test_assertions.py
@@ -2,6 +2,7 @@
 import warnings
 import weakref
 import unittest
+from test.support import gc_collect
 from itertools import product
 
 
@@ -124,8 +125,10 @@ def test_with(self):
                     self.foo()
 
         Foo("test_functional").run()
+        gc_collect()  # For PyPy or other GCs.
         self.assertIsNone(wr())
         Foo("test_with").run()
+        gc_collect()  # For PyPy or other GCs.
         self.assertIsNone(wr())
 
     def testAssertNotRegex(self):
diff --git a/Lib/unittest/test/test_case.py b/Lib/unittest/test/test_case.py
index b8aca92a8ebe9..35334851304d8 100644
--- a/Lib/unittest/test/test_case.py
+++ b/Lib/unittest/test/test_case.py
@@ -19,7 +19,7 @@
     TestEquality, TestHashing, LoggingResult, LegacyLoggingResult,
     ResultWithNoStartTestRunStopTestRun
 )
-from test.support import captured_stderr
+from test.support import captured_stderr, gc_collect
 
 
 log_foo = logging.getLogger('foo')
@@ -1947,6 +1947,7 @@ def test2(self):
         for method_name in ('test1', 'test2'):
             testcase = TestCase(method_name)
             testcase.run()
+            gc_collect()  # For PyPy or other GCs.
             self.assertEqual(MyException.ninstance, 0)
 
 
diff --git a/Misc/NEWS.d/next/Tests/2021-08-27-22-37-19.bpo-25130.ig4oJe.rst b/Misc/NEWS.d/next/Tests/2021-08-27-22-37-19.bpo-25130.ig4oJe.rst
new file mode 100644
index 0000000000000..43ce68bef4609
--- /dev/null
+++ b/Misc/NEWS.d/next/Tests/2021-08-27-22-37-19.bpo-25130.ig4oJe.rst
@@ -0,0 +1 @@
+Add calls of :func:`gc.collect` in tests to support PyPy.



More information about the Python-checkins mailing list