Skip to content

Commit b445672

Browse files
authored
Merge branch 'main' into gh-130279-backward-jump-handler
2 parents 3030c13 + c7a1716 commit b445672

20 files changed

Lines changed: 136 additions & 106 deletions

‎Doc/c-api/interp-lifecycle.rst‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -514,7 +514,7 @@ Process-wide parameters
514514
Return the version of this Python interpreter. This is a string that looks
515515
something like ::
516516
517-
"3.15.0rc2 (3.15.0~rc2-1.fc44.x86_64, Sep 3 2026, 00:00:00) [GCC 16.2.1 20260819 (Red Hat 16.2.1-2)]"
517+
"3.0a5+ (py3k:63103M, May 12 2008, 00:53:55) \n[GCC 4.2.3]"
518518
519519
.. index:: single: version (in module sys)
520520

‎Doc/using/windows.rst‎

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -283,8 +283,8 @@ Passing ``--update`` will replace existing installs if the new version is newer.
283283
Otherwise, they will be left. If no tags are provided with ``--update``, all
284284
installs managed by the Python install manager will be updated if newer versions
285285
are available. Updates will remove any modifications made to the install,
286-
including globally installed packages, but virtual environments will continue to
287-
work.
286+
including globally installed packages, but will leave ``site-packages`` and
287+
``Scripts`` directories as is. Virtual environments are also unaffected.
288288

289289
Passing ``--dry-run`` will generate output and logs, but will not modify any
290290
installs.
@@ -399,8 +399,9 @@ override all other settings, but not every option is available.
399399
This section will describe the defaults, but be aware that modified or
400400
overridden installs may resolve settings differently.
401401

402-
A global configuration file may be configured by an administrator, and would be
403-
read first. The user configuration file is stored at
402+
A global configuration file may be configured by an
403+
:ref:`administrator <pymanager-admin-config>`
404+
and would be read first. The user configuration file is stored at
404405
:file:`%AppData%\\Python\\pymanager.json`
405406
(note that this location is under ``Roaming``, not ``Local``) and is read next,
406407
overwriting any settings from earlier files. An additional configuration file

‎Include/internal/pycore_pylifecycle.h‎

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ extern int _Py_IsLocaleCoercionTarget(const char *ctype_loc);
2323

2424
/* Various one-time initializers */
2525

26-
extern PyStatus _Py_GetVersion_Init(void);
26+
extern void _Py_InitVersion(void);
2727
extern PyStatus _PyFaulthandler_Init(int enable);
2828
extern PyObject * _PyBuiltin_Init(PyInterpreterState *interp);
2929
extern int _PyBuiltin_InitPythonFunctions(PyObject *dict);
@@ -43,7 +43,6 @@ extern PyStatus _PyDateTime_InitTypes(PyInterpreterState *interp);
4343

4444
/* Various internal finalizers */
4545

46-
extern void _Py_GetVersion_Fini(void);
4746
extern int _PySignal_Init(int install_signal_handlers);
4847
extern void _PySignal_Fini(void);
4948

‎Lib/email/message.py‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1026,7 +1026,7 @@ def _find_body(self, part, preferencelist):
10261026
if subtype in preferencelist:
10271027
yield (preferencelist.index(subtype), part)
10281028
return
1029-
if maintype != 'multipart' or not self.is_multipart():
1029+
if maintype != 'multipart' or not part.is_multipart():
10301030
return
10311031
if subtype != 'related':
10321032
for subpart in part.iter_parts():

‎Lib/logging/__init__.py‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1680,6 +1680,8 @@ def _log(self, level, msg, args, exc_info=None, extra=None, stack_info=False,
16801680
exc_info = (type(exc_info), exc_info, exc_info.__traceback__)
16811681
elif not isinstance(exc_info, tuple):
16821682
exc_info = sys.exc_info()
1683+
else: # Normalize any falsy value to None, for type precision
1684+
exc_info = None
16831685
record = self.makeRecord(self.name, level, fn, lno, msg, args,
16841686
exc_info, func, extra, sinfo)
16851687
self.handle(record)

‎Lib/mimetypes.py‎

Lines changed: 19 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,8 @@
2323
read_mime_types(file) -- parse one file, return a dictionary or None
2424
"""
2525

26+
import sys
27+
2628
try:
2729
from _winapi import _mimetypes_read_windows_registry
2830
except ImportError:
@@ -40,17 +42,23 @@
4042
"suffix_map", "encodings_map", "types_map", "common_types"
4143
]
4244

43-
knownfiles = [
44-
"/etc/mime.types",
45-
"/etc/httpd/mime.types", # Mac OS X
46-
"/etc/httpd/conf/mime.types", # Apache
47-
"/etc/apache/mime.types", # Apache 1
48-
"/etc/apache2/mime.types", # Apache 2
49-
"/usr/local/etc/httpd/conf/mime.types",
50-
"/usr/local/lib/netscape/mime.types",
51-
"/usr/local/etc/httpd/conf/mime.types", # Apache 1.2
52-
"/usr/local/etc/mime.types", # Apache 1.3
53-
]
45+
if sys.platform == "win32":
46+
# The default paths would resolve to the root of the current drive on Windows
47+
# (e.g. C:\etc\mime.types), which unprivileged users can usually create.
48+
# Only the registry is used by default.
49+
knownfiles = []
50+
else:
51+
knownfiles = [
52+
"/etc/mime.types",
53+
"/etc/httpd/mime.types", # Mac OS X
54+
"/etc/httpd/conf/mime.types", # Apache
55+
"/etc/apache/mime.types", # Apache 1
56+
"/etc/apache2/mime.types", # Apache 2
57+
"/usr/local/etc/httpd/conf/mime.types",
58+
"/usr/local/lib/netscape/mime.types",
59+
"/usr/local/etc/httpd/conf/mime.types", # Apache 1.2
60+
"/usr/local/etc/mime.types", # Apache 1.3
61+
]
5462

5563
inited = False
5664
_db = None

‎Lib/test/support/__init__.py‎

Lines changed: 33 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
import types
2020
import unittest
2121
import warnings
22+
lazy import platform
2223

2324

2425
__all__ = [
@@ -33,6 +34,7 @@
3334
"is_resource_enabled", "get_resource_value", "requires", "requires_resource",
3435
"requires_freebsd_version",
3536
"requires_gil_enabled", "requires_linux_version", "requires_mac_ver",
37+
"requires_ios_ver",
3638
"check_syntax_error",
3739
"requires_gzip", "requires_bz2", "requires_lzma", "requires_zstd",
3840
"bigmemtest", "nomemtest", "bigaddrspacetest", "cpython_only", "get_attribute",
@@ -229,7 +231,6 @@ def _force_run(path, func, *args):
229231
def _is_gui_available():
230232
if hasattr(_is_gui_available, 'result'):
231233
return _is_gui_available.result
232-
import platform
233234
reason = None
234235
if sys.platform.startswith('win') and platform.win32_is_iot():
235236
reason = "gui is not available on Windows IoT Core"
@@ -354,7 +355,6 @@ def _requires_unix_version(sysname, min_version):
354355
For example, @_requires_unix_version('FreeBSD', (7, 2)) raises SkipTest if
355356
the FreeBSD version is less than 7.2.
356357
"""
357-
import platform
358358
min_version_txt = '.'.join(map(str, min_version))
359359
version_txt = platform.release().split('-', 1)[0]
360360
if platform.system() == sysname:
@@ -392,19 +392,12 @@ def requires_linux_version(*min_version):
392392
"""
393393
return _requires_unix_version('Linux', min_version)
394394

395-
def requires_mac_ver(*min_version):
396-
"""Decorator raising SkipTest if the OS is Mac OS X and the OS X
397-
version if less than min_version.
398-
399-
For example, @requires_mac_ver(10, 5) raises SkipTest if the OS X version
400-
is lesser than 10.5.
401-
"""
395+
def _requires_apple_os_version(name, sys_platform, get_version_text, min_version):
402396
def decorator(func):
403397
@functools.wraps(func)
404398
def wrapper(*args, **kw):
405-
if sys.platform == 'darwin':
406-
import platform
407-
version_txt = platform.mac_ver()[0]
399+
if sys.platform == sys_platform:
400+
version_txt = get_version_text()
408401
try:
409402
version = tuple(map(int, version_txt.split('.')))
410403
except ValueError:
@@ -413,14 +406,40 @@ def wrapper(*args, **kw):
413406
if version < min_version:
414407
min_version_txt = '.'.join(map(str, min_version))
415408
raise unittest.SkipTest(
416-
"Mac OS X %s or higher required, not %s"
417-
% (min_version_txt, version_txt))
409+
f"{name} {min_version_txt} or higher required, "
410+
+ f"not {version_txt}")
418411
return func(*args, **kw)
419412
wrapper.min_version = min_version
420413
return wrapper
421414
return decorator
422415

423416

417+
def requires_mac_ver(*min_version):
418+
"""Decorator raising SkipTest if the OS is Mac OS X and the OS X
419+
version if less than min_version.
420+
421+
For example, @requires_mac_ver(10, 5) raises SkipTest if the OS X version
422+
is lesser than 10.5.
423+
"""
424+
return _requires_apple_os_version(
425+
"macOS", "darwin",
426+
get_version_text=lambda: platform.mac_ver()[0],
427+
min_version=min_version)
428+
429+
430+
def requires_ios_ver(*min_version):
431+
"""Decorator raising SkipTest if the OS is iOS and the OS version
432+
version if less than min_version.
433+
434+
For example, requires_ios_ver(16, 0) raises SkipTest if the iOS version
435+
is lesser than 16.0.
436+
"""
437+
return _requires_apple_os_version(
438+
"iOS", "ios",
439+
get_version_text=lambda: platform.ios_ver().release,
440+
min_version=min_version)
441+
442+
424443
def thread_unsafe(reason):
425444
"""Mark a test as not thread safe. When the test runner is run with
426445
--parallel-threads=N, the test will be run in a single thread."""
@@ -2223,7 +2242,6 @@ def setswitchinterval(interval):
22232242
if is_android and interval < minimum_interval:
22242243
global _old_android_emulator
22252244
if _old_android_emulator is None:
2226-
import platform
22272245
av = platform.android_ver()
22282246
_old_android_emulator = av.is_emulator and av.api_level < 24
22292247
if _old_android_emulator:
@@ -3480,7 +3498,6 @@ def linked_to_musl():
34803498

34813499
# On linux, we'll depend on the platform module to do the check, so new
34823500
# musl platforms should add support in that module if possible.
3483-
import platform
34843501
lib, version = platform.libc_ver()
34853502
if lib != 'musl':
34863503
_linked_to_musl = False

‎Lib/test/test_capi/test_build.py‎

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,11 +20,15 @@ def test_getcopyright(self):
2020

2121
# Test Py_GetCompiler()
2222
def test_getcompiler(self):
23-
self.assertIn(_testlimitedcapi.py_getcompiler(), sys.version)
23+
compiler = _testlimitedcapi.py_getcompiler()
24+
self.assertIsInstance(compiler, str)
25+
self.assertNotEqual(compiler, '')
2426

2527
# Test Py_GetBuildInfo()
2628
def test_getbuildinfo(self):
27-
self.assertIn(_testlimitedcapi.py_getbuildinfo(), sys.version)
29+
buildinfo = _testlimitedcapi.py_getbuildinfo()
30+
self.assertIsInstance(buildinfo, str)
31+
self.assertNotEqual(buildinfo, '')
2832

2933
# Test internal _Py_GetBuiltWithAssert()
3034
def test__getbuiltwithassert(self):

‎Lib/test/test_email/test_message.py‎

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1081,6 +1081,25 @@ def test_get_body_malformed(self):
10811081
# AttributeError: 'str' object has no attribute 'is_attachment'
10821082
m.get_body()
10831083

1084+
def test_get_body_malformed_nested_multipart(self):
1085+
# gh-159304: a nested multipart part without a boundary has a
1086+
# string payload, which get_body() must not iterate over.
1087+
msg = textwrap.dedent("""\
1088+
From: sender@example.com
1089+
To: receiver@example.com
1090+
Subject: Malformed
1091+
Content-Type: multipart/related; boundary=OUTER
1092+
1093+
--OUTER
1094+
Content-Type: multipart/related
1095+
1096+
raw body no boundary
1097+
--OUTER--
1098+
""")
1099+
m = self._str_msg(msg)
1100+
self.assertIsNone(m.get_body(('plain', 'html')))
1101+
self.assertIs(m.get_body(('related',)), m)
1102+
10841103
def test_get_bytes_payload_with_quoted_printable_encoding(self):
10851104
# We use a memoryview to avoid directly changing the private payload
10861105
# and to prevent using the dedicated paths for string or bytes objects.

‎Lib/test/test_isinstance.py‎

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -263,6 +263,20 @@ def test_subclass_tuple(self):
263263
self.assertEqual(True, issubclass(int, (int, (float, int))))
264264
self.assertEqual(True, issubclass(str, (str, (Child, str))))
265265

266+
def test_tuple_subclass_methods_not_called(self):
267+
# gh-83731: make sure isinstance() reads the items of a tuple
268+
# subclass directly, without calling its __iter__(),
269+
# __getitem__() or __len__().
270+
class T(tuple):
271+
def __iter__(self):
272+
raise AssertionError('__iter__ called')
273+
def __getitem__(self, index):
274+
raise AssertionError('__getitem__ called')
275+
def __len__(self):
276+
raise AssertionError('__len__ called')
277+
278+
self.assertTrue(isinstance(1, T((int,))))
279+
266280
@support.skip_if_huge_c_stack()
267281
@support.skip_wasi_stack_overflow()
268282
@support.skip_emscripten_stack_overflow()

0 commit comments

Comments
 (0)