Skip to content

Commit ed5d9ed

Browse files
generatedunixname1734921407115435meta-codesync[bot]
authored andcommitted
Sync pre-release CPython main branch from GitHub (2026-06-04)
Summary: Imported python/cpython `3.16.0a0` from upstream rev [`e28a2f4`](https://www.github.com/python/cpython/commit/e28a2f493044ecfc0f76fe78ff6dde8e395504a9) (committed 2026-06-04 20:37:18+00:00). # Commit Info - Base: (`3.16.0a0`) - [`57d4446`](https://www.github.com/python/cpython/commit/57d444612d9c8a0eab66543d5bf8539103a59b47) (commit date: 2026-06-04 00:00:51+00:00) - Imported: (`3.16.0a0`) - [`e28a2f4`](https://www.github.com/python/cpython/commit/e28a2f493044ecfc0f76fe78ff6dde8e395504a9) (commit date: 2026-06-04 20:37:18+00:00) # Noteworthy file changes - Low-signal files (8 added) (NEWS.d, docs, .github) Complete list of added/removed files: https://www.internalfb.com/intern/everpaste/?color=0&handle=GPQGPShGeRXJEqEEAJilEKcc3pYXbr0LAAAz Differential Revision: D107613581 fbshipit-source-id: dbe62ccba45e6870d04eaacb6c0e11695f861b10
1 parent 102f894 commit ed5d9ed

35 files changed

Lines changed: 758 additions & 384 deletions

Doc/c-api/complex.rst

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -130,7 +130,7 @@ rather than dereferencing them through pointers.
130130
131131
Please note, that these functions are :term:`soft deprecated` since Python
132132
3.15. Avoid using this API in a new code to do complex arithmetic: either use
133-
the `Number Protocol <number>`_ API or use native complex types, like
133+
the :ref:`Number Protocol <number>` API or use native complex types, like
134134
:c:expr:`double complex`.
135135
136136

Doc/extending/first-extension-module.rst

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -164,7 +164,7 @@ Then, create ``meson.build`` containing the following:
164164
165165
.. note::
166166

167-
See `meson-python documentation <meson-python>`_ for details on
167+
See the `meson-python documentation <meson-python_>`_ for details on
168168
configuration.
169169

170170
Now, build install the *project in the current directory* (``.``) via ``pip``:

Doc/library/shlex.rst

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,12 +44,15 @@ The :mod:`!shlex` module defines the following functions:
4444
.. versionadded:: 3.8
4545

4646

47-
.. function:: quote(s)
47+
.. function:: quote(s, *, force=False)
4848

4949
Return a shell-escaped version of the string *s*. The returned value is a
5050
string that can safely be used as one token in a shell command line, for
5151
cases where you cannot use a list.
5252

53+
If *force* is :const:`True`, then *s* is unconditionally quoted,
54+
even if it is already safe for a shell without being quoted.
55+
5356
.. _shlex-quote-warning:
5457

5558
.. warning::
@@ -91,8 +94,23 @@ The :mod:`!shlex` module defines the following functions:
9194
>>> command
9295
['ls', '-l', 'somefile; rm -rf ~']
9396

97+
The *force* keyword can be used to produce consistent behavior when
98+
escaping multiple strings:
99+
100+
>>> from shlex import quote
101+
>>> filenames = ['my first file', 'file2', 'file 3']
102+
>>> filenames_some_escaped = [quote(f) for f in filenames]
103+
>>> filenames_some_escaped
104+
["'my first file'", 'file2', "'file 3'"]
105+
>>> filenames_all_escaped = [quote(f, force=True) for f in filenames]
106+
>>> filenames_all_escaped
107+
["'my first file'", "'file2'", "'file 3'"]
108+
94109
.. versionadded:: 3.3
95110

111+
.. versionchanged:: next
112+
The *force* keyword was added.
113+
96114
The :mod:`!shlex` module defines the following class:
97115

98116

Doc/library/stdtypes.rst

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2616,7 +2616,9 @@ expression support in the :mod:`re` module).
26162616
:func:`re.split`). Splitting an empty string with a specified separator
26172617
returns ``['']``.
26182618

2619-
For example::
2619+
For example:
2620+
2621+
.. doctest::
26202622

26212623
>>> '1,2,3'.split(',')
26222624
['1', '2', '3']
@@ -2634,7 +2636,9 @@ expression support in the :mod:`re` module).
26342636
string or a string consisting of just whitespace with a ``None`` separator
26352637
returns ``[]``.
26362638

2637-
For example::
2639+
For example:
2640+
2641+
.. doctest::
26382642

26392643
>>> '1 2 3'.split()
26402644
['1', '2', '3']
@@ -2646,7 +2650,9 @@ expression support in the :mod:`re` module).
26462650
If *sep* is not specified or is ``None`` and *maxsplit* is ``0``, only
26472651
leading runs of consecutive whitespace are considered.
26482652

2649-
For example::
2653+
For example:
2654+
2655+
.. doctest::
26502656

26512657
>>> "".split(None, 0)
26522658
[]
@@ -2655,7 +2661,7 @@ expression support in the :mod:`re` module).
26552661
>>> " foo ".split(maxsplit=0)
26562662
['foo ']
26572663

2658-
See also :meth:`join`.
2664+
See also :meth:`join` and :meth:`rsplit`.
26592665

26602666

26612667
.. index::

Doc/using/windows.rst

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -455,6 +455,12 @@ customization.
455455
Python runtimes, or false to prevent it.
456456
By default, true.
457457

458+
* - ``shebang_templates``
459+
- (none)
460+
- Mapping from shebang line template to alternative command, such as
461+
``py -V:<tag>`` or a substitute string.
462+
See :ref:`pymanager-shebang` for more details.
463+
458464
* - ``log_level``
459465
- ``PYMANAGER_VERBOSE``, ``PYMANAGER_DEBUG``
460466
- Set the default level of output (0-50).
@@ -568,6 +574,30 @@ which the path to the script and any additional arguments will be appended.
568574
This functionality may be disabled by the ``shebang_can_run_anything``
569575
configuration option.
570576

577+
Since version 26.3 of the Python install manager, custom shebang templates may
578+
be added to your configuration file. Add the ``shebang_templates`` object with
579+
one member for each template (the string to match) and the command to use when
580+
the template is matched. Most commands should be ``py -V:<tag>`` (or ``pyw``) to
581+
launch one of your installed runtimes. The ``py -3.<version>`` form is also
582+
allowed, as is a plain ``py`` to launch the default. No other arguments are
583+
supported.
584+
585+
.. code:: json5
586+
587+
{
588+
"shebang_templates": {
589+
"/usr/bin/python": "py",
590+
"/usr/bin/my_custom_python": "py -V:MyCustomPython/3"
591+
}
592+
}
593+
594+
If the substitute command is not ``py`` or ``pyw``, it will be written back into
595+
the shebang and regular handling continues. If launching arbitrary executables
596+
is permitted, then providing a full path will allow you to redirect from Python
597+
to any executable. The template should match either the entire line (ignoring
598+
leading and trailing whitespace), or up to the first space in the shebang line.
599+
600+
571601
.. note::
572602

573603
The behaviour of shebangs in the Python install manager is subtly different

Doc/whatsnew/3.16.rst

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,13 @@ os
109109
process via a pidfd. Available on Linux 5.6+.
110110
(Contributed by Maurycy Pawłowski-Wieroński in :gh:`149464`.)
111111

112+
shlex
113+
-----
114+
115+
* Add keyword-only parameter *force* to :func:`shlex.quote` to force quoting
116+
a string, even if it is already safe for a shell without being quoted.
117+
(Contributed by Jay Berry in :gh:`148846`.)
118+
112119
xml
113120
---
114121

Lib/enum.py

Lines changed: 15 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1620,32 +1620,38 @@ def __or__(self, other):
16201620
if other_value is NotImplemented:
16211621
return NotImplemented
16221622

1623-
for flag in self, other:
1624-
if self._get_value(flag) is None:
1625-
raise TypeError(f"'{flag}' cannot be combined with other flags with |")
16261623
value = self._value_
1624+
# _get_value(self) is self._value_ and _get_value(other) is
1625+
# other_value, so only walk the operands (to raise on the offending
1626+
# flag) when one of those values is actually None.
1627+
if value is None or other_value is None:
1628+
for flag in self, other:
1629+
if self._get_value(flag) is None:
1630+
raise TypeError(f"'{flag}' cannot be combined with other flags with |")
16271631
return self.__class__(value | other_value)
16281632

16291633
def __and__(self, other):
16301634
other_value = self._get_value(other)
16311635
if other_value is NotImplemented:
16321636
return NotImplemented
16331637

1634-
for flag in self, other:
1635-
if self._get_value(flag) is None:
1636-
raise TypeError(f"'{flag}' cannot be combined with other flags with &")
16371638
value = self._value_
1639+
if value is None or other_value is None:
1640+
for flag in self, other:
1641+
if self._get_value(flag) is None:
1642+
raise TypeError(f"'{flag}' cannot be combined with other flags with &")
16381643
return self.__class__(value & other_value)
16391644

16401645
def __xor__(self, other):
16411646
other_value = self._get_value(other)
16421647
if other_value is NotImplemented:
16431648
return NotImplemented
16441649

1645-
for flag in self, other:
1646-
if self._get_value(flag) is None:
1647-
raise TypeError(f"'{flag}' cannot be combined with other flags with ^")
16481650
value = self._value_
1651+
if value is None or other_value is None:
1652+
for flag in self, other:
1653+
if self._get_value(flag) is None:
1654+
raise TypeError(f"'{flag}' cannot be combined with other flags with ^")
16491655
return self.__class__(value ^ other_value)
16501656

16511657
def __invert__(self):

Lib/importlib/_bootstrap.py

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -20,12 +20,6 @@
2020
# reference any injected objects! This includes not only global code but also
2121
# anything specified at the class level.
2222

23-
def _object_name(obj):
24-
try:
25-
return obj.__qualname__
26-
except AttributeError:
27-
return type(obj).__qualname__
28-
2923
# Bootstrap-related code ######################################################
3024

3125
# Modules injected manually by _setup()

Lib/logging/__init__.py

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1373,9 +1373,16 @@ def getLogger(self, name):
13731373
logger and fix up the parent/child references which pointed to the
13741374
placeholder to now point to the logger.
13751375
"""
1376-
rv = None
13771376
if not isinstance(name, str):
13781377
raise TypeError('A logger name must be a string')
1378+
# Fast path: an already-registered, non-placeholder logger can be
1379+
# returned without taking the lock. dict.get() is atomic under both
1380+
# the GIL and free threading, and a Logger is fully initialised before
1381+
# being inserted into loggerDict under the lock, so this never sees a
1382+
# partially-constructed object.
1383+
rv = self.loggerDict.get(name)
1384+
if rv is not None and not isinstance(rv, PlaceHolder):
1385+
return rv
13791386
with _lock:
13801387
if name in self.loggerDict:
13811388
rv = self.loggerDict[name]

Lib/logging/handlers.py

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -282,7 +282,16 @@ def __init__(self, filename, when='h', interval=1, backupCount=0,
282282
# path object (see Issue #27493), but self.baseFilename will be a string
283283
filename = self.baseFilename
284284
if os.path.exists(filename):
285-
t = int(os.stat(filename).st_mtime)
285+
# Use the minimum of file creation and modification time as
286+
# the base of the rollover calculation
287+
stat_result = os.stat(filename)
288+
# Use st_birthtime whenever it is available or use st_ctime
289+
# instead otherwise
290+
try:
291+
creation_time = stat_result.st_birthtime
292+
except AttributeError:
293+
creation_time = stat_result.st_ctime
294+
t = int(min(creation_time, stat_result.st_mtime))
286295
else:
287296
t = int(time.time())
288297
self.rolloverAt = self.computeRollover(t)

0 commit comments

Comments
 (0)