Update threading lib and tests from CPython 3.12.0a0 (#4156)

* Update threading.py from CPython v3.12.0a0

* Update test_threading.py from CPython v3.12.0a0

* mark failing tests

---------

Co-authored-by: Jeong YunWon <jeong@youknowone.org>
This commit is contained in:
Gyubong LeeandJeong YunWon authored and GitHub committed 2026-01-05 08:01:00 +09:00
1 parent 6cc103bad3
commit ce5e1bd455
2 files changed
+117 -27

No files matched your search

+106 -27
View File
@@ -3,7 +3,7 @@ Tests for the threading module.
"""
import test.support
from test.support import threading_helper
from test.support import threading_helper, requires_subprocess
from test.support import verbose, cpython_only, os_helper
from test.support.import_helper import import_module
from test.support.script_helper import assert_python_ok, assert_python_failure
@@ -25,6 +25,7 @@ from unittest import mock
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
@@ -32,9 +33,6 @@ from test import support
# on platforms known to behave badly.
platforms_to_skip = ('netbsd5', 'hp-ux11')
# Is Python built with Py_DEBUG macro defined?
Py_DEBUG = hasattr(sys, 'gettotalrefcount')
def restore_default_excepthook(testcase):
testcase.addCleanup(setattr, threading, 'excepthook', threading.excepthook)
@@ -123,6 +121,33 @@ class ThreadTests(BaseTestCase):
thread = threading.Thread(target=func)
self.assertEqual(thread.name, "Thread-5 (func)")
def test_args_argument(self):
# bpo-45735: Using list or tuple as *args* in constructor could
# achieve the same effect.
num_list = [1]
num_tuple = (1,)
str_list = ["str"]
str_tuple = ("str",)
list_in_tuple = ([1],)
tuple_in_list = [(1,)]
test_cases = (
(num_list, lambda arg: self.assertEqual(arg, 1)),
(num_tuple, lambda arg: self.assertEqual(arg, 1)),
(str_list, lambda arg: self.assertEqual(arg, "str")),
(str_tuple, lambda arg: self.assertEqual(arg, "str")),
(list_in_tuple, lambda arg: self.assertEqual(arg, [1])),
(tuple_in_list, lambda arg: self.assertEqual(arg, (1,)))
)
for args, target in test_cases:
with self.subTest(target=target, args=args):
t = threading.Thread(target=target, args=args)
t.start()
t.join()
@cpython_only
def test_disallow_instantiation(self):
# Ensure that the type disallows instantiation (bpo-43916)
@@ -509,8 +534,7 @@ class ThreadTests(BaseTestCase):
t = threading.Thread(daemon=True)
self.assertTrue(t.daemon)
@unittest.skipUnless(hasattr(threading.Lock(), '_at_fork_reinit'), 'TODO: RUSTPYTHON, exit_handler needs lock._at_fork_reinit')
@unittest.skipUnless(hasattr(os, 'fork'), 'needs os.fork()')
@support.requires_fork()
def test_fork_at_exit(self):
# bpo-42350: Calling os.fork() after threading._shutdown() must
# not log an error.
@@ -538,7 +562,7 @@ class ThreadTests(BaseTestCase):
self.assertEqual(out, b'')
self.assertEqual(err.rstrip(), b'child process ok')
@unittest.skipUnless(hasattr(os, 'fork'), 'test needs fork()')
@support.requires_fork()
def test_dummy_thread_after_fork(self):
# Issue #14308: a dummy thread in the active list doesn't mess up
# the after-fork mechanism.
@@ -565,8 +589,7 @@ class ThreadTests(BaseTestCase):
self.assertEqual(out, b'')
self.assertEqual(err, b'')
@unittest.skipUnless(hasattr(sys, 'getswitchinterval'), "TODO: RUSTPYTHON, needs sys.getswitchinterval()")
@unittest.skipUnless(hasattr(os, 'fork'), "needs os.fork()")
@support.requires_fork()
def test_is_alive_after_fork(self):
# Try hard to trigger #18418: is_alive() could sometimes be True on
# threads that vanished after a fork.
@@ -600,7 +623,7 @@ class ThreadTests(BaseTestCase):
th.start()
th.join()
@unittest.skipUnless(hasattr(os, 'fork'), "test needs os.fork()")
@support.requires_fork()
@unittest.skipUnless(hasattr(os, 'waitpid'), "test needs os.waitpid()")
def test_main_thread_after_fork(self):
code = """if 1:
@@ -622,7 +645,7 @@ class ThreadTests(BaseTestCase):
self.assertEqual(data, "MainThread\nTrue\nTrue\n")
@unittest.skipIf(sys.platform in platforms_to_skip, "due to known OS bug")
@unittest.skipUnless(hasattr(os, 'fork'), "test needs os.fork()")
@support.requires_fork()
@unittest.skipUnless(hasattr(os, 'waitpid'), "test needs os.waitpid()")
@unittest.skipIf(os.name != 'posix', "test needs POSIX semantics")
def test_main_thread_after_fork_from_nonmain_thread(self):
@@ -837,6 +860,7 @@ class ThreadTests(BaseTestCase):
callback()
finally:
sys.settrace(old_trace)
threading.settrace(old_trace)
def test_gettrace(self):
def noop_trace(frame, event, arg):
@@ -850,6 +874,37 @@ class ThreadTests(BaseTestCase):
finally:
threading.settrace(old_trace)
# TODO: RUSTPYTHON
@unittest.expectedFailure
def test_gettrace_all_threads(self):
def fn(*args): pass
old_trace = threading.gettrace()
first_check = threading.Event()
second_check = threading.Event()
trace_funcs = []
def checker():
trace_funcs.append(sys.gettrace())
first_check.set()
second_check.wait()
trace_funcs.append(sys.gettrace())
try:
t = threading.Thread(target=checker)
t.start()
first_check.wait()
threading.settrace_all_threads(fn)
second_check.set()
t.join()
self.assertEqual(trace_funcs, [None, fn])
self.assertEqual(threading.gettrace(), fn)
self.assertEqual(sys.gettrace(), fn)
finally:
threading.settrace_all_threads(old_trace)
self.assertEqual(threading.gettrace(), old_trace)
self.assertEqual(sys.gettrace(), old_trace)
def test_getprofile(self):
def fn(*args): pass
old_profile = threading.getprofile()
@@ -859,6 +914,37 @@ class ThreadTests(BaseTestCase):
finally:
threading.setprofile(old_profile)
# TODO: RUSTPYTHON
@unittest.expectedFailure
def test_getprofile_all_threads(self):
def fn(*args): pass
old_profile = threading.getprofile()
first_check = threading.Event()
second_check = threading.Event()
profile_funcs = []
def checker():
profile_funcs.append(sys.getprofile())
first_check.set()
second_check.wait()
profile_funcs.append(sys.getprofile())
try:
t = threading.Thread(target=checker)
t.start()
first_check.wait()
threading.setprofile_all_threads(fn)
second_check.set()
t.join()
self.assertEqual(profile_funcs, [None, fn])
self.assertEqual(threading.getprofile(), fn)
self.assertEqual(sys.getprofile(), fn)
finally:
threading.setprofile_all_threads(old_profile)
self.assertEqual(threading.getprofile(), old_profile)
self.assertEqual(sys.getprofile(), old_profile)
@cpython_only
def test_shutdown_locks(self):
for daemon in (False, True):
@@ -929,16 +1015,6 @@ class ThreadTests(BaseTestCase):
threading.Thread(target=noop).start()
# Thread.join() is not called
@unittest.skipUnless(Py_DEBUG, 'need debug build (Py_DEBUG)')
def test_debug_deprecation(self):
# bpo-44584: The PYTHONTHREADDEBUG environment variable is deprecated
rc, out, err = assert_python_ok("-Wdefault", "-c", "pass",
PYTHONTHREADDEBUG="1")
msg = (b'DeprecationWarning: The threading debug '
b'(PYTHONTHREADDEBUG environment variable) '
b'is deprecated and will be removed in Python 3.12')
self.assertIn(msg, err)
def test_import_from_another_thread(self):
# bpo-1596321: If the threading module is first import from a thread
# different than the main thread, threading._shutdown() must handle
@@ -1006,7 +1082,7 @@ class ThreadJoinOnShutdown(BaseTestCase):
"""
self._run_and_join(script)
@unittest.skipUnless(hasattr(os, 'fork'), "needs os.fork()")
@support.requires_fork()
@unittest.skipIf(sys.platform in platforms_to_skip, "due to known OS bug")
# TODO: RUSTPYTHON need to fix test_1_join_on_shutdown then this might work
@unittest.expectedFailure
@@ -1029,7 +1105,7 @@ class ThreadJoinOnShutdown(BaseTestCase):
"""
self._run_and_join(script)
@unittest.skipUnless(hasattr(os, 'fork'), "needs os.fork()")
@support.requires_fork()
@unittest.skipIf(sys.platform in platforms_to_skip, "due to known OS bug")
@unittest.skip("TODO: RUSTPYTHON, flaky test")
def test_3_join_in_forked_from_thread(self):
@@ -1075,8 +1151,9 @@ class ThreadJoinOnShutdown(BaseTestCase):
def random_io():
'''Loop for a while sleeping random tiny amounts and doing some I/O.'''
import test.test_threading as mod
while True:
with open(os.__file__, 'rb') as in_f:
with open(mod.__file__, 'rb') as in_f:
stuff = in_f.read(200)
with open(os.devnull, 'wb') as null_f:
null_f.write(stuff)
@@ -1100,7 +1177,7 @@ class ThreadJoinOnShutdown(BaseTestCase):
rc, out, err = assert_python_ok('-c', script)
self.assertFalse(err)
@unittest.skipUnless(hasattr(os, 'fork'), "needs os.fork()")
@support.requires_fork()
@unittest.skipIf(sys.platform in platforms_to_skip, "due to known OS bug")
def test_reinit_tls_after_fork(self):
# Issue #13817: fork() would deadlock in a multithreaded program with
@@ -1124,8 +1201,9 @@ class ThreadJoinOnShutdown(BaseTestCase):
for t in threads:
t.join()
@unittest.skipUnless(hasattr(sys, '_current_frames'), "TODO: RUSTPYTHON, needs sys._current_frames()")
@unittest.skipUnless(hasattr(os, 'fork'), "needs os.fork()")
@support.requires_fork()
# TODO: RUSTPYTHON
@unittest.expectedFailure
def test_clear_threads_states_after_fork(self):
# Issue #17094: check that threads states are cleared after fork()
@@ -1280,6 +1358,7 @@ class ThreadingExceptionTests(BaseTestCase):
self.assertRaises(RuntimeError, lock.release)
@unittest.skip("TODO: RUSTPYTHON, flaky test")
@requires_subprocess()
def test_recursion_limit(self):
# Issue 9670
# test that excessive recursion within a non-main thread causes
+11
View File
@@ -79,6 +79,17 @@ def settrace(func):
global _trace_hook
_trace_hook = func
# TODO: RUSTPYTHON
def settrace_all_threads(func):
"""Set a trace function for all threads started from the threading module
and all Python threads that are currently executing.
The func will be passed to sys.settrace() for each thread, before its run()
method is called.
"""
settrace(func)
_sys._settraceallthreads(func)
def gettrace():
"""Get the trace function as set by threading.settrace()."""
return _trace_hook