Skip to content

Commit b1d5ba1

Browse files
authored
Merge branch 'main' into gh-105623
2 parents d3a1875 + 14d0126 commit b1d5ba1

20 files changed

+247
-154
lines changed

.github/workflows/build.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -232,7 +232,7 @@ jobs:
232232
path: config.cache
233233
key: ${{ github.job }}-${{ runner.os }}-${{ needs.check_source.outputs.config_hash }}
234234
- name: Install Homebrew dependencies
235-
run: brew install pkg-config openssl@1.1 xz gdbm tcl-tk
235+
run: brew install pkg-config openssl@3.0 xz gdbm tcl-tk
236236
- name: Configure CPython
237237
run: |
238238
GDBM_CFLAGS="-I$(brew --prefix gdbm)/include" \
@@ -241,7 +241,7 @@ jobs:
241241
--config-cache \
242242
--with-pydebug \
243243
--prefix=/opt/python-dev \
244-
--with-openssl="$(brew --prefix openssl@1.1)"
244+
--with-openssl="$(brew --prefix openssl@3.0)"
245245
- name: Build CPython
246246
run: make -j4
247247
- name: Display build info

Doc/library/dis.rst

Lines changed: 26 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -318,6 +318,12 @@ operation is being performed, so the intermediate analysis object isn't useful:
318318
.. versionchanged:: 3.8
319319
Added *jump* parameter.
320320

321+
.. versionchanged:: 3.13
322+
If ``oparg`` is omitted (or ``None``), the stack effect is now returned
323+
for ``oparg=0``. Previously this was an error for opcodes that use their
324+
arg. It is also no longer an error to pass an integer ``oparg`` when
325+
the ``opcode`` does not use it; the ``oparg`` in this case is ignored.
326+
321327

322328
.. _bytecodes:
323329

@@ -1421,23 +1427,34 @@ iterations of the loop.
14211427
.. versionadded:: 3.11
14221428

14231429

1424-
.. opcode:: MAKE_FUNCTION (flags)
1430+
.. opcode:: MAKE_FUNCTION
1431+
1432+
Pushes a new function object on the stack built from the code object at ``STACK[1]``.
1433+
1434+
.. versionchanged:: 3.10
1435+
Flag value ``0x04`` is a tuple of strings instead of dictionary
1436+
1437+
.. versionchanged:: 3.11
1438+
Qualified name at ``STACK[-1]`` was removed.
14251439

1426-
Pushes a new function object on the stack. From bottom to top, the consumed
1427-
stack must consist of values if the argument carries a specified flag value
1440+
.. versionchanged:: 3.13
1441+
Extra function attributes on the stack, signaled by oparg flags, were
1442+
removed. They now use :opcode:`SET_FUNCTION_ATTRIBUTE`.
1443+
1444+
1445+
.. opcode:: SET_FUNCTION_ATTRIBUTE (flag)
1446+
1447+
Sets an attribute on a function object. Expects the function at ``STACK[-1]``
1448+
and the attribute value to set at ``STACK[-2]``; consumes both and leaves the
1449+
function at ``STACK[-1]``. The flag determines which attribute to set:
14281450

14291451
* ``0x01`` a tuple of default values for positional-only and
14301452
positional-or-keyword parameters in positional order
14311453
* ``0x02`` a dictionary of keyword-only parameters' default values
14321454
* ``0x04`` a tuple of strings containing parameters' annotations
14331455
* ``0x08`` a tuple containing cells for free variables, making a closure
1434-
* the code associated with the function (at ``STACK[-1]``)
14351456

1436-
.. versionchanged:: 3.10
1437-
Flag value ``0x04`` is a tuple of strings instead of dictionary
1438-
1439-
.. versionchanged:: 3.11
1440-
Qualified name at ``STACK[-1]`` was removed.
1457+
.. versionadded:: 3.13
14411458

14421459

14431460
.. opcode:: BUILD_SLICE (argc)

Include/internal/pycore_opcode.h

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

Include/internal/pycore_opcode_utils.h

Lines changed: 1 addition & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -15,10 +15,7 @@ extern "C" {
1515

1616
#define IS_WITHIN_OPCODE_RANGE(opcode) \
1717
(((opcode) >= 0 && (opcode) <= MAX_REAL_OPCODE) || \
18-
IS_PSEUDO_OPCODE(opcode))
19-
20-
#define IS_JUMP_OPCODE(opcode) \
21-
is_bit_set_in_table(_PyOpcode_Jump, opcode)
18+
IS_PSEUDO_INSTR(opcode))
2219

2320
#define IS_BLOCK_PUSH_OPCODE(opcode) \
2421
((opcode) == SETUP_FINALLY || \
@@ -55,27 +52,6 @@ extern "C" {
5552
(opcode) == RAISE_VARARGS || \
5653
(opcode) == RERAISE)
5754

58-
#define LOG_BITS_PER_INT 5
59-
#define MASK_LOW_LOG_BITS 31
60-
61-
static inline int
62-
is_bit_set_in_table(const uint32_t *table, int bitindex) {
63-
/* Is the relevant bit set in the relevant word? */
64-
/* 512 bits fit into 9 32-bits words.
65-
* Word is indexed by (bitindex>>ln(size of int in bits)).
66-
* Bit within word is the low bits of bitindex.
67-
*/
68-
if (bitindex >= 0 && bitindex < 512) {
69-
uint32_t word = table[bitindex >> LOG_BITS_PER_INT];
70-
return (word >> (bitindex & MASK_LOW_LOG_BITS)) & 1;
71-
}
72-
else {
73-
return 0;
74-
}
75-
}
76-
77-
#undef LOG_BITS_PER_INT
78-
#undef MASK_LOW_LOG_BITS
7955

8056
/* Flags used in the oparg for MAKE_FUNCTION */
8157
#define MAKE_FUNCTION_DEFAULTS 0x01

Include/opcode.h

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

Lib/ast.py

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1051,7 +1051,8 @@ def visit_ClassDef(self, node):
10511051
self.fill("@")
10521052
self.traverse(deco)
10531053
self.fill("class " + node.name)
1054-
self._type_params_helper(node.type_params)
1054+
if hasattr(node, "type_params"):
1055+
self._type_params_helper(node.type_params)
10551056
with self.delimit_if("(", ")", condition = node.bases or node.keywords):
10561057
comma = False
10571058
for e in node.bases:
@@ -1083,7 +1084,8 @@ def _function_helper(self, node, fill_suffix):
10831084
self.traverse(deco)
10841085
def_str = fill_suffix + " " + node.name
10851086
self.fill(def_str)
1086-
self._type_params_helper(node.type_params)
1087+
if hasattr(node, "type_params"):
1088+
self._type_params_helper(node.type_params)
10871089
with self.delimit("(", ")"):
10881090
self.traverse(node.args)
10891091
if node.returns:

Lib/test/test__opcode.py

Lines changed: 2 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -15,20 +15,14 @@ def test_stack_effect(self):
1515
self.assertEqual(stack_effect(dis.opmap['BUILD_SLICE'], 1), -1)
1616
self.assertEqual(stack_effect(dis.opmap['BUILD_SLICE'], 3), -2)
1717
self.assertRaises(ValueError, stack_effect, 30000)
18-
self.assertRaises(ValueError, stack_effect, dis.opmap['BUILD_SLICE'])
19-
self.assertRaises(ValueError, stack_effect, dis.opmap['POP_TOP'], 0)
2018
# All defined opcodes
2119
has_arg = dis.hasarg
2220
for name, code in filter(lambda item: item[0] not in dis.deoptmap, dis.opmap.items()):
2321
if code >= opcode.MIN_INSTRUMENTED_OPCODE:
2422
continue
2523
with self.subTest(opname=name):
26-
if code not in has_arg:
27-
stack_effect(code)
28-
self.assertRaises(ValueError, stack_effect, code, 0)
29-
else:
30-
stack_effect(code, 0)
31-
self.assertRaises(ValueError, stack_effect, code)
24+
stack_effect(code)
25+
stack_effect(code, 0)
3226
# All not defined opcodes
3327
for code in set(range(256)) - set(dis.opmap.values()):
3428
with self.subTest(opcode=code):

Lib/test/test_opcache.py

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -452,6 +452,35 @@ def f():
452452
self.assertFalse(f())
453453

454454

455+
class TestCallCache(unittest.TestCase):
456+
def test_too_many_defaults_0(self):
457+
def f():
458+
pass
459+
460+
f.__defaults__ = (None,)
461+
for _ in range(1025):
462+
f()
463+
464+
def test_too_many_defaults_1(self):
465+
def f(x):
466+
pass
467+
468+
f.__defaults__ = (None, None)
469+
for _ in range(1025):
470+
f(None)
471+
f()
472+
473+
def test_too_many_defaults_2(self):
474+
def f(x, y):
475+
pass
476+
477+
f.__defaults__ = (None, None, None)
478+
for _ in range(1025):
479+
f(None, None)
480+
f(None)
481+
f()
482+
483+
455484
if __name__ == "__main__":
456485
import unittest
457486
unittest.main()

Lib/test/test_typing.py

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2759,6 +2759,80 @@ def x(self): ...
27592759
with self.assertRaisesRegex(TypeError, only_classes_allowed):
27602760
issubclass(1, BadPG)
27612761

2762+
def test_implicit_issubclass_between_two_protocols(self):
2763+
@runtime_checkable
2764+
class CallableMembersProto(Protocol):
2765+
def meth(self): ...
2766+
2767+
# All the below protocols should be considered "subclasses"
2768+
# of CallableMembersProto at runtime,
2769+
# even though none of them explicitly subclass CallableMembersProto
2770+
2771+
class IdenticalProto(Protocol):
2772+
def meth(self): ...
2773+
2774+
class SupersetProto(Protocol):
2775+
def meth(self): ...
2776+
def meth2(self): ...
2777+
2778+
class NonCallableMembersProto(Protocol):
2779+
meth: Callable[[], None]
2780+
2781+
class NonCallableMembersSupersetProto(Protocol):
2782+
meth: Callable[[], None]
2783+
meth2: Callable[[str, int], bool]
2784+
2785+
class MixedMembersProto1(Protocol):
2786+
meth: Callable[[], None]
2787+
def meth2(self): ...
2788+
2789+
class MixedMembersProto2(Protocol):
2790+
def meth(self): ...
2791+
meth2: Callable[[str, int], bool]
2792+
2793+
for proto in (
2794+
IdenticalProto, SupersetProto, NonCallableMembersProto,
2795+
NonCallableMembersSupersetProto, MixedMembersProto1, MixedMembersProto2
2796+
):
2797+
with self.subTest(proto=proto.__name__):
2798+
self.assertIsSubclass(proto, CallableMembersProto)
2799+
2800+
# These two shouldn't be considered subclasses of CallableMembersProto, however,
2801+
# since they don't have the `meth` protocol member
2802+
2803+
class EmptyProtocol(Protocol): ...
2804+
class UnrelatedProtocol(Protocol):
2805+
def wut(self): ...
2806+
2807+
self.assertNotIsSubclass(EmptyProtocol, CallableMembersProto)
2808+
self.assertNotIsSubclass(UnrelatedProtocol, CallableMembersProto)
2809+
2810+
# These aren't protocols at all (despite having annotations),
2811+
# so they should only be considered subclasses of CallableMembersProto
2812+
# if they *actually have an attribute* matching the `meth` member
2813+
# (just having an annotation is insufficient)
2814+
2815+
class AnnotatedButNotAProtocol:
2816+
meth: Callable[[], None]
2817+
2818+
class NotAProtocolButAnImplicitSubclass:
2819+
def meth(self): pass
2820+
2821+
class NotAProtocolButAnImplicitSubclass2:
2822+
meth: Callable[[], None]
2823+
def meth(self): pass
2824+
2825+
class NotAProtocolButAnImplicitSubclass3:
2826+
meth: Callable[[], None]
2827+
meth2: Callable[[int, str], bool]
2828+
def meth(self): pass
2829+
def meth(self, x, y): return True
2830+
2831+
self.assertNotIsSubclass(AnnotatedButNotAProtocol, CallableMembersProto)
2832+
self.assertIsSubclass(NotAProtocolButAnImplicitSubclass, CallableMembersProto)
2833+
self.assertIsSubclass(NotAProtocolButAnImplicitSubclass2, CallableMembersProto)
2834+
self.assertIsSubclass(NotAProtocolButAnImplicitSubclass3, CallableMembersProto)
2835+
27622836
def test_isinstance_checks_not_at_whim_of_gc(self):
27632837
self.addCleanup(gc.enable)
27642838
gc.disable()

0 commit comments

Comments
 (0)