Sync from SUSE:SLFO:Main python313 revision f3fded152e9ee7e3c3e8a86fe18815c2

This commit is contained in:
2025-06-27 16:00:14 +02:00
parent b8ba5ea90c
commit 6fe6053eb5
14 changed files with 894 additions and 732 deletions

View File

@@ -1,483 +0,0 @@
From 0afcdf15f64273dc5e4ed12ea63a01f7f1136d71 Mon Sep 17 00:00:00 2001
From: Serhiy Storchaka <storchaka@gmail.com>
Date: Mon, 12 May 2025 20:42:23 +0300
Subject: [PATCH] [3.13] gh-133767: Fix use-after-free in the unicode-escape
decoder with an error handler (GH-129648)
If the error handler is used, a new bytes object is created to set as
the object attribute of UnicodeDecodeError, and that bytes object then
replaces the original data. A pointer to the decoded data will became invalid
after destroying that temporary bytes object. So we need other way to return
the first invalid escape from _PyUnicode_DecodeUnicodeEscapeInternal().
_PyBytes_DecodeEscape() does not have such issue, because it does not
use the error handlers registry, but it should be changed for compatibility
with _PyUnicode_DecodeUnicodeEscapeInternal().
(cherry picked from commit 9f69a58623bd01349a18ba0c7a9cb1dad6a51e8e)
Co-authored-by: Serhiy Storchaka <storchaka@gmail.com>
---
Include/internal/pycore_bytesobject.h | 5
Include/internal/pycore_unicodeobject.h | 12 +-
Lib/test/test_codeccallbacks.py | 39 +++++++
Lib/test/test_codecs.py | 52 ++++++++--
Misc/NEWS.d/next/Security/2025-05-09-20-22-54.gh-issue-133767.kN2i3Q.rst | 2
Objects/bytesobject.c | 41 ++++---
Objects/unicodeobject.c | 46 +++++---
Parser/string_parser.c | 26 +++--
8 files changed, 160 insertions(+), 63 deletions(-)
create mode 100644 Misc/NEWS.d/next/Security/2025-05-09-20-22-54.gh-issue-133767.kN2i3Q.rst
Index: Python-3.13.3/Include/internal/pycore_bytesobject.h
===================================================================
--- Python-3.13.3.orig/Include/internal/pycore_bytesobject.h 2025-04-08 13:54:08.000000000 +0000
+++ Python-3.13.3/Include/internal/pycore_bytesobject.h 2025-05-17 07:33:22.001814947 +0000
@@ -20,8 +20,9 @@
// Helper for PyBytes_DecodeEscape that detects invalid escape chars.
// Export for test_peg_generator.
-PyAPI_FUNC(PyObject*) _PyBytes_DecodeEscape(const char *, Py_ssize_t,
- const char *, const char **);
+PyAPI_FUNC(PyObject*) _PyBytes_DecodeEscape2(const char *, Py_ssize_t,
+ const char *,
+ int *, const char **);
// Substring Search.
Index: Python-3.13.3/Include/internal/pycore_unicodeobject.h
===================================================================
--- Python-3.13.3.orig/Include/internal/pycore_unicodeobject.h 2025-04-08 13:54:08.000000000 +0000
+++ Python-3.13.3/Include/internal/pycore_unicodeobject.h 2025-05-17 07:33:22.001974979 +0000
@@ -142,14 +142,18 @@
// Helper for PyUnicode_DecodeUnicodeEscape that detects invalid escape
// chars.
// Export for test_peg_generator.
-PyAPI_FUNC(PyObject*) _PyUnicode_DecodeUnicodeEscapeInternal(
+PyAPI_FUNC(PyObject*) _PyUnicode_DecodeUnicodeEscapeInternal2(
const char *string, /* Unicode-Escape encoded string */
Py_ssize_t length, /* size of string */
const char *errors, /* error handling */
Py_ssize_t *consumed, /* bytes consumed */
- const char **first_invalid_escape); /* on return, points to first
- invalid escaped char in
- string. */
+ int *first_invalid_escape_char, /* on return, if not -1, contain the first
+ invalid escaped char (<= 0xff) or invalid
+ octal escape (> 0xff) in string. */
+ const char **first_invalid_escape_ptr); /* on return, if not NULL, may
+ point to the first invalid escaped
+ char in string.
+ May be NULL if errors is not NULL. */
/* --- Raw-Unicode-Escape Codecs ---------------------------------------------- */
Index: Python-3.13.3/Lib/test/test_codeccallbacks.py
===================================================================
--- Python-3.13.3.orig/Lib/test/test_codeccallbacks.py 2025-04-08 13:54:08.000000000 +0000
+++ Python-3.13.3/Lib/test/test_codeccallbacks.py 2025-05-17 07:33:22.002185827 +0000
@@ -1,6 +1,7 @@
import codecs
import html.entities
import itertools
+import re
import sys
import unicodedata
import unittest
@@ -1124,7 +1125,7 @@
text = 'abc<def>ghi'*n
text.translate(charmap)
- def test_mutatingdecodehandler(self):
+ def test_mutating_decode_handler(self):
baddata = [
("ascii", b"\xff"),
("utf-7", b"++"),
@@ -1159,6 +1160,42 @@
for (encoding, data) in baddata:
self.assertEqual(data.decode(encoding, "test.mutating"), "\u4242")
+ def test_mutating_decode_handler_unicode_escape(self):
+ decode = codecs.unicode_escape_decode
+ def mutating(exc):
+ if isinstance(exc, UnicodeDecodeError):
+ r = data.get(exc.object[:exc.end])
+ if r is not None:
+ exc.object = r[0] + exc.object[exc.end:]
+ return ('\u0404', r[1])
+ raise AssertionError("don't know how to handle %r" % exc)
+
+ codecs.register_error('test.mutating2', mutating)
+ data = {
+ br'\x0': (b'\\', 0),
+ br'\x3': (b'xxx\\', 3),
+ br'\x5': (b'x\\', 1),
+ }
+ def check(input, expected, msg):
+ with self.assertWarns(DeprecationWarning) as cm:
+ self.assertEqual(decode(input, 'test.mutating2'), (expected, len(input)))
+ self.assertIn(msg, str(cm.warning))
+
+ check(br'\x0n\z', '\u0404\n\\z', r"invalid escape sequence '\z'")
+ check(br'\x0n\501', '\u0404\n\u0141', r"invalid octal escape sequence '\501'")
+ check(br'\x0z', '\u0404\\z', r"invalid escape sequence '\z'")
+
+ check(br'\x3n\zr', '\u0404\n\\zr', r"invalid escape sequence '\z'")
+ check(br'\x3zr', '\u0404\\zr', r"invalid escape sequence '\z'")
+ check(br'\x3z5', '\u0404\\z5', r"invalid escape sequence '\z'")
+ check(memoryview(br'\x3z5x')[:-1], '\u0404\\z5', r"invalid escape sequence '\z'")
+ check(memoryview(br'\x3z5xy')[:-2], '\u0404\\z5', r"invalid escape sequence '\z'")
+
+ check(br'\x5n\z', '\u0404\n\\z', r"invalid escape sequence '\z'")
+ check(br'\x5n\501', '\u0404\n\u0141', r"invalid octal escape sequence '\501'")
+ check(br'\x5z', '\u0404\\z', r"invalid escape sequence '\z'")
+ check(memoryview(br'\x5zy')[:-1], '\u0404\\z', r"invalid escape sequence '\z'")
+
# issue32583
def test_crashing_decode_handler(self):
# better generating one more character to fill the extra space slot
Index: Python-3.13.3/Lib/test/test_codecs.py
===================================================================
--- Python-3.13.3.orig/Lib/test/test_codecs.py 2025-04-08 13:54:08.000000000 +0000
+++ Python-3.13.3/Lib/test/test_codecs.py 2025-05-17 07:33:22.002507164 +0000
@@ -1196,23 +1196,39 @@
check(br"[\1010]", b"[A0]")
check(br"[\x41]", b"[A]")
check(br"[\x410]", b"[A0]")
+
+ def test_warnings(self):
+ decode = codecs.escape_decode
+ check = coding_checker(self, decode)
for i in range(97, 123):
b = bytes([i])
if b not in b'abfnrtvx':
- with self.assertWarns(DeprecationWarning):
+ with self.assertWarnsRegex(DeprecationWarning,
+ r"invalid escape sequence '\\%c'" % i):
check(b"\\" + b, b"\\" + b)
- with self.assertWarns(DeprecationWarning):
+ with self.assertWarnsRegex(DeprecationWarning,
+ r"invalid escape sequence '\\%c'" % (i-32)):
check(b"\\" + b.upper(), b"\\" + b.upper())
- with self.assertWarns(DeprecationWarning):
+ with self.assertWarnsRegex(DeprecationWarning,
+ r"invalid escape sequence '\\8'"):
check(br"\8", b"\\8")
with self.assertWarns(DeprecationWarning):
check(br"\9", b"\\9")
- with self.assertWarns(DeprecationWarning):
+ with self.assertWarnsRegex(DeprecationWarning,
+ r"invalid escape sequence '\\\xfa'") as cm:
check(b"\\\xfa", b"\\\xfa")
for i in range(0o400, 0o1000):
- with self.assertWarns(DeprecationWarning):
+ with self.assertWarnsRegex(DeprecationWarning,
+ r"invalid octal escape sequence '\\%o'" % i):
check(rb'\%o' % i, bytes([i & 0o377]))
+ with self.assertWarnsRegex(DeprecationWarning,
+ r"invalid escape sequence '\\z'"):
+ self.assertEqual(decode(br'\x\z', 'ignore'), (b'\\z', 4))
+ with self.assertWarnsRegex(DeprecationWarning,
+ r"invalid octal escape sequence '\\501'"):
+ self.assertEqual(decode(br'\x\501', 'ignore'), (b'A', 6))
+
def test_errors(self):
decode = codecs.escape_decode
self.assertRaises(ValueError, decode, br"\x")
@@ -2661,24 +2677,40 @@
check(br"[\x410]", "[A0]")
check(br"\u20ac", "\u20ac")
check(br"\U0001d120", "\U0001d120")
+
+ def test_decode_warnings(self):
+ decode = codecs.unicode_escape_decode
+ check = coding_checker(self, decode)
for i in range(97, 123):
b = bytes([i])
if b not in b'abfnrtuvx':
- with self.assertWarns(DeprecationWarning):
+ with self.assertWarnsRegex(DeprecationWarning,
+ r"invalid escape sequence '\\%c'" % i):
check(b"\\" + b, "\\" + chr(i))
if b.upper() not in b'UN':
- with self.assertWarns(DeprecationWarning):
+ with self.assertWarnsRegex(DeprecationWarning,
+ r"invalid escape sequence '\\%c'" % (i-32)):
check(b"\\" + b.upper(), "\\" + chr(i-32))
- with self.assertWarns(DeprecationWarning):
+ with self.assertWarnsRegex(DeprecationWarning,
+ r"invalid escape sequence '\\8'"):
check(br"\8", "\\8")
with self.assertWarns(DeprecationWarning):
check(br"\9", "\\9")
- with self.assertWarns(DeprecationWarning):
+ with self.assertWarnsRegex(DeprecationWarning,
+ r"invalid escape sequence '\\\xfa'") as cm:
check(b"\\\xfa", "\\\xfa")
for i in range(0o400, 0o1000):
- with self.assertWarns(DeprecationWarning):
+ with self.assertWarnsRegex(DeprecationWarning,
+ r"invalid octal escape sequence '\\%o'" % i):
check(rb'\%o' % i, chr(i))
+ with self.assertWarnsRegex(DeprecationWarning,
+ r"invalid escape sequence '\\z'"):
+ self.assertEqual(decode(br'\x\z', 'ignore'), ('\\z', 4))
+ with self.assertWarnsRegex(DeprecationWarning,
+ r"invalid octal escape sequence '\\501'"):
+ self.assertEqual(decode(br'\x\501', 'ignore'), ('\u0141', 6))
+
def test_decode_errors(self):
decode = codecs.unicode_escape_decode
for c, d in (b'x', 2), (b'u', 4), (b'U', 4):
Index: Python-3.13.3/Misc/NEWS.d/next/Security/2025-05-09-20-22-54.gh-issue-133767.kN2i3Q.rst
===================================================================
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ Python-3.13.3/Misc/NEWS.d/next/Security/2025-05-09-20-22-54.gh-issue-133767.kN2i3Q.rst 2025-05-17 07:33:22.002786511 +0000
@@ -0,0 +1,2 @@
+Fix use-after-free in the "unicode-escape" decoder with a non-"strict" error
+handler.
Index: Python-3.13.3/Objects/bytesobject.c
===================================================================
--- Python-3.13.3.orig/Objects/bytesobject.c 2025-04-08 13:54:08.000000000 +0000
+++ Python-3.13.3/Objects/bytesobject.c 2025-05-17 07:33:22.003325939 +0000
@@ -1065,10 +1065,11 @@
}
/* Unescape a backslash-escaped string. */
-PyObject *_PyBytes_DecodeEscape(const char *s,
+PyObject *_PyBytes_DecodeEscape2(const char *s,
Py_ssize_t len,
const char *errors,
- const char **first_invalid_escape)
+ int *first_invalid_escape_char,
+ const char **first_invalid_escape_ptr)
{
int c;
char *p;
@@ -1082,7 +1083,8 @@
return NULL;
writer.overallocate = 1;
- *first_invalid_escape = NULL;
+ *first_invalid_escape_char = -1;
+ *first_invalid_escape_ptr = NULL;
end = s + len;
while (s < end) {
@@ -1120,9 +1122,10 @@
c = (c<<3) + *s++ - '0';
}
if (c > 0377) {
- if (*first_invalid_escape == NULL) {
- *first_invalid_escape = s-3; /* Back up 3 chars, since we've
- already incremented s. */
+ if (*first_invalid_escape_char == -1) {
+ *first_invalid_escape_char = c;
+ /* Back up 3 chars, since we've already incremented s. */
+ *first_invalid_escape_ptr = s - 3;
}
}
*p++ = c;
@@ -1163,9 +1166,10 @@
break;
default:
- if (*first_invalid_escape == NULL) {
- *first_invalid_escape = s-1; /* Back up one char, since we've
- already incremented s. */
+ if (*first_invalid_escape_char == -1) {
+ *first_invalid_escape_char = (unsigned char)s[-1];
+ /* Back up one char, since we've already incremented s. */
+ *first_invalid_escape_ptr = s - 1;
}
*p++ = '\\';
s--;
@@ -1185,17 +1189,18 @@
Py_ssize_t Py_UNUSED(unicode),
const char *Py_UNUSED(recode_encoding))
{
- const char* first_invalid_escape;
- PyObject *result = _PyBytes_DecodeEscape(s, len, errors,
- &first_invalid_escape);
+ int first_invalid_escape_char;
+ const char *first_invalid_escape_ptr;
+ PyObject *result = _PyBytes_DecodeEscape2(s, len, errors,
+ &first_invalid_escape_char,
+ &first_invalid_escape_ptr);
if (result == NULL)
return NULL;
- if (first_invalid_escape != NULL) {
- unsigned char c = *first_invalid_escape;
- if ('4' <= c && c <= '7') {
+ if (first_invalid_escape_char != -1) {
+ if (first_invalid_escape_char > 0xff) {
if (PyErr_WarnFormat(PyExc_DeprecationWarning, 1,
- "invalid octal escape sequence '\\%.3s'",
- first_invalid_escape) < 0)
+ "invalid octal escape sequence '\\%o'",
+ first_invalid_escape_char) < 0)
{
Py_DECREF(result);
return NULL;
@@ -1204,7 +1209,7 @@
else {
if (PyErr_WarnFormat(PyExc_DeprecationWarning, 1,
"invalid escape sequence '\\%c'",
- c) < 0)
+ first_invalid_escape_char) < 0)
{
Py_DECREF(result);
return NULL;
Index: Python-3.13.3/Objects/unicodeobject.c
===================================================================
--- Python-3.13.3.orig/Objects/unicodeobject.c 2025-04-08 13:54:08.000000000 +0000
+++ Python-3.13.3/Objects/unicodeobject.c 2025-05-17 07:33:22.004748214 +0000
@@ -6177,13 +6177,15 @@
/* --- Unicode Escape Codec ----------------------------------------------- */
PyObject *
-_PyUnicode_DecodeUnicodeEscapeInternal(const char *s,
+_PyUnicode_DecodeUnicodeEscapeInternal2(const char *s,
Py_ssize_t size,
const char *errors,
Py_ssize_t *consumed,
- const char **first_invalid_escape)
+ int *first_invalid_escape_char,
+ const char **first_invalid_escape_ptr)
{
const char *starts = s;
+ const char *initial_starts = starts;
_PyUnicodeWriter writer;
const char *end;
PyObject *errorHandler = NULL;
@@ -6191,7 +6193,8 @@
_PyUnicode_Name_CAPI *ucnhash_capi;
// so we can remember if we've seen an invalid escape char or not
- *first_invalid_escape = NULL;
+ *first_invalid_escape_char = -1;
+ *first_invalid_escape_ptr = NULL;
if (size == 0) {
if (consumed) {
@@ -6279,9 +6282,12 @@
}
}
if (ch > 0377) {
- if (*first_invalid_escape == NULL) {
- *first_invalid_escape = s-3; /* Back up 3 chars, since we've
- already incremented s. */
+ if (*first_invalid_escape_char == -1) {
+ *first_invalid_escape_char = ch;
+ if (starts == initial_starts) {
+ /* Back up 3 chars, since we've already incremented s. */
+ *first_invalid_escape_ptr = s - 3;
+ }
}
}
WRITE_CHAR(ch);
@@ -6376,9 +6382,12 @@
goto error;
default:
- if (*first_invalid_escape == NULL) {
- *first_invalid_escape = s-1; /* Back up one char, since we've
- already incremented s. */
+ if (*first_invalid_escape_char == -1) {
+ *first_invalid_escape_char = c;
+ if (starts == initial_starts) {
+ /* Back up one char, since we've already incremented s. */
+ *first_invalid_escape_ptr = s - 1;
+ }
}
WRITE_ASCII_CHAR('\\');
WRITE_CHAR(c);
@@ -6423,18 +6432,19 @@
const char *errors,
Py_ssize_t *consumed)
{
- const char *first_invalid_escape;
- PyObject *result = _PyUnicode_DecodeUnicodeEscapeInternal(s, size, errors,
+ int first_invalid_escape_char;
+ const char *first_invalid_escape_ptr;
+ PyObject *result = _PyUnicode_DecodeUnicodeEscapeInternal2(s, size, errors,
consumed,
- &first_invalid_escape);
+ &first_invalid_escape_char,
+ &first_invalid_escape_ptr);
if (result == NULL)
return NULL;
- if (first_invalid_escape != NULL) {
- unsigned char c = *first_invalid_escape;
- if ('4' <= c && c <= '7') {
+ if (first_invalid_escape_char != -1) {
+ if (first_invalid_escape_char > 0xff) {
if (PyErr_WarnFormat(PyExc_DeprecationWarning, 1,
- "invalid octal escape sequence '\\%.3s'",
- first_invalid_escape) < 0)
+ "invalid octal escape sequence '\\%o'",
+ first_invalid_escape_char) < 0)
{
Py_DECREF(result);
return NULL;
@@ -6443,7 +6453,7 @@
else {
if (PyErr_WarnFormat(PyExc_DeprecationWarning, 1,
"invalid escape sequence '\\%c'",
- c) < 0)
+ first_invalid_escape_char) < 0)
{
Py_DECREF(result);
return NULL;
Index: Python-3.13.3/Parser/string_parser.c
===================================================================
--- Python-3.13.3.orig/Parser/string_parser.c 2025-04-08 13:54:08.000000000 +0000
+++ Python-3.13.3/Parser/string_parser.c 2025-05-17 07:33:22.005519309 +0000
@@ -184,15 +184,18 @@
len = (size_t)(p - buf);
s = buf;
- const char *first_invalid_escape;
- v = _PyUnicode_DecodeUnicodeEscapeInternal(s, (Py_ssize_t)len, NULL, NULL, &first_invalid_escape);
+ int first_invalid_escape_char;
+ const char *first_invalid_escape_ptr;
+ v = _PyUnicode_DecodeUnicodeEscapeInternal2(s, (Py_ssize_t)len, NULL, NULL,
+ &first_invalid_escape_char,
+ &first_invalid_escape_ptr);
// HACK: later we can simply pass the line no, since we don't preserve the tokens
// when we are decoding the string but we preserve the line numbers.
- if (v != NULL && first_invalid_escape != NULL && t != NULL) {
- if (warn_invalid_escape_sequence(parser, s, first_invalid_escape, t) < 0) {
- /* We have not decref u before because first_invalid_escape points
- inside u. */
+ if (v != NULL && first_invalid_escape_ptr != NULL && t != NULL) {
+ if (warn_invalid_escape_sequence(parser, s, first_invalid_escape_ptr, t) < 0) {
+ /* We have not decref u before because first_invalid_escape_ptr
+ points inside u. */
Py_XDECREF(u);
Py_DECREF(v);
return NULL;
@@ -205,14 +208,17 @@
static PyObject *
decode_bytes_with_escapes(Parser *p, const char *s, Py_ssize_t len, Token *t)
{
- const char *first_invalid_escape;
- PyObject *result = _PyBytes_DecodeEscape(s, len, NULL, &first_invalid_escape);
+ int first_invalid_escape_char;
+ const char *first_invalid_escape_ptr;
+ PyObject *result = _PyBytes_DecodeEscape2(s, len, NULL,
+ &first_invalid_escape_char,
+ &first_invalid_escape_ptr);
if (result == NULL) {
return NULL;
}
- if (first_invalid_escape != NULL) {
- if (warn_invalid_escape_sequence(p, s, first_invalid_escape, t) < 0) {
+ if (first_invalid_escape_ptr != NULL) {
+ if (warn_invalid_escape_sequence(p, s, first_invalid_escape_ptr, t) < 0) {
Py_DECREF(result);
return NULL;
}

BIN
Python-3.13.3.tar.xz (Stored with Git LFS)

Binary file not shown.

File diff suppressed because one or more lines are too long

BIN
Python-3.13.5.tar.xz (Stored with Git LFS) Normal file

Binary file not shown.

File diff suppressed because one or more lines are too long

View File

@@ -13,11 +13,9 @@ Co-Authored-By: Xavier de Gaye <xdegaye@gmail.com>
5 files changed, 37 insertions(+), 9 deletions(-)
create mode 100644 Misc/NEWS.d/next/Build/2019-12-16-17-50-42.bpo-31046.XA-Qfr.rst
Index: Python-3.13.3/Doc/library/ensurepip.rst
===================================================================
--- Python-3.13.3.orig/Doc/library/ensurepip.rst 2025-04-08 15:54:08.000000000 +0200
+++ Python-3.13.3/Doc/library/ensurepip.rst 2025-04-11 21:54:47.449458319 +0200
@@ -61,7 +61,11 @@
--- a/Doc/library/ensurepip.rst
+++ b/Doc/library/ensurepip.rst
@@ -61,7 +61,11 @@ is at least as recent as the one availab
By default, ``pip`` is installed into the current virtual environment
(if one is active) or into the system site packages (if there is no
active virtual environment). The installation location can be controlled
@@ -30,7 +28,7 @@ Index: Python-3.13.3/Doc/library/ensurepip.rst
.. option:: --root <dir>
@@ -102,7 +106,7 @@
@@ -102,7 +106,7 @@ Module API
Returns a string specifying the available version of pip that will be
installed when bootstrapping an environment.
@@ -39,7 +37,7 @@ Index: Python-3.13.3/Doc/library/ensurepip.rst
altinstall=False, default_pip=False, \
verbosity=0)
@@ -112,6 +116,8 @@
@@ -112,6 +116,8 @@ Module API
If *root* is ``None``, then installation uses the default install location
for the current environment.
@@ -48,7 +46,7 @@ Index: Python-3.13.3/Doc/library/ensurepip.rst
*upgrade* indicates whether or not to upgrade an existing installation
of an earlier version of ``pip`` to the available version.
@@ -132,6 +138,8 @@
@@ -132,6 +138,8 @@ Module API
*verbosity* controls the level of output to :data:`sys.stdout` from the
bootstrapping operation.
@@ -57,11 +55,9 @@ Index: Python-3.13.3/Doc/library/ensurepip.rst
.. audit-event:: ensurepip.bootstrap root ensurepip.bootstrap
.. note::
Index: Python-3.13.3/Lib/ensurepip/__init__.py
===================================================================
--- Python-3.13.3.orig/Lib/ensurepip/__init__.py 2025-04-08 15:54:08.000000000 +0200
+++ Python-3.13.3/Lib/ensurepip/__init__.py 2025-04-11 21:53:49.548370352 +0200
@@ -106,27 +106,27 @@
--- a/Lib/ensurepip/__init__.py
+++ b/Lib/ensurepip/__init__.py
@@ -106,27 +106,27 @@ def _disable_pip_configuration_settings(
os.environ['PIP_CONFIG_FILE'] = os.devnull
@@ -94,7 +90,7 @@ Index: Python-3.13.3/Lib/ensurepip/__init__.py
Note that calling this function will alter both sys.path and os.environ.
"""
@@ -162,6 +162,8 @@
@@ -162,6 +162,8 @@ def _bootstrap(*, root=None, upgrade=Fal
args = ["install", "--no-cache-dir", "--no-index", "--find-links", tmpdir]
if root:
args += ["--root", root]
@@ -103,7 +99,7 @@ Index: Python-3.13.3/Lib/ensurepip/__init__.py
if upgrade:
args += ["--upgrade"]
if user:
@@ -238,6 +240,11 @@
@@ -238,6 +240,11 @@ def _main(argv=None):
help="Install everything relative to this alternate root directory.",
)
parser.add_argument(
@@ -115,7 +111,7 @@ Index: Python-3.13.3/Lib/ensurepip/__init__.py
"--altinstall",
action="store_true",
default=False,
@@ -256,6 +263,7 @@
@@ -256,6 +263,7 @@ def _main(argv=None):
return _bootstrap(
root=args.root,
@@ -123,11 +119,9 @@ Index: Python-3.13.3/Lib/ensurepip/__init__.py
upgrade=args.upgrade,
user=args.user,
verbosity=args.verbosity,
Index: Python-3.13.3/Lib/test/test_ensurepip.py
===================================================================
--- Python-3.13.3.orig/Lib/test/test_ensurepip.py 2025-04-08 15:54:08.000000000 +0200
+++ Python-3.13.3/Lib/test/test_ensurepip.py 2025-04-11 21:53:49.548691764 +0200
@@ -101,6 +101,17 @@
--- a/Lib/test/test_ensurepip.py
+++ b/Lib/test/test_ensurepip.py
@@ -101,6 +101,17 @@ class TestBootstrap(EnsurepipMixin, unit
unittest.mock.ANY,
)
@@ -145,11 +139,9 @@ Index: Python-3.13.3/Lib/test/test_ensurepip.py
def test_bootstrapping_with_user(self):
ensurepip.bootstrap(user=True)
Index: Python-3.13.3/Makefile.pre.in
===================================================================
--- Python-3.13.3.orig/Makefile.pre.in 2025-04-11 21:52:35.635495820 +0200
+++ Python-3.13.3/Makefile.pre.in 2025-04-11 21:53:49.549094822 +0200
@@ -2139,7 +2139,7 @@
--- a/Makefile.pre.in
+++ b/Makefile.pre.in
@@ -2145,7 +2145,7 @@ install: @FRAMEWORKINSTALLFIRST@ @INSTAL
install|*) ensurepip="" ;; \
esac; \
$(RUNSHARED) $(PYTHON_FOR_BUILD) -m ensurepip \
@@ -158,7 +150,7 @@ Index: Python-3.13.3/Makefile.pre.in
fi
.PHONY: altinstall
@@ -2150,7 +2150,7 @@
@@ -2156,7 +2156,7 @@ altinstall: commoninstall
install|*) ensurepip="--altinstall" ;; \
esac; \
$(RUNSHARED) $(PYTHON_FOR_BUILD) -m ensurepip \
@@ -167,9 +159,7 @@ Index: Python-3.13.3/Makefile.pre.in
fi
.PHONY: commoninstall
Index: Python-3.13.3/Misc/NEWS.d/next/Build/2019-12-16-17-50-42.bpo-31046.XA-Qfr.rst
===================================================================
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ Python-3.13.3/Misc/NEWS.d/next/Build/2019-12-16-17-50-42.bpo-31046.XA-Qfr.rst 2025-04-11 21:53:49.549612071 +0200
--- /dev/null
+++ b/Misc/NEWS.d/next/Build/2019-12-16-17-50-42.bpo-31046.XA-Qfr.rst
@@ -0,0 +1 @@
+A directory prefix can now be specified when using :mod:`ensurepip`.

View File

@@ -1,28 +1,133 @@
---
Doc/conf.py | 17 ++++++++--
Doc/tools/check-warnings.py | 3 +
Doc/tools/extensions/audit_events.py | 54 ++++++++++++++++----------------
Doc/tools/extensions/availability.py | 15 ++++----
Doc/tools/extensions/c_annotations.py | 45 ++++++++++++++++----------
Doc/tools/extensions/glossary_search.py | 10 +----
Doc/tools/extensions/patchlevel.py | 9 ++---
7 files changed, 87 insertions(+), 66 deletions(-)
Doc/Makefile | 8 +--
Doc/c-api/arg.rst | 1
Doc/c-api/typeobj.rst | 8 +--
Doc/conf.py | 29 ++++++++++---
Doc/howto/free-threading-python.rst | 2
Doc/library/doctest.rst | 1
Doc/library/email.compat32-message.rst | 1
Doc/library/xml.etree.elementtree.rst | 1
Doc/Makefile | 8 +--
Doc/c-api/arg.rst | 1
Doc/c-api/typeobj.rst | 8 +--
Doc/conf.py | 29 ++++++++++---
Doc/library/doctest.rst | 1
Doc/library/email.compat32-message.rst | 1
Doc/library/xml.etree.elementtree.rst | 1
Doc/tools/check-warnings.py | 5 +-
Doc/tools/extensions/audit_events.py | 56 ++++++++++++++------------
Doc/tools/extensions/availability.py | 15 +++---
Doc/tools/extensions/c_annotations.py | 53 ++++++++++++++++--------
Doc/tools/extensions/changes.py | 8 +--
Doc/tools/extensions/glossary_search.py | 20 ++++++---
Doc/tools/extensions/implementation_detail.py | 22 +++-------
Doc/tools/extensions/issue_role.py | 16 ++-----
Doc/tools/extensions/misc_news.py | 14 ++----
Doc/tools/extensions/patchlevel.py | 9 ++--
Doc/tools/extensions/pydoc_topics.py | 22 +++++-----
18 files changed, 159 insertions(+), 130 deletions(-)
Index: Python-3.13.3/Doc/conf.py
Index: Python-3.13.5/Doc/Makefile
===================================================================
--- Python-3.13.3.orig/Doc/conf.py 2025-04-11 21:52:28.845065297 +0200
+++ Python-3.13.3/Doc/conf.py 2025-04-11 21:55:28.065280454 +0200
@@ -18,6 +18,9 @@
# Python specific content from Doc/Tools/extensions/pyspecific.py
from pyspecific import SOURCE_URI
--- Python-3.13.5.orig/Doc/Makefile 2025-06-12 21:37:37.257659788 +0200
+++ Python-3.13.5/Doc/Makefile 2025-06-12 21:38:04.908380762 +0200
@@ -14,15 +14,15 @@
SOURCES =
DISTVERSION = $(shell $(PYTHON) tools/extensions/patchlevel.py)
REQUIREMENTS = requirements.txt
-SPHINXERRORHANDLING = --fail-on-warning
+SPHINXERRORHANDLING =
+# Needed for fixing extlinks modification
+from sphinx import version_info as sphinx_version
# Internal variables.
PAPEROPT_a4 = --define latex_elements.papersize=a4paper
PAPEROPT_letter = --define latex_elements.papersize=letterpaper
-ALLSPHINXOPTS = --builder $(BUILDER) \
- --doctree-dir build/doctrees \
- --jobs $(JOBS) \
+ALLSPHINXOPTS = -b $(BUILDER) \
+ -d build/doctrees \
+ -j $(JOBS) \
$(PAPEROPT_$(PAPER)) \
$(SPHINXOPTS) $(SPHINXERRORHANDLING) \
. build/$(BUILDER) $(SOURCES)
Index: Python-3.13.5/Doc/c-api/arg.rst
===================================================================
--- Python-3.13.5.orig/Doc/c-api/arg.rst 2025-06-12 21:37:37.257659788 +0200
+++ Python-3.13.5/Doc/c-api/arg.rst 2025-06-12 21:38:04.908705133 +0200
@@ -334,7 +334,6 @@
should raise an exception and leave the content of *address* unmodified.
.. c:macro:: Py_CLEANUP_SUPPORTED
- :no-typesetting:
If the *converter* returns :c:macro:`!Py_CLEANUP_SUPPORTED`, it may get called a
second time if the argument parsing eventually fails, giving the converter a
Index: Python-3.13.5/Doc/c-api/typeobj.rst
===================================================================
--- Python-3.13.5.orig/Doc/c-api/typeobj.rst 2025-06-12 21:37:37.257659788 +0200
+++ Python-3.13.5/Doc/c-api/typeobj.rst 2025-06-12 21:38:04.908874058 +0200
@@ -610,7 +610,7 @@
Functions like :c:func:`PyObject_NewVar` will take the value of N as an
argument, and store in the instance's :c:member:`~PyVarObject.ob_size` field.
Note that the :c:member:`~PyVarObject.ob_size` field may later be used for
- other purposes. For example, :py:type:`int` instances use the bits of
+ other purposes. For example, :py:obj:`int` instances use the bits of
:c:member:`~PyVarObject.ob_size` in an implementation-defined
way; the underlying storage and its size should be accessed using
:c:func:`PyLong_Export`.
@@ -622,9 +622,9 @@
Also, the presence of an :c:member:`~PyVarObject.ob_size` field in the
instance layout doesn't mean that the instance structure is variable-length.
- For example, the :py:type:`list` type has fixed-length instances, yet those
+ For example, the :py:obj:`list` type has fixed-length instances, yet those
instances have a :c:member:`~PyVarObject.ob_size` field.
- (As with :py:type:`int`, avoid reading lists' :c:member:`!ob_size` directly.
+ (As with :py:obj:`int`, avoid reading lists' :c:member:`!ob_size` directly.
Call :c:func:`PyList_Size` instead.)
The :c:member:`!tp_basicsize` includes size needed for data of the type's
@@ -637,7 +637,7 @@
In other words, :c:member:`!tp_basicsize` must be greater than or equal
to the base's :c:member:`!tp_basicsize`.
- Since every type is a subtype of :py:type:`object`, this struct must
+ Since every type is a subtype of :py:obj:`object`, this struct must
include :c:type:`PyObject` or :c:type:`PyVarObject` (depending on
whether :c:member:`~PyVarObject.ob_size` should be included). These are
usually defined by the macro :c:macro:`PyObject_HEAD` or
Index: Python-3.13.5/Doc/conf.py
===================================================================
--- Python-3.13.5.orig/Doc/conf.py 2025-06-12 21:37:37.257659788 +0200
+++ Python-3.13.5/Doc/conf.py 2025-06-12 21:38:04.909609597 +0200
@@ -11,6 +11,8 @@
from importlib import import_module
from importlib.util import find_spec
+from sphinx import version_info
+
# General configuration
# ---------------------
# Make our custom extensions available to Sphinx
sys.path.append(os.path.abspath('tools/extensions'))
sys.path.append(os.path.abspath('includes'))
@@ -57,11 +59,11 @@
import _tkinter
except ImportError:
_tkinter = None
-# Treat warnings as errors, done here to prevent warnings in Sphinx code from
-# causing spurious CPython test failures.
-import warnings
-warnings.simplefilter('error')
-del warnings
+# # Treat warnings as errors, done here to prevent warnings in Sphinx code from
+# # causing spurious CPython test failures.
+# import warnings
+# warnings.simplefilter('error')
+# del warnings
'''
@@ -92,7 +95,7 @@
manpages_url = 'https://manpages.debian.org/{path}'
@@ -92,7 +94,7 @@
# Minimum version of sphinx required
# Keep this version in sync with ``Doc/requirements.txt``.
@@ -31,7 +136,17 @@ Index: Python-3.13.3/Doc/conf.py
# Create table of contents entries for domain objects (e.g. functions, classes,
# attributes, etc.). Default is True.
@@ -361,7 +364,7 @@
@@ -323,6 +325,9 @@
# Avoid a warning with Sphinx >= 4.0
root_doc = 'contents'
+# Compatibility on old Sphinx
+suppress_warnings = ['pygments.ParserNotFound']
+
# Allow translation of index directives
gettext_additional_targets = [
'index',
@@ -362,7 +367,7 @@
# (See .readthedocs.yml and https://docs.readthedocs.io/en/stable/reference/environment-variables.html)
is_deployment_preview = os.getenv("READTHEDOCS_VERSION_TYPE") == "external"
repository_url = os.getenv("READTHEDOCS_GIT_CLONE_URL", "")
@@ -40,11 +155,11 @@ Index: Python-3.13.3/Doc/conf.py
html_context = {
"is_deployment_preview": is_deployment_preview,
"repository_url": repository_url or None,
@@ -606,6 +609,16 @@
@@ -607,6 +612,16 @@
}
extlinks_detect_hardcoded_links = True
+if sphinx_version[:2] < (8, 1):
+if version_info[:2] < (8, 1):
+ # Sphinx 8.1 has in-built CVE and CWE roles.
+ extlinks.update({
+ "cve": (
@@ -57,10 +172,46 @@ Index: Python-3.13.3/Doc/conf.py
# Options for c_annotations extension
# -----------------------------------
Index: Python-3.13.3/Doc/tools/check-warnings.py
Index: Python-3.13.5/Doc/library/doctest.rst
===================================================================
--- Python-3.13.3.orig/Doc/tools/check-warnings.py 2025-04-08 15:54:08.000000000 +0200
+++ Python-3.13.3/Doc/tools/check-warnings.py 2025-04-11 21:55:11.212002463 +0200
--- Python-3.13.5.orig/Doc/library/doctest.rst 2025-06-12 21:37:37.257659788 +0200
+++ Python-3.13.5/Doc/library/doctest.rst 2025-06-12 21:38:04.909944989 +0200
@@ -308,7 +308,6 @@
searched. Objects imported into the module are not searched.
.. attribute:: module.__test__
- :no-typesetting:
In addition, there are cases when you want tests to be part of a module but not part
of the help text, which requires that the tests not be included in the docstring.
Index: Python-3.13.5/Doc/library/email.compat32-message.rst
===================================================================
--- Python-3.13.5.orig/Doc/library/email.compat32-message.rst 2025-06-12 21:37:37.257659788 +0200
+++ Python-3.13.5/Doc/library/email.compat32-message.rst 2025-06-12 21:38:04.910320877 +0200
@@ -7,7 +7,6 @@
:synopsis: The base class representing email messages in a fashion
backward compatible with Python 3.2
:noindex:
- :no-index:
The :class:`Message` class is very similar to the
Index: Python-3.13.5/Doc/library/xml.etree.elementtree.rst
===================================================================
--- Python-3.13.5.orig/Doc/library/xml.etree.elementtree.rst 2025-06-12 21:37:37.257659788 +0200
+++ Python-3.13.5/Doc/library/xml.etree.elementtree.rst 2025-06-12 21:38:04.910594893 +0200
@@ -874,7 +874,6 @@
.. module:: xml.etree.ElementTree
:noindex:
- :no-index:
.. class:: Element(tag, attrib={}, **extra)
Index: Python-3.13.5/Doc/tools/check-warnings.py
===================================================================
--- Python-3.13.5.orig/Doc/tools/check-warnings.py 2025-06-12 21:37:37.257659788 +0200
+++ Python-3.13.5/Doc/tools/check-warnings.py 2025-06-12 21:38:04.910896050 +0200
@@ -228,7 +228,8 @@
print(filename)
for warning in warnings:
@@ -71,10 +222,19 @@ Index: Python-3.13.3/Doc/tools/check-warnings.py
print(" {line}: {msg}".format_map(match))
return -1
return 0
Index: Python-3.13.3/Doc/tools/extensions/audit_events.py
@@ -316,7 +317,7 @@
cwd = str(Path.cwd()) + os.path.sep
files_with_nits = {
- warning.removeprefix(cwd).split(":")[0]
+ (warning[len(cwd):].split(":")[0] if warning.startswith(cwd) else warning.split(":")[0])
for warning in warnings
if "Doc/" in warning
}
Index: Python-3.13.5/Doc/tools/extensions/audit_events.py
===================================================================
--- Python-3.13.3.orig/Doc/tools/extensions/audit_events.py 2025-04-08 15:54:08.000000000 +0200
+++ Python-3.13.3/Doc/tools/extensions/audit_events.py 2025-04-11 21:55:11.212275615 +0200
--- Python-3.13.5.orig/Doc/tools/extensions/audit_events.py 2025-06-12 21:37:37.257659788 +0200
+++ Python-3.13.5/Doc/tools/extensions/audit_events.py 2025-06-12 21:38:04.911151491 +0200
@@ -1,9 +1,6 @@
"""Support for documenting audit events."""
@@ -85,34 +245,42 @@ Index: Python-3.13.3/Doc/tools/extensions/audit_events.py
from docutils import nodes
from sphinx.errors import NoUri
@@ -12,12 +9,11 @@
@@ -12,12 +9,19 @@
from sphinx.util import logging
from sphinx.util.docutils import SphinxDirective
-if TYPE_CHECKING:
- from collections.abc import Iterator
+from typing import Any, List, Tuple
- from collections.abc import Iterator, Set
+from typing import Any, Iterator, List, Set, Tuple
+
+from sphinx.application import Sphinx
+from sphinx.builders import Builder
+from sphinx.environment import BuildEnvironment
+
+# --- The Monkey Patch ---
+def findall_patch(self, *args, **kwargs):
+ """A backwards-compatible findall method that calls traverse."""
+ return self.traverse(*args, **kwargs)
- from sphinx.application import Sphinx
- from sphinx.builders import Builder
- from sphinx.environment import BuildEnvironment
+from sphinx.application import Sphinx
+from sphinx.builders import Builder
+from sphinx.environment import BuildEnvironment
+if not hasattr(nodes.Node, 'findall'):
+ nodes.Node.findall = findall_patch
logger = logging.getLogger(__name__)
@@ -32,16 +28,16 @@
@@ -32,16 +36,16 @@
class AuditEvents:
def __init__(self) -> None:
- self.events: dict[str, list[str]] = {}
- self.sources: dict[str, list[tuple[str, str]]] = {}
- self.sources: dict[str, set[tuple[str, str]]] = {}
+ self.events: dict[str, List[str]] = {}
+ self.sources: dict[str, List[Tuple[str, str]]] = {}
+ self.sources: dict[str, Set[Tuple[str, str]]] = {}
- def __iter__(self) -> Iterator[tuple[str, list[str], tuple[str, str]]]:
+ def __iter__(self) -> Any:
+ def __iter__(self) -> Iterator[Any]:
for name, args in self.events.items():
for source in self.sources[name]:
yield name, args, source
@@ -123,16 +291,16 @@ Index: Python-3.13.3/Doc/tools/extensions/audit_events.py
) -> None:
if name in self.events:
self._check_args_match(name, args)
@@ -49,7 +45,7 @@
@@ -49,7 +53,7 @@
self.events[name] = args
self.sources.setdefault(name, []).append(source)
self.sources.setdefault(name, set()).add(source)
- def _check_args_match(self, name: str, args: list[str]) -> None:
+ def _check_args_match(self, name: str, args: List[str]) -> None:
current_args = self.events[name]
msg = (
f"Mismatched arguments for audit-event {name}: "
@@ -60,7 +56,7 @@
@@ -60,7 +64,7 @@
if len(current_args) != len(args):
logger.warning(msg)
return
@@ -141,16 +309,16 @@ Index: Python-3.13.3/Doc/tools/extensions/audit_events.py
if a1 == a2:
continue
if any(a1 in s and a2 in s for s in _SYNONYMS):
@@ -73,7 +69,7 @@
@@ -73,7 +77,7 @@
name_clean = re.sub(r"\W", "_", name)
return f"audit_event_{name_clean}_{source_count}"
- def rows(self) -> Iterator[tuple[str, list[str], list[tuple[str, str]]]]:
+ def rows(self) -> Any:
- def rows(self) -> Iterator[tuple[str, list[str], Set[tuple[str, str]]]]:
+ def rows(self) -> Iterator[Any]:
for name in sorted(self.events.keys()):
yield name, self.events[name], self.sources[name]
@@ -97,7 +93,7 @@
@@ -97,7 +101,7 @@
def audit_events_merge(
app: Sphinx,
env: BuildEnvironment,
@@ -159,7 +327,7 @@ Index: Python-3.13.3/Doc/tools/extensions/audit_events.py
other: BuildEnvironment,
) -> None:
"""In Sphinx parallel builds, this merges audit_events from subprocesses."""
@@ -126,14 +122,16 @@
@@ -126,14 +130,16 @@
),
]
@@ -182,7 +350,7 @@ Index: Python-3.13.3/Doc/tools/extensions/audit_events.py
else:
args = []
ids = []
@@ -169,7 +167,7 @@
@@ -169,7 +175,7 @@
class AuditEventListDirective(SphinxDirective):
@@ -191,34 +359,21 @@ Index: Python-3.13.3/Doc/tools/extensions/audit_events.py
return [audit_event_list()]
@@ -181,7 +179,11 @@
return
table = self._make_table(self.app.builder, self.env.docname)
- for node in self.document.findall(audit_event_list):
+ try:
+ findall = self.document.findall
+ except AttributeError:
+ findall = self.document.traverse
+ for node in findall(audit_event_list):
node.replace_self(table)
def _make_table(self, builder: Builder, docname: str) -> nodes.table:
@@ -217,8 +219,8 @@
@@ -217,8 +223,8 @@
builder: Builder,
docname: str,
name: str,
- args: list[str],
- sources: list[tuple[str, str]],
- sources: Set[tuple[str, str]],
+ args: List[str],
+ sources: List[Tuple[str, str]],
+ sources: Set[Tuple[str, str]],
) -> nodes.row:
row = nodes.row()
name_node = nodes.paragraph("", nodes.Text(name))
Index: Python-3.13.3/Doc/tools/extensions/availability.py
Index: Python-3.13.5/Doc/tools/extensions/availability.py
===================================================================
--- Python-3.13.3.orig/Doc/tools/extensions/availability.py 2025-04-08 15:54:08.000000000 +0200
+++ Python-3.13.3/Doc/tools/extensions/availability.py 2025-04-11 21:55:11.212578519 +0200
--- Python-3.13.5.orig/Doc/tools/extensions/availability.py 2025-06-12 21:37:37.257659788 +0200
+++ Python-3.13.5/Doc/tools/extensions/availability.py 2025-06-12 21:38:04.911376735 +0200
@@ -1,8 +1,6 @@
"""Support for documenting platform availability"""
@@ -272,11 +427,11 @@ Index: Python-3.13.3/Doc/tools/extensions/availability.py
app.add_directive("availability", Availability)
return {
Index: Python-3.13.3/Doc/tools/extensions/c_annotations.py
Index: Python-3.13.5/Doc/tools/extensions/c_annotations.py
===================================================================
--- Python-3.13.3.orig/Doc/tools/extensions/c_annotations.py 2025-04-08 15:54:08.000000000 +0200
+++ Python-3.13.3/Doc/tools/extensions/c_annotations.py 2025-04-11 21:55:11.212780990 +0200
@@ -9,22 +9,18 @@
--- Python-3.13.5.orig/Doc/tools/extensions/c_annotations.py 2025-06-12 21:37:37.257659788 +0200
+++ Python-3.13.5/Doc/tools/extensions/c_annotations.py 2025-06-12 21:38:04.911575881 +0200
@@ -9,22 +9,26 @@
* Set ``stable_abi_file`` to the path to stable ABI list.
"""
@@ -299,10 +454,18 @@ Index: Python-3.13.3/Doc/tools/extensions/c_annotations.py
- from sphinx.application import Sphinx
- from sphinx.util.typing import ExtensionMetadata
+from sphinx.application import Sphinx
+
+# --- The Monkey Patch ---
+def findall_patch(self, *args, **kwargs):
+ """A backwards-compatible findall method that calls traverse."""
+ return self.traverse(*args, **kwargs)
+
+if not hasattr(nodes.Node, 'findall'):
+ nodes.Node.findall = findall_patch
ROLE_TO_OBJECT_TYPE = {
"func": "function",
@@ -35,20 +31,20 @@
@@ -35,20 +39,20 @@
}
@@ -327,7 +490,7 @@ Index: Python-3.13.3/Doc/tools/extensions/c_annotations.py
class StableABIEntry:
# Role of the object.
# Source: Each [item_kind] in stable_abi.toml is mapped to a C Domain role.
@@ -67,7 +63,7 @@
@@ -67,7 +71,7 @@
struct_abi_kind: str
@@ -336,7 +499,7 @@ Index: Python-3.13.3/Doc/tools/extensions/c_annotations.py
refcount_data = {}
refcounts = refcount_filename.read_text(encoding="utf8")
for line in refcounts.splitlines():
@@ -103,7 +99,7 @@
@@ -103,7 +107,7 @@
return refcount_data
@@ -345,7 +508,7 @@ Index: Python-3.13.3/Doc/tools/extensions/c_annotations.py
stable_abi_data = {}
with open(stable_abi_file, encoding="utf8") as fp:
for record in csv.DictReader(fp):
@@ -123,11 +119,14 @@
@@ -123,11 +127,14 @@
continue
if not par[0].get("ids", None):
continue
@@ -362,7 +525,7 @@ Index: Python-3.13.3/Doc/tools/extensions/c_annotations.py
if ROLE_TO_OBJECT_TYPE[record.role] != objtype:
msg = (
f"Object type mismatch in limited API annotation for {name}: "
@@ -234,7 +233,7 @@
@@ -234,7 +241,7 @@
)
@@ -371,7 +534,7 @@ Index: Python-3.13.3/Doc/tools/extensions/c_annotations.py
classes = ["refcount"]
if result_refs is None:
rc = sphinx_gettext("Return value: Always NULL.")
@@ -254,7 +253,7 @@
@@ -254,7 +261,7 @@
optional_arguments = 0
final_argument_whitespace = True
@@ -380,7 +543,7 @@ Index: Python-3.13.3/Doc/tools/extensions/c_annotations.py
state = self.env.domaindata["c_annotations"]
content = [
f"* :c:{record.role}:`{record.name}`"
@@ -277,13 +276,23 @@
@@ -277,13 +284,23 @@
)
@@ -405,11 +568,50 @@ Index: Python-3.13.3/Doc/tools/extensions/c_annotations.py
return {
"version": "1.0",
"parallel_read_safe": True,
Index: Python-3.13.3/Doc/tools/extensions/glossary_search.py
Index: Python-3.13.5/Doc/tools/extensions/changes.py
===================================================================
--- Python-3.13.3.orig/Doc/tools/extensions/glossary_search.py 2025-04-08 15:54:08.000000000 +0200
+++ Python-3.13.3/Doc/tools/extensions/glossary_search.py 2025-04-11 21:55:11.212983043 +0200
@@ -1,18 +1,14 @@
--- Python-3.13.5.orig/Doc/tools/extensions/changes.py 2025-06-12 21:37:37.257659788 +0200
+++ Python-3.13.5/Doc/tools/extensions/changes.py 2025-06-12 21:38:04.911758715 +0200
@@ -1,7 +1,5 @@
"""Support for documenting version of changes, additions, deprecations."""
-from __future__ import annotations
-
from typing import TYPE_CHECKING
from sphinx.domains.changeset import (
@@ -25,7 +23,7 @@
class PyVersionChange(VersionChange):
- def run(self) -> list[Node]:
+ def run(self) -> "list[Node]":
# Replace the 'next' special token with the current development version
self.arguments[0] = expand_version_arg(
self.arguments[0], self.config.release
@@ -43,7 +41,7 @@
"Deprecated since version %s, removed in version %s"
)
- def run(self) -> list[Node]:
+ def run(self) -> "list[Node]":
# Replace the first two arguments (deprecated version and removed version)
# with a single tuple of both versions.
version_deprecated = expand_version_arg(
@@ -73,7 +71,7 @@
versionlabel_classes[self.name] = ""
-def setup(app: Sphinx) -> ExtensionMetadata:
+def setup(app: "Sphinx") -> "ExtensionMetadata":
# Override Sphinx's directives with support for 'next'
app.add_directive("versionadded", PyVersionChange, override=True)
app.add_directive("versionchanged", PyVersionChange, override=True)
Index: Python-3.13.5/Doc/tools/extensions/glossary_search.py
===================================================================
--- Python-3.13.5.orig/Doc/tools/extensions/glossary_search.py 2025-06-12 21:37:37.257659788 +0200
+++ Python-3.13.5/Doc/tools/extensions/glossary_search.py 2025-06-12 21:38:04.911907976 +0200
@@ -1,21 +1,27 @@
"""Feature search results for glossary items prominently."""
-from __future__ import annotations
@@ -430,7 +632,20 @@ Index: Python-3.13.3/Doc/tools/extensions/glossary_search.py
logger = logging.getLogger(__name__)
@@ -52,7 +48,7 @@
+from docutils import nodes
+from sphinx import addnodes
+
+# --- The Monkey Patch ---
+def findall_patch(self, *args, **kwargs):
+ """A backwards-compatible findall method that calls traverse."""
+ return self.traverse(*args, **kwargs)
+
+if not hasattr(nodes.Node, 'findall'):
+ nodes.Node.findall = findall_patch
def process_glossary_nodes(
app: Sphinx,
@@ -52,7 +58,7 @@
dest.write_text(json.dumps(app.env.glossary_terms), encoding='utf-8')
@@ -439,10 +654,169 @@ Index: Python-3.13.3/Doc/tools/extensions/glossary_search.py
app.connect('doctree-resolved', process_glossary_nodes)
app.connect('build-finished', write_glossary_json)
Index: Python-3.13.3/Doc/tools/extensions/patchlevel.py
Index: Python-3.13.5/Doc/tools/extensions/implementation_detail.py
===================================================================
--- Python-3.13.3.orig/Doc/tools/extensions/patchlevel.py 2025-04-08 15:54:08.000000000 +0200
+++ Python-3.13.3/Doc/tools/extensions/patchlevel.py 2025-04-11 21:55:11.213150035 +0200
--- Python-3.13.5.orig/Doc/tools/extensions/implementation_detail.py 2025-06-12 21:37:37.257659788 +0200
+++ Python-3.13.5/Doc/tools/extensions/implementation_detail.py 2025-06-12 21:38:04.912061736 +0200
@@ -1,17 +1,10 @@
"""Support for marking up implementation details."""
-from __future__ import annotations
-
-from typing import TYPE_CHECKING
-
from docutils import nodes
from sphinx.locale import _ as sphinx_gettext
from sphinx.util.docutils import SphinxDirective
-if TYPE_CHECKING:
- from sphinx.application import Sphinx
- from sphinx.util.typing import ExtensionMetadata
-
+from sphinx.application import Sphinx
class ImplementationDetail(SphinxDirective):
has_content = True
@@ -21,23 +14,24 @@
label_text = sphinx_gettext("CPython implementation detail:")
def run(self):
- self.assert_has_content()
- content_nodes = self.parse_content_to_nodes()
+ container_node = nodes.container()
+ container_node.document = self.state.document # Ensure node has document context
+ self.state.nested_parse(self.content, self.content_offset, container_node)
+ parsed_nodes = container_node.children
# insert our prefix at the start of the first paragraph
- first_node = content_nodes[0]
+ first_node = parsed_nodes[0]
first_node[:0] = [
nodes.strong(self.label_text, self.label_text),
nodes.Text(" "),
]
- # create a new compound container node
- cnode = nodes.compound("", *content_nodes, classes=["impl-detail"])
+ cnode = nodes.compound("", *parsed_nodes, classes=["impl-detail"])
self.set_source_info(cnode)
return [cnode]
-def setup(app: Sphinx) -> ExtensionMetadata:
+def setup(app: Sphinx):
app.add_directive("impl-detail", ImplementationDetail)
return {
Index: Python-3.13.5/Doc/tools/extensions/issue_role.py
===================================================================
--- Python-3.13.5.orig/Doc/tools/extensions/issue_role.py 2025-06-12 21:37:37.257659788 +0200
+++ Python-3.13.5/Doc/tools/extensions/issue_role.py 2025-06-12 21:38:04.912236134 +0200
@@ -1,22 +1,18 @@
"""Support for referencing issues in the tracker."""
-from __future__ import annotations
-
-from typing import TYPE_CHECKING
+from typing import TYPE_CHECKING, List, Tuple
from docutils import nodes
from sphinx.util.docutils import SphinxRole
-if TYPE_CHECKING:
- from docutils.nodes import Element
- from sphinx.application import Sphinx
- from sphinx.util.typing import ExtensionMetadata
+from docutils.nodes import Element
+from sphinx.application import Sphinx
class BPOIssue(SphinxRole):
ISSUE_URI = "https://bugs.python.org/issue?@action=redirect&bpo={0}"
- def run(self) -> tuple[list[Element], list[nodes.system_message]]:
+ def run(self) -> Tuple[List[Element], List[nodes.system_message]]:
issue = self.text
# sanity check: there are no bpo issues within these two values
@@ -38,7 +34,7 @@
class GitHubIssue(SphinxRole):
ISSUE_URI = "https://github.com/python/cpython/issues/{0}"
- def run(self) -> tuple[list[Element], list[nodes.system_message]]:
+ def run(self) -> Tuple[List[Element], List[nodes.system_message]]:
issue = self.text
# sanity check: all GitHub issues have ID >= 32426
@@ -58,7 +54,7 @@
return [refnode], []
-def setup(app: Sphinx) -> ExtensionMetadata:
+def setup(app: Sphinx) -> "ExtensionMetadata":
app.add_role("issue", BPOIssue())
app.add_role("gh", GitHubIssue())
Index: Python-3.13.5/Doc/tools/extensions/misc_news.py
===================================================================
--- Python-3.13.5.orig/Doc/tools/extensions/misc_news.py 2025-06-12 21:37:37.257659788 +0200
+++ Python-3.13.5/Doc/tools/extensions/misc_news.py 2025-06-12 21:38:04.912390144 +0200
@@ -1,7 +1,5 @@
"""Support for including Misc/NEWS."""
-from __future__ import annotations
-
import re
from pathlib import Path
from typing import TYPE_CHECKING
@@ -24,13 +22,13 @@
+++++++++++
"""
-bpo_issue_re: Final[re.Pattern[str]] = re.compile(
+bpo_issue_re: "Final[re.Pattern[str]]" = re.compile(
"(?:issue #|bpo-)([0-9]+)", re.ASCII
)
-gh_issue_re: Final[re.Pattern[str]] = re.compile(
+gh_issue_re: "Final[re.Pattern[str]]" = re.compile(
"gh-(?:issue-)?([0-9]+)", re.ASCII | re.IGNORECASE
)
-whatsnew_re: Final[re.Pattern[str]] = re.compile(
+whatsnew_re: "Final[re.Pattern[str]]" = re.compile(
r"^what's new in (.*?)\??$", re.ASCII | re.IGNORECASE | re.MULTILINE
)
@@ -42,7 +40,7 @@
final_argument_whitespace = False
option_spec = {}
- def run(self) -> list[Node]:
+ def run(self) -> "list[Node]":
# Get content of NEWS file
source, _ = self.get_source_info()
news_file = Path(source).resolve().parent / self.arguments[0]
@@ -54,7 +52,7 @@
return [nodes.strong(text, text)]
# remove first 3 lines as they are the main heading
- news_text = news_text.removeprefix(BLURB_HEADER)
+ news_text = news_text[len(BLURB_HEADER):] if news_text.startswith(BLURB_HEADER) else news_text
news_text = bpo_issue_re.sub(r":issue:`\1`", news_text)
# Fallback handling for GitHub issues
@@ -65,7 +63,7 @@
return []
-def setup(app: Sphinx) -> ExtensionMetadata:
+def setup(app: "Sphinx") -> "ExtensionMetadata":
app.add_directive("miscnews", MiscNews)
return {
Index: Python-3.13.5/Doc/tools/extensions/patchlevel.py
===================================================================
--- Python-3.13.5.orig/Doc/tools/extensions/patchlevel.py 2025-06-12 21:37:37.257659788 +0200
+++ Python-3.13.5/Doc/tools/extensions/patchlevel.py 2025-06-12 21:38:04.912563631 +0200
@@ -3,7 +3,7 @@
import re
import sys
@@ -480,3 +854,65 @@ Index: Python-3.13.3/Doc/tools/extensions/patchlevel.py
version = f"{info.major}.{info.minor}"
release = f"{info.major}.{info.minor}.{info.micro}"
if info.releaselevel != "final":
Index: Python-3.13.5/Doc/tools/extensions/pydoc_topics.py
===================================================================
--- Python-3.13.5.orig/Doc/tools/extensions/pydoc_topics.py 2025-06-12 21:37:37.257659788 +0200
+++ Python-3.13.5/Doc/tools/extensions/pydoc_topics.py 2025-06-12 21:38:04.912726688 +0200
@@ -1,21 +1,23 @@
"""Support for building "topic help" for pydoc."""
-from __future__ import annotations
-
from time import asctime
-from typing import TYPE_CHECKING
+from typing import TYPE_CHECKING, Tuple
from sphinx.builders.text import TextBuilder
from sphinx.util import logging
-from sphinx.util.display import status_iterator
+try:
+ from sphinx.util.display import status_iterator
+except ModuleNotFoundError:
+ from sphinx.util import status_iterator
from sphinx.util.docutils import new_document
from sphinx.writers.text import TextTranslator
-if TYPE_CHECKING:
+try:
+ from typing import Sequence, Set
+except ModuleNotFoundError:
from collections.abc import Sequence, Set
- from sphinx.application import Sphinx
- from sphinx.util.typing import ExtensionMetadata
+from sphinx.application import Sphinx
logger = logging.getLogger(__name__)
@@ -162,7 +164,7 @@
self.outdir.joinpath("topics.py").write_text(topics, encoding="utf-8")
-def _display_labels(item: tuple[str, Sequence[tuple[str, str]]]) -> str:
+def _display_labels(item: Tuple[str, Sequence[Tuple[str, str]]]) -> str:
_docname, label_ids = item
labels = [name for name, _id in label_ids]
if len(labels) > 4:
@@ -170,7 +172,7 @@
return ", ".join(labels)
-def _repr(text: str, /) -> str:
+def _repr(text: str) -> str:
"""Return a triple-single-quoted representation of text."""
if "'''" not in text:
return f"r'''{text}'''"
@@ -178,7 +180,7 @@
return f"'''{text}'''"
-def setup(app: Sphinx) -> ExtensionMetadata:
+def setup(app: Sphinx) -> "ExtensionMetadata":
app.add_builder(PydocTopicsBuilder)
return {

View File

@@ -1,94 +0,0 @@
From 0e461dd411e9ec3dbdf376435154ca2834bcab51 Mon Sep 17 00:00:00 2001
From: Serhiy Storchaka <storchaka@gmail.com>
Date: Wed, 16 Apr 2025 00:24:56 +0300
Subject: [PATCH] gh-132535: Fix resource warnings in test_timeout
They were emitted if internet connection was not available.
---
Lib/test/test_timeout.py | 43 ++++++++++++++++---------------------------
1 file changed, 16 insertions(+), 27 deletions(-)
Index: Python-3.13.3/Lib/test/test_timeout.py
===================================================================
--- Python-3.13.3.orig/Lib/test/test_timeout.py 2025-04-08 15:54:08.000000000 +0200
+++ Python-3.13.3/Lib/test/test_timeout.py 2025-04-15 23:45:55.028517897 +0200
@@ -26,10 +26,8 @@
"""Test case for socket.gettimeout() and socket.settimeout()"""
def setUp(self):
- self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
-
- def tearDown(self):
- self.sock.close()
+ self.sock = self.enterContext(
+ socket.socket(socket.AF_INET, socket.SOCK_STREAM))
def testObjectCreation(self):
# Test Socket creation
@@ -113,8 +111,6 @@
def setUp(self):
raise NotImplementedError()
- tearDown = setUp
-
def _sock_operation(self, count, timeout, method, *args):
"""
Test the specified socket method.
@@ -142,12 +138,10 @@
"""TCP test case for socket.socket() timeout functions"""
def setUp(self):
- self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
+ self.sock = self.enterContext(
+ socket.socket(socket.AF_INET, socket.SOCK_STREAM))
self.addr_remote = resolve_address('www.python.org.', 80)
- def tearDown(self):
- self.sock.close()
-
def testConnectTimeout(self):
# Testing connect timeout is tricky: we need to have IP connectivity
# to a host that silently drops our packets. We can't simulate this
@@ -190,19 +184,16 @@
# for the current configuration.
skip = True
- sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
- timeout = support.LOOPBACK_TIMEOUT
- sock.settimeout(timeout)
- try:
- sock.connect((whitehole))
- except TimeoutError:
- pass
- except OSError as err:
- if err.errno == errno.ECONNREFUSED:
- skip = False
- finally:
- sock.close()
- del sock
+ with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as sock:
+ try:
+ timeout = support.LOOPBACK_TIMEOUT
+ sock.settimeout(timeout)
+ sock.connect((whitehole))
+ except TimeoutError:
+ pass
+ except OSError as err:
+ if err.errno == errno.ECONNREFUSED:
+ skip = False
if skip:
self.skipTest(
@@ -269,10 +260,8 @@
"""UDP test case for socket.socket() timeout functions"""
def setUp(self):
- self.sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
-
- def tearDown(self):
- self.sock.close()
+ self.sock = self.enterContext(
+ socket.socket(socket.AF_INET, socket.SOCK_DGRAM))
def testRecvfromTimeout(self):
# Test recvfrom() timeout

View File

@@ -8,10 +8,10 @@ Date: Tue Nov 26 13:46:33 2024 +0000
Lib/test/test_sysconfig.py | 67 ---------------------------------------------
1 file changed, 1 insertion(+), 66 deletions(-)
Index: Python-3.13.3/Lib/test/test_sysconfig.py
Index: Python-3.13.5/Lib/test/test_sysconfig.py
===================================================================
--- Python-3.13.3.orig/Lib/test/test_sysconfig.py 2025-04-15 14:13:08.581364697 +0200
+++ Python-3.13.3/Lib/test/test_sysconfig.py 2025-04-15 14:13:54.955529034 +0200
--- Python-3.13.5.orig/Lib/test/test_sysconfig.py 2025-06-12 19:55:42.184491497 +0200
+++ Python-3.13.5/Lib/test/test_sysconfig.py 2025-06-12 19:56:05.737665419 +0200
@@ -110,6 +110,7 @@
**venv_create_args,
)

View File

@@ -4,7 +4,7 @@
--- a/Makefile.pre.in
+++ b/Makefile.pre.in
@@ -1679,11 +1679,18 @@ Modules/getbuildinfo.o: $(PARSER_OBJS) \
@@ -1684,11 +1684,18 @@ Modules/getbuildinfo.o: $(PARSER_OBJS) \
$(DTRACE_OBJS) \
$(srcdir)/Modules/getbuildinfo.c
$(CC) -c $(PY_CORE_CFLAGS) \

View File

@@ -1,9 +1,11 @@
Index: Python-3.13.0a3/Lib/site.py
===================================================================
--- Python-3.13.0a3.orig/Lib/site.py
+++ Python-3.13.0a3/Lib/site.py
@@ -77,7 +77,7 @@ import io
import stat
---
Lib/site.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
--- a/Lib/site.py
+++ b/Lib/site.py
@@ -78,7 +78,7 @@ import stat
import errno
# Prefixes for site-packages; add additional prefixes like /usr/local here
-PREFIXES = [sys.prefix, sys.exec_prefix]

View File

@@ -1,3 +1,315 @@
-------------------------------------------------------------------
Sat Jun 21 14:32:16 UTC 2025 - Marcus Meissner <meissner@suse.com>
- adjusted sofilename for "nogil" build correctly.
-------------------------------------------------------------------
Wed Jun 11 22:02:59 UTC 2025 - Matej Cepl <mcepl@cepl.eu>
- Update to 3.13.5:
- Tests
- gh-135120: Add test.support.subTests().
- Library
- gh-133967: Do not normalize locale name C.UTF-8 to
en_US.UTF-8.
- gh-135326: Restore support of integer-like objects with
__index__() in random.getrandbits().
- gh-135321: Raise a correct exception for values greater
than 0x7fffffff for the BINSTRING opcode in the C
implementation of pickle.
- gh-135276: Backported bugfixes in zipfile.Path from
zipp 3.23. Fixed .name, .stem and other basename-based
properties on Windows when working with a zipfile on disk.
- gh-134151: email: Fix TypeError in
email.utils.decode_params() when sorting RFC 2231
continuations that contain an unnumbered section.
- gh-134152: email: Fix parsing of email message ID with
invalid domain.
- gh-127081: Fix libc thread safety issues with os by
replacing getlogin with getlogin_r re-entrant version.
- gh-131884: Fix formatting issues in json.dump() when both
indent and skipkeys are used.
- Core and Builtins
- gh-135171: Roll back changes to generator and list
comprehensions that went into 3.13.4 to fix gh-127682,
but which involved semantic and bytecode changes not
appropriate for a bugfix release.
- C API
- gh-134989: Fix Py_RETURN_NONE, Py_RETURN_TRUE and
Py_RETURN_FALSE macros in the limited C API 3.11 and
older: dont treat Py_None, Py_True and Py_False as
immortal. Patch by Victor Stinner.
- gh-134989: Implement PyObject_DelAttr() and
PyObject_DelAttrString() as macros in the limited C API
3.12 and older. Patch by Victor Stinner.
- Substantially rewritten doc-py38-to-py36.patch patch to be more
flexible and covering even unexpected changes.
-------------------------------------------------------------------
Mon Jun 9 21:24:09 UTC 2025 - Matej Cepl <mcepl@cepl.eu>
- Update to 3.13.4:
- Security
- gh-135034: Fixes multiple issues that allowed tarfile
extraction filters (filter="data" and filter="tar") to be
bypassed using crafted symlinks and hard links.
Addresses CVE-2024-12718 (bsc#1244056), CVE-2025-4138
(bsc#1244059), CVE-2025-4330 (bsc#1244060), and
CVE-2025-4517 (bsc#1244032).
- gh-133767: Fix use-after-free in the “unicode-escape”
decoder with a non-“strict” error handler (CVE-2025-4516,
bsc#1243273).
- gh-128840: Short-circuit the processing of long IPv6
addresses early in ipaddress to prevent excessive memory
consumption and a minor denial-of-service.
- Library
- gh-134718: ast.dump() now only omits None and [] values if
they are default values.
- gh-128840: Fix parsing long IPv6 addresses with embedded
IPv4 address.
- gh-134696: Built-in HACL* and OpenSSL implementations of
hash function constructors now correctly accept the same
documented named arguments. For instance, md5() could be
previously invoked as md5(data=data) or md5(string=string)
depending on the underlying implementation but these calls
were not compatible. Patch by Bénédikt Tran.
- gh-134210: curses.window.getch() now correctly handles
signals. Patch by Bénédikt Tran.
- gh-80334: multiprocessing.freeze_support() now checks for
work on any “spawn” start method platform rather than only
on Windows.
- gh-114177: Fix asyncio to not close subprocess pipes which
would otherwise error out when the event loop is already
closed.
- gh-134152: Fixed UnboundLocalError that could occur during
email header parsing if an expected trailing delimiter is
missing in some contexts.
- gh-62184: Remove import of C implementation of io.FileIO
from Python implementation which has its own implementation
- gh-133982: Emit RuntimeWarning in the Python implementation
of io when the file-like object is not closed explicitly in
the presence of multiple I/O layers.
- gh-133890: The tarfile module now handles
UnicodeEncodeError in the same way as OSError when cannot
extract a member.
- gh-134097: Fix interaction of the new REPL and -X
showrefcount command line option.
- gh-133889: The generated directory listing page in
http.server.SimpleHTTPRequestHandler now only shows the
decoded path component of the requested URL, and not the
query and fragment.
- gh-134098: Fix handling paths that end with
a percent-encoded slash (%2f or %2F) in
http.server.SimpleHTTPRequestHandler.
- gh-134062: ipaddress: fix collisions in __hash__() for
IPv4Network and IPv6Network objects.
- gh-133745: In 3.13.3 we accidentally changed the signature
of the asyncio create_task() family of methods and how it
calls a custom task factory in a backwards incompatible
way. Since some 3rd party libraries have already made
changes to work around the issue that might break if
we simply reverted the changes, were instead changing
things to be backwards compatible with 3.13.2 while still
supporting those workarounds for 3.13.3. In particular, the
special-casing of name and context is back (until 3.14) and
consequently eager tasks may still find that their name
hasnt been set before they execute their first yielding
await.
- gh-71253: Raise ValueError in open() if opener returns a
negative file-descriptor in the Python implementation of io
to match the C implementation.
- gh-77057: Fix handling of invalid markup declarations in
html.parser.HTMLParser.
- gh-133489: random.getrandbits() can now generate more that
231 bits. random.randbytes() can now generate more that 256
MiB.
- gh-133290: Fix attribute caching issue when setting
ctypes._Pointer._type_ in the undocumented and deprecated
ctypes.SetPointerType() function and the undocumented
set_type() method.
- gh-132876: ldexp() on Windows doesnt round subnormal
results before Windows 11, but should. Pythons
math.ldexp() wrapper now does round them, so results may
change slightly, in rare cases of very small results, on
Windows versions before 11.
- gh-133089: Use original timeout value for
subprocess.TimeoutExpired when the func subprocess.run()
is called with a timeout instead of sometimes a confusing
partial remaining time out value used internally on the
final wait().
- gh-133009: xml.etree.ElementTree: Fix a crash in
Element.__deepcopy__ when the element is concurrently
mutated. Patch by Bénédikt Tran.
- gh-132995: Bump the version of pip bundled in ensurepip to
version 25.1.1
- gh-132017: Fix error when pyrepl is suspended, then resumed
and terminated.
- gh-132673: Fix a crash when using _align_ = 0 and _fields_
= [] in a ctypes.Structure.
- gh-132527: Include the valid typecode w in the error
message when an invalid typecode is passed to array.array.
- gh-132439: Fix PyREPL on Windows: characters entered via
AltGr are swallowed. Patch by Chris Eibl.
- gh-132429: Fix support of Bluetooth sockets on NetBSD and
DragonFly BSD.
- gh-132106: QueueListener.start now raises a RuntimeError if
the listener is already started.
- gh-132417: Fix a NULL pointer dereference when a C function
called using ctypes with restype py_object returns NULL.
- gh-132385: Fix instance error suggestions trigger potential
exceptions in object.__getattr__() in traceback.
- gh-132308: A traceback.TracebackException now correctly
renders the __context__ and __cause__ attributes from
falsey Exception, and the exceptions attribute from falsey
ExceptionGroup.
- gh-132250: Fixed the SystemError in cProfile when locating
the actual C function of a method raises an exception.
- gh-132063: Prevent exceptions that evaluate as
falsey (namely, when their __bool__ method returns
False or their __len__ method returns 0) from being
ignored by concurrent.futures.ProcessPoolExecutor and
concurrent.futures.ThreadPoolExecutor.
- gh-119605: Respect follow_wrapped for __init__() and
__new__() methods when getting the class signature for a
class with inspect.signature(). Preserve class signature
after wrapping with warnings.deprecated(). Patch by Xuehai
Pan.
- gh-91555: Ignore log messages generated during handling of
log messages, to avoid deadlock or infinite recursion.
- gh-131434: Improve error reporting for incorrect format in
time.strptime().
- gh-131127: Systems using LibreSSL now successfully build.
- gh-130999: Avoid exiting the new REPL and offer suggestions
even if there are non-string candidates when errors occur.
- gh-130941: Fix configparser.ConfigParser parsing empty
interpolation with allow_no_value set to True.
- gh-129098: Fix REPL traceback reporting when using
compile() with an inexisting file. Patch by Bénédikt Tran.
- gh-130631: http.cookiejar.join_header_words() is now more
similar to the original Perl version. It now quotes the
same set of characters and always quote values that end
with "\n".
- gh-129719: Fix missing socket.CAN_RAW_ERR_FILTER constant
in the socket module on Linux systems. It was missing since
Python 3.11.
- gh-124096: Turn on virtual terminal mode and enable
bracketed paste in REPL on Windows console. (If the
terminal does not support bracketed paste, enabling it does
nothing.)
- gh-122559: Remove __reduce__() and __reduce_ex__() methods
that always raise TypeError in the C implementation
of io.FileIO, io.BufferedReader, io.BufferedWriter
and io.BufferedRandom and replace them with default
__getstate__() methods that raise TypeError. This restores
fine details of behavior of Python 3.11 and older versions.
- gh-122179: hashlib.file_digest() now raises BlockingIOError
when no data is available during non-blocking I/O. Before,
it added spurious null bytes to the digest.
- gh-86155: html.parser.HTMLParser.close() no longer loses
data when the <script> tag is not closed. Patch by Waylan
Limberg.
- gh-69426: Fix html.parser.HTMLParser to not unescape
character entities in attribute values if they are followed
by an ASCII alphanumeric or an equals sign.
- bpo-44172: Keep a reference to original curses windows in
subwindows so that the original window does not get deleted
before subwindows.
- Tests
- gh-133744: Fix multiprocessing interrupt test. Add an event
to synchronize the parent process with the child process:
wait until the child process starts sleeping. Patch by
Victor Stinner.
- gh-133639: Fix
TestPyReplAutoindent.test_auto_indent_default() doesnt run
input_code.
- gh-133131: The iOS testbed will now select the most
recently released “SE-class” device for testing if a device
isnt explicitly specified.
- gh-109981: The test helper that counts the list of open
file descriptors now uses the optimised /dev/fd approach on
all Apple platforms, not just macOS. This avoids crashes
caused by guarded file descriptors.
- IDLE
- gh-112936: fix IDLE: no Shell menu item in single-process
mode.
- Documentation
- gh-107006: Move documentation and example code for
threading.local from its docstring to the official docs.
- Core and Builtins
- gh-134908: Fix crash when iterating over lines in a text
file on the free threaded build.
- gh-127682: No longer call __iter__ twice in list
comprehensions. This brings the behavior of list
comprehensions in line with other forms of iteration
- gh-134381: Fix RuntimeError when using a not-started
threading.Thread after calling os.fork()
- gh-128066: Fixes an edge case where PyREPL improperly threw
an error when Python is invoked on a read only filesystem
while trying to write history file entries.
- gh-134100: Fix a use-after-free bug that occurs when an
imported module isnt in sys.modules after its initial
import. Patch by Nico-Posada.
- gh-133703: Fix hashtable in dict can be bigger than
intended in some situations.
- gh-132869: Fix crash in the free threading build when
accessing an object attribute that may be concurrently
inserted or deleted.
- gh-132762: fromkeys() no longer loops forever when adding
a small set of keys to a large base dict. Patch by Angela
Liss.
- gh-133543: Fix a possible memory leak that could occur when
directly accessing instance dictionaries (__dict__) that
later become part of a reference cycle.
- gh-133516: Raise ValueError when constants True, False or
None are used as an identifier after NFKC normalization.
- gh-133441: Fix crash upon setting an attribute with a dict
subclass. Patch by Victor Stinner.
- gh-132942: Fix two races in the type lookup cache. This
affected the free-threaded build and could cause crashes
(apparently quite difficult to trigger).
- gh-132713: Fix repr(list) race condition: hold a strong
reference to the item while calling repr(item). Patch by
Victor Stinner.
- gh-132747: Fix a crash when calling __get__() of a method
with a None second argument.
- gh-132542: Update Thread.native_id after fork(2) to ensure
accuracy. Patch by Noam Cohen.
- gh-124476: Fix decoding from the locale encoding in the
C.UTF-8 locale.
- gh-131927: Compiler warnings originating from the same
module and line number are now only emitted once, matching
the behaviour of warnings emitted from user code. This can
also be configured with warnings filters.
- gh-127682: No longer call __iter__ twice when creating and
executing a generator expression. Creating a generator
expression from a non-interable will raise only when the
generator expression is executed. This brings the behavior
of generator expressions in line with other generators.
- gh-131878: Handle uncaught exceptions in the main input
loop for the new REPL.
- gh-131878: Fix support of unicode characters with two or
more codepoints on Windows in the new REPL.
- gh-130804: Fix support of unicode characters on Windows in
the new REPL.
- gh-130070: Fixed an assertion error for exec() passed a
string source and a non-None closure. Patch by Bartosz
Sławecki.
- gh-129958: Fix a bug that was allowing newlines
inconsitently in format specifiers for single-quoted
f-strings. Patch by Pablo Galindo.
- C API
- gh-132909: Fix an overflow when handling the K format in
Py_BuildValue(). Patch by Bénédikt Tran.
- Remove upstreamed patches:
- CVE-2025-4516-DecodeError-handler.patch
- gh-132535-rsrc-warn-test_timeout.patch
-------------------------------------------------------------------
Wed May 28 09:46:40 UTC 2025 - Matej Cepl <mcepl@cepl.eu>
- Don't use %elif, it is supported only from rpm 4.15.0, which is
not in SLE-15.
-------------------------------------------------------------------
Fri May 16 13:44:12 UTC 2025 - Matej Cepl <mcepl@cepl.eu>

View File

@@ -83,19 +83,20 @@
# No experimental_jit in SLES, there's no clang >=18
%if 0%{?suse_version} <= 1600
%bcond_with experimental_jit
# Disable experimental_jit for primary python.
# llvm is not part of ring0 and experimental_jit requires clang >= 18
%elif !%{primary_interpreter}
# Currently supported architectures
# https://peps.python.org/pep-0744/#support
%ifarch x86_64 %{x86_64} aarch64
%bcond_without experimental_jit
%else
%bcond_with experimental_jit
%endif
%else
%bcond_with experimental_jit
# Disable experimental_jit for primary python.
# llvm is not part of ring0 and experimental_jit requires clang >= 18
%if !%{primary_interpreter}
# Currently supported architectures
# https://peps.python.org/pep-0744/#support
%ifarch x86_64 %{x86_64} aarch64
%bcond_without experimental_jit
%else
%bcond_with experimental_jit
%endif
%else
%bcond_with experimental_jit
%endif
%endif
# %%if 0%%{?sle_version} && 0%%{?suse_version} < 1550
@@ -139,7 +140,11 @@
# version part of "libpython" package
%define so_major 1
%define so_minor 0
%if "%{abi_kind}" == "t"
%define so_version %{python_version_soname}t%{so_major}_%{so_minor}
%else
%define so_version %{python_version_soname}%{abi_kind}-%{so_major}_%{so_minor}
%endif
# rpm and python have different ideas about what is an arch-dependent name, so:
%if "%{__isa_name}" == "ppc"
%define archname %(echo %{_arch} | sed s/ppc/powerpc/)
@@ -162,7 +167,7 @@
# _md5.cpython-38m-x86_64-linux-gnu.so
%define dynlib() %{sitedir}/lib-dynload/%{1}.cpython-%{abi_tag}-%{archname}-%{_os}%{?_gnu}%{?armsuffix}.so
Name: %{python_pkg_name}%{psuffix}
Version: 3.13.3
Version: 3.13.5
%define tarversion %{version}
%define tarname Python-%{tarversion}
Release: 0
@@ -223,12 +228,6 @@ Patch41: doc-py38-to-py36.patch
# PATCH-FIX-UPSTREAM gh126985-mv-pyvenv.cfg2getpath.patch mcepl@suse.com
# Remove tests failing in test_sysconfig
Patch42: gh126985-mv-pyvenv.cfg2getpath.patch
# PATCH-FIX-UPSTREAM gh-132535-rsrc-warn-test_timeout.patch gh#python/cpython#132535 mcepl@suse.com
# allows test_timeout tests to pass
Patch43: gh-132535-rsrc-warn-test_timeout.patch
# PATCH-FIX-UPSTREAM CVE-2025-4516-DecodeError-handler.patch bsc#1243273 mcepl@suse.com
# this patch makes things totally awesome
Patch44: CVE-2025-4516-DecodeError-handler.patch
BuildRequires: autoconf-archive
BuildRequires: automake
BuildRequires: fdupes
@@ -265,7 +264,9 @@ BuildRequires: python3-Sphinx >= 4.0.0
%if 0%{?suse_version} >= 1500
BuildRequires: python3-python-docs-theme >= 2022.1
%endif
%if 0%{?suse_version} < 1599
BuildRequires: python3-dataclasses
%endif
%endif
%endif
# end of {with doc}

View File

@@ -2,11 +2,9 @@
Lib/test/test_subprocess.py | 6 +++++-
1 file changed, 5 insertions(+), 1 deletion(-)
Index: Python-3.13.3/Lib/test/test_subprocess.py
===================================================================
--- Python-3.13.3.orig/Lib/test/test_subprocess.py 2025-04-08 15:54:08.000000000 +0200
+++ Python-3.13.3/Lib/test/test_subprocess.py 2025-04-11 21:53:36.198770341 +0200
@@ -274,7 +274,11 @@
--- a/Lib/test/test_subprocess.py
+++ b/Lib/test/test_subprocess.py
@@ -292,7 +292,11 @@ class ProcessTestCase(BaseTestCase):
output = subprocess.check_output(
[sys.executable, "-c",
"import time; time.sleep(3600)"],