Update 16 stdlib test modules from CPython 3.15 (#9411)

* Update 16 stdlib test modules from CPython 3.15

Sync with scripts/update_lib migrate from CPython d220409a13b77de7a6c30abe16ea90db01528edc, preserving existing RustPython markers.

Assisted-by: Codex:GPT-6.1

* Limit SEND completion tracing to generators and coroutines

Match CPython INSTRUMENTED_END_SEND receiver semantics: other awaitables returning values must not synthesize caller StopIteration trace events. Preserve actual exceptions, builtin generator/coroutine completion and trampoline paths.

Assisted-by: Codex:GPT-6.1

---------

Co-authored-by: Codex <codex@openai.com>
This commit is contained in:
youknowdotandCodex authored and GitHub committed 2026-10-28 17:29:13 +09:00
1 parent 058bebf0f0
commit dc8ea56566
17 files changed
+178 -41

No files matched your search

+9 -14
View File
@@ -1835,20 +1835,6 @@ class AsyncGenAsyncioTest(unittest.TestCase):
res = self.loop.run_until_complete(run())
self.assertEqual(res, [i * 2 for i in range(1, 10)])
def test_async_gen_expression_incorrect(self):
async def ag():
yield 42
async def run(arg):
(x async for x in arg)
err_msg_async = "'async for' requires an object with " \
"__aiter__ method, got .*"
self.loop.run_until_complete(run(ag()))
with self.assertRaisesRegex(TypeError, err_msg_async):
self.loop.run_until_complete(run(None))
def test_asyncgen_nonstarted_hooks_are_cancellable(self):
# See https://bugs.python.org/issue38013
messages = []
@@ -2035,6 +2021,15 @@ class TestUnawaitedWarnings(unittest.TestCase):
g.athrow(RuntimeError)
gc_collect()
def test_athrow_throws_immediately(self):
async def gen():
yield 1
g = gen()
msg = "athrow expected at least 1 argument, got 0"
with self.assertRaisesRegex(TypeError, msg):
g.athrow()
def test_aclose(self):
async def gen():
yield 1
+43
View File
@@ -1,5 +1,6 @@
import socket
import asyncio
import select
import sys
import unittest
@@ -257,6 +258,38 @@ class BaseSockTestsMixin:
self.skipTest(skip_reason)
async def _basetest_sock_accept_racing(self, listener, sock):
# gh-153761: cancelling sock_accept() must not let a scheduled
# _sock_accept run on the cancelled future.
listener.setblocking(False)
listener.bind(('127.0.0.1', 0))
listener.listen(1)
addr = listener.getsockname()
errors = []
self.loop.set_exception_handler(lambda loop, ctx: errors.append(ctx))
task = asyncio.create_task(self.loop.sock_accept(listener))
await asyncio.sleep(0)
sock.connect(addr)
select.select([listener], [], [], support.SHORT_TIMEOUT)
self.loop.call_soon(task.cancel)
await asyncio.sleep(0)
await asyncio.sleep(0)
with self.assertRaises(asyncio.CancelledError):
await task
self.assertEqual(errors, [])
# The pending connection must survive
conn, conn_addr = await self.loop.sock_accept(listener)
with conn:
self.assertEqual(conn_addr, sock.getsockname())
sock.setblocking(False)
await self.loop.sock_sendall(conn, b'ping')
self.assertEqual(await self.loop.sock_recv(sock, 4), b'ping')
def test_sock_client_racing(self):
with test_utils.run_test_server() as httpd:
sock = socket.socket()
@@ -280,6 +313,16 @@ class BaseSockTestsMixin:
self.loop.run_until_complete(asyncio.wait_for(
self._basetest_sock_connect_racing(listener, sock), 10))
def test_sock_accept_racing(self):
if sys.platform == 'win32':
if isinstance(self.loop, asyncio.ProactorEventLoop):
raise unittest.SkipTest('Not relevant to ProactorEventLoop')
listener = socket.socket()
sock = socket.socket()
with listener, sock:
self.loop.run_until_complete(asyncio.wait_for(
self._basetest_sock_accept_racing(listener, sock), 10))
async def _basetest_huge_content(self, address):
sock = socket.socket()
sock.setblocking(False)
+1
View File
@@ -516,6 +516,7 @@ class CMathTests(ComplexesAreIdenticalMixin, unittest.TestCase):
self.assertFalse(cmath.isinf(1j))
self.assertFalse(cmath.isinf(NAN))
self.assertTrue(cmath.isinf(INF))
self.assertTrue(cmath.isinf(-INF))
self.assertTrue(cmath.isinf(complex(INF, 0)))
self.assertTrue(cmath.isinf(complex(0, INF)))
self.assertTrue(cmath.isinf(complex(INF, INF)))
+25
View File
@@ -1282,6 +1282,31 @@ class HamtTest(unittest.TestCase):
self.assertIsNone(ref())
def test_hamt_gc_3(self):
# gh-154535: the iterators must be tracked by the GC, otherwise a
# cycle running through one is never collected and the HAMT it
# holds -- and everything in it -- leaks.
A = HashKey(100, 'A')
container = []
h = hamt()
h = h.set(A, container)
hi = h.items()
self.assertTrue(gc.is_tracked(hi))
# Close the cycle: hi -> h -> container -> hi.
container.append(hi)
ref = weakref.ref(h)
del h, hi, container
gc.collect()
gc.collect()
gc.collect()
self.assertIsNone(ref())
def test_hamt_in_1(self):
A = HashKey(100, 'A')
AA = HashKey(100, 'A')
+10
View File
@@ -2,6 +2,7 @@
# Initial tests are copied as is from "test_poll.py"
import errno
import os
import random
import select
@@ -112,6 +113,15 @@ class DevPollTests(unittest.TestCase):
self.assertRaises(ValueError, devpoll.register, fd, select.POLLIN)
self.assertRaises(ValueError, devpoll.unregister, fd)
def test_close_error(self):
# gh-146205: close() should raise OSError if underlying fd is invalid
devpoll = select.devpoll()
fd = devpoll.fileno()
os.close(fd)
with self.assertRaises(OSError) as cm:
devpoll.close()
self.assertEqual(cm.exception.errno, errno.EBADF)
def test_fd_non_inheritable(self):
devpoll = select.devpoll()
self.addCleanup(devpoll.close)
+14 -2
View File
@@ -25,6 +25,7 @@ import errno
import os
import select
import socket
import sys
import time
import unittest
from test import support
@@ -52,12 +53,11 @@ class TestEPoll(unittest.TestCase):
def _connected_pair(self):
client = socket.socket()
client.setblocking(False)
# The connection is either established immediately or in progress.
try:
client.connect(('127.0.0.1', self.serverSocket.getsockname()[1]))
except OSError as e:
self.assertEqual(e.args[0], errno.EINPROGRESS)
else:
raise AssertionError("Connect should have raised EINPROGRESS")
server, addr = self.serverSocket.accept()
self.connections.extend((client, server))
@@ -218,6 +218,9 @@ class TestEPoll(unittest.TestCase):
self.assertRaises(ValueError, select.epoll().register, -1,
select.EPOLLIN)
@unittest.skipIf(sys.platform.startswith('sunos'),
'unregistering a closed file descriptor succeeds '
'on Solaris')
def test_unregister_closed(self):
server, client = self._connected_pair()
fd = server.fileno()
@@ -259,6 +262,15 @@ class TestEPoll(unittest.TestCase):
self.assertRaises(ValueError, epoll.register, fd, select.EPOLLIN)
self.assertRaises(ValueError, epoll.unregister, fd)
def test_close_error(self):
# gh-146205: close() should raise OSError if underlying fd is invalid
epoll = select.epoll()
fd = epoll.fileno()
os.close(fd)
with self.assertRaises(OSError) as cm:
epoll.close()
self.assertEqual(cm.exception.errno, errno.EBADF)
def test_fd_non_inheritable(self):
epoll = select.epoll()
self.addCleanup(epoll.close)
+3 -1
View File
@@ -11,6 +11,7 @@ import unittest
from test.fork_wait import ForkWait
from test import support
from test.support import warnings_helper
# Skip test if fork does not exist.
@@ -19,6 +20,7 @@ if not support.has_fork_support:
class ForkTest(ForkWait):
@warnings_helper.ignore_fork_in_thread_deprecation_warnings()
def test_threaded_import_lock_fork(self):
"""Check fork() in main thread works while a subthread is doing an import"""
import_started = threading.Event()
@@ -61,7 +63,7 @@ class ForkTest(ForkWait):
except OSError:
pass
@warnings_helper.ignore_fork_in_thread_deprecation_warnings()
def test_nested_import_lock_fork(self):
"""Check fork() in main thread works while the main thread is doing an import"""
exitcode = 42
+26
View File
@@ -9,6 +9,8 @@ from test import support
import time
import unittest
from test.support import warnings_helper
if not hasattr(select, "kqueue"):
raise unittest.SkipTest("test works only on BSD")
@@ -21,6 +23,20 @@ class TestKQueue(unittest.TestCase):
self.assertTrue(kq.closed)
self.assertRaises(ValueError, kq.fileno)
def test_control_overflowing_timeout(self):
# gh-154836: out-of-range timeouts must raise OverflowError,
# not a (misleading) TypeError, like select(), poll() and
# epoll() do.
kq = select.kqueue()
self.addCleanup(kq.close)
for timeout in (1e300, float('inf'), 2**200):
with self.subTest(timeout=timeout):
with self.assertRaises(OverflowError):
kq.control(None, 0, timeout)
# Non-numbers still raise TypeError.
with self.assertRaises(TypeError):
kq.control(None, 0, "0.1")
def test_create_event(self):
from operator import lt, le, gt, ge
@@ -252,11 +268,21 @@ class TestKQueue(unittest.TestCase):
# operations must fail with ValueError("I/O operation on closed ...")
self.assertRaises(ValueError, kqueue.control, None, 4)
def test_close_error(self):
# gh-146205: close() should raise OSError if underlying fd is invalid
kqueue = select.kqueue()
fd = kqueue.fileno()
os.close(fd)
with self.assertRaises(OSError) as cm:
kqueue.close()
self.assertEqual(cm.exception.errno, errno.EBADF)
def test_fd_non_inheritable(self):
kqueue = select.kqueue()
self.addCleanup(kqueue.close)
self.assertEqual(os.get_inheritable(kqueue.fileno()), False)
@warnings_helper.ignore_fork_in_thread_deprecation_warnings()
@support.requires_fork()
def test_fork(self):
# gh-110395: kqueue objects must be closed after fork
+10 -2
View File
@@ -173,17 +173,25 @@ class PollTests(unittest.TestCase):
@cpython_only
def test_poll_c_limits(self):
try:
import _testcapi
from _testcapi import USHRT_MAX, INT_MAX, UINT_MAX
HAVE_PPOLL = getattr(_testcapi, 'HAVE_PPOLL', False)
except ImportError:
raise unittest.SkipTest("requires _testcapi")
pollster = select.poll()
pollster.register(1)
# Issues #15989, #17919
self.assertRaises(OverflowError, pollster.register, 0, USHRT_MAX + 1)
self.assertRaises(OverflowError, pollster.modify, 1, USHRT_MAX + 1)
self.assertRaises(OverflowError, pollster.poll, INT_MAX + 1)
self.assertRaises(OverflowError, pollster.poll, UINT_MAX + 1)
if HAVE_PPOLL:
MS_TO_NS = 1_000_000
tmax = _testcapi.INT64_MAX // MS_TO_NS
self.assertRaises(OverflowError, pollster.poll, tmax + 1)
else:
self.assertRaises(OverflowError, pollster.poll, INT_MAX + 1)
self.assertRaises(OverflowError, pollster.poll, UINT_MAX + 1)
@threading_helper.reap_threads
def test_threaded_poll(self):
+5 -3
View File
@@ -1,6 +1,6 @@
import unittest
from test.support import (
is_android, is_apple_mobile, is_wasm32, reap_children, verbose
is_android, is_apple_mobile, is_wasm32, reap_children, verbose, warnings_helper
)
from test.support.import_helper import import_module
@@ -19,7 +19,6 @@ import select
import signal
import socket
import io # readline
import warnings
TEST_STRING_1 = b"I wish to buy a fish license.\n"
TEST_STRING_2 = b"For my pet fish, Eric.\n"
@@ -194,6 +193,7 @@ class PtyTest(unittest.TestCase):
s2 = _readline(master_fd)
self.assertEqual(b'For my pet fish, Eric.\n', normalize_output(s2))
@warnings_helper.ignore_fork_in_thread_deprecation_warnings()
def test_fork(self):
debug("calling pty.fork()")
pid, master_fd = pty.fork()
@@ -229,6 +229,7 @@ class PtyTest(unittest.TestCase):
os._exit(2)
os._exit(4)
else:
self.assertFalse(os.get_inheritable(master_fd))
debug("Waiting for child (%d) to finish." % pid)
# In verbose mode, we have to consume the debug output from the
# child or the child will block, causing this test to hang in the
@@ -295,6 +296,7 @@ class PtyTest(unittest.TestCase):
self.assertEqual(data, b"")
@warnings_helper.ignore_fork_in_thread_deprecation_warnings()
def test_spawn_doesnt_hang(self):
# gh-140482: Do the test in a pty.fork() child to avoid messing
# with the interactive test runner's terminal settings.
@@ -314,7 +316,7 @@ class PtyTest(unittest.TestCase):
(pid, status) = os.waitpid(pid, 0)
self.assertEqual(status, 0)
self.assertEqual(bytes(buf), b"hi there\r\n")
self.assertEqual(buf.take_bytes(), b"hi there\r\n")
finally:
os.close(fd)
+5 -2
View File
@@ -695,8 +695,11 @@ class LongReprTest(unittest.TestCase):
source_path_len += 2 * (len(self.longname) + 1)
# a path separator + `module_name` + ".py"
source_path_len += len(module_name) + 1 + len(".py")
cached_path_len = (source_path_len +
len(importlib.util.cache_from_source("x.py")) - len("x.py"))
try:
cached_path_len = (source_path_len +
len(importlib.util.cache_from_source("x.py")) - len("x.py"))
except NotImplementedError:
cached_path_len = source_path_len
if os.name == 'nt' and cached_path_len >= 258:
# Under Windows, the max path len is 260 including C's terminating
# NUL character.
+4 -4
View File
@@ -1185,9 +1185,9 @@ class SMTPSimTests(unittest.TestCase):
self.assertEqual(resp, (235, b'Authentication Succeeded'))
smtp.close()
@mock.patch("hmac.HMAC")
@hashlib_helper.block_algorithm('md5')
@mock.patch("smtplib._have_cram_md5_support", False)
def testAUTH_CRAM_MD5_blocked(self, hmac_constructor):
def testAUTH_CRAM_MD5_blocked(self):
# CRAM-MD5 is the only "known" method by the server,
# but it is not supported by the client. In particular,
# no challenge will ever be sent.
@@ -1198,8 +1198,8 @@ class SMTPSimTests(unittest.TestCase):
msg = re.escape("No suitable authentication method found.")
with self.assertRaisesRegex(smtplib.SMTPException, msg):
smtp.login(sim_auth[0], sim_auth[1])
hmac_constructor.assert_not_called() # call has been bypassed
@hashlib_helper.block_algorithm('md5')
@mock.patch("smtplib._have_cram_md5_support", False)
def testAUTH_CRAM_MD5_blocked_and_fallback(self):
# Test that PLAIN is tried after CRAM-MD5 failed
@@ -1215,7 +1215,7 @@ class SMTPSimTests(unittest.TestCase):
):
resp = smtp.login(sim_auth[0], sim_auth[1])
smtp_auth_plain.assert_called_once()
smtp_auth_cram_md5.assert_not_called() # no call to HMAC constructor
smtp_auth_cram_md5.assert_not_called()
self.assertEqual(resp, (235, b'Authentication Succeeded'))
@hashlib_helper.requires_hashdigest('md5', openssl=True)
+2 -6
View File
@@ -360,6 +360,8 @@ class TraceTestCase(unittest.TestCase):
# Disable gc collection when tracing, otherwise the
# deallocators may be traced as well.
def setUp(self):
if os.environ.get('PYTHON_UOPS_OPTIMIZE') == '0':
self.skipTest("Line tracing behavior differs when JIT optimizer is disabled")
self.using_gc = gc.isenabled()
gc.disable()
self.addCleanup(sys.settrace, sys.gettrace())
@@ -664,21 +666,18 @@ class TraceTestCase(unittest.TestCase):
(-2, 'line'),
(-1, 'line'),
(-1, 'return'),
(1, 'exception'),
(2, 'line'),
(1, 'line'),
(-1, 'call'),
(-2, 'line'),
(-1, 'line'),
(-1, 'return'),
(1, 'exception'),
(2, 'line'),
(1, 'line'),
(-1, 'call'),
(-2, 'line'),
(-1, 'line'),
(-1, 'return'),
(1, 'exception'),
(2, 'line'),
(1, 'line'),
(-1, 'call'),
@@ -1799,9 +1798,6 @@ class SkipLineEventsTraceTestCase(TraceTestCase):
def make_tracer():
return Tracer(trace_line_events=False)
def test_12_tighterloop(self):
TraceTestCase.test_12_tighterloop(self)
@support.cpython_only
class TraceOpcodesTestCase(TraceTestCase):
+4 -1
View File
@@ -104,7 +104,7 @@ class TestFunctions(unittest.TestCase):
try:
termios.tcsendbreak(self.fd, 1)
except termios.error as exc:
if exc.args[0] == errno.ENOTTY and sys.platform.startswith(('freebsd', "netbsd")):
if exc.args[0] == errno.ENOTTY and sys.platform.startswith(('freebsd', 'netbsd', 'openbsd', 'dragonfly')):
self.skipTest('termios.tcsendbreak() is not supported '
'with pseudo-terminals (?) on this platform')
raise
@@ -180,6 +180,9 @@ class TestFunctions(unittest.TestCase):
termios.tcflow(self.fd, termios.TCOON)
termios.tcflow(self.fd, termios.TCIOFF)
termios.tcflow(self.fd, termios.TCION)
# Discard the transmitted STOP and START characters,
# otherwise closing the pseudo-terminal can block.
termios.tcflush(self.fd, termios.TCOFLUSH)
@support.skip_android_selinux('tcflow')
def test_tcflow_errors(self):
+3 -3
View File
@@ -114,10 +114,10 @@ class UnicodeNamesTest(unittest.TestCase):
@unittest.expectedFailure # TODO: RUSTPYTHON; SyntaxError: got unexpected unicode
def test_tangut_ideographs(self):
self.checkletter("TANGUT IDEOGRAPH-17000", "\U00017000")
self.checkletter("TANGUT IDEOGRAPH-187F7", "\U000187f7")
self.checkletter("TANGUT IDEOGRAPH-187FF", "\U000187ff")
self.checkletter("TANGUT IDEOGRAPH-18D00", "\U00018D00")
self.checkletter("TANGUT IDEOGRAPH-18D08", "\U00018d08")
self.checkletter("tangut ideograph-18d08", "\U00018d08")
self.checkletter("TANGUT IDEOGRAPH-18D1E", "\U00018d1e")
self.checkletter("tangut ideograph-18d1e", "\U00018d1e")
def test_egyptian_hieroglyphs(self):
self.checkletter("EGYPTIAN HIEROGLYPH-13460", "\U00013460")
+2 -1
View File
@@ -12,7 +12,6 @@ import threading
from test.support.import_helper import import_module
from test.support import threading_helper
from test.support import _1M
from test.support import Py_GIL_DISABLED
_zstd = import_module("_zstd")
zstd = import_module("compression.zstd")
@@ -2374,6 +2373,8 @@ class FileTestCase(unittest.TestCase):
f.read(100)
with self.assertRaises(io.UnsupportedOperation):
f.seek(100)
with self.assertRaises(io.UnsupportedOperation):
next(iter(f))
self.assertEqual(f.closed, True)
with self.assertRaises(ValueError):
f.readable()
+12 -2
View File
@@ -6122,7 +6122,12 @@ impl ExecutingFrame<'_> {
Ok(None)
}
PyIterReturn::StopIteration(value) => {
if vm.use_tracing.get() && self.trace_is_set(vm) {
// CPython's INSTRUMENTED_END_SEND synthesizes this event
// only for generator/coroutine receivers, not other awaitables.
if vm.use_tracing.get()
&& self.trace_is_set(vm)
&& self.builtin_coro(receiver).is_some()
{
let stop_exc = vm.new_stop_iteration(value.clone());
self.fire_exception_trace(&stop_exc, vm)?;
}
@@ -6190,7 +6195,12 @@ impl ExecutingFrame<'_> {
Ok(None)
}
PyIterReturn::StopIteration(value) => {
if vm.use_tracing.get() && self.trace_is_set(vm) {
// CPython's INSTRUMENTED_END_SEND synthesizes this event
// only for generator/coroutine receivers, not other awaitables.
if vm.use_tracing.get()
&& self.trace_is_set(vm)
&& self.builtin_coro(receiver).is_some()
{
let stop_exc = vm.new_stop_iteration(value.clone());
self.fire_exception_trace(&stop_exc, vm)?;
}