Skip to content

Commit ae0bd02

Browse files
committed
Merge branch 'main' into inlinecomp2
* main: pythongh-101810: Remove duplicated st_ino calculation (pythonGH-101811) pythongh-92547: Purge sqlite3_enable_shared_cache() detection from configure (python#101873) pythonGH-100987: Refactor `_PyInterpreterFrame` a bit, to assist generator improvement. (pythonGH-100988) pythonGH-87849: Simplify stack effect of SEND and specialize it for generators and coroutines. (pythonGH-101788) Correct trivial grammar in reset_mock docs (python#101861) pythongh-101845: pyspecific: Fix i18n for availability directive (pythonGH-101846) pythongh-89792: Limit test_tools freeze test build parallelism based on the number of cores (python#101841) pythongh-85984: Utilize new "winsize" functions from termios in pty tests. (python#101831) pythongh-89792: Prevent test_tools from copying 1000M of "source" in freeze test (python#101837) Fix typo in test_fstring.py (python#101823) pythonGH-101797: allocate `PyExpat_CAPI` capsule on heap (python#101798) pythongh-101390: Fix docs for `imporlib.util.LazyLoader.factory` to properly call it a class method (pythonGH-101391)
2 parents 36b2917 + 95cbb3d commit ae0bd02

28 files changed

+306
-272
lines changed

Doc/library/importlib.rst

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1387,7 +1387,7 @@ an :term:`importer`.
13871387

13881388
.. classmethod:: factory(loader)
13891389

1390-
A static method which returns a callable that creates a lazy loader. This
1390+
A class method which returns a callable that creates a lazy loader. This
13911391
is meant to be used in situations where the loader is passed by class
13921392
instead of by instance.
13931393
::

Doc/library/unittest.mock.rst

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -406,7 +406,7 @@ the *new_callable* argument to :func:`patch`.
406406
False
407407

408408
.. versionchanged:: 3.6
409-
Added two keyword only argument to the reset_mock function.
409+
Added two keyword-only arguments to the reset_mock function.
410410

411411
This can be useful where you want to make a series of assertions that
412412
reuse the same object. Note that :meth:`reset_mock` *doesn't* clear the
@@ -416,8 +416,8 @@ the *new_callable* argument to :func:`patch`.
416416
parameter as ``True``. Child mocks and the return value mock
417417
(if any) are reset as well.
418418

419-
.. note:: *return_value*, and :attr:`side_effect` are keyword only
420-
argument.
419+
.. note:: *return_value*, and :attr:`side_effect` are keyword-only
420+
arguments.
421421

422422

423423
.. method:: mock_add_spec(spec, spec_set=False)

Doc/tools/extensions/pyspecific.py

Lines changed: 11 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
from sphinx.environment import NoUri
2929
from sphinx.locale import _ as sphinx_gettext
3030
from sphinx.util import status_iterator, logging
31+
from sphinx.util.docutils import SphinxDirective
3132
from sphinx.util.nodes import split_explicit_title
3233
from sphinx.writers.text import TextWriter, TextTranslator
3334

@@ -119,7 +120,7 @@ def run(self):
119120

120121
# Support for documenting platform availability
121122

122-
class Availability(Directive):
123+
class Availability(SphinxDirective):
123124

124125
has_content = True
125126
required_arguments = 1
@@ -139,18 +140,19 @@ class Availability(Directive):
139140

140141
def run(self):
141142
availability_ref = ':ref:`Availability <availability>`: '
143+
avail_nodes, avail_msgs = self.state.inline_text(
144+
availability_ref + self.arguments[0],
145+
self.lineno)
142146
pnode = nodes.paragraph(availability_ref + self.arguments[0],
143-
classes=["availability"],)
144-
n, m = self.state.inline_text(availability_ref, self.lineno)
145-
pnode.extend(n + m)
146-
n, m = self.state.inline_text(self.arguments[0], self.lineno)
147-
pnode.extend(n + m)
147+
'', *avail_nodes, *avail_msgs)
148+
self.set_source_info(pnode)
149+
cnode = nodes.container("", pnode, classes=["availability"])
150+
self.set_source_info(cnode)
148151
if self.content:
149-
self.state.nested_parse(self.content, self.content_offset, pnode)
150-
152+
self.state.nested_parse(self.content, self.content_offset, cnode)
151153
self.parse_platforms()
152154

153-
return [pnode]
155+
return [cnode]
154156

155157
def parse_platforms(self):
156158
"""Parse platform information from arguments

Include/internal/pycore_code.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,12 @@ typedef struct {
9292

9393
#define INLINE_CACHE_ENTRIES_FOR_ITER CACHE_ENTRIES(_PyForIterCache)
9494

95+
typedef struct {
96+
uint16_t counter;
97+
} _PySendCache;
98+
99+
#define INLINE_CACHE_ENTRIES_SEND CACHE_ENTRIES(_PySendCache)
100+
95101
// Borrowed references to common callables:
96102
struct callable_cache {
97103
PyObject *isinstance;
@@ -233,6 +239,7 @@ extern void _Py_Specialize_CompareAndBranch(PyObject *lhs, PyObject *rhs,
233239
extern void _Py_Specialize_UnpackSequence(PyObject *seq, _Py_CODEUNIT *instr,
234240
int oparg);
235241
extern void _Py_Specialize_ForIter(PyObject *iter, _Py_CODEUNIT *instr, int oparg);
242+
extern void _Py_Specialize_Send(PyObject *receiver, _Py_CODEUNIT *instr);
236243

237244
/* Finalizer function for static codeobjects used in deepfreeze.py */
238245
extern void _PyStaticCode_Fini(PyCodeObject *co);

Include/internal/pycore_frame.h

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -47,15 +47,13 @@ enum _frameowner {
4747
};
4848

4949
typedef struct _PyInterpreterFrame {
50-
/* "Specials" section */
50+
PyCodeObject *f_code; /* Strong reference */
51+
struct _PyInterpreterFrame *previous;
5152
PyObject *f_funcobj; /* Strong reference. Only valid if not on C stack */
5253
PyObject *f_globals; /* Borrowed reference. Only valid if not on C stack */
5354
PyObject *f_builtins; /* Borrowed reference. Only valid if not on C stack */
5455
PyObject *f_locals; /* Strong reference, may be NULL. Only valid if not on C stack */
55-
PyCodeObject *f_code; /* Strong reference */
5656
PyFrameObject *frame_obj; /* Strong reference, may be NULL. Only valid if not on C stack */
57-
/* Linkage section */
58-
struct _PyInterpreterFrame *previous;
5957
// NOTE: This is not necessarily the last instruction started in the given
6058
// frame. Rather, it is the code unit *prior to* the *next* instruction. For
6159
// example, it may be an inline CACHE entry, an instruction we just jumped

Include/internal/pycore_opcode.h

Lines changed: 3 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Include/opcode.h

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Lib/dis.py

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@
3939
BINARY_OP = opmap['BINARY_OP']
4040
JUMP_BACKWARD = opmap['JUMP_BACKWARD']
4141
FOR_ITER = opmap['FOR_ITER']
42+
SEND = opmap['SEND']
4243
LOAD_ATTR = opmap['LOAD_ATTR']
4344

4445
CACHE = opmap["CACHE"]
@@ -453,6 +454,7 @@ def _get_instructions_bytes(code, varname_from_oparg=None,
453454
argrepr = ''
454455
positions = Positions(*next(co_positions, ()))
455456
deop = _deoptop(op)
457+
caches = _inline_cache_entries[deop]
456458
if arg is not None:
457459
# Set argval to the dereferenced value of the argument when
458460
# available, and argrepr to the string representation of argval.
@@ -478,8 +480,7 @@ def _get_instructions_bytes(code, varname_from_oparg=None,
478480
elif deop in hasjrel:
479481
signed_arg = -arg if _is_backward_jump(deop) else arg
480482
argval = offset + 2 + signed_arg*2
481-
if deop == FOR_ITER:
482-
argval += 2
483+
argval += 2 * caches
483484
argrepr = "to " + repr(argval)
484485
elif deop in haslocal or deop in hasfree:
485486
argval, argrepr = _get_name_info(arg, varname_from_oparg)
@@ -633,12 +634,12 @@ def findlabels(code):
633634
for offset, op, arg in _unpack_opargs(code):
634635
if arg is not None:
635636
deop = _deoptop(op)
637+
caches = _inline_cache_entries[deop]
636638
if deop in hasjrel:
637639
if _is_backward_jump(deop):
638640
arg = -arg
639641
label = offset + 2 + arg*2
640-
if deop == FOR_ITER:
641-
label += 2
642+
label += 2 * caches
642643
elif deop in hasjabs:
643644
label = arg*2
644645
else:

Lib/importlib/_bootstrap_external.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -432,7 +432,8 @@ def _write_atomic(path, data, mode=0o666):
432432
# Python 3.12a5 3516 (Add COMPARE_AND_BRANCH instruction)
433433
# Python 3.12a5 3517 (Change YIELD_VALUE oparg to exception block depth)
434434
# Python 3.12a5 3518 (Add RETURN_CONST instruction)
435-
# Python 3.12a5 3519 (Inline list/dict/set comprehensions)
435+
# Python 3.12a5 3519 (Modify SEND instruction)
436+
# Python 3.12a5 3520 (Inline list/dict/set comprehensions)
436437

437438
# Python 3.13 will start with 3550
438439

@@ -445,7 +446,7 @@ def _write_atomic(path, data, mode=0o666):
445446
# Whenever MAGIC_NUMBER is changed, the ranges in the magic_values array
446447
# in PC/launcher.c must also be updated.
447448

448-
MAGIC_NUMBER = (3519).to_bytes(2, 'little') + b'\r\n'
449+
MAGIC_NUMBER = (3520).to_bytes(2, 'little') + b'\r\n'
449450

450451
_RAW_MAGIC_NUMBER = int.from_bytes(MAGIC_NUMBER, 'little') # For import.c
451452

Lib/opcode.py

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -167,7 +167,7 @@ def pseudo_op(name, op, real_ops):
167167
def_op('RETURN_CONST', 121)
168168
hasconst.append(121)
169169
def_op('BINARY_OP', 122)
170-
jrel_op('SEND', 123) # Number of bytes to skip
170+
jrel_op('SEND', 123) # Number of words to skip
171171
def_op('LOAD_FAST', 124) # Local variable number, no null check
172172
haslocal.append(124)
173173
def_op('STORE_FAST', 125) # Local variable number
@@ -374,6 +374,9 @@ def pseudo_op(name, op, real_ops):
374374
"UNPACK_SEQUENCE_TUPLE",
375375
"UNPACK_SEQUENCE_TWO_TUPLE",
376376
],
377+
"SEND": [
378+
"SEND_GEN",
379+
],
377380
}
378381
_specialized_instructions = [
379382
opcode for family in _specializations.values() for opcode in family
@@ -433,6 +436,9 @@ def pseudo_op(name, op, real_ops):
433436
"STORE_SUBSCR": {
434437
"counter": 1,
435438
},
439+
"SEND": {
440+
"counter": 1,
441+
},
436442
}
437443

438444
_inline_cache_entries = [

Lib/test/test_dis.py

Lines changed: 15 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -475,11 +475,13 @@ async def _asyncwith(c):
475475
BEFORE_ASYNC_WITH
476476
GET_AWAITABLE 1
477477
LOAD_CONST 0 (None)
478-
>> SEND 3 (to 22)
478+
>> SEND 3 (to 24)
479479
YIELD_VALUE 2
480480
RESUME 3
481-
JUMP_BACKWARD_NO_INTERRUPT 4 (to 14)
482-
>> POP_TOP
481+
JUMP_BACKWARD_NO_INTERRUPT 5 (to 14)
482+
>> SWAP 2
483+
POP_TOP
484+
POP_TOP
483485
484486
%3d LOAD_CONST 1 (1)
485487
STORE_FAST 1 (x)
@@ -490,30 +492,33 @@ async def _asyncwith(c):
490492
CALL 2
491493
GET_AWAITABLE 2
492494
LOAD_CONST 0 (None)
493-
>> SEND 3 (to 56)
495+
>> SEND 3 (to 64)
494496
YIELD_VALUE 2
495497
RESUME 3
496-
JUMP_BACKWARD_NO_INTERRUPT 4 (to 48)
498+
JUMP_BACKWARD_NO_INTERRUPT 5 (to 54)
497499
>> POP_TOP
500+
POP_TOP
498501
499502
%3d LOAD_CONST 2 (2)
500503
STORE_FAST 2 (y)
501504
RETURN_CONST 0 (None)
502505
503506
%3d >> CLEANUP_THROW
504-
JUMP_BACKWARD 23 (to 22)
507+
JUMP_BACKWARD 27 (to 24)
505508
>> CLEANUP_THROW
506-
JUMP_BACKWARD 8 (to 56)
509+
JUMP_BACKWARD 9 (to 64)
507510
>> PUSH_EXC_INFO
508511
WITH_EXCEPT_START
509512
GET_AWAITABLE 2
510513
LOAD_CONST 0 (None)
511-
>> SEND 4 (to 90)
514+
>> SEND 4 (to 102)
512515
YIELD_VALUE 3
513516
RESUME 3
514-
JUMP_BACKWARD_NO_INTERRUPT 4 (to 80)
517+
JUMP_BACKWARD_NO_INTERRUPT 5 (to 90)
515518
>> CLEANUP_THROW
516-
>> POP_JUMP_IF_TRUE 1 (to 94)
519+
>> SWAP 2
520+
POP_TOP
521+
POP_JUMP_IF_TRUE 1 (to 110)
517522
RERAISE 2
518523
>> POP_TOP
519524
POP_EXCEPT

Lib/test/test_fstring.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -667,7 +667,7 @@ def test_missing_expression(self):
667667
"f'''{\t\f\r\n}'''",
668668
])
669669

670-
# Different error messages are raised when a specfier ('!', ':' or '=') is used after an empty expression
670+
# Different error messages are raised when a specifier ('!', ':' or '=') is used after an empty expression
671671
self.assertAllRaise(SyntaxError, "f-string: expression required before '!'",
672672
["f'{!r}'",
673673
"f'{ !r}'",

0 commit comments

Comments
 (0)