[Python-checkins] bpo-40280: Detect missing threading on WASM platforms (GH-32352)

tiran webhook-mailer at python.org
Thu Apr 7 03:23:19 EDT 2022


https://github.com/python/cpython/commit/2b16a08bc77475917dd5c96417aef4c5210b45ac
commit: 2b16a08bc77475917dd5c96417aef4c5210b45ac
branch: main
author: Christian Heimes <christian at python.org>
committer: tiran <christian at python.org>
date: 2022-04-07T09:22:47+02:00
summary:

bpo-40280: Detect missing threading on WASM platforms (GH-32352)

Co-authored-by: Brett Cannon <brett at python.org>

files:
A Misc/NEWS.d/next/Tests/2022-04-06-10-16-27.bpo-40280.KT5Apg.rst
M Lib/distutils/tests/test_build_ext.py
M Lib/test/libregrtest/main.py
M Lib/test/pickletester.py
M Lib/test/support/threading_helper.py
M Lib/test/test_bz2.py
M Lib/test/test_capi.py
M Lib/test/test_context.py
M Lib/test/test_decimal.py
M Lib/test/test_email/test_email.py
M Lib/test/test_enum.py
M Lib/test/test_functools.py
M Lib/test/test_gc.py
M Lib/test/test_hashlib.py
M Lib/test/test_import/__init__.py
M Lib/test/test_importlib/test_locks.py
M Lib/test/test_importlib/test_threaded_import.py
M Lib/test/test_io.py
M Lib/test/test_itertools.py
M Lib/test/test_logging.py
M Lib/test/test_queue.py
M Lib/test/test_sched.py
M Lib/test/test_signal.py
M Lib/test/test_support.py
M Lib/test/test_sys.py
M Lib/test/test_thread.py
M Lib/test/test_threadedtempfile.py
M Lib/test/test_threading.py
M Lib/test/test_threading_local.py
M Lib/test/test_threadsignals.py
M Lib/test/test_weakref.py
M configure
M configure.ac

diff --git a/Lib/distutils/tests/test_build_ext.py b/Lib/distutils/tests/test_build_ext.py
index 460b62f50bc12..031897bd2734f 100644
--- a/Lib/distutils/tests/test_build_ext.py
+++ b/Lib/distutils/tests/test_build_ext.py
@@ -17,6 +17,7 @@
 from test import support
 from test.support import os_helper
 from test.support.script_helper import assert_python_ok
+from test.support import threading_helper
 
 # http://bugs.python.org/issue4373
 # Don't load the xx module more than once.
@@ -165,6 +166,7 @@ def test_user_site(self):
         self.assertIn(lib, cmd.rpath)
         self.assertIn(incl, cmd.include_dirs)
 
+    @threading_helper.requires_working_threading()
     def test_optional_extension(self):
 
         # this extension will fail, but let's ignore this failure
diff --git a/Lib/test/libregrtest/main.py b/Lib/test/libregrtest/main.py
index af58114ed925c..e7e3dde0b0a66 100644
--- a/Lib/test/libregrtest/main.py
+++ b/Lib/test/libregrtest/main.py
@@ -20,6 +20,7 @@
 from test.libregrtest.utils import removepy, count, format_duration, printlist
 from test import support
 from test.support import os_helper
+from test.support import threading_helper
 
 
 # bpo-38203: Maximum delay in seconds to exit Python (call Py_Finalize()).
@@ -676,7 +677,8 @@ def main(self, tests=None, **kwargs):
         except SystemExit as exc:
             # bpo-38203: Python can hang at exit in Py_Finalize(), especially
             # on threading._shutdown() call: put a timeout
-            faulthandler.dump_traceback_later(EXIT_TIMEOUT, exit=True)
+            if threading_helper.can_start_thread:
+                faulthandler.dump_traceback_later(EXIT_TIMEOUT, exit=True)
 
             sys.exit(exc.code)
 
diff --git a/Lib/test/pickletester.py b/Lib/test/pickletester.py
index 63fa7604fbfc9..d0ea7d0e55e7d 100644
--- a/Lib/test/pickletester.py
+++ b/Lib/test/pickletester.py
@@ -1380,6 +1380,7 @@ def test_truncated_data(self):
             self.check_unpickling_error(self.truncated_errors, p)
 
     @threading_helper.reap_threads
+    @threading_helper.requires_working_threading()
     def test_unpickle_module_race(self):
         # https://bugs.python.org/issue34572
         locker_module = dedent("""
diff --git a/Lib/test/support/threading_helper.py b/Lib/test/support/threading_helper.py
index 2ae4577f41f7b..7b636f0ccf097 100644
--- a/Lib/test/support/threading_helper.py
+++ b/Lib/test/support/threading_helper.py
@@ -4,6 +4,7 @@
 import sys
 import threading
 import time
+import unittest
 
 from test import support
 
@@ -210,7 +211,7 @@ def __exit__(self, *exc_info):
 
 
 def _can_start_thread() -> bool:
-    """Detect if Python can start new threads.
+    """Detect whether Python can start new threads.
 
     Some WebAssembly platforms do not provide a working pthread
     implementation. Thread support is stubbed and any attempt
@@ -234,3 +235,15 @@ def _can_start_thread() -> bool:
         return True
 
 can_start_thread = _can_start_thread()
+
+def requires_working_threading(*, module=False):
+    """Skip tests or modules that require working threading.
+
+    Can be used as a function/class decorator or to skip an entire module.
+    """
+    msg = "requires threading support"
+    if module:
+        if not can_start_thread:
+            raise unittest.SkipTest(msg)
+    else:
+        return unittest.skipUnless(can_start_thread, msg)
diff --git a/Lib/test/test_bz2.py b/Lib/test/test_bz2.py
index 9965c1fe2e5f1..c97ed1cea0d11 100644
--- a/Lib/test/test_bz2.py
+++ b/Lib/test/test_bz2.py
@@ -496,6 +496,7 @@ def testContextProtocol(self):
         else:
             self.fail("1/0 didn't raise an exception")
 
+    @threading_helper.requires_working_threading()
     def testThreading(self):
         # Issue #7205: Using a BZ2File from several threads shouldn't deadlock.
         data = b"1" * 2**20
diff --git a/Lib/test/test_capi.py b/Lib/test/test_capi.py
index 714a2d98e9fb5..3837f801b3c73 100644
--- a/Lib/test/test_capi.py
+++ b/Lib/test/test_capi.py
@@ -710,6 +710,7 @@ def pendingcalls_wait(self, l, n, context = None):
         if False and support.verbose:
             print("(%i)"%(len(l),))
 
+    @threading_helper.requires_working_threading()
     def test_pendingcalls_threaded(self):
 
         #do every callback on a separate thread
@@ -840,6 +841,7 @@ def test_module_state_shared_in_global(self):
 class TestThreadState(unittest.TestCase):
 
     @threading_helper.reap_threads
+    @threading_helper.requires_working_threading()
     def test_thread_state(self):
         # some extra thread-state tests driven via _testcapi
         def target():
diff --git a/Lib/test/test_context.py b/Lib/test/test_context.py
index 2d8b63a1f5958..3132cea668cb1 100644
--- a/Lib/test/test_context.py
+++ b/Lib/test/test_context.py
@@ -6,6 +6,7 @@
 import time
 import unittest
 import weakref
+from test.support import threading_helper
 
 try:
     from _testcapi import hamt
@@ -341,6 +342,7 @@ def ctx2_fun():
         ctx1.run(ctx1_fun)
 
     @isolated_context
+    @threading_helper.requires_working_threading()
     def test_context_threads_1(self):
         cvar = contextvars.ContextVar('cvar')
 
diff --git a/Lib/test/test_decimal.py b/Lib/test/test_decimal.py
index b68cfbef23f16..0e7491ecdd45c 100644
--- a/Lib/test/test_decimal.py
+++ b/Lib/test/test_decimal.py
@@ -39,6 +39,7 @@
                           run_with_locale, cpython_only,
                           darwin_malloc_err_warning)
 from test.support.import_helper import import_fresh_module
+from test.support import threading_helper
 from test.support import warnings_helper
 import random
 import inspect
@@ -1591,6 +1592,8 @@ def thfunc2(cls):
     for sig in Overflow, Underflow, DivisionByZero, InvalidOperation:
         cls.assertFalse(thiscontext.flags[sig])
 
+
+ at threading_helper.requires_working_threading()
 class ThreadingTest(unittest.TestCase):
     '''Unit tests for thread local contexts in Decimal.'''
 
diff --git a/Lib/test/test_email/test_email.py b/Lib/test/test_email/test_email.py
index a3ccbbbabfb32..ca9c773bbc559 100644
--- a/Lib/test/test_email/test_email.py
+++ b/Lib/test/test_email/test_email.py
@@ -3285,6 +3285,7 @@ def test_getaddresses_header_obj(self):
         addrs = utils.getaddresses([Header('Al Person <aperson at dom.ain>')])
         self.assertEqual(addrs[0][1], 'aperson at dom.ain')
 
+    @threading_helper.requires_working_threading()
     def test_make_msgid_collisions(self):
         # Test make_msgid uniqueness, even with multiple threads
         class MsgidsThread(Thread):
diff --git a/Lib/test/test_enum.py b/Lib/test/test_enum.py
index f2572b2ac351a..b1b8e82b3859f 100644
--- a/Lib/test/test_enum.py
+++ b/Lib/test/test_enum.py
@@ -2949,6 +2949,7 @@ class Color(StrMixin, AllMixin, Flag):
         self.assertEqual(str(Color.BLUE), 'blue')
 
     @threading_helper.reap_threads
+    @threading_helper.requires_working_threading()
     def test_unique_composite(self):
         # override __eq__ to be identity only
         class TestFlag(Flag):
@@ -3481,6 +3482,7 @@ class Color(StrMixin, AllMixin, IntFlag):
         self.assertEqual(str(Color.BLUE), 'blue')
 
     @threading_helper.reap_threads
+    @threading_helper.requires_working_threading()
     def test_unique_composite(self):
         # override __eq__ to be identity only
         class TestFlag(IntFlag):
diff --git a/Lib/test/test_functools.py b/Lib/test/test_functools.py
index 82e73f46a3fba..e3c065615778f 100644
--- a/Lib/test/test_functools.py
+++ b/Lib/test/test_functools.py
@@ -1637,6 +1637,7 @@ def f(zomg: 'zomg_annotation'):
         for attr in self.module.WRAPPER_ASSIGNMENTS:
             self.assertEqual(getattr(g, attr), getattr(f, attr))
 
+    @threading_helper.requires_working_threading()
     def test_lru_cache_threaded(self):
         n, m = 5, 11
         def orig(x, y):
@@ -1685,6 +1686,7 @@ def clear():
         finally:
             sys.setswitchinterval(orig_si)
 
+    @threading_helper.requires_working_threading()
     def test_lru_cache_threaded2(self):
         # Simultaneous call with the same arguments
         n, m = 5, 7
@@ -1712,6 +1714,7 @@ def test():
                 pause.reset()
                 self.assertEqual(f.cache_info(), (0, (i+1)*n, m*n, i+1))
 
+    @threading_helper.requires_working_threading()
     def test_lru_cache_threaded3(self):
         @self.module.lru_cache(maxsize=2)
         def f(x):
@@ -2914,6 +2917,7 @@ def test_cached_attribute_name_differs_from_func_name(self):
         self.assertEqual(item.get_cost(), 4)
         self.assertEqual(item.cached_cost, 3)
 
+    @threading_helper.requires_working_threading()
     def test_threaded(self):
         go = threading.Event()
         item = CachedCostItemWait(go)
diff --git a/Lib/test/test_gc.py b/Lib/test/test_gc.py
index c4d4355dec9c6..ce04042679bbc 100644
--- a/Lib/test/test_gc.py
+++ b/Lib/test/test_gc.py
@@ -365,6 +365,7 @@ def __del__(self):
                 v = {1: v, 2: Ouch()}
         gc.disable()
 
+    @threading_helper.requires_working_threading()
     def test_trashcan_threads(self):
         # Issue #13992: trashcan mechanism should be thread-safe
         NESTING = 60
diff --git a/Lib/test/test_hashlib.py b/Lib/test/test_hashlib.py
index d2a92147d5f02..67becdd6d317f 100644
--- a/Lib/test/test_hashlib.py
+++ b/Lib/test/test_hashlib.py
@@ -915,6 +915,7 @@ def test_gil(self):
         )
 
     @threading_helper.reap_threads
+    @threading_helper.requires_working_threading()
     def test_threaded_hashing(self):
         # Updating the same hash object from several threads at once
         # using data chunk sizes containing the same byte sequences.
diff --git a/Lib/test/test_import/__init__.py b/Lib/test/test_import/__init__.py
index 7cca9f9d60ab6..be88677dc697e 100644
--- a/Lib/test/test_import/__init__.py
+++ b/Lib/test/test_import/__init__.py
@@ -448,6 +448,7 @@ def test_issue31492(self):
             with self.assertRaises(AttributeError):
                 os.does_not_exist
 
+    @threading_helper.requires_working_threading()
     def test_concurrency(self):
         # bpo 38091: this is a hack to slow down the code that calls
         # has_deadlock(); the logic was itself sometimes deadlocking.
diff --git a/Lib/test/test_importlib/test_locks.py b/Lib/test/test_importlib/test_locks.py
index 584d013caacad..56d73c496e6bb 100644
--- a/Lib/test/test_importlib/test_locks.py
+++ b/Lib/test/test_importlib/test_locks.py
@@ -12,6 +12,9 @@
 from test import lock_tests
 
 
+threading_helper.requires_working_threading(module=True)
+
+
 class ModuleLockAsRLockTests:
     locktype = classmethod(lambda cls: cls.LockType("some_lock"))
 
@@ -146,4 +149,4 @@ def setUpModule():
 
 
 if __name__ == '__main__':
-    unittets.main()
+    unittest.main()
diff --git a/Lib/test/test_importlib/test_threaded_import.py b/Lib/test/test_importlib/test_threaded_import.py
index 76b028eac97bf..cc1d804f35f91 100644
--- a/Lib/test/test_importlib/test_threaded_import.py
+++ b/Lib/test/test_importlib/test_threaded_import.py
@@ -19,6 +19,8 @@
 from test.support.os_helper import (TESTFN, unlink, rmtree)
 from test.support import script_helper, threading_helper
 
+threading_helper.requires_working_threading(module=True)
+
 def task(N, done, done_tasks, errors):
     try:
         # We don't use modulefinder but still import it in order to stress
diff --git a/Lib/test/test_io.py b/Lib/test/test_io.py
index 67be108d2526f..29fe287550b2d 100644
--- a/Lib/test/test_io.py
+++ b/Lib/test/test_io.py
@@ -1451,6 +1451,7 @@ def test_read_all(self):
         self.assertEqual(b"abcdefg", bufio.read())
 
     @support.requires_resource('cpu')
+    @threading_helper.requires_working_threading()
     def test_threads(self):
         try:
             # Write out many bytes with exactly the same number of 0's,
@@ -1825,6 +1826,7 @@ def test_truncate_after_write(self):
                 self.assertEqual(f.tell(), buffer_size + 2)
 
     @support.requires_resource('cpu')
+    @threading_helper.requires_working_threading()
     def test_threads(self):
         try:
             # Write out many bytes from many threads and test they were
@@ -1895,6 +1897,7 @@ def bad_write(b):
         self.assertRaises(OSError, b.close) # exception not swallowed
         self.assertTrue(b.closed)
 
+    @threading_helper.requires_working_threading()
     def test_slow_close_from_thread(self):
         # Issue #31976
         rawio = self.SlowFlushRawIO()
@@ -3287,6 +3290,7 @@ def test_errors_property(self):
             self.assertEqual(f.errors, "replace")
 
     @support.no_tracing
+    @threading_helper.requires_working_threading()
     def test_threads_write(self):
         # Issue6750: concurrent writes could duplicate data
         event = threading.Event()
@@ -4362,9 +4366,11 @@ def run():
         else:
             self.assertFalse(err.strip('.!'))
 
+    @threading_helper.requires_working_threading()
     def test_daemon_threads_shutdown_stdout_deadlock(self):
         self.check_daemon_threads_shutdown_deadlock('stdout')
 
+    @threading_helper.requires_working_threading()
     def test_daemon_threads_shutdown_stderr_deadlock(self):
         self.check_daemon_threads_shutdown_deadlock('stderr')
 
diff --git a/Lib/test/test_itertools.py b/Lib/test/test_itertools.py
index 3f3f7cb35d0bc..238afbbd883d3 100644
--- a/Lib/test/test_itertools.py
+++ b/Lib/test/test_itertools.py
@@ -1,6 +1,7 @@
 import doctest
 import unittest
 from test import support
+from test.support import threading_helper
 from itertools import *
 import weakref
 from decimal import Decimal
@@ -1533,6 +1534,7 @@ def __next__(self):
         with self.assertRaisesRegex(RuntimeError, "tee"):
             next(a)
 
+    @threading_helper.requires_working_threading()
     def test_tee_concurrent(self):
         start = threading.Event()
         finish = threading.Event()
diff --git a/Lib/test/test_logging.py b/Lib/test/test_logging.py
index f6f5977df2a1e..7555f05d1d0cf 100644
--- a/Lib/test/test_logging.py
+++ b/Lib/test/test_logging.py
@@ -630,6 +630,7 @@ def test_path_objects(self):
     @unittest.skipIf(
         support.is_emscripten, "Emscripten cannot fstat unlinked files."
     )
+    @threading_helper.requires_working_threading()
     def test_race(self):
         # Issue #14632 refers.
         def remove_loop(fname, tries):
@@ -679,6 +680,7 @@ def remove_loop(fname, tries):
     # This helps ensure that when fork exists (the important concept) that the
     # register_at_fork mechanism is also present and used.
     @support.requires_fork()
+    @threading_helper.requires_working_threading()
     def test_post_fork_child_no_deadlock(self):
         """Ensure child logging locks are not held; bpo-6721 & bpo-36533."""
         class _OurHandler(logging.Handler):
@@ -1063,6 +1065,7 @@ class TestUnixDatagramServer(TestUDPServer):
 # - end of server_helper section
 
 @support.requires_working_socket()
+ at threading_helper.requires_working_threading()
 class SMTPHandlerTest(BaseTest):
     # bpo-14314, bpo-19665, bpo-34092: don't wait forever
     TIMEOUT = support.LONG_TIMEOUT
@@ -1172,6 +1175,7 @@ def test_flush_on_close(self):
         # assert that no new lines have been added
         self.assert_log_lines(lines)  # no change
 
+    @threading_helper.requires_working_threading()
     def test_race_between_set_target_and_flush(self):
         class MockRaceConditionHandler:
             def __init__(self, mem_hdlr):
@@ -1687,6 +1691,7 @@ def test_defaults_do_no_interpolation(self):
 
 
 @support.requires_working_socket()
+ at threading_helper.requires_working_threading()
 class SocketHandlerTest(BaseTest):
 
     """Test for SocketHandler objects."""
@@ -1802,6 +1807,7 @@ def tearDown(self):
         os_helper.unlink(self.address)
 
 @support.requires_working_socket()
+ at threading_helper.requires_working_threading()
 class DatagramHandlerTest(BaseTest):
 
     """Test for DatagramHandler."""
@@ -1884,6 +1890,7 @@ def tearDown(self):
         os_helper.unlink(self.address)
 
 @support.requires_working_socket()
+ at threading_helper.requires_working_threading()
 class SysLogHandlerTest(BaseTest):
 
     """Test for SysLogHandler using UDP."""
@@ -1994,6 +2001,7 @@ def tearDown(self):
         super(IPv6SysLogHandlerTest, self).tearDown()
 
 @support.requires_working_socket()
+ at threading_helper.requires_working_threading()
 class HTTPHandlerTest(BaseTest):
     """Test for HTTPHandler."""
 
@@ -3575,6 +3583,7 @@ def test_logrecord_class(self):
         ])
 
 
+ at threading_helper.requires_working_threading()
 class QueueHandlerTest(BaseTest):
     # Do not bother with a logger name group.
     expected_log_pat = r"^[\w.]+ -> (\w+): (\d+)$"
@@ -3684,6 +3693,7 @@ def test_queue_listener_with_multiple_handlers(self):
     import multiprocessing
     from unittest.mock import patch
 
+    @threading_helper.requires_working_threading()
     class QueueListenerTest(BaseTest):
         """
         Tests based on patch submitted for issue #27930. Ensure that
diff --git a/Lib/test/test_queue.py b/Lib/test/test_queue.py
index cfa6003a867da..e3080376a9de5 100644
--- a/Lib/test/test_queue.py
+++ b/Lib/test/test_queue.py
@@ -87,6 +87,7 @@ def do_exceptional_blocking_test(self,block_func, block_args, trigger_func,
                 self.fail("trigger thread ended but event never set")
 
 
+ at threading_helper.requires_working_threading()
 class BaseQueueTestMixin(BlockingTestMixin):
     def setUp(self):
         self.cum = 0
@@ -289,6 +290,8 @@ class CPriorityQueueTest(PriorityQueueTest, unittest.TestCase):
 # A Queue subclass that can provoke failure at a moment's notice :)
 class FailingQueueException(Exception): pass
 
+
+ at threading_helper.requires_working_threading()
 class FailingQueueTest(BlockingTestMixin):
 
     def setUp(self):
@@ -464,6 +467,7 @@ def consume_timeout(self, q, results, sentinel):
                 return
             results.append(val)
 
+    @threading_helper.requires_working_threading()
     def run_threads(self, n_threads, q, inputs, feed_func, consume_func):
         results = []
         sentinel = None
diff --git a/Lib/test/test_sched.py b/Lib/test/test_sched.py
index 7ae7baae85e2c..32cc8105bc055 100644
--- a/Lib/test/test_sched.py
+++ b/Lib/test/test_sched.py
@@ -58,6 +58,7 @@ def test_enterabs(self):
         scheduler.run()
         self.assertEqual(l, [0.01, 0.02, 0.03, 0.04, 0.05])
 
+    @threading_helper.requires_working_threading()
     def test_enter_concurrent(self):
         q = queue.Queue()
         fun = q.put
@@ -111,6 +112,7 @@ def test_cancel(self):
         scheduler.run()
         self.assertEqual(l, [0.02, 0.03, 0.04])
 
+    @threading_helper.requires_working_threading()
     def test_cancel_concurrent(self):
         q = queue.Queue()
         fun = q.put
diff --git a/Lib/test/test_signal.py b/Lib/test/test_signal.py
index 37b46065e532c..ea13c59ec711e 100644
--- a/Lib/test/test_signal.py
+++ b/Lib/test/test_signal.py
@@ -14,6 +14,7 @@
 from test import support
 from test.support import os_helper
 from test.support.script_helper import assert_python_ok, spawn_python
+from test.support import threading_helper
 try:
     import _testcapi
 except ImportError:
@@ -876,6 +877,7 @@ def handler(signum, frame):
 
     @unittest.skipUnless(hasattr(signal, 'pthread_kill'),
                          'need signal.pthread_kill()')
+    @threading_helper.requires_working_threading()
     def test_pthread_kill(self):
         code = """if 1:
             import signal
@@ -1012,6 +1014,7 @@ def test_sigtimedwait_negative_timeout(self):
                          'need signal.sigwait()')
     @unittest.skipUnless(hasattr(signal, 'pthread_sigmask'),
                          'need signal.pthread_sigmask()')
+    @threading_helper.requires_working_threading()
     def test_sigwait_thread(self):
         # Check that calling sigwait() from a thread doesn't suspend the whole
         # process. A new interpreter is spawned to avoid problems when mixing
@@ -1067,6 +1070,7 @@ def test_pthread_sigmask_valid_signals(self):
 
     @unittest.skipUnless(hasattr(signal, 'pthread_sigmask'),
                          'need signal.pthread_sigmask()')
+    @threading_helper.requires_working_threading()
     def test_pthread_sigmask(self):
         code = """if 1:
         import signal
@@ -1144,6 +1148,7 @@ def read_sigmask():
 
     @unittest.skipUnless(hasattr(signal, 'pthread_kill'),
                          'need signal.pthread_kill()')
+    @threading_helper.requires_working_threading()
     def test_pthread_kill_main_thread(self):
         # Test that a signal can be sent to the main thread with pthread_kill()
         # before any other thread has been created (see issue #12392).
@@ -1298,6 +1303,7 @@ def handler(signum, frame):
 
     @unittest.skipUnless(hasattr(signal, "SIGUSR1"),
                          "test needs SIGUSR1")
+    @threading_helper.requires_working_threading()
     def test_stress_modifying_handlers(self):
         # bpo-43406: race condition between trip_signal() and signal.signal
         signum = signal.SIGUSR1
diff --git a/Lib/test/test_support.py b/Lib/test/test_support.py
index 2cff377cf629e..90e971deb397f 100644
--- a/Lib/test/test_support.py
+++ b/Lib/test/test_support.py
@@ -123,15 +123,18 @@ def test_forget(self):
             os_helper.unlink(mod_filename)
             os_helper.rmtree('__pycache__')
 
+    @support.requires_working_socket()
     def test_HOST(self):
         s = socket.create_server((socket_helper.HOST, 0))
         s.close()
 
+    @support.requires_working_socket()
     def test_find_unused_port(self):
         port = socket_helper.find_unused_port()
         s = socket.create_server((socket_helper.HOST, port))
         s.close()
 
+    @support.requires_working_socket()
     def test_bind_port(self):
         s = socket.socket()
         socket_helper.bind_port(s)
diff --git a/Lib/test/test_sys.py b/Lib/test/test_sys.py
index 445ff893ff6fc..b70871ff551d9 100644
--- a/Lib/test/test_sys.py
+++ b/Lib/test/test_sys.py
@@ -401,6 +401,7 @@ def test_getframe(self):
 
     # sys._current_frames() is a CPython-only gimmick.
     @threading_helper.reap_threads
+    @threading_helper.requires_working_threading()
     def test_current_frames(self):
         import threading
         import traceback
@@ -466,6 +467,7 @@ def g456():
         t.join()
 
     @threading_helper.reap_threads
+    @threading_helper.requires_working_threading()
     def test_current_exceptions(self):
         import threading
         import traceback
@@ -1176,11 +1178,12 @@ class X(Exception):
         for moduleName in 'builtins', '__main__', 'some_module':
             with self.subTest(moduleName=moduleName):
                 A.B.X.__module__ = moduleName
-                with test.support.captured_stderr() as stderr, \
-                     test.support.swap_attr(sys, 'unraisablehook',
-                                            sys.__unraisablehook__):
+                with test.support.captured_stderr() as stderr, test.support.swap_attr(
+                    sys, 'unraisablehook', sys.__unraisablehook__
+                ):
                     expected = self.write_unraisable_exc(
-                        A.B.X(), "msg", "obj");
+                        A.B.X(), "msg", "obj"
+                    )
                 report = stderr.getvalue()
                 self.assertIn(A.B.X.__qualname__, report)
                 if moduleName in ['builtins', '__main__']:
diff --git a/Lib/test/test_thread.py b/Lib/test/test_thread.py
index d55fb731b6df5..ed527e7164fd0 100644
--- a/Lib/test/test_thread.py
+++ b/Lib/test/test_thread.py
@@ -9,6 +9,8 @@
 
 from test import lock_tests
 
+threading_helper.requires_working_threading(module=True)
+
 NUMTASKS = 10
 NUMTRIPS = 3
 POLL_SLEEP = 0.010 # seconds = 10 ms
diff --git a/Lib/test/test_threadedtempfile.py b/Lib/test/test_threadedtempfile.py
index fe63c9e91437b..420fc6ec8be3d 100644
--- a/Lib/test/test_threadedtempfile.py
+++ b/Lib/test/test_threadedtempfile.py
@@ -21,6 +21,7 @@
 import threading
 from traceback import print_exc
 
+threading_helper.requires_working_threading(module=True)
 
 NUM_THREADS = 20
 FILES_PER_THREAD = 50
diff --git a/Lib/test/test_threading.py b/Lib/test/test_threading.py
index 16c6934c6d432..f7dea136a87c0 100644
--- a/Lib/test/test_threading.py
+++ b/Lib/test/test_threading.py
@@ -25,6 +25,7 @@
 from test import lock_tests
 from test import support
 
+threading_helper.requires_working_threading(module=True)
 
 # Between fork() and exec(), only async-safe functions are allowed (issues
 # #12316 and #11870), and fork() from a worker thread is known to trigger
diff --git a/Lib/test/test_threading_local.py b/Lib/test/test_threading_local.py
index 1567c41000bc5..9888e631881fa 100644
--- a/Lib/test/test_threading_local.py
+++ b/Lib/test/test_threading_local.py
@@ -12,6 +12,9 @@
 import _threading_local
 
 
+threading_helper.requires_working_threading(module=True)
+
+
 class Weak(object):
     pass
 
diff --git a/Lib/test/test_threadsignals.py b/Lib/test/test_threadsignals.py
index bac82b8a44511..e0ac18c946398 100644
--- a/Lib/test/test_threadsignals.py
+++ b/Lib/test/test_threadsignals.py
@@ -36,6 +36,7 @@ def send_signals():
     os.kill(process_pid, signal.SIGUSR2)
     signalled_all.release()
 
+ at threading_helper.requires_working_threading()
 class ThreadSignals(unittest.TestCase):
 
     def test_signals(self):
diff --git a/Lib/test/test_weakref.py b/Lib/test/test_weakref.py
index 46dac0228295d..702bb4495e749 100644
--- a/Lib/test/test_weakref.py
+++ b/Lib/test/test_weakref.py
@@ -14,6 +14,7 @@
 from test import support
 from test.support import script_helper, ALWAYS_EQ
 from test.support import gc_collect
+from test.support import threading_helper
 
 # Used in ReferencesTestCase.test_ref_created_during_del() .
 ref_from_del = None
@@ -1851,6 +1852,7 @@ def test_make_weak_keyed_dict_repr(self):
         dict = weakref.WeakKeyDictionary()
         self.assertRegex(repr(dict), '<WeakKeyDictionary at 0x.*>')
 
+    @threading_helper.requires_working_threading()
     def test_threaded_weak_valued_setdefault(self):
         d = weakref.WeakValueDictionary()
         with collect_in_thread():
@@ -1859,6 +1861,7 @@ def test_threaded_weak_valued_setdefault(self):
                 self.assertIsNot(x, None)  # we never put None in there!
                 del x
 
+    @threading_helper.requires_working_threading()
     def test_threaded_weak_valued_pop(self):
         d = weakref.WeakValueDictionary()
         with collect_in_thread():
@@ -1867,6 +1870,7 @@ def test_threaded_weak_valued_pop(self):
                 x = d.pop(10, 10)
                 self.assertIsNot(x, None)  # we never put None in there!
 
+    @threading_helper.requires_working_threading()
     def test_threaded_weak_valued_consistency(self):
         # Issue #28427: old keys should not remove new values from
         # WeakValueDictionary when collecting from another thread.
@@ -1940,21 +1944,25 @@ def pop_and_collect(lst):
         if exc:
             raise exc[0]
 
+    @threading_helper.requires_working_threading()
     def test_threaded_weak_key_dict_copy(self):
         # Issue #35615: Weakref keys or values getting GC'ed during dict
         # copying should not result in a crash.
         self.check_threaded_weak_dict_copy(weakref.WeakKeyDictionary, False)
 
+    @threading_helper.requires_working_threading()
     def test_threaded_weak_key_dict_deepcopy(self):
         # Issue #35615: Weakref keys or values getting GC'ed during dict
         # copying should not result in a crash.
         self.check_threaded_weak_dict_copy(weakref.WeakKeyDictionary, True)
 
+    @threading_helper.requires_working_threading()
     def test_threaded_weak_value_dict_copy(self):
         # Issue #35615: Weakref keys or values getting GC'ed during dict
         # copying should not result in a crash.
         self.check_threaded_weak_dict_copy(weakref.WeakValueDictionary, False)
 
+    @threading_helper.requires_working_threading()
     def test_threaded_weak_value_dict_deepcopy(self):
         # Issue #35615: Weakref keys or values getting GC'ed during dict
         # copying should not result in a crash.
diff --git a/Misc/NEWS.d/next/Tests/2022-04-06-10-16-27.bpo-40280.KT5Apg.rst b/Misc/NEWS.d/next/Tests/2022-04-06-10-16-27.bpo-40280.KT5Apg.rst
new file mode 100644
index 0000000000000..9fcb4c9a8b3b0
--- /dev/null
+++ b/Misc/NEWS.d/next/Tests/2022-04-06-10-16-27.bpo-40280.KT5Apg.rst
@@ -0,0 +1 @@
+Threading tests are now skipped on WASM targets without pthread support.
diff --git a/configure b/configure
index e10462cf4dbfc..69b12309de578 100755
--- a/configure
+++ b/configure
@@ -6311,15 +6311,7 @@ esac
 
 else
 
-  case $ac_sys_system in #(
-  Emscripten) :
-    enable_wasm_dynamic_linking=no ;; #(
-  WASI) :
-    enable_wasm_dynamic_linking=no ;; #(
-  *) :
-    enable_wasm_dynamic_linking=missing
-   ;;
-esac
+  enable_wasm_dynamic_linking=missing
 
 fi
 
diff --git a/configure.ac b/configure.ac
index 4f256eeff5d7b..5860595b752c8 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1122,11 +1122,7 @@ AC_ARG_ENABLE([wasm-dynamic-linking],
     [AC_MSG_ERROR([--enable-wasm-dynamic-linking only applies to Emscripten and WASI])]
   )
 ], [
-  AS_CASE([$ac_sys_system],
-    [Emscripten], [enable_wasm_dynamic_linking=no],
-    [WASI], [enable_wasm_dynamic_linking=no],
-    [enable_wasm_dynamic_linking=missing]
-  )
+  enable_wasm_dynamic_linking=missing
 ])
 AC_MSG_RESULT([$enable_wasm_dynamic_linking])
 



More information about the Python-checkins mailing list