Skip to content

Commit 715949f

Browse files
authored
Merge branch 'main' into fix-functools_partial_repr_bug
2 parents 192ff1e + fd190d1 commit 715949f

30 files changed

+452
-80
lines changed

Doc/c-api/module.rst

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -725,10 +725,11 @@ remove it.
725725
726726
An array of additional slots, terminated by a ``{0, NULL}`` entry.
727727
728-
This array may not contain slots corresponding to :c:type:`PyModuleDef`
729-
members.
730-
For example, you cannot use :c:macro:`Py_mod_name` in :c:member:`!m_slots`;
731-
the module name must be given as :c:member:`PyModuleDef.m_name`.
728+
If the array contains slots corresponding to :c:type:`PyModuleDef`
729+
members, the values must match.
730+
For example, if you use :c:macro:`Py_mod_name` in :c:member:`!m_slots`,
731+
:c:member:`PyModuleDef.m_name` must be set to the same pointer
732+
(not just an equal string).
732733
733734
.. versionchanged:: 3.5
734735

Doc/deprecations/pending-removal-in-future.rst

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,6 @@ although there is currently no date scheduled for their removal.
3535
* Support for ``__complex__()`` method returning a strict subclass of
3636
:class:`complex`: these methods will be required to return an instance of
3737
:class:`complex`.
38-
* Delegation of ``int()`` to ``__trunc__()`` method.
3938
* Passing a complex number as the *real* or *imag* argument in the
4039
:func:`complex` constructor is now deprecated; it should only be passed
4140
as a single positional argument.

Doc/library/datetime.rst

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2540,7 +2540,7 @@ requires, and these work on all supported platforms.
25402540
| ``%e`` | The day of the month as a | ␣1, ␣2, ..., 31 | |
25412541
| | space-padded decimal number. | | |
25422542
+-----------+--------------------------------+------------------------+-------+
2543-
| ``%F`` | Equivalent to ``%Y-%m-%d``, | 2025-10-11, | \(0) |
2543+
| ``%F`` | Equivalent to ``%Y-%m-%d``, | 2025-10-11, | |
25442544
| | the ISO 8601 format. | 1001-12-30 | |
25452545
+-----------+--------------------------------+------------------------+-------+
25462546
| ``%g`` | Last 2 digits of ISO 8601 year | 00, 01, ..., 99 | \(0) |
@@ -2673,10 +2673,10 @@ differences between platforms in handling of unsupported format specifiers.
26732673
``%G``, ``%u`` and ``%V`` were added.
26742674

26752675
.. versionadded:: 3.12
2676-
``%:z`` was added for :meth:`~.datetime.strftime`
2676+
``%:z`` was added for :meth:`~.datetime.strftime`.
26772677

26782678
.. versionadded:: 3.15
2679-
``%:z`` was added for :meth:`~.datetime.strptime`
2679+
``%:z`` and ``%F`` were added for :meth:`~.datetime.strptime`.
26802680

26812681
Technical Detail
26822682
^^^^^^^^^^^^^^^^

Doc/library/stdtypes.rst

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2180,7 +2180,18 @@ expression support in the :mod:`re` module).
21802180
Return ``True`` if all characters in the string are alphanumeric and there is at
21812181
least one character, ``False`` otherwise. A character ``c`` is alphanumeric if one
21822182
of the following returns ``True``: ``c.isalpha()``, ``c.isdecimal()``,
2183-
``c.isdigit()``, or ``c.isnumeric()``.
2183+
``c.isdigit()``, or ``c.isnumeric()``. For example::
2184+
2185+
.. doctest::
2186+
2187+
>>> 'abc123'.isalnum()
2188+
True
2189+
>>> 'abc123!@#'.isalnum()
2190+
False
2191+
>>> ''.isalnum()
2192+
False
2193+
>>> ' '.isalnum()
2194+
False
21842195

21852196

21862197
.. method:: str.isalpha()
@@ -2472,6 +2483,19 @@ expression support in the :mod:`re` module).
24722483
after the separator. If the separator is not found, return a 3-tuple containing
24732484
the string itself, followed by two empty strings.
24742485

2486+
For example:
2487+
2488+
.. doctest::
2489+
2490+
>>> 'Monty Python'.partition(' ')
2491+
('Monty', ' ', 'Python')
2492+
>>> "Monty Python's Flying Circus".partition(' ')
2493+
('Monty', ' ', "Python's Flying Circus")
2494+
>>> 'Monty Python'.partition('-')
2495+
('Monty Python', '', '')
2496+
2497+
See also :meth:`rpartition`.
2498+
24752499

24762500
.. method:: str.removeprefix(prefix, /)
24772501

Doc/library/typing.rst

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2527,6 +2527,12 @@ types.
25272527

25282528
.. versionadded:: 3.8
25292529

2530+
.. deprecated-removed:: 3.15 3.20
2531+
It is deprecated to call :func:`isinstance` and :func:`issubclass` checks on
2532+
protocol classes that were not explicitly decorated with :func:`!runtime_checkable`
2533+
but that inherit from a runtime-checkable protocol class. This will throw
2534+
a :exc:`TypeError` in Python 3.20.
2535+
25302536
.. decorator:: runtime_checkable
25312537

25322538
Mark a protocol class as a runtime protocol.
@@ -2548,6 +2554,18 @@ types.
25482554
import threading
25492555
assert isinstance(threading.Thread(name='Bob'), Named)
25502556

2557+
Runtime checkability of protocols is not inherited. A subclass of a runtime-checkable protocol
2558+
is only runtime-checkable if it is explicitly marked as such, regardless of class hierarchy::
2559+
2560+
@runtime_checkable
2561+
class Iterable(Protocol):
2562+
def __iter__(self): ...
2563+
2564+
# Without @runtime_checkable, Reversible would no longer be runtime-checkable.
2565+
@runtime_checkable
2566+
class Reversible(Iterable, Protocol):
2567+
def __reversed__(self): ...
2568+
25512569
This decorator raises :exc:`TypeError` when applied to a non-protocol class.
25522570

25532571
.. note::
@@ -2588,6 +2606,11 @@ types.
25882606
protocol. See :ref:`What's new in Python 3.12 <whatsnew-typing-py312>`
25892607
for more details.
25902608

2609+
.. deprecated-removed:: 3.15 3.20
2610+
It is deprecated to call :func:`isinstance` and :func:`issubclass` checks on
2611+
protocol classes that were not explicitly decorated with :func:`!runtime_checkable`
2612+
but that inherit from a runtime-checkable protocol class. This will throw
2613+
a :exc:`TypeError` in Python 3.20.
25912614

25922615
.. class:: TypedDict(dict)
25932616

Include/datetime.h

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -196,8 +196,23 @@ typedef struct {
196196
/* Define global variable for the C API and a macro for setting it. */
197197
static PyDateTime_CAPI *PyDateTimeAPI = NULL;
198198

199-
#define PyDateTime_IMPORT \
200-
PyDateTimeAPI = (PyDateTime_CAPI *)PyCapsule_Import(PyDateTime_CAPSULE_NAME, 0)
199+
static inline PyDateTime_CAPI *
200+
_PyDateTime_IMPORT(void) {
201+
PyDateTime_CAPI *val = _Py_atomic_load_ptr(&PyDateTimeAPI);
202+
if (val == NULL) {
203+
PyDateTime_CAPI *capi = (PyDateTime_CAPI *)PyCapsule_Import(
204+
PyDateTime_CAPSULE_NAME, 0);
205+
if (capi != NULL) {
206+
/* if the compare exchange fails then in that case
207+
another thread would have initialized it */
208+
_Py_atomic_compare_exchange_ptr(&PyDateTimeAPI, &val, (void *)capi);
209+
return capi;
210+
}
211+
}
212+
return val;
213+
}
214+
215+
#define PyDateTime_IMPORT _PyDateTime_IMPORT()
201216

202217
/* Macro for access to the UTC singleton */
203218
#define PyDateTime_TimeZone_UTC PyDateTimeAPI->TimeZone_UTC

Lib/_strptime.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -418,6 +418,7 @@ def __init__(self, locale_time=None):
418418
mapping['W'] = mapping['U'].replace('U', 'W')
419419

420420
base.__init__(mapping)
421+
base.__setitem__('F', self.pattern('%Y-%m-%d'))
421422
base.__setitem__('T', self.pattern('%H:%M:%S'))
422423
base.__setitem__('R', self.pattern('%H:%M'))
423424
base.__setitem__('r', self.pattern(self.locale_time.LC_time_ampm))

Lib/test/datetimetester.py

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2193,6 +2193,13 @@ def test_fromisocalendar_type_errors(self):
21932193
with self.assertRaises(TypeError):
21942194
self.theclass.fromisocalendar(*isocal)
21952195

2196+
def test_strptime_F_format(self):
2197+
test_date = "2025-10-26"
2198+
self.assertEqual(
2199+
self.theclass.strptime(test_date, "%F"),
2200+
self.theclass.strptime(test_date, "%Y-%m-%d")
2201+
)
2202+
21962203

21972204
#############################################################################
21982205
# datetime tests
@@ -3780,6 +3787,13 @@ def test_repr_subclass(self):
37803787
td = SubclassDatetime(2010, 10, 2, second=3)
37813788
self.assertEqual(repr(td), "SubclassDatetime(2010, 10, 2, 0, 0, 3)")
37823789

3790+
def test_strptime_T_format(self):
3791+
test_time = "15:00:00"
3792+
self.assertEqual(
3793+
self.theclass.strptime(test_time, "%T"),
3794+
self.theclass.strptime(test_time, "%H:%M:%S")
3795+
)
3796+
37833797

37843798
class TestSubclassDateTime(TestDateTime):
37853799
theclass = SubclassDatetime

Lib/test/test_capi/test_module.py

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -122,8 +122,7 @@ def test_create(self):
122122
_testcapi.pymodule_get_token(mod)
123123

124124
def test_def_slot(self):
125-
"""Slots that replace PyModuleDef fields can't be used with PyModuleDef
126-
"""
125+
"""Slots cannot contradict PyModuleDef fields"""
127126
for name in DEF_SLOTS:
128127
with self.subTest(name):
129128
spec = FakeSpec()
@@ -133,6 +132,11 @@ def test_def_slot(self):
133132
self.assertIn(name, str(cm.exception))
134133
self.assertIn("PyModuleDef", str(cm.exception))
135134

135+
def test_def_slot_parrot(self):
136+
"""Slots with same value as PyModuleDef fields are allowed"""
137+
spec = FakeSpec()
138+
_testcapi.module_from_def_slot_parrot(spec)
139+
136140
def test_repeated_def_slot(self):
137141
"""Slots that replace PyModuleDef fields can't be repeated"""
138142
for name in (*DEF_SLOTS, 'Py_mod_exec'):

Lib/test/test_cmd_line.py

Lines changed: 4 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@
99
import tempfile
1010
import textwrap
1111
import unittest
12-
import warnings
1312
from test import support
1413
from test.support import os_helper
1514
from test.support import force_not_colorized
@@ -943,21 +942,15 @@ def test_python_asyncio_debug(self):
943942

944943
@unittest.skipUnless(sysconfig.get_config_var('Py_TRACE_REFS'), "Requires --with-trace-refs build option")
945944
def test_python_dump_refs(self):
946-
code = 'import sys; sys._clear_type_cache()'
947-
# TODO: Remove warnings context manager once sys._clear_type_cache is removed
948-
with warnings.catch_warnings():
949-
warnings.simplefilter("ignore", DeprecationWarning)
950-
rc, out, err = assert_python_ok('-c', code, PYTHONDUMPREFS='1')
945+
code = 'import sys; sys._clear_internal_caches()'
946+
rc, out, err = assert_python_ok('-c', code, PYTHONDUMPREFS='1')
951947
self.assertEqual(rc, 0)
952948

953949
@unittest.skipUnless(sysconfig.get_config_var('Py_TRACE_REFS'), "Requires --with-trace-refs build option")
954950
def test_python_dump_refs_file(self):
955951
with tempfile.NamedTemporaryFile() as dump_file:
956-
code = 'import sys; sys._clear_type_cache()'
957-
# TODO: Remove warnings context manager once sys._clear_type_cache is removed
958-
with warnings.catch_warnings():
959-
warnings.simplefilter("ignore", DeprecationWarning)
960-
rc, out, err = assert_python_ok('-c', code, PYTHONDUMPREFSFILE=dump_file.name)
952+
code = 'import sys; sys._clear_internal_caches()'
953+
rc, out, err = assert_python_ok('-c', code, PYTHONDUMPREFSFILE=dump_file.name)
961954
self.assertEqual(rc, 0)
962955
with open(dump_file.name, 'r') as file:
963956
contents = file.read()

0 commit comments

Comments
 (0)