mirror of https://github.com/python/cpython
bpo-40280: Detect missing threading on WASM platforms (GH-32352)
Co-authored-by: Brett Cannon <brett@python.org>
This commit is contained in:
parent
5aee46b31b
commit
2b16a08bc7
|
@ -17,6 +17,7 @@ import unittest
|
||||||
from test import support
|
from test import support
|
||||||
from test.support import os_helper
|
from test.support import os_helper
|
||||||
from test.support.script_helper import assert_python_ok
|
from test.support.script_helper import assert_python_ok
|
||||||
|
from test.support import threading_helper
|
||||||
|
|
||||||
# http://bugs.python.org/issue4373
|
# http://bugs.python.org/issue4373
|
||||||
# Don't load the xx module more than once.
|
# Don't load the xx module more than once.
|
||||||
|
@ -165,6 +166,7 @@ class BuildExtTestCase(TempdirManager,
|
||||||
self.assertIn(lib, cmd.rpath)
|
self.assertIn(lib, cmd.rpath)
|
||||||
self.assertIn(incl, cmd.include_dirs)
|
self.assertIn(incl, cmd.include_dirs)
|
||||||
|
|
||||||
|
@threading_helper.requires_working_threading()
|
||||||
def test_optional_extension(self):
|
def test_optional_extension(self):
|
||||||
|
|
||||||
# this extension will fail, but let's ignore this failure
|
# this extension will fail, but let's ignore this failure
|
||||||
|
|
|
@ -20,6 +20,7 @@ from test.libregrtest.pgo import setup_pgo_tests
|
||||||
from test.libregrtest.utils import removepy, count, format_duration, printlist
|
from test.libregrtest.utils import removepy, count, format_duration, printlist
|
||||||
from test import support
|
from test import support
|
||||||
from test.support import os_helper
|
from test.support import os_helper
|
||||||
|
from test.support import threading_helper
|
||||||
|
|
||||||
|
|
||||||
# bpo-38203: Maximum delay in seconds to exit Python (call Py_Finalize()).
|
# bpo-38203: Maximum delay in seconds to exit Python (call Py_Finalize()).
|
||||||
|
@ -676,7 +677,8 @@ class Regrtest:
|
||||||
except SystemExit as exc:
|
except SystemExit as exc:
|
||||||
# bpo-38203: Python can hang at exit in Py_Finalize(), especially
|
# bpo-38203: Python can hang at exit in Py_Finalize(), especially
|
||||||
# on threading._shutdown() call: put a timeout
|
# 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)
|
sys.exit(exc.code)
|
||||||
|
|
||||||
|
|
|
@ -1380,6 +1380,7 @@ class AbstractUnpickleTests:
|
||||||
self.check_unpickling_error(self.truncated_errors, p)
|
self.check_unpickling_error(self.truncated_errors, p)
|
||||||
|
|
||||||
@threading_helper.reap_threads
|
@threading_helper.reap_threads
|
||||||
|
@threading_helper.requires_working_threading()
|
||||||
def test_unpickle_module_race(self):
|
def test_unpickle_module_race(self):
|
||||||
# https://bugs.python.org/issue34572
|
# https://bugs.python.org/issue34572
|
||||||
locker_module = dedent("""
|
locker_module = dedent("""
|
||||||
|
|
|
@ -4,6 +4,7 @@ import functools
|
||||||
import sys
|
import sys
|
||||||
import threading
|
import threading
|
||||||
import time
|
import time
|
||||||
|
import unittest
|
||||||
|
|
||||||
from test import support
|
from test import support
|
||||||
|
|
||||||
|
@ -210,7 +211,7 @@ class catch_threading_exception:
|
||||||
|
|
||||||
|
|
||||||
def _can_start_thread() -> bool:
|
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
|
Some WebAssembly platforms do not provide a working pthread
|
||||||
implementation. Thread support is stubbed and any attempt
|
implementation. Thread support is stubbed and any attempt
|
||||||
|
@ -234,3 +235,15 @@ def _can_start_thread() -> bool:
|
||||||
return True
|
return True
|
||||||
|
|
||||||
can_start_thread = _can_start_thread()
|
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)
|
||||||
|
|
|
@ -496,6 +496,7 @@ class BZ2FileTest(BaseTest):
|
||||||
else:
|
else:
|
||||||
self.fail("1/0 didn't raise an exception")
|
self.fail("1/0 didn't raise an exception")
|
||||||
|
|
||||||
|
@threading_helper.requires_working_threading()
|
||||||
def testThreading(self):
|
def testThreading(self):
|
||||||
# Issue #7205: Using a BZ2File from several threads shouldn't deadlock.
|
# Issue #7205: Using a BZ2File from several threads shouldn't deadlock.
|
||||||
data = b"1" * 2**20
|
data = b"1" * 2**20
|
||||||
|
|
|
@ -710,6 +710,7 @@ class TestPendingCalls(unittest.TestCase):
|
||||||
if False and support.verbose:
|
if False and support.verbose:
|
||||||
print("(%i)"%(len(l),))
|
print("(%i)"%(len(l),))
|
||||||
|
|
||||||
|
@threading_helper.requires_working_threading()
|
||||||
def test_pendingcalls_threaded(self):
|
def test_pendingcalls_threaded(self):
|
||||||
|
|
||||||
#do every callback on a separate thread
|
#do every callback on a separate thread
|
||||||
|
@ -840,6 +841,7 @@ class SubinterpreterTest(unittest.TestCase):
|
||||||
class TestThreadState(unittest.TestCase):
|
class TestThreadState(unittest.TestCase):
|
||||||
|
|
||||||
@threading_helper.reap_threads
|
@threading_helper.reap_threads
|
||||||
|
@threading_helper.requires_working_threading()
|
||||||
def test_thread_state(self):
|
def test_thread_state(self):
|
||||||
# some extra thread-state tests driven via _testcapi
|
# some extra thread-state tests driven via _testcapi
|
||||||
def target():
|
def target():
|
||||||
|
|
|
@ -6,6 +6,7 @@ import random
|
||||||
import time
|
import time
|
||||||
import unittest
|
import unittest
|
||||||
import weakref
|
import weakref
|
||||||
|
from test.support import threading_helper
|
||||||
|
|
||||||
try:
|
try:
|
||||||
from _testcapi import hamt
|
from _testcapi import hamt
|
||||||
|
@ -341,6 +342,7 @@ class ContextTest(unittest.TestCase):
|
||||||
ctx1.run(ctx1_fun)
|
ctx1.run(ctx1_fun)
|
||||||
|
|
||||||
@isolated_context
|
@isolated_context
|
||||||
|
@threading_helper.requires_working_threading()
|
||||||
def test_context_threads_1(self):
|
def test_context_threads_1(self):
|
||||||
cvar = contextvars.ContextVar('cvar')
|
cvar = contextvars.ContextVar('cvar')
|
||||||
|
|
||||||
|
|
|
@ -39,6 +39,7 @@ from test.support import (TestFailed,
|
||||||
run_with_locale, cpython_only,
|
run_with_locale, cpython_only,
|
||||||
darwin_malloc_err_warning)
|
darwin_malloc_err_warning)
|
||||||
from test.support.import_helper import import_fresh_module
|
from test.support.import_helper import import_fresh_module
|
||||||
|
from test.support import threading_helper
|
||||||
from test.support import warnings_helper
|
from test.support import warnings_helper
|
||||||
import random
|
import random
|
||||||
import inspect
|
import inspect
|
||||||
|
@ -1591,6 +1592,8 @@ def thfunc2(cls):
|
||||||
for sig in Overflow, Underflow, DivisionByZero, InvalidOperation:
|
for sig in Overflow, Underflow, DivisionByZero, InvalidOperation:
|
||||||
cls.assertFalse(thiscontext.flags[sig])
|
cls.assertFalse(thiscontext.flags[sig])
|
||||||
|
|
||||||
|
|
||||||
|
@threading_helper.requires_working_threading()
|
||||||
class ThreadingTest(unittest.TestCase):
|
class ThreadingTest(unittest.TestCase):
|
||||||
'''Unit tests for thread local contexts in Decimal.'''
|
'''Unit tests for thread local contexts in Decimal.'''
|
||||||
|
|
||||||
|
|
|
@ -3285,6 +3285,7 @@ Foo
|
||||||
addrs = utils.getaddresses([Header('Al Person <aperson@dom.ain>')])
|
addrs = utils.getaddresses([Header('Al Person <aperson@dom.ain>')])
|
||||||
self.assertEqual(addrs[0][1], 'aperson@dom.ain')
|
self.assertEqual(addrs[0][1], 'aperson@dom.ain')
|
||||||
|
|
||||||
|
@threading_helper.requires_working_threading()
|
||||||
def test_make_msgid_collisions(self):
|
def test_make_msgid_collisions(self):
|
||||||
# Test make_msgid uniqueness, even with multiple threads
|
# Test make_msgid uniqueness, even with multiple threads
|
||||||
class MsgidsThread(Thread):
|
class MsgidsThread(Thread):
|
||||||
|
|
|
@ -2949,6 +2949,7 @@ class OldTestFlag(unittest.TestCase):
|
||||||
self.assertEqual(str(Color.BLUE), 'blue')
|
self.assertEqual(str(Color.BLUE), 'blue')
|
||||||
|
|
||||||
@threading_helper.reap_threads
|
@threading_helper.reap_threads
|
||||||
|
@threading_helper.requires_working_threading()
|
||||||
def test_unique_composite(self):
|
def test_unique_composite(self):
|
||||||
# override __eq__ to be identity only
|
# override __eq__ to be identity only
|
||||||
class TestFlag(Flag):
|
class TestFlag(Flag):
|
||||||
|
@ -3481,6 +3482,7 @@ class OldTestIntFlag(unittest.TestCase):
|
||||||
self.assertEqual(str(Color.BLUE), 'blue')
|
self.assertEqual(str(Color.BLUE), 'blue')
|
||||||
|
|
||||||
@threading_helper.reap_threads
|
@threading_helper.reap_threads
|
||||||
|
@threading_helper.requires_working_threading()
|
||||||
def test_unique_composite(self):
|
def test_unique_composite(self):
|
||||||
# override __eq__ to be identity only
|
# override __eq__ to be identity only
|
||||||
class TestFlag(IntFlag):
|
class TestFlag(IntFlag):
|
||||||
|
|
|
@ -1637,6 +1637,7 @@ class TestLRU:
|
||||||
for attr in self.module.WRAPPER_ASSIGNMENTS:
|
for attr in self.module.WRAPPER_ASSIGNMENTS:
|
||||||
self.assertEqual(getattr(g, attr), getattr(f, attr))
|
self.assertEqual(getattr(g, attr), getattr(f, attr))
|
||||||
|
|
||||||
|
@threading_helper.requires_working_threading()
|
||||||
def test_lru_cache_threaded(self):
|
def test_lru_cache_threaded(self):
|
||||||
n, m = 5, 11
|
n, m = 5, 11
|
||||||
def orig(x, y):
|
def orig(x, y):
|
||||||
|
@ -1685,6 +1686,7 @@ class TestLRU:
|
||||||
finally:
|
finally:
|
||||||
sys.setswitchinterval(orig_si)
|
sys.setswitchinterval(orig_si)
|
||||||
|
|
||||||
|
@threading_helper.requires_working_threading()
|
||||||
def test_lru_cache_threaded2(self):
|
def test_lru_cache_threaded2(self):
|
||||||
# Simultaneous call with the same arguments
|
# Simultaneous call with the same arguments
|
||||||
n, m = 5, 7
|
n, m = 5, 7
|
||||||
|
@ -1712,6 +1714,7 @@ class TestLRU:
|
||||||
pause.reset()
|
pause.reset()
|
||||||
self.assertEqual(f.cache_info(), (0, (i+1)*n, m*n, i+1))
|
self.assertEqual(f.cache_info(), (0, (i+1)*n, m*n, i+1))
|
||||||
|
|
||||||
|
@threading_helper.requires_working_threading()
|
||||||
def test_lru_cache_threaded3(self):
|
def test_lru_cache_threaded3(self):
|
||||||
@self.module.lru_cache(maxsize=2)
|
@self.module.lru_cache(maxsize=2)
|
||||||
def f(x):
|
def f(x):
|
||||||
|
@ -2914,6 +2917,7 @@ class TestCachedProperty(unittest.TestCase):
|
||||||
self.assertEqual(item.get_cost(), 4)
|
self.assertEqual(item.get_cost(), 4)
|
||||||
self.assertEqual(item.cached_cost, 3)
|
self.assertEqual(item.cached_cost, 3)
|
||||||
|
|
||||||
|
@threading_helper.requires_working_threading()
|
||||||
def test_threaded(self):
|
def test_threaded(self):
|
||||||
go = threading.Event()
|
go = threading.Event()
|
||||||
item = CachedCostItemWait(go)
|
item = CachedCostItemWait(go)
|
||||||
|
|
|
@ -365,6 +365,7 @@ class GCTests(unittest.TestCase):
|
||||||
v = {1: v, 2: Ouch()}
|
v = {1: v, 2: Ouch()}
|
||||||
gc.disable()
|
gc.disable()
|
||||||
|
|
||||||
|
@threading_helper.requires_working_threading()
|
||||||
def test_trashcan_threads(self):
|
def test_trashcan_threads(self):
|
||||||
# Issue #13992: trashcan mechanism should be thread-safe
|
# Issue #13992: trashcan mechanism should be thread-safe
|
||||||
NESTING = 60
|
NESTING = 60
|
||||||
|
|
|
@ -915,6 +915,7 @@ class HashLibTestCase(unittest.TestCase):
|
||||||
)
|
)
|
||||||
|
|
||||||
@threading_helper.reap_threads
|
@threading_helper.reap_threads
|
||||||
|
@threading_helper.requires_working_threading()
|
||||||
def test_threaded_hashing(self):
|
def test_threaded_hashing(self):
|
||||||
# Updating the same hash object from several threads at once
|
# Updating the same hash object from several threads at once
|
||||||
# using data chunk sizes containing the same byte sequences.
|
# using data chunk sizes containing the same byte sequences.
|
||||||
|
|
|
@ -448,6 +448,7 @@ class ImportTests(unittest.TestCase):
|
||||||
with self.assertRaises(AttributeError):
|
with self.assertRaises(AttributeError):
|
||||||
os.does_not_exist
|
os.does_not_exist
|
||||||
|
|
||||||
|
@threading_helper.requires_working_threading()
|
||||||
def test_concurrency(self):
|
def test_concurrency(self):
|
||||||
# bpo 38091: this is a hack to slow down the code that calls
|
# bpo 38091: this is a hack to slow down the code that calls
|
||||||
# has_deadlock(); the logic was itself sometimes deadlocking.
|
# has_deadlock(); the logic was itself sometimes deadlocking.
|
||||||
|
|
|
@ -12,6 +12,9 @@ from test.support import threading_helper
|
||||||
from test import lock_tests
|
from test import lock_tests
|
||||||
|
|
||||||
|
|
||||||
|
threading_helper.requires_working_threading(module=True)
|
||||||
|
|
||||||
|
|
||||||
class ModuleLockAsRLockTests:
|
class ModuleLockAsRLockTests:
|
||||||
locktype = classmethod(lambda cls: cls.LockType("some_lock"))
|
locktype = classmethod(lambda cls: cls.LockType("some_lock"))
|
||||||
|
|
||||||
|
@ -146,4 +149,4 @@ def setUpModule():
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
unittets.main()
|
unittest.main()
|
||||||
|
|
|
@ -19,6 +19,8 @@ from test.support.import_helper import forget
|
||||||
from test.support.os_helper import (TESTFN, unlink, rmtree)
|
from test.support.os_helper import (TESTFN, unlink, rmtree)
|
||||||
from test.support import script_helper, threading_helper
|
from test.support import script_helper, threading_helper
|
||||||
|
|
||||||
|
threading_helper.requires_working_threading(module=True)
|
||||||
|
|
||||||
def task(N, done, done_tasks, errors):
|
def task(N, done, done_tasks, errors):
|
||||||
try:
|
try:
|
||||||
# We don't use modulefinder but still import it in order to stress
|
# We don't use modulefinder but still import it in order to stress
|
||||||
|
|
|
@ -1451,6 +1451,7 @@ class BufferedReaderTest(unittest.TestCase, CommonBufferedTests):
|
||||||
self.assertEqual(b"abcdefg", bufio.read())
|
self.assertEqual(b"abcdefg", bufio.read())
|
||||||
|
|
||||||
@support.requires_resource('cpu')
|
@support.requires_resource('cpu')
|
||||||
|
@threading_helper.requires_working_threading()
|
||||||
def test_threads(self):
|
def test_threads(self):
|
||||||
try:
|
try:
|
||||||
# Write out many bytes with exactly the same number of 0's,
|
# Write out many bytes with exactly the same number of 0's,
|
||||||
|
@ -1825,6 +1826,7 @@ class BufferedWriterTest(unittest.TestCase, CommonBufferedTests):
|
||||||
self.assertEqual(f.tell(), buffer_size + 2)
|
self.assertEqual(f.tell(), buffer_size + 2)
|
||||||
|
|
||||||
@support.requires_resource('cpu')
|
@support.requires_resource('cpu')
|
||||||
|
@threading_helper.requires_working_threading()
|
||||||
def test_threads(self):
|
def test_threads(self):
|
||||||
try:
|
try:
|
||||||
# Write out many bytes from many threads and test they were
|
# Write out many bytes from many threads and test they were
|
||||||
|
@ -1895,6 +1897,7 @@ class BufferedWriterTest(unittest.TestCase, CommonBufferedTests):
|
||||||
self.assertRaises(OSError, b.close) # exception not swallowed
|
self.assertRaises(OSError, b.close) # exception not swallowed
|
||||||
self.assertTrue(b.closed)
|
self.assertTrue(b.closed)
|
||||||
|
|
||||||
|
@threading_helper.requires_working_threading()
|
||||||
def test_slow_close_from_thread(self):
|
def test_slow_close_from_thread(self):
|
||||||
# Issue #31976
|
# Issue #31976
|
||||||
rawio = self.SlowFlushRawIO()
|
rawio = self.SlowFlushRawIO()
|
||||||
|
@ -3287,6 +3290,7 @@ class TextIOWrapperTest(unittest.TestCase):
|
||||||
self.assertEqual(f.errors, "replace")
|
self.assertEqual(f.errors, "replace")
|
||||||
|
|
||||||
@support.no_tracing
|
@support.no_tracing
|
||||||
|
@threading_helper.requires_working_threading()
|
||||||
def test_threads_write(self):
|
def test_threads_write(self):
|
||||||
# Issue6750: concurrent writes could duplicate data
|
# Issue6750: concurrent writes could duplicate data
|
||||||
event = threading.Event()
|
event = threading.Event()
|
||||||
|
@ -4362,9 +4366,11 @@ class CMiscIOTest(MiscIOTest):
|
||||||
else:
|
else:
|
||||||
self.assertFalse(err.strip('.!'))
|
self.assertFalse(err.strip('.!'))
|
||||||
|
|
||||||
|
@threading_helper.requires_working_threading()
|
||||||
def test_daemon_threads_shutdown_stdout_deadlock(self):
|
def test_daemon_threads_shutdown_stdout_deadlock(self):
|
||||||
self.check_daemon_threads_shutdown_deadlock('stdout')
|
self.check_daemon_threads_shutdown_deadlock('stdout')
|
||||||
|
|
||||||
|
@threading_helper.requires_working_threading()
|
||||||
def test_daemon_threads_shutdown_stderr_deadlock(self):
|
def test_daemon_threads_shutdown_stderr_deadlock(self):
|
||||||
self.check_daemon_threads_shutdown_deadlock('stderr')
|
self.check_daemon_threads_shutdown_deadlock('stderr')
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
import doctest
|
import doctest
|
||||||
import unittest
|
import unittest
|
||||||
from test import support
|
from test import support
|
||||||
|
from test.support import threading_helper
|
||||||
from itertools import *
|
from itertools import *
|
||||||
import weakref
|
import weakref
|
||||||
from decimal import Decimal
|
from decimal import Decimal
|
||||||
|
@ -1533,6 +1534,7 @@ class TestBasicOps(unittest.TestCase):
|
||||||
with self.assertRaisesRegex(RuntimeError, "tee"):
|
with self.assertRaisesRegex(RuntimeError, "tee"):
|
||||||
next(a)
|
next(a)
|
||||||
|
|
||||||
|
@threading_helper.requires_working_threading()
|
||||||
def test_tee_concurrent(self):
|
def test_tee_concurrent(self):
|
||||||
start = threading.Event()
|
start = threading.Event()
|
||||||
finish = threading.Event()
|
finish = threading.Event()
|
||||||
|
|
|
@ -630,6 +630,7 @@ class HandlerTest(BaseTest):
|
||||||
@unittest.skipIf(
|
@unittest.skipIf(
|
||||||
support.is_emscripten, "Emscripten cannot fstat unlinked files."
|
support.is_emscripten, "Emscripten cannot fstat unlinked files."
|
||||||
)
|
)
|
||||||
|
@threading_helper.requires_working_threading()
|
||||||
def test_race(self):
|
def test_race(self):
|
||||||
# Issue #14632 refers.
|
# Issue #14632 refers.
|
||||||
def remove_loop(fname, tries):
|
def remove_loop(fname, tries):
|
||||||
|
@ -679,6 +680,7 @@ class HandlerTest(BaseTest):
|
||||||
# This helps ensure that when fork exists (the important concept) that the
|
# This helps ensure that when fork exists (the important concept) that the
|
||||||
# register_at_fork mechanism is also present and used.
|
# register_at_fork mechanism is also present and used.
|
||||||
@support.requires_fork()
|
@support.requires_fork()
|
||||||
|
@threading_helper.requires_working_threading()
|
||||||
def test_post_fork_child_no_deadlock(self):
|
def test_post_fork_child_no_deadlock(self):
|
||||||
"""Ensure child logging locks are not held; bpo-6721 & bpo-36533."""
|
"""Ensure child logging locks are not held; bpo-6721 & bpo-36533."""
|
||||||
class _OurHandler(logging.Handler):
|
class _OurHandler(logging.Handler):
|
||||||
|
@ -1063,6 +1065,7 @@ if hasattr(socket, "AF_UNIX"):
|
||||||
# - end of server_helper section
|
# - end of server_helper section
|
||||||
|
|
||||||
@support.requires_working_socket()
|
@support.requires_working_socket()
|
||||||
|
@threading_helper.requires_working_threading()
|
||||||
class SMTPHandlerTest(BaseTest):
|
class SMTPHandlerTest(BaseTest):
|
||||||
# bpo-14314, bpo-19665, bpo-34092: don't wait forever
|
# bpo-14314, bpo-19665, bpo-34092: don't wait forever
|
||||||
TIMEOUT = support.LONG_TIMEOUT
|
TIMEOUT = support.LONG_TIMEOUT
|
||||||
|
@ -1172,6 +1175,7 @@ class MemoryHandlerTest(BaseTest):
|
||||||
# assert that no new lines have been added
|
# assert that no new lines have been added
|
||||||
self.assert_log_lines(lines) # no change
|
self.assert_log_lines(lines) # no change
|
||||||
|
|
||||||
|
@threading_helper.requires_working_threading()
|
||||||
def test_race_between_set_target_and_flush(self):
|
def test_race_between_set_target_and_flush(self):
|
||||||
class MockRaceConditionHandler:
|
class MockRaceConditionHandler:
|
||||||
def __init__(self, mem_hdlr):
|
def __init__(self, mem_hdlr):
|
||||||
|
@ -1687,6 +1691,7 @@ class ConfigFileTest(BaseTest):
|
||||||
|
|
||||||
|
|
||||||
@support.requires_working_socket()
|
@support.requires_working_socket()
|
||||||
|
@threading_helper.requires_working_threading()
|
||||||
class SocketHandlerTest(BaseTest):
|
class SocketHandlerTest(BaseTest):
|
||||||
|
|
||||||
"""Test for SocketHandler objects."""
|
"""Test for SocketHandler objects."""
|
||||||
|
@ -1802,6 +1807,7 @@ class UnixSocketHandlerTest(SocketHandlerTest):
|
||||||
os_helper.unlink(self.address)
|
os_helper.unlink(self.address)
|
||||||
|
|
||||||
@support.requires_working_socket()
|
@support.requires_working_socket()
|
||||||
|
@threading_helper.requires_working_threading()
|
||||||
class DatagramHandlerTest(BaseTest):
|
class DatagramHandlerTest(BaseTest):
|
||||||
|
|
||||||
"""Test for DatagramHandler."""
|
"""Test for DatagramHandler."""
|
||||||
|
@ -1884,6 +1890,7 @@ class UnixDatagramHandlerTest(DatagramHandlerTest):
|
||||||
os_helper.unlink(self.address)
|
os_helper.unlink(self.address)
|
||||||
|
|
||||||
@support.requires_working_socket()
|
@support.requires_working_socket()
|
||||||
|
@threading_helper.requires_working_threading()
|
||||||
class SysLogHandlerTest(BaseTest):
|
class SysLogHandlerTest(BaseTest):
|
||||||
|
|
||||||
"""Test for SysLogHandler using UDP."""
|
"""Test for SysLogHandler using UDP."""
|
||||||
|
@ -1994,6 +2001,7 @@ class IPv6SysLogHandlerTest(SysLogHandlerTest):
|
||||||
super(IPv6SysLogHandlerTest, self).tearDown()
|
super(IPv6SysLogHandlerTest, self).tearDown()
|
||||||
|
|
||||||
@support.requires_working_socket()
|
@support.requires_working_socket()
|
||||||
|
@threading_helper.requires_working_threading()
|
||||||
class HTTPHandlerTest(BaseTest):
|
class HTTPHandlerTest(BaseTest):
|
||||||
"""Test for HTTPHandler."""
|
"""Test for HTTPHandler."""
|
||||||
|
|
||||||
|
@ -3575,6 +3583,7 @@ class LogRecordFactoryTest(BaseTest):
|
||||||
])
|
])
|
||||||
|
|
||||||
|
|
||||||
|
@threading_helper.requires_working_threading()
|
||||||
class QueueHandlerTest(BaseTest):
|
class QueueHandlerTest(BaseTest):
|
||||||
# Do not bother with a logger name group.
|
# Do not bother with a logger name group.
|
||||||
expected_log_pat = r"^[\w.]+ -> (\w+): (\d+)$"
|
expected_log_pat = r"^[\w.]+ -> (\w+): (\d+)$"
|
||||||
|
@ -3684,6 +3693,7 @@ if hasattr(logging.handlers, 'QueueListener'):
|
||||||
import multiprocessing
|
import multiprocessing
|
||||||
from unittest.mock import patch
|
from unittest.mock import patch
|
||||||
|
|
||||||
|
@threading_helper.requires_working_threading()
|
||||||
class QueueListenerTest(BaseTest):
|
class QueueListenerTest(BaseTest):
|
||||||
"""
|
"""
|
||||||
Tests based on patch submitted for issue #27930. Ensure that
|
Tests based on patch submitted for issue #27930. Ensure that
|
||||||
|
|
|
@ -87,6 +87,7 @@ class BlockingTestMixin:
|
||||||
self.fail("trigger thread ended but event never set")
|
self.fail("trigger thread ended but event never set")
|
||||||
|
|
||||||
|
|
||||||
|
@threading_helper.requires_working_threading()
|
||||||
class BaseQueueTestMixin(BlockingTestMixin):
|
class BaseQueueTestMixin(BlockingTestMixin):
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
self.cum = 0
|
self.cum = 0
|
||||||
|
@ -289,6 +290,8 @@ class CPriorityQueueTest(PriorityQueueTest, unittest.TestCase):
|
||||||
# A Queue subclass that can provoke failure at a moment's notice :)
|
# A Queue subclass that can provoke failure at a moment's notice :)
|
||||||
class FailingQueueException(Exception): pass
|
class FailingQueueException(Exception): pass
|
||||||
|
|
||||||
|
|
||||||
|
@threading_helper.requires_working_threading()
|
||||||
class FailingQueueTest(BlockingTestMixin):
|
class FailingQueueTest(BlockingTestMixin):
|
||||||
|
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
|
@ -464,6 +467,7 @@ class BaseSimpleQueueTest:
|
||||||
return
|
return
|
||||||
results.append(val)
|
results.append(val)
|
||||||
|
|
||||||
|
@threading_helper.requires_working_threading()
|
||||||
def run_threads(self, n_threads, q, inputs, feed_func, consume_func):
|
def run_threads(self, n_threads, q, inputs, feed_func, consume_func):
|
||||||
results = []
|
results = []
|
||||||
sentinel = None
|
sentinel = None
|
||||||
|
|
|
@ -58,6 +58,7 @@ class TestCase(unittest.TestCase):
|
||||||
scheduler.run()
|
scheduler.run()
|
||||||
self.assertEqual(l, [0.01, 0.02, 0.03, 0.04, 0.05])
|
self.assertEqual(l, [0.01, 0.02, 0.03, 0.04, 0.05])
|
||||||
|
|
||||||
|
@threading_helper.requires_working_threading()
|
||||||
def test_enter_concurrent(self):
|
def test_enter_concurrent(self):
|
||||||
q = queue.Queue()
|
q = queue.Queue()
|
||||||
fun = q.put
|
fun = q.put
|
||||||
|
@ -111,6 +112,7 @@ class TestCase(unittest.TestCase):
|
||||||
scheduler.run()
|
scheduler.run()
|
||||||
self.assertEqual(l, [0.02, 0.03, 0.04])
|
self.assertEqual(l, [0.02, 0.03, 0.04])
|
||||||
|
|
||||||
|
@threading_helper.requires_working_threading()
|
||||||
def test_cancel_concurrent(self):
|
def test_cancel_concurrent(self):
|
||||||
q = queue.Queue()
|
q = queue.Queue()
|
||||||
fun = q.put
|
fun = q.put
|
||||||
|
|
|
@ -14,6 +14,7 @@ import unittest
|
||||||
from test import support
|
from test import support
|
||||||
from test.support import os_helper
|
from test.support import os_helper
|
||||||
from test.support.script_helper import assert_python_ok, spawn_python
|
from test.support.script_helper import assert_python_ok, spawn_python
|
||||||
|
from test.support import threading_helper
|
||||||
try:
|
try:
|
||||||
import _testcapi
|
import _testcapi
|
||||||
except ImportError:
|
except ImportError:
|
||||||
|
@ -876,6 +877,7 @@ class PendingSignalsTests(unittest.TestCase):
|
||||||
|
|
||||||
@unittest.skipUnless(hasattr(signal, 'pthread_kill'),
|
@unittest.skipUnless(hasattr(signal, 'pthread_kill'),
|
||||||
'need signal.pthread_kill()')
|
'need signal.pthread_kill()')
|
||||||
|
@threading_helper.requires_working_threading()
|
||||||
def test_pthread_kill(self):
|
def test_pthread_kill(self):
|
||||||
code = """if 1:
|
code = """if 1:
|
||||||
import signal
|
import signal
|
||||||
|
@ -1012,6 +1014,7 @@ class PendingSignalsTests(unittest.TestCase):
|
||||||
'need signal.sigwait()')
|
'need signal.sigwait()')
|
||||||
@unittest.skipUnless(hasattr(signal, 'pthread_sigmask'),
|
@unittest.skipUnless(hasattr(signal, 'pthread_sigmask'),
|
||||||
'need signal.pthread_sigmask()')
|
'need signal.pthread_sigmask()')
|
||||||
|
@threading_helper.requires_working_threading()
|
||||||
def test_sigwait_thread(self):
|
def test_sigwait_thread(self):
|
||||||
# Check that calling sigwait() from a thread doesn't suspend the whole
|
# Check that calling sigwait() from a thread doesn't suspend the whole
|
||||||
# process. A new interpreter is spawned to avoid problems when mixing
|
# process. A new interpreter is spawned to avoid problems when mixing
|
||||||
|
@ -1067,6 +1070,7 @@ class PendingSignalsTests(unittest.TestCase):
|
||||||
|
|
||||||
@unittest.skipUnless(hasattr(signal, 'pthread_sigmask'),
|
@unittest.skipUnless(hasattr(signal, 'pthread_sigmask'),
|
||||||
'need signal.pthread_sigmask()')
|
'need signal.pthread_sigmask()')
|
||||||
|
@threading_helper.requires_working_threading()
|
||||||
def test_pthread_sigmask(self):
|
def test_pthread_sigmask(self):
|
||||||
code = """if 1:
|
code = """if 1:
|
||||||
import signal
|
import signal
|
||||||
|
@ -1144,6 +1148,7 @@ class PendingSignalsTests(unittest.TestCase):
|
||||||
|
|
||||||
@unittest.skipUnless(hasattr(signal, 'pthread_kill'),
|
@unittest.skipUnless(hasattr(signal, 'pthread_kill'),
|
||||||
'need signal.pthread_kill()')
|
'need signal.pthread_kill()')
|
||||||
|
@threading_helper.requires_working_threading()
|
||||||
def test_pthread_kill_main_thread(self):
|
def test_pthread_kill_main_thread(self):
|
||||||
# Test that a signal can be sent to the main thread with pthread_kill()
|
# Test that a signal can be sent to the main thread with pthread_kill()
|
||||||
# before any other thread has been created (see issue #12392).
|
# before any other thread has been created (see issue #12392).
|
||||||
|
@ -1298,6 +1303,7 @@ class StressTest(unittest.TestCase):
|
||||||
|
|
||||||
@unittest.skipUnless(hasattr(signal, "SIGUSR1"),
|
@unittest.skipUnless(hasattr(signal, "SIGUSR1"),
|
||||||
"test needs SIGUSR1")
|
"test needs SIGUSR1")
|
||||||
|
@threading_helper.requires_working_threading()
|
||||||
def test_stress_modifying_handlers(self):
|
def test_stress_modifying_handlers(self):
|
||||||
# bpo-43406: race condition between trip_signal() and signal.signal
|
# bpo-43406: race condition between trip_signal() and signal.signal
|
||||||
signum = signal.SIGUSR1
|
signum = signal.SIGUSR1
|
||||||
|
|
|
@ -123,15 +123,18 @@ class TestSupport(unittest.TestCase):
|
||||||
os_helper.unlink(mod_filename)
|
os_helper.unlink(mod_filename)
|
||||||
os_helper.rmtree('__pycache__')
|
os_helper.rmtree('__pycache__')
|
||||||
|
|
||||||
|
@support.requires_working_socket()
|
||||||
def test_HOST(self):
|
def test_HOST(self):
|
||||||
s = socket.create_server((socket_helper.HOST, 0))
|
s = socket.create_server((socket_helper.HOST, 0))
|
||||||
s.close()
|
s.close()
|
||||||
|
|
||||||
|
@support.requires_working_socket()
|
||||||
def test_find_unused_port(self):
|
def test_find_unused_port(self):
|
||||||
port = socket_helper.find_unused_port()
|
port = socket_helper.find_unused_port()
|
||||||
s = socket.create_server((socket_helper.HOST, port))
|
s = socket.create_server((socket_helper.HOST, port))
|
||||||
s.close()
|
s.close()
|
||||||
|
|
||||||
|
@support.requires_working_socket()
|
||||||
def test_bind_port(self):
|
def test_bind_port(self):
|
||||||
s = socket.socket()
|
s = socket.socket()
|
||||||
socket_helper.bind_port(s)
|
socket_helper.bind_port(s)
|
||||||
|
|
|
@ -401,6 +401,7 @@ class SysModuleTest(unittest.TestCase):
|
||||||
|
|
||||||
# sys._current_frames() is a CPython-only gimmick.
|
# sys._current_frames() is a CPython-only gimmick.
|
||||||
@threading_helper.reap_threads
|
@threading_helper.reap_threads
|
||||||
|
@threading_helper.requires_working_threading()
|
||||||
def test_current_frames(self):
|
def test_current_frames(self):
|
||||||
import threading
|
import threading
|
||||||
import traceback
|
import traceback
|
||||||
|
@ -466,6 +467,7 @@ class SysModuleTest(unittest.TestCase):
|
||||||
t.join()
|
t.join()
|
||||||
|
|
||||||
@threading_helper.reap_threads
|
@threading_helper.reap_threads
|
||||||
|
@threading_helper.requires_working_threading()
|
||||||
def test_current_exceptions(self):
|
def test_current_exceptions(self):
|
||||||
import threading
|
import threading
|
||||||
import traceback
|
import traceback
|
||||||
|
@ -1176,11 +1178,12 @@ class UnraisableHookTest(unittest.TestCase):
|
||||||
for moduleName in 'builtins', '__main__', 'some_module':
|
for moduleName in 'builtins', '__main__', 'some_module':
|
||||||
with self.subTest(moduleName=moduleName):
|
with self.subTest(moduleName=moduleName):
|
||||||
A.B.X.__module__ = moduleName
|
A.B.X.__module__ = moduleName
|
||||||
with test.support.captured_stderr() as stderr, \
|
with test.support.captured_stderr() as stderr, test.support.swap_attr(
|
||||||
test.support.swap_attr(sys, 'unraisablehook',
|
sys, 'unraisablehook', sys.__unraisablehook__
|
||||||
sys.__unraisablehook__):
|
):
|
||||||
expected = self.write_unraisable_exc(
|
expected = self.write_unraisable_exc(
|
||||||
A.B.X(), "msg", "obj");
|
A.B.X(), "msg", "obj"
|
||||||
|
)
|
||||||
report = stderr.getvalue()
|
report = stderr.getvalue()
|
||||||
self.assertIn(A.B.X.__qualname__, report)
|
self.assertIn(A.B.X.__qualname__, report)
|
||||||
if moduleName in ['builtins', '__main__']:
|
if moduleName in ['builtins', '__main__']:
|
||||||
|
|
|
@ -9,6 +9,8 @@ import weakref
|
||||||
|
|
||||||
from test import lock_tests
|
from test import lock_tests
|
||||||
|
|
||||||
|
threading_helper.requires_working_threading(module=True)
|
||||||
|
|
||||||
NUMTASKS = 10
|
NUMTASKS = 10
|
||||||
NUMTRIPS = 3
|
NUMTRIPS = 3
|
||||||
POLL_SLEEP = 0.010 # seconds = 10 ms
|
POLL_SLEEP = 0.010 # seconds = 10 ms
|
||||||
|
|
|
@ -21,6 +21,7 @@ import io
|
||||||
import threading
|
import threading
|
||||||
from traceback import print_exc
|
from traceback import print_exc
|
||||||
|
|
||||||
|
threading_helper.requires_working_threading(module=True)
|
||||||
|
|
||||||
NUM_THREADS = 20
|
NUM_THREADS = 20
|
||||||
FILES_PER_THREAD = 50
|
FILES_PER_THREAD = 50
|
||||||
|
|
|
@ -25,6 +25,7 @@ from unittest import mock
|
||||||
from test import lock_tests
|
from test import lock_tests
|
||||||
from test import support
|
from test import support
|
||||||
|
|
||||||
|
threading_helper.requires_working_threading(module=True)
|
||||||
|
|
||||||
# Between fork() and exec(), only async-safe functions are allowed (issues
|
# Between fork() and exec(), only async-safe functions are allowed (issues
|
||||||
# #12316 and #11870), and fork() from a worker thread is known to trigger
|
# #12316 and #11870), and fork() from a worker thread is known to trigger
|
||||||
|
|
|
@ -12,6 +12,9 @@ import threading
|
||||||
import _threading_local
|
import _threading_local
|
||||||
|
|
||||||
|
|
||||||
|
threading_helper.requires_working_threading(module=True)
|
||||||
|
|
||||||
|
|
||||||
class Weak(object):
|
class Weak(object):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
|
@ -36,6 +36,7 @@ def send_signals():
|
||||||
os.kill(process_pid, signal.SIGUSR2)
|
os.kill(process_pid, signal.SIGUSR2)
|
||||||
signalled_all.release()
|
signalled_all.release()
|
||||||
|
|
||||||
|
@threading_helper.requires_working_threading()
|
||||||
class ThreadSignals(unittest.TestCase):
|
class ThreadSignals(unittest.TestCase):
|
||||||
|
|
||||||
def test_signals(self):
|
def test_signals(self):
|
||||||
|
|
|
@ -14,6 +14,7 @@ import random
|
||||||
from test import support
|
from test import support
|
||||||
from test.support import script_helper, ALWAYS_EQ
|
from test.support import script_helper, ALWAYS_EQ
|
||||||
from test.support import gc_collect
|
from test.support import gc_collect
|
||||||
|
from test.support import threading_helper
|
||||||
|
|
||||||
# Used in ReferencesTestCase.test_ref_created_during_del() .
|
# Used in ReferencesTestCase.test_ref_created_during_del() .
|
||||||
ref_from_del = None
|
ref_from_del = None
|
||||||
|
@ -1851,6 +1852,7 @@ class MappingTestCase(TestBase):
|
||||||
dict = weakref.WeakKeyDictionary()
|
dict = weakref.WeakKeyDictionary()
|
||||||
self.assertRegex(repr(dict), '<WeakKeyDictionary at 0x.*>')
|
self.assertRegex(repr(dict), '<WeakKeyDictionary at 0x.*>')
|
||||||
|
|
||||||
|
@threading_helper.requires_working_threading()
|
||||||
def test_threaded_weak_valued_setdefault(self):
|
def test_threaded_weak_valued_setdefault(self):
|
||||||
d = weakref.WeakValueDictionary()
|
d = weakref.WeakValueDictionary()
|
||||||
with collect_in_thread():
|
with collect_in_thread():
|
||||||
|
@ -1859,6 +1861,7 @@ class MappingTestCase(TestBase):
|
||||||
self.assertIsNot(x, None) # we never put None in there!
|
self.assertIsNot(x, None) # we never put None in there!
|
||||||
del x
|
del x
|
||||||
|
|
||||||
|
@threading_helper.requires_working_threading()
|
||||||
def test_threaded_weak_valued_pop(self):
|
def test_threaded_weak_valued_pop(self):
|
||||||
d = weakref.WeakValueDictionary()
|
d = weakref.WeakValueDictionary()
|
||||||
with collect_in_thread():
|
with collect_in_thread():
|
||||||
|
@ -1867,6 +1870,7 @@ class MappingTestCase(TestBase):
|
||||||
x = d.pop(10, 10)
|
x = d.pop(10, 10)
|
||||||
self.assertIsNot(x, None) # we never put None in there!
|
self.assertIsNot(x, None) # we never put None in there!
|
||||||
|
|
||||||
|
@threading_helper.requires_working_threading()
|
||||||
def test_threaded_weak_valued_consistency(self):
|
def test_threaded_weak_valued_consistency(self):
|
||||||
# Issue #28427: old keys should not remove new values from
|
# Issue #28427: old keys should not remove new values from
|
||||||
# WeakValueDictionary when collecting from another thread.
|
# WeakValueDictionary when collecting from another thread.
|
||||||
|
@ -1940,21 +1944,25 @@ class MappingTestCase(TestBase):
|
||||||
if exc:
|
if exc:
|
||||||
raise exc[0]
|
raise exc[0]
|
||||||
|
|
||||||
|
@threading_helper.requires_working_threading()
|
||||||
def test_threaded_weak_key_dict_copy(self):
|
def test_threaded_weak_key_dict_copy(self):
|
||||||
# Issue #35615: Weakref keys or values getting GC'ed during dict
|
# Issue #35615: Weakref keys or values getting GC'ed during dict
|
||||||
# copying should not result in a crash.
|
# copying should not result in a crash.
|
||||||
self.check_threaded_weak_dict_copy(weakref.WeakKeyDictionary, False)
|
self.check_threaded_weak_dict_copy(weakref.WeakKeyDictionary, False)
|
||||||
|
|
||||||
|
@threading_helper.requires_working_threading()
|
||||||
def test_threaded_weak_key_dict_deepcopy(self):
|
def test_threaded_weak_key_dict_deepcopy(self):
|
||||||
# Issue #35615: Weakref keys or values getting GC'ed during dict
|
# Issue #35615: Weakref keys or values getting GC'ed during dict
|
||||||
# copying should not result in a crash.
|
# copying should not result in a crash.
|
||||||
self.check_threaded_weak_dict_copy(weakref.WeakKeyDictionary, True)
|
self.check_threaded_weak_dict_copy(weakref.WeakKeyDictionary, True)
|
||||||
|
|
||||||
|
@threading_helper.requires_working_threading()
|
||||||
def test_threaded_weak_value_dict_copy(self):
|
def test_threaded_weak_value_dict_copy(self):
|
||||||
# Issue #35615: Weakref keys or values getting GC'ed during dict
|
# Issue #35615: Weakref keys or values getting GC'ed during dict
|
||||||
# copying should not result in a crash.
|
# copying should not result in a crash.
|
||||||
self.check_threaded_weak_dict_copy(weakref.WeakValueDictionary, False)
|
self.check_threaded_weak_dict_copy(weakref.WeakValueDictionary, False)
|
||||||
|
|
||||||
|
@threading_helper.requires_working_threading()
|
||||||
def test_threaded_weak_value_dict_deepcopy(self):
|
def test_threaded_weak_value_dict_deepcopy(self):
|
||||||
# Issue #35615: Weakref keys or values getting GC'ed during dict
|
# Issue #35615: Weakref keys or values getting GC'ed during dict
|
||||||
# copying should not result in a crash.
|
# copying should not result in a crash.
|
||||||
|
|
|
@ -0,0 +1 @@
|
||||||
|
Threading tests are now skipped on WASM targets without pthread support.
|
|
@ -6311,15 +6311,7 @@ esac
|
||||||
|
|
||||||
else
|
else
|
||||||
|
|
||||||
case $ac_sys_system in #(
|
enable_wasm_dynamic_linking=missing
|
||||||
Emscripten) :
|
|
||||||
enable_wasm_dynamic_linking=no ;; #(
|
|
||||||
WASI) :
|
|
||||||
enable_wasm_dynamic_linking=no ;; #(
|
|
||||||
*) :
|
|
||||||
enable_wasm_dynamic_linking=missing
|
|
||||||
;;
|
|
||||||
esac
|
|
||||||
|
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
|
|
@ -1122,11 +1122,7 @@ AC_ARG_ENABLE([wasm-dynamic-linking],
|
||||||
[AC_MSG_ERROR([--enable-wasm-dynamic-linking only applies to Emscripten and WASI])]
|
[AC_MSG_ERROR([--enable-wasm-dynamic-linking only applies to Emscripten and WASI])]
|
||||||
)
|
)
|
||||||
], [
|
], [
|
||||||
AS_CASE([$ac_sys_system],
|
enable_wasm_dynamic_linking=missing
|
||||||
[Emscripten], [enable_wasm_dynamic_linking=no],
|
|
||||||
[WASI], [enable_wasm_dynamic_linking=no],
|
|
||||||
[enable_wasm_dynamic_linking=missing]
|
|
||||||
)
|
|
||||||
])
|
])
|
||||||
AC_MSG_RESULT([$enable_wasm_dynamic_linking])
|
AC_MSG_RESULT([$enable_wasm_dynamic_linking])
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue