Skip to content

Commit 170cac8

Browse files
authored
Merge branch 'main' into binaryops_shift
2 parents 1895d69 + d89a5f6 commit 170cac8

File tree

90 files changed

+1789
-1352
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

90 files changed

+1789
-1352
lines changed

Doc/glossary.rst

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -658,6 +658,9 @@ Glossary
658658
and therefore it is never deallocated while the interpreter is running.
659659
For example, :const:`True` and :const:`None` are immortal in CPython.
660660

661+
Immortal objects can be identified via :func:`sys._is_immortal`, or
662+
via :c:func:`PyUnstable_IsImmortal` in the C API.
663+
661664
immutable
662665
An object with a fixed value. Immutable objects include numbers, strings and
663666
tuples. Such an object cannot be altered. A new object has to

Doc/library/sys.rst

Lines changed: 33 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -855,6 +855,11 @@ always available. Unless explicitly noted otherwise, all variables are read-only
855855
reflect the actual number of references. Consequently, do not rely
856856
on the returned value to be accurate, other than a value of 0 or 1.
857857

858+
.. impl-detail::
859+
860+
:term:`Immortal <immortal>` objects with a large reference count can be
861+
identified via :func:`_is_immortal`.
862+
858863
.. versionchanged:: 3.12
859864
Immortal objects have very large refcounts that do not match
860865
the actual number of references to the object.
@@ -1264,6 +1269,24 @@ always available. Unless explicitly noted otherwise, all variables are read-only
12641269

12651270
.. versionadded:: 3.12
12661271

1272+
.. function:: _is_immortal(op)
1273+
1274+
Return :const:`True` if the given object is :term:`immortal`, :const:`False`
1275+
otherwise.
1276+
1277+
.. note::
1278+
1279+
Objects that are immortal (and thus return ``True`` upon being passed
1280+
to this function) are not guaranteed to be immortal in future versions,
1281+
and vice versa for mortal objects.
1282+
1283+
.. versionadded:: next
1284+
1285+
.. impl-detail::
1286+
1287+
This function should be used for specialized purposes only.
1288+
It is not guaranteed to exist in all implementations of Python.
1289+
12671290
.. function:: _is_interned(string)
12681291

12691292
Return :const:`True` if the given string is "interned", :const:`False`
@@ -1422,6 +1445,7 @@ always available. Unless explicitly noted otherwise, all variables are read-only
14221445
AIX ``'aix'``
14231446
Android ``'android'``
14241447
Emscripten ``'emscripten'``
1448+
FreeBSD ``'freebsd'``
14251449
iOS ``'ios'``
14261450
Linux ``'linux'``
14271451
macOS ``'darwin'``
@@ -1432,12 +1456,12 @@ always available. Unless explicitly noted otherwise, all variables are read-only
14321456

14331457
On Unix systems not listed in the table, the value is the lowercased OS name
14341458
as returned by ``uname -s``, with the first part of the version as returned by
1435-
``uname -r`` appended, e.g. ``'sunos5'`` or ``'freebsd8'``, *at the time
1436-
when Python was built*. Unless you want to test for a specific system
1437-
version, it is therefore recommended to use the following idiom::
1459+
``uname -r`` appended, e.g. ``'sunos5'``, *at the time when Python was built*.
1460+
Unless you want to test for a specific system version, it is therefore
1461+
recommended to use the following idiom::
14381462

1439-
if sys.platform.startswith('freebsd'):
1440-
# FreeBSD-specific code here...
1463+
if sys.platform.startswith('sunos'):
1464+
# SunOS-specific code here...
14411465

14421466
.. versionchanged:: 3.3
14431467
On Linux, :data:`sys.platform` doesn't contain the major version anymore.
@@ -1451,6 +1475,10 @@ always available. Unless explicitly noted otherwise, all variables are read-only
14511475
On Android, :data:`sys.platform` now returns ``'android'`` rather than
14521476
``'linux'``.
14531477

1478+
.. versionchanged:: 3.14
1479+
On FreeBSD, :data:`sys.platform` doesn't contain the major version anymore.
1480+
It is always ``'freebsd'``, instead of ``'freebsd13'`` or ``'freebsd14'``.
1481+
14541482
.. seealso::
14551483

14561484
:data:`os.name` has a coarser granularity. :func:`os.uname` gives

Doc/whatsnew/3.14.rst

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -649,6 +649,13 @@ sys
649649
which only exists in specialized builds of Python, may now return objects
650650
from other interpreters than the one it's called in.
651651

652+
* Add :func:`sys._is_immortal` for determining if an object is :term:`immortal`.
653+
(Contributed by Peter Bierma in :gh:`128509`.)
654+
655+
* On FreeBSD, :data:`sys.platform` doesn't contain the major version anymore.
656+
It is always ``'freebsd'``, instead of ``'freebsd13'`` or ``'freebsd14'``.
657+
658+
652659
sys.monitoring
653660
--------------
654661

Lib/_pyio.py

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1062,9 +1062,6 @@ def _read_unlocked(self, n=None):
10621062
if chunk is None:
10631063
return buf[pos:] or None
10641064
else:
1065-
# Avoid slice + copy if there is no data in buf
1066-
if not buf:
1067-
return chunk
10681065
return buf[pos:] + chunk
10691066
chunks = [buf[pos:]] # Strip the consumed bytes.
10701067
current_size = 0

Lib/ast.py

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1196,9 +1196,14 @@ def visit_JoinedStr(self, node):
11961196
fallback_to_repr = True
11971197
break
11981198
quote_types = new_quote_types
1199-
elif "\n" in value:
1200-
quote_types = [q for q in quote_types if q in _MULTI_QUOTES]
1201-
assert quote_types
1199+
else:
1200+
if "\n" in value:
1201+
quote_types = [q for q in quote_types if q in _MULTI_QUOTES]
1202+
assert quote_types
1203+
1204+
new_quote_types = [q for q in quote_types if q not in value]
1205+
if new_quote_types:
1206+
quote_types = new_quote_types
12021207
new_fstring_parts.append(value)
12031208

12041209
if fallback_to_repr:

Lib/multiprocessing/forkserver.py

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -382,13 +382,14 @@ def _serve_one(child_r, fds, unused_fds, handlers):
382382
#
383383

384384
def read_signed(fd):
385-
data = b''
386-
length = SIGNED_STRUCT.size
387-
while len(data) < length:
388-
s = os.read(fd, length - len(data))
389-
if not s:
385+
data = bytearray(SIGNED_STRUCT.size)
386+
unread = memoryview(data)
387+
while unread:
388+
count = os.readinto(fd, unread)
389+
if count == 0:
390390
raise EOFError('unexpected EOF')
391-
data += s
391+
unread = unread[count:]
392+
392393
return SIGNED_STRUCT.unpack(data)[0]
393394

394395
def write_signed(fd, n):

Lib/string.py

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -212,19 +212,20 @@ def _vformat(self, format_string, args, kwargs, used_args, recursion_depth,
212212
# this is some markup, find the object and do
213213
# the formatting
214214

215-
# handle arg indexing when empty field_names are given.
216-
if field_name == '':
215+
# handle arg indexing when empty field first parts are given.
216+
field_first, _ = _string.formatter_field_name_split(field_name)
217+
if field_first == '':
217218
if auto_arg_index is False:
218219
raise ValueError('cannot switch from manual field '
219220
'specification to automatic field '
220221
'numbering')
221-
field_name = str(auto_arg_index)
222+
field_name = str(auto_arg_index) + field_name
222223
auto_arg_index += 1
223-
elif field_name.isdigit():
224+
elif isinstance(field_first, int):
224225
if auto_arg_index:
225-
raise ValueError('cannot switch from manual field '
226-
'specification to automatic field '
227-
'numbering')
226+
raise ValueError('cannot switch from automatic field '
227+
'numbering to manual field '
228+
'specification')
228229
# disable auto arg incrementing, if it gets
229230
# used later on, then an exception will be raised
230231
auto_arg_index = False

Lib/test/support/__init__.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,7 @@
6666
"BrokenIter",
6767
"in_systemd_nspawn_sync_suppressed",
6868
"run_no_yield_async_fn", "run_yielding_async_fn", "async_yield",
69+
"reset_code",
6970
]
7071

7172

@@ -1286,6 +1287,12 @@ def requires_specialization_ft(test):
12861287
_opcode.ENABLE_SPECIALIZATION_FT, "requires specialization")(test)
12871288

12881289

1290+
def reset_code(f: types.FunctionType) -> types.FunctionType:
1291+
"""Clear all specializations, local instrumentation, and JIT code for the given function."""
1292+
f.__code__ = f.__code__.replace()
1293+
return f
1294+
1295+
12891296
#=======================================================================
12901297
# Check for the presence of docstrings.
12911298

Lib/test/test_capi/test_frame.py

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
import sys
2+
import unittest
3+
from test.support import import_helper
4+
5+
6+
_testcapi = import_helper.import_module('_testcapi')
7+
8+
9+
class FrameTest(unittest.TestCase):
10+
def getframe(self):
11+
return sys._getframe()
12+
13+
def test_frame_getters(self):
14+
frame = self.getframe()
15+
self.assertEqual(frame.f_locals, _testcapi.frame_getlocals(frame))
16+
self.assertIs(frame.f_globals, _testcapi.frame_getglobals(frame))
17+
self.assertIs(frame.f_builtins, _testcapi.frame_getbuiltins(frame))
18+
self.assertEqual(frame.f_lasti, _testcapi.frame_getlasti(frame))
19+
20+
def test_getvar(self):
21+
current_frame = sys._getframe()
22+
x = 1
23+
self.assertEqual(_testcapi.frame_getvar(current_frame, "x"), 1)
24+
self.assertEqual(_testcapi.frame_getvarstring(current_frame, b"x"), 1)
25+
with self.assertRaises(NameError):
26+
_testcapi.frame_getvar(current_frame, "y")
27+
with self.assertRaises(NameError):
28+
_testcapi.frame_getvarstring(current_frame, b"y")
29+
30+
# wrong name type
31+
with self.assertRaises(TypeError):
32+
_testcapi.frame_getvar(current_frame, b'x')
33+
with self.assertRaises(TypeError):
34+
_testcapi.frame_getvar(current_frame, 123)
35+
36+
def getgenframe(self):
37+
yield sys._getframe()
38+
39+
def test_frame_get_generator(self):
40+
gen = self.getgenframe()
41+
frame = next(gen)
42+
self.assertIs(gen, _testcapi.frame_getgenerator(frame))
43+
44+
def test_frame_fback_api(self):
45+
"""Test that accessing `f_back` does not cause a segmentation fault on
46+
a frame created with `PyFrame_New` (GH-99110)."""
47+
def dummy():
48+
pass
49+
50+
frame = _testcapi.frame_new(dummy.__code__, globals(), locals())
51+
# The following line should not cause a segmentation fault.
52+
self.assertIsNone(frame.f_back)
53+
54+
55+
if __name__ == "__main__":
56+
unittest.main()

0 commit comments

Comments
 (0)