Skip to content

Commit c11f856

Browse files
generatedunixname1734921407115435meta-codesync[bot]
authored andcommitted
Import CPython 3.14.7+ stable branch (2026-08-17)
Summary: Imported python/cpython `3.14.7+` from upstream rev [`601e695`](https://www.github.com/python/cpython/commit/601e69562e8c5b290922671ad8fc53c59e54ca47) (committed 2026-08-17 05:00:35+00:00). # Commit Info - Base: (`3.14.7+`) - [`422e679`](https://www.github.com/python/cpython/commit/422e6793fc3d64c289b37f0df08c782c8efcf2e8) (commit date: 2026-08-15 20:17:39+00:00) - Imported: (`3.14.7+`) - [`601e695`](https://www.github.com/python/cpython/commit/601e69562e8c5b290922671ad8fc53c59e54ca47) (commit date: 2026-08-17 05:00:35+00:00) # Noteworthy file changes - Low-signal files (3 added) (NEWS.d, docs, .github) Complete list of added/removed files: https://www.internalfb.com/intern/everpaste/?color=0&handle=GFbCsSJlqThehJEGABb6oZx7XZxlbr0LAAAz Reviewed By: KasraGhodsi Differential Revision: D116289343 fbshipit-source-id: ce76aed6e2b9be575e022c928f6e50df261d6e30
1 parent 909aff7 commit c11f856

14 files changed

Lines changed: 280 additions & 27 deletions

File tree

.github/CODEOWNERS

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ Python/ceval*.h @markshannon
4848
Python/codegen.c @markshannon @iritkatriel
4949
Python/compile.c @markshannon @iritkatriel
5050
Python/assemble.c @markshannon @iritkatriel
51-
Python/flowgraph.c @markshannon @iritkatriel
51+
Python/flowgraph.c @markshannon @iritkatriel @eclips4
5252
Python/instruction_sequence.c @iritkatriel
5353
Python/bytecodes.c @markshannon
5454
Python/optimizer*.c @markshannon

Doc/extending/extending.rst

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1405,7 +1405,7 @@ Finally it should be mentioned that Capsules offer additional functionality,
14051405
which is especially useful for memory allocation and deallocation of the pointer
14061406
stored in a Capsule. The details are described in the Python/C API Reference
14071407
Manual in the section :ref:`capsules` and in the implementation of Capsules (files
1408-
:file:`Include/pycapsule.h` and :file:`Objects/pycapsule.c` in the Python source
1408+
:file:`Include/pycapsule.h` and :file:`Objects/capsule.c` in the Python source
14091409
code distribution).
14101410

14111411
.. rubric:: Footnotes

Doc/library/sys.rst

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1798,7 +1798,7 @@ always available. Unless explicitly noted otherwise, all variables are read-only
17981798
The interpreter is about to execute a new line of code or re-execute the
17991799
condition of a loop. The local trace function is called; *arg* is
18001800
``None``; the return value specifies the new local trace function. See
1801-
:file:`Objects/lnotab_notes.txt` for a detailed explanation of how this
1801+
:source:`InternalDocs/code_objects.md` for a detailed explanation of how this
18021802
works.
18031803
Per-line events may be disabled for a frame by setting
18041804
:attr:`~frame.f_trace_lines` to :const:`False` on that

InternalDocs/code_objects.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ Note that traceback objects don't store all this information -- they store the s
4848
number, for backward compatibility, and the "last instruction" value.
4949
The rest can be computed from the last instruction (`tb_lasti`) with the help of the
5050
locations table. For Python code, there is a convenience method
51-
(`codeobject.co_positions`)[https://docs.python.org/dev/reference/datamodel.html#codeobject.co_positions]
51+
[`codeobject.co_positions`](https://docs.python.org/dev/reference/datamodel.html#codeobject.co_positions)
5252
which returns an iterator of `({line}, {endline}, {column}, {endcolumn})` tuples,
5353
one per instruction.
5454
There is also `co_lines()` which returns an iterator of `({start}, {end}, {line})` tuples,

InternalDocs/jit.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -115,7 +115,7 @@ template file [`Tools/jit/template.c`](../Tools/jit/template.c).
115115
Each of the `.c` files is compiled by LLVM, to produce an object file
116116
that contains a function that executes the opcode. These compiled
117117
functions are used to generate the file
118-
[`jit_stencils.h`](../jit_stencils.h), which contains the functions
118+
`jit_stencils.h`, which contains the functions
119119
that the JIT can use to emit code for each of the bytecodes.
120120

121121
For Python maintainers this means that changes to the bytecodes and

Lib/asyncio/selector_events.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1183,7 +1183,11 @@ def writelines(self, list_of_data):
11831183
self._conn_lost += 1
11841184
return
11851185

1186-
self._buffer.extend([memoryview(data) for data in list_of_data])
1186+
# gh-155888: an empty chunk can never be drained, so never buffer it
1187+
self._buffer.extend(
1188+
[memoryview(data) for data in list_of_data if data])
1189+
if not self._buffer:
1190+
return
11871191
self._write_ready()
11881192
# If the entire buffer couldn't be written, register a write handler
11891193
if self._buffer:

Lib/test/test_asyncio/test_events.py

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -560,6 +560,19 @@ def writer(data):
560560
r.close()
561561
self.assertEqual(read, data)
562562

563+
def test_writelines_empty_chunk(self):
564+
# gh-155888: an empty chunk can never be drained, so never buffer it
565+
rsock, wsock = socket.socketpair()
566+
self.addCleanup(rsock.close)
567+
568+
async def main():
569+
reader, writer = await asyncio.open_connection(sock=wsock)
570+
writer.writelines([b'data', b''])
571+
writer.close()
572+
await asyncio.wait_for(writer.wait_closed(), support.SHORT_TIMEOUT)
573+
574+
self.loop.run_until_complete(main())
575+
563576
@unittest.skipUnless(hasattr(signal, 'SIGKILL'), 'No SIGKILL')
564577
def test_add_signal_handler(self):
565578
caught = 0

Lib/test/test_context.py

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1288,6 +1288,31 @@ def test_hamt_gc_2(self):
12881288

12891289
self.assertIsNone(ref())
12901290

1291+
def test_hamt_gc_3(self):
1292+
# gh-154535: the iterators must be tracked by the GC, otherwise a
1293+
# cycle running through one is never collected and the HAMT it
1294+
# holds -- and everything in it -- leaks.
1295+
A = HashKey(100, 'A')
1296+
1297+
container = []
1298+
h = hamt()
1299+
h = h.set(A, container)
1300+
1301+
hi = h.items()
1302+
self.assertTrue(gc.is_tracked(hi))
1303+
1304+
# Close the cycle: hi -> h -> container -> hi.
1305+
container.append(hi)
1306+
ref = weakref.ref(h)
1307+
1308+
del h, hi, container
1309+
1310+
gc.collect()
1311+
gc.collect()
1312+
gc.collect()
1313+
1314+
self.assertIsNone(ref())
1315+
12911316
def test_hamt_in_1(self):
12921317
A = HashKey(100, 'A')
12931318
AA = HashKey(100, 'A')

Lib/test/test_peepholer.py

Lines changed: 162 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2432,6 +2432,168 @@ def test_list_to_tuple_get_iter_is_safe(self):
24322432
self.assertEqual(b, [3, 2, 1, 0])
24332433
self.assertEqual(items, [])
24342434

2435+
def test_fold_constant_big_list_for_iter(self):
2436+
# for x in [c1, c2, ..., cN] (N > 30) should fold to LOAD_CONST tuple
2437+
consts = 35
2438+
before = (
2439+
[("BUILD_LIST", 0, 1)] +
2440+
[("LOAD_CONST", 0, 2), ("LIST_APPEND", 1, 3)] * consts +
2441+
[("GET_ITER", None, 4),
2442+
top := self.Label(),
2443+
("FOR_ITER", end := self.Label(), 5),
2444+
("STORE_FAST", 0, 6),
2445+
("JUMP", top, 7),
2446+
end,
2447+
("END_FOR", None, 8),
2448+
("POP_ITER", None, 9),
2449+
("LOAD_CONST", 0, 10),
2450+
("RETURN_VALUE", None, 11)]
2451+
)
2452+
after = [
2453+
("LOAD_CONST", 1, 3),
2454+
("GET_ITER", None, 4),
2455+
top := self.Label(),
2456+
("FOR_ITER", end := self.Label(), 5),
2457+
("STORE_FAST", 0, 6),
2458+
("JUMP", top, 7),
2459+
end,
2460+
("END_FOR", None, 8),
2461+
("POP_ITER", None, 9),
2462+
("LOAD_CONST", 0, 10),
2463+
("RETURN_VALUE", None, 11),
2464+
]
2465+
result_const = tuple(["test"] * consts)
2466+
self.cfg_optimization_test(before, after, consts=["test"],
2467+
expected_consts=["test", result_const])
2468+
2469+
def test_fold_constant_big_set_for_iter(self):
2470+
# for x in {c1, c2, ..., cN} (N > 30) should fold to LOAD_CONST frozenset
2471+
before = [
2472+
("BUILD_SET", 0, 1),
2473+
("LOAD_SMALL_INT", 1, 2), ("SET_ADD", 1, 3),
2474+
("LOAD_SMALL_INT", 2, 4), ("SET_ADD", 1, 5),
2475+
("LOAD_SMALL_INT", 3, 6), ("SET_ADD", 1, 7),
2476+
("GET_ITER", None, 8),
2477+
top := self.Label(),
2478+
("FOR_ITER", end := self.Label(), 9),
2479+
("STORE_FAST", 0, 10),
2480+
("JUMP", top, 11),
2481+
end,
2482+
("END_FOR", None, 12),
2483+
("POP_ITER", None, 13),
2484+
("LOAD_CONST", 0, 14),
2485+
("RETURN_VALUE", None, 15),
2486+
]
2487+
after = [
2488+
("LOAD_CONST", 1, 7),
2489+
("GET_ITER", None, 8),
2490+
top := self.Label(),
2491+
("FOR_ITER", end := self.Label(), 9),
2492+
("STORE_FAST", 0, 10),
2493+
("JUMP", top, 11),
2494+
end,
2495+
("END_FOR", None, 12),
2496+
("POP_ITER", None, 13),
2497+
("LOAD_CONST", 0, 14),
2498+
("RETURN_VALUE", None, 15),
2499+
]
2500+
self.cfg_optimization_test(before, after, consts=["test"],
2501+
expected_consts=["test", frozenset({1, 2, 3})])
2502+
2503+
def test_fold_constant_list_to_tuple_for_iter(self):
2504+
INTRINSIC_LIST_TO_TUPLE = 6
2505+
before = [
2506+
("BUILD_LIST", 0, 1),
2507+
("LOAD_SMALL_INT", 1, 2), ("LIST_APPEND", 1, 3),
2508+
("LOAD_SMALL_INT", 2, 4), ("LIST_APPEND", 1, 5),
2509+
("LOAD_SMALL_INT", 3, 6), ("LIST_APPEND", 1, 7),
2510+
("CALL_INTRINSIC_1", INTRINSIC_LIST_TO_TUPLE, 8),
2511+
("GET_ITER", None, 9),
2512+
top := self.Label(),
2513+
("FOR_ITER", end := self.Label(), 10),
2514+
("STORE_FAST", 0, 11),
2515+
("JUMP", top, 12),
2516+
end,
2517+
("END_FOR", None, 13),
2518+
("POP_ITER", None, 14),
2519+
("LOAD_CONST", 0, 15),
2520+
("RETURN_VALUE", None, 16),
2521+
]
2522+
after = [
2523+
("LOAD_CONST", 1, 8),
2524+
("GET_ITER", None, 9),
2525+
top := self.Label(),
2526+
("FOR_ITER", end := self.Label(), 10),
2527+
("STORE_FAST", 0, 11),
2528+
("JUMP", top, 12),
2529+
end,
2530+
("END_FOR", None, 13),
2531+
("POP_ITER", None, 14),
2532+
("LOAD_CONST", 0, 15),
2533+
("RETURN_VALUE", None, 16),
2534+
]
2535+
self.cfg_optimization_test(before, after, consts=["test"],
2536+
expected_consts=["test", (1, 2, 3)])
2537+
2538+
def test_fold_constant_big_list_contains_op(self):
2539+
# x in [c1, c2, ..., cN] (N > 30) should fold to LOAD_CONST tuple
2540+
before = [
2541+
("LOAD_FAST", 0, 1),
2542+
("BUILD_LIST", 0, 2),
2543+
("LOAD_SMALL_INT", 1, 3), ("LIST_APPEND", 1, 4),
2544+
("LOAD_SMALL_INT", 2, 5), ("LIST_APPEND", 1, 6),
2545+
("LOAD_SMALL_INT", 3, 7), ("LIST_APPEND", 1, 8),
2546+
("CONTAINS_OP", 0, 9),
2547+
("RETURN_VALUE", None, 10),
2548+
]
2549+
after = [
2550+
("LOAD_FAST_BORROW", 0, 1),
2551+
("LOAD_CONST", 1, 8),
2552+
("CONTAINS_OP", 0, 9),
2553+
("RETURN_VALUE", None, 10),
2554+
]
2555+
self.cfg_optimization_test(before, after, consts=[None],
2556+
expected_consts=[None, (1, 2, 3)])
2557+
2558+
def test_fold_constant_big_set_contains_op(self):
2559+
# x in {c1, c2, ..., cN} (N > 30) should fold to LOAD_CONST frozenset
2560+
before = [
2561+
("LOAD_FAST", 0, 1),
2562+
("BUILD_SET", 0, 2),
2563+
("LOAD_SMALL_INT", 1, 3), ("SET_ADD", 1, 4),
2564+
("LOAD_SMALL_INT", 2, 5), ("SET_ADD", 1, 6),
2565+
("LOAD_SMALL_INT", 3, 7), ("SET_ADD", 1, 8),
2566+
("CONTAINS_OP", 0, 9),
2567+
("RETURN_VALUE", None, 10),
2568+
]
2569+
after = [
2570+
("LOAD_FAST_BORROW", 0, 1),
2571+
("LOAD_CONST", 1, 8),
2572+
("CONTAINS_OP", 0, 9),
2573+
("RETURN_VALUE", None, 10),
2574+
]
2575+
self.cfg_optimization_test(before, after, consts=[None],
2576+
expected_consts=[None, frozenset({1, 2, 3})])
2577+
2578+
def test_no_fold_big_list_for_iter_with_non_const(self):
2579+
same = [
2580+
("BUILD_LIST", 0, 1),
2581+
("LOAD_SMALL_INT", 1, 2), ("LIST_APPEND", 1, 3),
2582+
("LOAD_FAST_BORROW", 0, 4), ("LIST_APPEND", 1, 5),
2583+
("LOAD_SMALL_INT", 3, 6), ("LIST_APPEND", 1, 7),
2584+
("GET_ITER", None, 8),
2585+
top := self.Label(),
2586+
("FOR_ITER", end := self.Label(), 9),
2587+
("STORE_FAST", 1, 10),
2588+
("JUMP", top, 11),
2589+
end,
2590+
("END_FOR", None, 12),
2591+
("POP_ITER", None, 13),
2592+
("LOAD_CONST", 0, 14),
2593+
("RETURN_VALUE", None, 15),
2594+
]
2595+
self.cfg_optimization_test(same, same, consts=["test"])
2596+
24352597

24362598
class OptimizeLoadFastTestCase(DirectCfgOptimizerTests):
24372599
def make_bb(self, insts):
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
Fold large constant list and set literals used as the iterable of a
2+
:keyword:`for` loop or ``in``/``not in`` test into a constant
3+
:class:`tuple` or :class:`frozenset`, restoring an optimization
4+
previously done by the AST optimizer that was lost when constant
5+
folding moved to the CFG.

0 commit comments

Comments
 (0)