Skip to content

Commit 0ee90f9

Browse files
authored
Merge branch 'main' into tstrings
2 parents 6bfc888 + ea23c89 commit 0ee90f9

File tree

14 files changed

+131
-35
lines changed

14 files changed

+131
-35
lines changed

Doc/tools/templates/layout.html

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,8 +27,7 @@
2727

2828
{% block extrahead %}
2929
{% if builder == "html" and enable_analytics %}
30-
<script defer data-domain="docs.python.org" src="https://plausible.io/js/script.js"></script>
31-
<script defer data-domain="docs.python.org" src="https://analytics.python.org/js/script.js"></script>
30+
<script defer data-domain="docs.python.org" src="https://analytics.python.org/js/script.outbound-links.js"></script>
3231
{% endif %}
3332
<link rel="canonical" href="https://docs.python.org/3/{{pagename}}.html">
3433
{% if builder != "htmlhelp" %}

Doc/whatsnew/3.14.rst

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -469,6 +469,10 @@ Other language changes
469469
of HMAC is not available.
470470
(Contributed by Bénédikt Tran in :gh:`99108`.)
471471

472+
* When subclassing from a pure C type, the C slots for the new type are no
473+
longer replaced with a wrapped version on class creation if they are not
474+
explicitly overridden in the subclass.
475+
(Contributed by Tomasz Pytel in :gh:`132329`.)
472476

473477
.. _whatsnew314-pep765:
474478

Lib/test/test_ctypes/test_find.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
import unittest.mock
66
from ctypes import CDLL, RTLD_GLOBAL
77
from ctypes.util import find_library
8-
from test.support import os_helper
8+
from test.support import os_helper, thread_unsafe
99

1010

1111
# On some systems, loading the OpenGL libraries needs the RTLD_GLOBAL mode.
@@ -78,6 +78,7 @@ def test_shell_injection(self):
7878
@unittest.skipUnless(sys.platform.startswith('linux'),
7979
'Test only valid for Linux')
8080
class FindLibraryLinux(unittest.TestCase):
81+
@thread_unsafe('uses setenv')
8182
def test_find_on_libpath(self):
8283
import subprocess
8384
import tempfile

Lib/test/test_ctypes/test_values.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
from ctypes import (Structure, CDLL, POINTER, pythonapi,
1010
_pointer_type_cache,
1111
c_ubyte, c_char_p, c_int)
12-
from test.support import import_helper
12+
from test.support import import_helper, thread_unsafe
1313

1414

1515
class ValuesTestCase(unittest.TestCase):
@@ -18,6 +18,7 @@ def setUp(self):
1818
_ctypes_test = import_helper.import_module("_ctypes_test")
1919
self.ctdll = CDLL(_ctypes_test.__file__)
2020

21+
@thread_unsafe("static global variables aren't thread-safe")
2122
def test_an_integer(self):
2223
# This test checks and changes an integer stored inside the
2324
# _ctypes_test dll/shared lib.
@@ -46,6 +47,7 @@ def test_optimizeflag(self):
4647
opt = c_int.in_dll(pythonapi, "Py_OptimizeFlag").value
4748
self.assertEqual(opt, sys.flags.optimize)
4849

50+
@thread_unsafe('overrides frozen modules')
4951
def test_frozentable(self):
5052
# Python exports a PyImport_FrozenModules symbol. This is a
5153
# pointer to an array of struct _frozen entries. The end of the

Lib/test/test_types.py

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1838,6 +1838,23 @@ class Model(metaclass=ModelBase):
18381838
with self.assertRaises(RuntimeWarning):
18391839
type("SouthPonies", (Model,), {})
18401840

1841+
def test_subclass_inherited_slot_update(self):
1842+
# gh-132284: Make sure slot update still works after fix.
1843+
# Note that after assignment to D.__getitem__ the actual C slot will
1844+
# never go back to dict_subscript as it was on class type creation but
1845+
# rather be set to slot_mp_subscript, unfortunately there is no way to
1846+
# check that here.
1847+
1848+
class D(dict):
1849+
pass
1850+
1851+
d = D({None: None})
1852+
self.assertIs(d[None], None)
1853+
D.__getitem__ = lambda self, item: 42
1854+
self.assertEqual(d[None], 42)
1855+
D.__getitem__ = dict.__getitem__
1856+
self.assertIs(d[None], None)
1857+
18411858
def test_tuple_subclass_as_bases(self):
18421859
# gh-132176: it used to crash on using
18431860
# tuple subclass for as base classes.

Lib/test/test_typing.py

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3149,6 +3149,21 @@ def x(self): ...
31493149
with self.assertRaisesRegex(TypeError, only_classes_allowed):
31503150
issubclass(1, BadPG)
31513151

3152+
def test_isinstance_against_superproto_doesnt_affect_subproto_instance(self):
3153+
@runtime_checkable
3154+
class Base(Protocol):
3155+
x: int
3156+
3157+
@runtime_checkable
3158+
class Child(Base, Protocol):
3159+
y: str
3160+
3161+
class Capybara:
3162+
x = 43
3163+
3164+
self.assertIsInstance(Capybara(), Base)
3165+
self.assertNotIsInstance(Capybara(), Child)
3166+
31523167
def test_implicit_issubclass_between_two_protocols(self):
31533168
@runtime_checkable
31543169
class CallableMembersProto(Protocol):
@@ -6323,7 +6338,7 @@ def test_lazy_import(self):
63236338
"inspect",
63246339
"re",
63256340
"contextlib",
6326-
# "annotationlib", # TODO
6341+
"annotationlib",
63276342
})
63286343

63296344

Lib/typing.py

Lines changed: 18 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1801,9 +1801,13 @@ def _get_protocol_attrs(cls):
18011801
for base in cls.__mro__[:-1]: # without object
18021802
if base.__name__ in {'Protocol', 'Generic'}:
18031803
continue
1804-
annotations = _lazy_annotationlib.get_annotations(
1805-
base, format=_lazy_annotationlib.Format.FORWARDREF
1806-
)
1804+
try:
1805+
annotations = base.__annotations__
1806+
except Exception:
1807+
# Only go through annotationlib to handle deferred annotations if we need to
1808+
annotations = _lazy_annotationlib.get_annotations(
1809+
base, format=_lazy_annotationlib.Format.FORWARDREF
1810+
)
18071811
for attr in (*base.__dict__, *annotations):
18081812
if not attr.startswith('_abc_') and attr not in EXCLUDED_ATTRIBUTES:
18091813
attrs.add(attr)
@@ -2020,14 +2024,17 @@ def _proto_hook(cls, other):
20202024
break
20212025

20222026
# ...or in annotations, if it is a sub-protocol.
2023-
if (
2024-
issubclass(other, Generic)
2025-
and getattr(other, "_is_protocol", False)
2026-
and attr in _lazy_annotationlib.get_annotations(
2027-
base, format=_lazy_annotationlib.Format.FORWARDREF
2028-
)
2029-
):
2030-
break
2027+
if issubclass(other, Generic) and getattr(other, "_is_protocol", False):
2028+
# We avoid the slower path through annotationlib here because in most
2029+
# cases it should be unnecessary.
2030+
try:
2031+
annos = base.__annotations__
2032+
except Exception:
2033+
annos = _lazy_annotationlib.get_annotations(
2034+
base, format=_lazy_annotationlib.Format.FORWARDREF
2035+
)
2036+
if attr in annos:
2037+
break
20312038
else:
20322039
return NotImplemented
20332040
return True
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
The :file:`PC\layout` script now allows passing ``--include-tcltk`` on
2+
Windows ARM64.
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Don't wrap base ``PyCFunction`` slots on class creation if not overridden.

Modules/_ctypes/_ctypes.c

Lines changed: 56 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -4892,8 +4892,10 @@ Array_init(PyObject *self, PyObject *args, PyObject *kw)
48924892
}
48934893

48944894
static PyObject *
4895-
Array_item(PyObject *myself, Py_ssize_t index)
4895+
Array_item_lock_held(PyObject *myself, Py_ssize_t index)
48964896
{
4897+
_Py_CRITICAL_SECTION_ASSERT_OBJECT_LOCKED(myself);
4898+
48974899
CDataObject *self = _CDataObject_CAST(myself);
48984900
Py_ssize_t offset, size;
48994901

@@ -4920,8 +4922,20 @@ Array_item(PyObject *myself, Py_ssize_t index)
49204922
}
49214923

49224924
static PyObject *
4923-
Array_subscript(PyObject *myself, PyObject *item)
4925+
Array_item(PyObject *myself, Py_ssize_t index)
49244926
{
4927+
PyObject *result;
4928+
Py_BEGIN_CRITICAL_SECTION(myself);
4929+
result = Array_item_lock_held(myself, index);
4930+
Py_END_CRITICAL_SECTION();
4931+
return result;
4932+
}
4933+
4934+
static PyObject *
4935+
Array_subscript_lock_held(PyObject *myself, PyObject *item)
4936+
{
4937+
_Py_CRITICAL_SECTION_ASSERT_OBJECT_LOCKED(myself);
4938+
49254939
CDataObject *self = _CDataObject_CAST(myself);
49264940

49274941
if (PyIndex_Check(item)) {
@@ -4931,7 +4945,7 @@ Array_subscript(PyObject *myself, PyObject *item)
49314945
return NULL;
49324946
if (i < 0)
49334947
i += self->b_length;
4934-
return Array_item(myself, i);
4948+
return Array_item_lock_held(myself, i);
49354949
}
49364950
else if (PySlice_Check(item)) {
49374951
PyObject *proto;
@@ -4966,23 +4980,19 @@ Array_subscript(PyObject *myself, PyObject *item)
49664980
return Py_GetConstant(Py_CONSTANT_EMPTY_BYTES);
49674981
if (step == 1) {
49684982
PyObject *res;
4969-
Py_BEGIN_CRITICAL_SECTION(self);
49704983
res = PyBytes_FromStringAndSize(ptr + start,
49714984
slicelen);
4972-
Py_END_CRITICAL_SECTION();
49734985
return res;
49744986
}
49754987
dest = (char *)PyMem_Malloc(slicelen);
49764988

49774989
if (dest == NULL)
49784990
return PyErr_NoMemory();
49794991

4980-
Py_BEGIN_CRITICAL_SECTION(self);
49814992
for (cur = start, i = 0; i < slicelen;
49824993
cur += step, i++) {
49834994
dest[i] = ptr[cur];
49844995
}
4985-
Py_END_CRITICAL_SECTION();
49864996

49874997
np = PyBytes_FromStringAndSize(dest, slicelen);
49884998
PyMem_Free(dest);
@@ -4996,10 +5006,8 @@ Array_subscript(PyObject *myself, PyObject *item)
49965006
return Py_GetConstant(Py_CONSTANT_EMPTY_STR);
49975007
if (step == 1) {
49985008
PyObject *res;
4999-
Py_BEGIN_CRITICAL_SECTION(self);
50005009
res = PyUnicode_FromWideChar(ptr + start,
50015010
slicelen);
5002-
Py_END_CRITICAL_SECTION();
50035011
return res;
50045012
}
50055013

@@ -5009,12 +5017,10 @@ Array_subscript(PyObject *myself, PyObject *item)
50095017
return NULL;
50105018
}
50115019

5012-
Py_BEGIN_CRITICAL_SECTION(self);
50135020
for (cur = start, i = 0; i < slicelen;
50145021
cur += step, i++) {
50155022
dest[i] = ptr[cur];
50165023
}
5017-
Py_END_CRITICAL_SECTION();
50185024

50195025
np = PyUnicode_FromWideChar(dest, slicelen);
50205026
PyMem_Free(dest);
@@ -5027,7 +5033,7 @@ Array_subscript(PyObject *myself, PyObject *item)
50275033

50285034
for (cur = start, i = 0; i < slicelen;
50295035
cur += step, i++) {
5030-
PyObject *v = Array_item(myself, cur);
5036+
PyObject *v = Array_item_lock_held(myself, cur);
50315037
if (v == NULL) {
50325038
Py_DECREF(np);
50335039
return NULL;
@@ -5041,12 +5047,24 @@ Array_subscript(PyObject *myself, PyObject *item)
50415047
"indices must be integers");
50425048
return NULL;
50435049
}
5050+
}
50445051

5052+
5053+
static PyObject *
5054+
Array_subscript(PyObject *myself, PyObject *item)
5055+
{
5056+
PyObject *result;
5057+
Py_BEGIN_CRITICAL_SECTION(myself);
5058+
result = Array_subscript_lock_held(myself, item);
5059+
Py_END_CRITICAL_SECTION();
5060+
return result;
50455061
}
50465062

50475063
static int
5048-
Array_ass_item(PyObject *myself, Py_ssize_t index, PyObject *value)
5064+
Array_ass_item_lock_held(PyObject *myself, Py_ssize_t index, PyObject *value)
50495065
{
5066+
_Py_CRITICAL_SECTION_ASSERT_OBJECT_LOCKED(myself);
5067+
50505068
CDataObject *self = _CDataObject_CAST(myself);
50515069
Py_ssize_t size, offset;
50525070
char *ptr;
@@ -5078,7 +5096,18 @@ Array_ass_item(PyObject *myself, Py_ssize_t index, PyObject *value)
50785096
}
50795097

50805098
static int
5081-
Array_ass_subscript(PyObject *myself, PyObject *item, PyObject *value)
5099+
Array_ass_item(PyObject *myself, Py_ssize_t index, PyObject *value)
5100+
{
5101+
int result;
5102+
Py_BEGIN_CRITICAL_SECTION(myself);
5103+
result = Array_ass_item_lock_held(myself, index, value);
5104+
Py_END_CRITICAL_SECTION();
5105+
return result;
5106+
}
5107+
5108+
5109+
static int
5110+
Array_ass_subscript_lock_held(PyObject *myself, PyObject *item, PyObject *value)
50825111
{
50835112
CDataObject *self = _CDataObject_CAST(myself);
50845113

@@ -5095,7 +5124,7 @@ Array_ass_subscript(PyObject *myself, PyObject *item, PyObject *value)
50955124
return -1;
50965125
if (i < 0)
50975126
i += self->b_length;
5098-
return Array_ass_item(myself, i, value);
5127+
return Array_ass_item_lock_held(myself, i, value);
50995128
}
51005129
else if (PySlice_Check(item)) {
51015130
Py_ssize_t start, stop, step, slicelen, otherlen, i;
@@ -5120,7 +5149,7 @@ Array_ass_subscript(PyObject *myself, PyObject *item, PyObject *value)
51205149
int result;
51215150
if (item == NULL)
51225151
return -1;
5123-
result = Array_ass_item(myself, cur, item);
5152+
result = Array_ass_item_lock_held(myself, cur, item);
51245153
Py_DECREF(item);
51255154
if (result == -1)
51265155
return -1;
@@ -5134,6 +5163,17 @@ Array_ass_subscript(PyObject *myself, PyObject *item, PyObject *value)
51345163
}
51355164
}
51365165

5166+
static int
5167+
Array_ass_subscript(PyObject *myself, PyObject *item, PyObject *value)
5168+
{
5169+
int result;
5170+
Py_BEGIN_CRITICAL_SECTION(myself);
5171+
result = Array_ass_subscript_lock_held(myself, item, value);
5172+
Py_END_CRITICAL_SECTION();
5173+
return result;
5174+
}
5175+
5176+
51375177
static Py_ssize_t
51385178
Array_length(PyObject *myself)
51395179
{

Objects/typeobject.c

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11233,7 +11233,14 @@ update_one_slot(PyTypeObject *type, pytype_slotdef *p)
1123311233
}
1123411234
else {
1123511235
use_generic = 1;
11236-
generic = p->function;
11236+
if (generic == NULL && Py_IS_TYPE(descr, &PyMethodDescr_Type) &&
11237+
*ptr == ((PyMethodDescrObject *)descr)->d_method->ml_meth)
11238+
{
11239+
generic = *ptr;
11240+
}
11241+
else {
11242+
generic = p->function;
11243+
}
1123711244
if (p->function == slot_tp_call) {
1123811245
/* A generic __call__ is incompatible with vectorcall */
1123911246
type_clear_flags(type, Py_TPFLAGS_HAVE_VECTORCALL);

PC/layout/main.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -657,7 +657,7 @@ def main():
657657
if ns.arch not in ("win32", "amd64", "arm32", "arm64"):
658658
log_error("--arch is not a valid value (win32, amd64, arm32, arm64)")
659659
return 4
660-
if ns.arch in ("arm32", "arm64"):
660+
if ns.arch == "arm32":
661661
for n in ("include_idle", "include_tcltk"):
662662
if getattr(ns, n):
663663
log_warning(f"Disabling --{n.replace('_', '-')} on unsupported platform")

Python/frame.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,7 @@ take_ownership(PyFrameObject *f, _PyInterpreterFrame *frame)
6969
_PyInterpreterFrame *prev = _PyFrame_GetFirstComplete(frame->previous);
7070
if (prev) {
7171
assert(prev->owner < FRAME_OWNED_BY_INTERPRETER);
72+
PyObject *exc = PyErr_GetRaisedException();
7273
/* Link PyFrameObjects.f_back and remove link through _PyInterpreterFrame.previous */
7374
PyFrameObject *back = _PyFrame_GetFrameObject(prev);
7475
if (back == NULL) {
@@ -80,6 +81,7 @@ take_ownership(PyFrameObject *f, _PyInterpreterFrame *frame)
8081
else {
8182
f->f_back = (PyFrameObject *)Py_NewRef(back);
8283
}
84+
PyErr_SetRaisedException(exc);
8385
}
8486
if (!_PyObject_GC_IS_TRACKED((PyObject *)f)) {
8587
_PyObject_GC_TRACK((PyObject *)f);

Python/importdl.c

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@
66
#include "pycore_import.h" // _PyImport_SwapPackageContext()
77
#include "pycore_importdl.h"
88
#include "pycore_moduleobject.h" // _PyModule_GetDef()
9-
#include "pycore_moduleobject.h" // _PyModule_GetDef()
109
#include "pycore_pyerrors.h" // _PyErr_FormatFromCause()
1110
#include "pycore_runtime.h" // _Py_ID()
1211

0 commit comments

Comments
 (0)