Skip to content

Commit efd3a4e

Browse files
authored
Update Lib with changed files in 3.13.8 (RustPython#6186)
* Update changed files from 3.13.7 -> 3.13.8 * Reapply some patches * Reaaply patches to `test_bytes.py` * fix test markers in `test_exceptions.py` * Patch `test_posix.py` * Patched `test_{pyexpat,site,sysconfig}.py` * Patched `test_typing.py` * Patch failing tests in `test_typing.py` * Update `seq_tests` from 3.13.8 * Mark failing tests in `test_genericalias.py` * mark failing tests in `test_pyexpat.py` * Mark failing tests in `test_posix.py` * reapply patch * mark failing tests * skip flaky test
2 parents 5d9e623 + a50cc9b commit efd3a4e

23 files changed

+1136
-399
lines changed

Lib/_android_support.py

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -29,15 +29,19 @@ def init_streams(android_log_write, stdout_prio, stderr_prio):
2929

3030
global logcat
3131
logcat = Logcat(android_log_write)
32-
33-
sys.stdout = TextLogStream(
34-
stdout_prio, "python.stdout", sys.stdout.fileno())
35-
sys.stderr = TextLogStream(
36-
stderr_prio, "python.stderr", sys.stderr.fileno())
32+
sys.stdout = TextLogStream(stdout_prio, "python.stdout", sys.stdout)
33+
sys.stderr = TextLogStream(stderr_prio, "python.stderr", sys.stderr)
3734

3835

3936
class TextLogStream(io.TextIOWrapper):
40-
def __init__(self, prio, tag, fileno=None, **kwargs):
37+
def __init__(self, prio, tag, original=None, **kwargs):
38+
# Respect the -u option.
39+
if original:
40+
kwargs.setdefault("write_through", original.write_through)
41+
fileno = original.fileno()
42+
else:
43+
fileno = None
44+
4145
# The default is surrogateescape for stdout and backslashreplace for
4246
# stderr, but in the context of an Android log, readability is more
4347
# important than reversibility.

Lib/_collections_abc.py

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -512,7 +512,7 @@ def __getitem__(self, item):
512512
new_args = (t_args, t_result)
513513
return _CallableGenericAlias(Callable, tuple(new_args))
514514

515-
# TODO: RUSTPYTHON patch for common call
515+
# TODO: RUSTPYTHON; patch for common call
516516
def __or__(self, other):
517517
super().__or__(other)
518518

@@ -1087,7 +1087,7 @@ def __new__(cls, name, bases, namespace, **kwargs):
10871087

10881088
warnings._deprecated(
10891089
"collections.abc.ByteString",
1090-
remove=(3, 14),
1090+
remove=(3, 17),
10911091
)
10921092
return super().__new__(cls, name, bases, namespace, **kwargs)
10931093

@@ -1096,14 +1096,18 @@ def __instancecheck__(cls, instance):
10961096

10971097
warnings._deprecated(
10981098
"collections.abc.ByteString",
1099-
remove=(3, 14),
1099+
remove=(3, 17),
11001100
)
11011101
return super().__instancecheck__(instance)
11021102

11031103
class ByteString(Sequence, metaclass=_DeprecateByteStringMeta):
1104-
"""This unifies bytes and bytearray.
1104+
"""Deprecated ABC serving as a common supertype of ``bytes`` and ``bytearray``.
11051105
1106-
XXX Should add all their methods.
1106+
This ABC is scheduled for removal in Python 3.17.
1107+
Use ``isinstance(obj, collections.abc.Buffer)`` to test if ``obj``
1108+
implements the buffer protocol at runtime. For use in type annotations,
1109+
either use ``Buffer`` or a union that explicitly specifies the types your
1110+
code supports (e.g., ``bytes | bytearray | memoryview``).
11071111
"""
11081112

11091113
__slots__ = ()

Lib/html/parser.py

Lines changed: 21 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -146,6 +146,7 @@ def reset(self):
146146
self.lasttag = '???'
147147
self.interesting = interesting_normal
148148
self.cdata_elem = None
149+
self._support_cdata = True
149150
self._escapable = True
150151
super().reset()
151152

@@ -183,6 +184,19 @@ def clear_cdata_mode(self):
183184
self.cdata_elem = None
184185
self._escapable = True
185186

187+
def _set_support_cdata(self, flag=True):
188+
"""Enable or disable support of the CDATA sections.
189+
If enabled, "<[CDATA[" starts a CDATA section which ends with "]]>".
190+
If disabled, "<[CDATA[" starts a bogus comments which ends with ">".
191+
192+
This method is not called by default. Its purpose is to be called
193+
in custom handle_starttag() and handle_endtag() methods, with
194+
value that depends on the adjusted current node.
195+
See https://html.spec.whatwg.org/multipage/parsing.html#markup-declaration-open-state
196+
for details.
197+
"""
198+
self._support_cdata = flag
199+
186200
# Internal -- handle data as far as reasonable. May leave state
187201
# and data to be processed by a subsequent call. If 'end' is
188202
# true, force handling all data as if followed by EOF marker.
@@ -257,7 +271,7 @@ def goahead(self, end):
257271
j -= len(suffix)
258272
break
259273
self.handle_comment(rawdata[i+4:j])
260-
elif startswith("<![CDATA[", i):
274+
elif startswith("<![CDATA[", i) and self._support_cdata:
261275
self.unknown_decl(rawdata[i+3:])
262276
elif rawdata[i:i+9].lower() == '<!doctype':
263277
self.handle_decl(rawdata[i+2:])
@@ -333,8 +347,12 @@ def parse_html_declaration(self, i):
333347
if rawdata[i:i+4] == '<!--':
334348
# this case is actually already handled in goahead()
335349
return self.parse_comment(i)
336-
elif rawdata[i:i+9] == '<![CDATA[':
337-
return self.parse_marked_section(i)
350+
elif rawdata[i:i+9] == '<![CDATA[' and self._support_cdata:
351+
j = rawdata.find(']]>', i+9)
352+
if j < 0:
353+
return -1
354+
self.unknown_decl(rawdata[i+3: j])
355+
return j + 3
338356
elif rawdata[i:i+9].lower() == '<!doctype':
339357
# find the closing >
340358
gtpos = rawdata.find('>', i+9)

Lib/multiprocessing/forkserver.py

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -127,12 +127,13 @@ def ensure_running(self):
127127
cmd = ('from multiprocessing.forkserver import main; ' +
128128
'main(%d, %d, %r, **%r)')
129129

130+
main_kws = {}
130131
if self._preload_modules:
131-
desired_keys = {'main_path', 'sys_path'}
132132
data = spawn.get_preparation_data('ignore')
133-
data = {x: y for x, y in data.items() if x in desired_keys}
134-
else:
135-
data = {}
133+
if 'sys_path' in data:
134+
main_kws['sys_path'] = data['sys_path']
135+
if 'init_main_from_path' in data:
136+
main_kws['main_path'] = data['init_main_from_path']
136137

137138
with socket.socket(socket.AF_UNIX) as listener:
138139
address = connection.arbitrary_address('AF_UNIX')
@@ -147,7 +148,7 @@ def ensure_running(self):
147148
try:
148149
fds_to_pass = [listener.fileno(), alive_r]
149150
cmd %= (listener.fileno(), alive_r, self._preload_modules,
150-
data)
151+
main_kws)
151152
exe = spawn.get_executable()
152153
args = [exe] + util._args_from_interpreter_flags()
153154
args += ['-c', cmd]
@@ -182,6 +183,10 @@ def main(listener_fd, alive_r, preload, main_path=None, sys_path=None):
182183
except ImportError:
183184
pass
184185

186+
# gh-135335: flush stdout/stderr in case any of the preloaded modules
187+
# wrote to them, otherwise children might inherit buffered data
188+
util._flush_std_streams()
189+
185190
util._close_stdin()
186191

187192
sig_r, sig_w = os.pipe()

Lib/multiprocessing/popen_spawn_posix.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,10 @@ def _launch(self, process_obj):
5757
self._fds.extend([child_r, child_w])
5858
self.pid = util.spawnv_passfds(spawn.get_executable(),
5959
cmd, self._fds)
60+
os.close(child_r)
61+
child_r = None
62+
os.close(child_w)
63+
child_w = None
6064
self.sentinel = parent_r
6165
with open(parent_w, 'wb', closefd=False) as f:
6266
f.write(fp.getbuffer())

Lib/sysconfig/__init__.py

Lines changed: 13 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -596,18 +596,22 @@ def get_platform():
596596
isn't particularly important.
597597
598598
Examples of returned values:
599-
linux-i586
600-
linux-alpha (?)
601-
solaris-2.6-sun4u
602599
603-
Windows will return one of:
604-
win-amd64 (64-bit Windows on AMD64 (aka x86_64, Intel64, EM64T, etc)
605-
win-arm64 (64-bit Windows on ARM64 (aka AArch64)
606-
win32 (all others - specifically, sys.platform is returned)
607600
608-
For other non-POSIX platforms, currently just returns 'sys.platform'.
601+
Windows:
609602
610-
"""
603+
- win-amd64 (64-bit Windows on AMD64, aka x86_64, Intel64, and EM64T)
604+
- win-arm64 (64-bit Windows on ARM64, aka AArch64)
605+
- win32 (all others - specifically, sys.platform is returned)
606+
607+
POSIX based OS:
608+
609+
- linux-x86_64
610+
- macosx-15.5-arm64
611+
- macosx-26.0-universal2 (macOS on Apple Silicon or Intel)
612+
- android-24-arm64_v8a
613+
614+
For other non-POSIX platforms, currently just returns :data:`sys.platform`."""
611615
if os.name == 'nt':
612616
if 'amd64' in sys.version.lower():
613617
return 'win-amd64'

Lib/test/_test_multiprocessing.py

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6451,6 +6451,35 @@ def test_child_sys_path(self):
64516451
self.assertEqual(child_sys_path[1:], sys.path[1:])
64526452
self.assertIsNone(import_error, msg=f"child could not import {self._mod_name}")
64536453

6454+
def test_std_streams_flushed_after_preload(self):
6455+
# gh-135335: Check fork server flushes standard streams after
6456+
# preloading modules
6457+
if multiprocessing.get_start_method() != "forkserver":
6458+
self.skipTest("forkserver specific test")
6459+
6460+
# Create a test module in the temporary directory on the child's path
6461+
# TODO: This can all be simplified once gh-126631 is fixed and we can
6462+
# use __main__ instead of a module.
6463+
dirname = os.path.join(self._temp_dir, 'preloaded_module')
6464+
init_name = os.path.join(dirname, '__init__.py')
6465+
os.mkdir(dirname)
6466+
with open(init_name, "w") as f:
6467+
cmd = '''if 1:
6468+
import sys
6469+
print('stderr', end='', file=sys.stderr)
6470+
print('stdout', end='', file=sys.stdout)
6471+
'''
6472+
f.write(cmd)
6473+
6474+
name = os.path.join(os.path.dirname(__file__), 'mp_preload_flush.py')
6475+
env = {'PYTHONPATH': self._temp_dir}
6476+
_, out, err = test.support.script_helper.assert_python_ok(name, **env)
6477+
6478+
# Check stderr first, as it is more likely to be useful to see in the
6479+
# event of a failure.
6480+
self.assertEqual(err.decode().rstrip(), 'stderr')
6481+
self.assertEqual(out.decode().rstrip(), 'stdout')
6482+
64546483

64556484
class MiscTestCase(unittest.TestCase):
64566485
def test__all__(self):
@@ -6516,6 +6545,18 @@ def child():
65166545
self.assertEqual(q.get_nowait(), "done")
65176546
close_queue(q)
65186547

6548+
def test_preload_main(self):
6549+
# gh-126631: Check that __main__ can be pre-loaded
6550+
if multiprocessing.get_start_method() != "forkserver":
6551+
self.skipTest("forkserver specific test")
6552+
6553+
name = os.path.join(os.path.dirname(__file__), 'mp_preload_main.py')
6554+
_, out, err = test.support.script_helper.assert_python_ok(name)
6555+
self.assertEqual(err, b'')
6556+
6557+
# The trailing empty string comes from split() on output ending with \n
6558+
out = out.decode().split("\n")
6559+
self.assertEqual(out, ['__main__', '__mp_main__', 'f', 'f', ''])
65196560

65206561
#
65216562
# Mixins

Lib/test/list_tests.py

Lines changed: 19 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,11 @@
22
Tests common to list and UserList.UserList
33
"""
44

5-
import unittest
65
import sys
7-
import os
86
from functools import cmp_to_key
97

10-
from test import support, seq_tests
11-
from test.support import ALWAYS_EQ, NEVER_EQ
8+
from test import seq_tests
9+
from test.support import ALWAYS_EQ, NEVER_EQ, get_c_recursion_limit
1210

1311

1412
class CommonTest(seq_tests.CommonTest):
@@ -33,13 +31,13 @@ def test_init(self):
3331
self.assertEqual(a, b)
3432

3533
def test_getitem_error(self):
36-
a = []
34+
a = self.type2test([])
3735
msg = "list indices must be integers or slices"
3836
with self.assertRaisesRegex(TypeError, msg):
3937
a['a']
4038

4139
def test_setitem_error(self):
42-
a = []
40+
a = self.type2test([])
4341
msg = "list indices must be integers or slices"
4442
with self.assertRaisesRegex(TypeError, msg):
4543
a['a'] = "python"
@@ -63,7 +61,7 @@ def test_repr(self):
6361

6462
def test_repr_deep(self):
6563
a = self.type2test([])
66-
for i in range(sys.getrecursionlimit() + 100):
64+
for i in range(get_c_recursion_limit() + 1):
6765
a = self.type2test([a])
6866
self.assertRaises(RecursionError, repr, a)
6967

@@ -193,6 +191,14 @@ def test_setslice(self):
193191

194192
self.assertRaises(TypeError, a.__setitem__)
195193

194+
def test_slice_assign_iterator(self):
195+
x = self.type2test(range(5))
196+
x[0:3] = reversed(range(3))
197+
self.assertEqual(x, self.type2test([2, 1, 0, 3, 4]))
198+
199+
x[:] = reversed(range(3))
200+
self.assertEqual(x, self.type2test([2, 1, 0]))
201+
196202
def test_delslice(self):
197203
a = self.type2test([0, 1])
198204
del a[1:2]
@@ -552,7 +558,7 @@ def test_constructor_exception_handling(self):
552558
class F(object):
553559
def __iter__(self):
554560
raise KeyboardInterrupt
555-
self.assertRaises(KeyboardInterrupt, list, F())
561+
self.assertRaises(KeyboardInterrupt, self.type2test, F())
556562

557563
def test_exhausted_iterator(self):
558564
a = self.type2test([1, 2, 3])
@@ -564,3 +570,8 @@ def test_exhausted_iterator(self):
564570
self.assertEqual(list(exhit), [])
565571
self.assertEqual(list(empit), [9])
566572
self.assertEqual(a, self.type2test([1, 2, 3, 9]))
573+
574+
# gh-115733: Crash when iterating over exhausted iterator
575+
exhit = iter(self.type2test([1, 2, 3]))
576+
for _ in exhit:
577+
next(exhit, 1)

Lib/test/mp_preload_main.py

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
import multiprocessing
2+
3+
print(f"{__name__}")
4+
5+
def f():
6+
print("f")
7+
8+
if __name__ == "__main__":
9+
ctx = multiprocessing.get_context("forkserver")
10+
ctx.set_forkserver_preload(['__main__'])
11+
for _ in range(2):
12+
p = ctx.Process(target=f)
13+
p.start()
14+
p.join()

Lib/test/seq_tests.py

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -145,6 +145,9 @@ def __getitem__(self, i):
145145
self.assertEqual(self.type2test(LyingTuple((2,))), self.type2test((1,)))
146146
self.assertEqual(self.type2test(LyingList([2])), self.type2test([1]))
147147

148+
with self.assertRaises(TypeError):
149+
self.type2test(unsupported_arg=[])
150+
148151
def test_truth(self):
149152
self.assertFalse(self.type2test())
150153
self.assertTrue(self.type2test([42]))
@@ -423,8 +426,8 @@ def test_pickle(self):
423426
self.assertEqual(lst2, lst)
424427
self.assertNotEqual(id(lst2), id(lst))
425428

426-
# TODO: RUSTPYTHON
427-
@unittest.expectedFailure
429+
@unittest.expectedFailure # TODO: RUSTPYTHON
430+
@support.suppress_immortalization()
428431
def test_free_after_iterating(self):
429432
support.check_free_after_iterating(self, iter, self.type2test)
430433
support.check_free_after_iterating(self, reversed, self.type2test)

0 commit comments

Comments
 (0)