Update to 3.10.20:

- Security
    - gh-144125: BytesGenerator will now refuse to serialize
      (write) headers that are unsafely folded or delimited; see
      verify_generated_headers. (Contributed by Bas Bloemsaat and
      Petr Viktorin in gh-121650).
    - gh-143935: Fixed a bug in the folding of comments when
      flattening an email message using a modern email policy.
      Comments consisting of a very long sequence of non-foldable
      characters could trigger a forced line wrap that omitted
      the required leading space on the continuation line,
      causing the remainder of the comment to be interpreted as
      a new header field. This enabled header injection with
      carefully crafted inputs (bsc#1257029 CVE-2025-11468).
    - gh-143925: Reject control characters in data: URL media
      types.
    - gh-143919: Reject control characters in http.cookies.Morsel
      fields and values (bsc#1257031, CVE-2026-0672).
    - gh-143916: Reject C0 control characters within
      wsgiref.headers.Headers fields, values, and parameters
      (bsc#1257042, CVE-2026-0865).
    - gh-142145: Remove quadratic behavior in xml.minidom node ID
      cache clearing. In order to do this without breaking
      existing users, we also add the ownerDocument attribute to
      xml.dom.minidom elements and attributes created by directly
      instantiating the Element or Attr class. Note that this way
      of creating nodes is not supported; creator functions like
      xml.dom.Document.documentElement() should be used instead
      (bsc#1254997, CVE-2025-12084).
    - gh-137836: Add support of the “plaintext” element, RAWTEXT
      elements “xmp”, “iframe”, “noembed” and “noframes”, and
      optionally RAWTEXT element “noscript” in
      html.parser.HTMLParser.
    - gh-136063: email.message: ensure linear complexity for
      legacy HTTP parameters parsing. Patch by Bénédikt Tran.
    - gh-136065: Fix quadratic complexity in
      os.path.expandvars() (bsc#1252974, CVE-2025-6075).
    - gh-119451: Fix a potential memory denial of service in the
      http.client module. When connecting to a malicious server,
      it could cause an arbitrary amount of memory to be
      allocated. This could have led to symptoms including
      a MemoryError, swapping, out of memory (OOM) killed
      processes or containers, or even system crashes
      (CVE-2025-13836, bsc#1254400).
    - gh-119452: Fix a potential memory denial of service in the
      http.server module. When a malicious user is connected to
      the CGI server on Windows, it could cause an arbitrary
      amount of memory to be allocated. This could have led to
      symptoms including a MemoryError, swapping, out of memory
      (OOM) killed processes or containers, or even system
      crashes.
    - gh-119342: Fix a potential memory denial of service in the
      plistlib module. When reading a Plist file received from
      untrusted source, it could cause an arbitrary amount of
      memory to be allocated. This could have led to symptoms
      including a MemoryError, swapping, out of memory (OOM)
      killed processes or containers, or even system crashes
      (bsc#1254401, CVE-2025-13837).
  - Library
    - gh-144833: Fixed a use-after-free in ssl when SSL_new()
      returns NULL in newPySSLSocket(). The error was reported
      via a dangling pointer after the object had already been
      freed.
    - gh-144363: Update bundled libexpat to 2.7.4
    - gh-90949: Add SetAllocTrackerActivationThreshold() and
      SetAllocTrackerMaximumAmplification() to xmlparser objects
      to prevent use of disproportional amounts of dynamic memory
      from within an Expat parser. Patch by Bénédikt Tran.
  - Core and Builtins
    - gh-120384: Fix an array out of bounds crash in
      list_ass_subscript, which could be invoked via some
      specificly tailored input: including concurrent
      modification of a list object, where one thread assigns
      a slice and another clears it.
    - gh-120298: Fix use-after free in list_richcompare_impl
      which can be invoked via some specificly tailored evil
      input.
Remove upstreamed patches:
  - CVE-2025-11468-email-hdr-fold-comment.patch
  - CVE-2025-12084-minidom-quad-search.patch
  - CVE-2025-13836-http-resp-cont-len.patch
  - CVE-2025-13837-plistlib-mailicious-length.patch
  - CVE-2025-6075-expandvars-perf-degrad.patch
  - CVE-2026-0672-http-hdr-inject-cookie-Morsel.patch
  - CVE-2026-0865-wsgiref-ctrl-chars.patch
This commit is contained in:
2026-03-06 15:53:00 +01:00
parent 539e53b74e
commit 33c2fe314e
20 changed files with 370 additions and 1451 deletions

View File

@@ -4,11 +4,11 @@
Lib/test/test_xml_etree.py | 7 +++++++
3 files changed, 14 insertions(+)
Index: Python-3.10.19/Lib/test/test_pyexpat.py
Index: Python-3.10.20/Lib/test/test_pyexpat.py
===================================================================
--- Python-3.10.19.orig/Lib/test/test_pyexpat.py 2025-10-09 17:25:03.000000000 +0200
+++ Python-3.10.19/Lib/test/test_pyexpat.py 2025-12-19 23:10:22.001497953 +0100
@@ -802,6 +802,10 @@
--- Python-3.10.20.orig/Lib/test/test_pyexpat.py 2026-03-05 19:42:14.505101236 +0100
+++ Python-3.10.20/Lib/test/test_pyexpat.py 2026-03-05 19:42:23.343680667 +0100
@@ -807,6 +807,10 @@
self.assertEqual(started, ['doc'])
def test_reparse_deferral_disabled(self):
@@ -19,10 +19,10 @@ Index: Python-3.10.19/Lib/test/test_pyexpat.py
started = []
def start_element(name, _):
Index: Python-3.10.19/Lib/test/test_sax.py
Index: Python-3.10.20/Lib/test/test_sax.py
===================================================================
--- Python-3.10.19.orig/Lib/test/test_sax.py 2025-10-09 17:25:03.000000000 +0200
+++ Python-3.10.19/Lib/test/test_sax.py 2025-12-19 23:10:22.002078897 +0100
--- Python-3.10.20.orig/Lib/test/test_sax.py 2026-03-05 19:42:14.505101236 +0100
+++ Python-3.10.20/Lib/test/test_sax.py 2026-03-05 19:42:23.344649745 +0100
@@ -1240,6 +1240,9 @@
self.assertEqual(result.getvalue(), start + b"<doc></doc>")
@@ -33,10 +33,10 @@ Index: Python-3.10.19/Lib/test/test_sax.py
def test_flush_reparse_deferral_disabled(self):
result = BytesIO()
xmlgen = XMLGenerator(result)
Index: Python-3.10.19/Lib/test/test_xml_etree.py
Index: Python-3.10.20/Lib/test/test_xml_etree.py
===================================================================
--- Python-3.10.19.orig/Lib/test/test_xml_etree.py 2025-10-09 17:25:03.000000000 +0200
+++ Python-3.10.19/Lib/test/test_xml_etree.py 2025-12-19 23:10:22.002413090 +0100
--- Python-3.10.20.orig/Lib/test/test_xml_etree.py 2026-03-05 19:42:14.505101236 +0100
+++ Python-3.10.20/Lib/test/test_xml_etree.py 2026-03-05 19:42:23.345531779 +0100
@@ -1420,9 +1420,13 @@
self.assert_event_tags(parser, [('end', 'root')])
self.assertIsNone(parser.close())

View File

@@ -1,116 +0,0 @@
From 2065aa5b8f2bcdea2f628686c57974793a62c42b Mon Sep 17 00:00:00 2001
From: Seth Michael Larson <seth@python.org>
Date: Mon, 19 Jan 2026 06:38:22 -0600
Subject: [PATCH] [3.10] gh-143935: Email preserve parens when folding comments
(GH-143936)
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Fix a bug in the folding of comments when flattening an email message
using a modern email policy. Comments consisting of a very long sequence of
non-foldable characters could trigger a forced line wrap that omitted the
required leading space on the continuation line, causing the remainder of
the comment to be interpreted as a new header field. This enabled header
injection with carefully crafted inputs.
(cherry picked from commit 17d1490)
Co-authored-by: Seth Michael Larson seth@python.org
Co-authored-by: Denis Ledoux dle@odoo.com
- Issue: Fix folding of long comments of unfoldable characters in email headers #143935
Signed-off-by: Edgar Ramírez Mondragón <edgarrm358@gmail.com>
---
Lib/email/_header_value_parser.py | 15 +++++++++++-
.../test_email/test__header_value_parser.py | 23 +++++++++++++++++++
...-01-16-14-40-31.gh-issue-143935.U2YtKl.rst | 6 +++++
3 files changed, 43 insertions(+), 1 deletion(-)
create mode 100644 Misc/NEWS.d/next/Security/2026-01-16-14-40-31.gh-issue-143935.U2YtKl.rst
diff --git a/Lib/email/_header_value_parser.py b/Lib/email/_header_value_parser.py
index dbc0bd8196af52..2c05abeadea22b 100644
--- a/Lib/email/_header_value_parser.py
+++ b/Lib/email/_header_value_parser.py
@@ -101,6 +101,12 @@ def make_quoted_pairs(value):
return str(value).replace('\\', '\\\\').replace('"', '\\"')
+def make_parenthesis_pairs(value):
+ """Escape parenthesis and backslash for use within a comment."""
+ return str(value).replace('\\', '\\\\') \
+ .replace('(', '\\(').replace(')', '\\)')
+
+
def quote_string(value):
escaped = make_quoted_pairs(value)
return f'"{escaped}"'
@@ -927,7 +933,7 @@ def value(self):
return ' '
def startswith_fws(self):
- return True
+ return self and self[0] in WSP
class ValueTerminal(Terminal):
@@ -2865,6 +2871,13 @@ def _refold_parse_tree(parse_tree, *, policy):
[ValueTerminal(make_quoted_pairs(p), 'ptext')
for p in newparts] +
[ValueTerminal('"', 'ptext')])
+ if part.token_type == 'comment':
+ newparts = (
+ [ValueTerminal('(', 'ptext')] +
+ [ValueTerminal(make_parenthesis_pairs(p), 'ptext')
+ if p.token_type == 'ptext' else p
+ for p in newparts] +
+ [ValueTerminal(')', 'ptext')])
if not part.as_ew_allowed:
wrap_as_ew_blocked += 1
newparts.append(end_ew_not_allowed)
diff --git a/Lib/test/test_email/test__header_value_parser.py b/Lib/test/test_email/test__header_value_parser.py
index 6a4ecafd68b4ab..2eaaaaef675284 100644
--- a/Lib/test/test_email/test__header_value_parser.py
+++ b/Lib/test/test_email/test__header_value_parser.py
@@ -2973,6 +2973,29 @@ def test_address_list_with_specials_in_long_quoted_string(self):
with self.subTest(to=to):
self._test(parser.get_address_list(to)[0], folded, policy=policy)
+ def test_address_list_with_long_unwrapable_comment(self):
+ policy = self.policy.clone(max_line_length=40)
+ cases = [
+ # (to, folded)
+ ('(loremipsumdolorsitametconsecteturadipi)<spy@example.org>',
+ '(loremipsumdolorsitametconsecteturadipi)<spy@example.org>\n'),
+ ('<spy@example.org>(loremipsumdolorsitametconsecteturadipi)',
+ '<spy@example.org>(loremipsumdolorsitametconsecteturadipi)\n'),
+ ('(loremipsum dolorsitametconsecteturadipi)<spy@example.org>',
+ '(loremipsum dolorsitametconsecteturadipi)<spy@example.org>\n'),
+ ('<spy@example.org>(loremipsum dolorsitametconsecteturadipi)',
+ '<spy@example.org>(loremipsum\n dolorsitametconsecteturadipi)\n'),
+ ('(Escaped \\( \\) chars \\\\ in comments stay escaped)<spy@example.org>',
+ '(Escaped \\( \\) chars \\\\ in comments stay\n escaped)<spy@example.org>\n'),
+ ('((loremipsum)(loremipsum)(loremipsum)(loremipsum))<spy@example.org>',
+ '((loremipsum)(loremipsum)(loremipsum)(loremipsum))<spy@example.org>\n'),
+ ('((loremipsum)(loremipsum)(loremipsum) (loremipsum))<spy@example.org>',
+ '((loremipsum)(loremipsum)(loremipsum)\n (loremipsum))<spy@example.org>\n'),
+ ]
+ for (to, folded) in cases:
+ with self.subTest(to=to):
+ self._test(parser.get_address_list(to)[0], folded, policy=policy)
+
def test_address_list_with_specials_in_encoded_word(self):
# An encoded-word parsed from a structured header must remain
# encoded when it contains specials. Regression for gh-121284.
diff --git a/Misc/NEWS.d/next/Security/2026-01-16-14-40-31.gh-issue-143935.U2YtKl.rst b/Misc/NEWS.d/next/Security/2026-01-16-14-40-31.gh-issue-143935.U2YtKl.rst
new file mode 100644
index 00000000000000..c3d864936884ac
--- /dev/null
+++ b/Misc/NEWS.d/next/Security/2026-01-16-14-40-31.gh-issue-143935.U2YtKl.rst
@@ -0,0 +1,6 @@
+Fixed a bug in the folding of comments when flattening an email message
+using a modern email policy. Comments consisting of a very long sequence of
+non-foldable characters could trigger a forced line wrap that omitted the
+required leading space on the continuation line, causing the remainder of
+the comment to be interpreted as a new header field. This enabled header
+injection with carefully crafted inputs.

View File

@@ -1,93 +0,0 @@
From f4eb9ab014545b521fb261b80adfa6d138e7e092 Mon Sep 17 00:00:00 2001
From: Seth Michael Larson <seth@python.org>
Date: Wed, 3 Dec 2025 01:16:37 -0600
Subject: [PATCH] gh-142145: Remove quadratic behavior in node ID cache
clearing (GH-142146)
* Remove quadratic behavior in node ID cache clearing
Co-authored-by: Jacob Walls <38668450+jacobtylerwalls@users.noreply.github.com>
* Add news fragment
---------
(cherry picked from commit 08d8e18ad81cd45bc4a27d6da478b51ea49486e4)
Co-authored-by: Seth Michael Larson <seth@python.org>
Co-authored-by: Jacob Walls <38668450+jacobtylerwalls@users.noreply.github.com>
---
Lib/test/test_minidom.py | 18 ++++++++++
Lib/xml/dom/minidom.py | 9 -----
Misc/NEWS.d/next/Security/2025-12-01-09-36-45.gh-issue-142145.tcAUhg.rst | 1
3 files changed, 20 insertions(+), 8 deletions(-)
create mode 100644 Misc/NEWS.d/next/Security/2025-12-01-09-36-45.gh-issue-142145.tcAUhg.rst
Index: Python-3.10.19/Lib/test/test_minidom.py
===================================================================
--- Python-3.10.19.orig/Lib/test/test_minidom.py 2025-12-19 23:10:45.263295780 +0100
+++ Python-3.10.19/Lib/test/test_minidom.py 2025-12-19 23:10:50.342493590 +0100
@@ -2,6 +2,7 @@
import copy
import pickle
+import time
import io
from test import support
import unittest
@@ -176,6 +177,23 @@
self.confirm(dom.documentElement.childNodes[-1].data == "Hello")
dom.unlink()
+ def testAppendChildNoQuadraticComplexity(self):
+ impl = getDOMImplementation()
+
+ newdoc = impl.createDocument(None, "some_tag", None)
+ top_element = newdoc.documentElement
+ children = [newdoc.createElement(f"child-{i}") for i in range(1, 2 ** 15 + 1)]
+ element = top_element
+
+ start = time.time()
+ for child in children:
+ element.appendChild(child)
+ element = child
+ end = time.time()
+
+ # This example used to take at least 30 seconds.
+ self.assertLess(end - start, 1)
+
def testAppendChildFragment(self):
dom, orig, c1, c2, c3, frag = self._create_fragment_test_nodes()
dom.documentElement.appendChild(frag)
Index: Python-3.10.19/Lib/xml/dom/minidom.py
===================================================================
--- Python-3.10.19.orig/Lib/xml/dom/minidom.py 2025-12-19 23:10:45.263295780 +0100
+++ Python-3.10.19/Lib/xml/dom/minidom.py 2025-12-19 23:10:50.342898393 +0100
@@ -292,13 +292,6 @@
childNodes.append(node)
node.parentNode = self
-def _in_document(node):
- # return True iff node is part of a document tree
- while node is not None:
- if node.nodeType == Node.DOCUMENT_NODE:
- return True
- node = node.parentNode
- return False
def _write_data(writer, data):
"Writes datachars to writer."
@@ -1539,7 +1532,7 @@
if node.nodeType == Node.DOCUMENT_NODE:
node._id_cache.clear()
node._id_search_stack = None
- elif _in_document(node):
+ elif node.ownerDocument:
node.ownerDocument._id_cache.clear()
node.ownerDocument._id_search_stack= None
Index: Python-3.10.19/Misc/NEWS.d/next/Security/2025-12-01-09-36-45.gh-issue-142145.tcAUhg.rst
===================================================================
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ Python-3.10.19/Misc/NEWS.d/next/Security/2025-12-01-09-36-45.gh-issue-142145.tcAUhg.rst 2025-12-19 23:10:50.343161277 +0100
@@ -0,0 +1 @@
+Remove quadratic behavior in ``xml.minidom`` node ID cache clearing.

View File

@@ -1,155 +0,0 @@
From b3a7998115e195c40e00cfa662bcaa899d937c05 Mon Sep 17 00:00:00 2001
From: Serhiy Storchaka <storchaka@gmail.com>
Date: Mon, 1 Dec 2025 17:26:07 +0200
Subject: [PATCH] gh-119451: Fix a potential denial of service in http.client
(GH-119454)
Reading the whole body of the HTTP response could cause OOM if
the Content-Length value is too large even if the server does not send
a large amount of data. Now the HTTP client reads large data by chunks,
therefore the amount of consumed memory is proportional to the amount
of sent data.
(cherry picked from commit 5a4c4a033a4a54481be6870aa1896fad732555b5)
Co-authored-by: Serhiy Storchaka <storchaka@gmail.com>
---
Lib/http/client.py | 28 ++++++--
Lib/test/test_httplib.py | 66 +++++++++++++++++++
...-05-23-11-47-48.gh-issue-119451.qkJe9-.rst | 5 ++
3 files changed, 95 insertions(+), 4 deletions(-)
create mode 100644 Misc/NEWS.d/next/Security/2024-05-23-11-47-48.gh-issue-119451.qkJe9-.rst
diff --git a/Lib/http/client.py b/Lib/http/client.py
index d1b7b1048c9171..c8ab5b7662c334 100644
--- a/Lib/http/client.py
+++ b/Lib/http/client.py
@@ -111,6 +111,11 @@
_MAXLINE = 65536
_MAXHEADERS = 100
+# Data larger than this will be read in chunks, to prevent extreme
+# overallocation.
+_MIN_READ_BUF_SIZE = 1 << 20
+
+
# Header name/value ABNF (http://tools.ietf.org/html/rfc7230#section-3.2)
#
# VCHAR = %x21-7E
@@ -628,10 +633,25 @@ def _safe_read(self, amt):
reading. If the bytes are truly not available (due to EOF), then the
IncompleteRead exception can be used to detect the problem.
"""
- data = self.fp.read(amt)
- if len(data) < amt:
- raise IncompleteRead(data, amt-len(data))
- return data
+ cursize = min(amt, _MIN_READ_BUF_SIZE)
+ data = self.fp.read(cursize)
+ if len(data) >= amt:
+ return data
+ if len(data) < cursize:
+ raise IncompleteRead(data, amt - len(data))
+
+ data = io.BytesIO(data)
+ data.seek(0, 2)
+ while True:
+ # This is a geometric increase in read size (never more than
+ # doubling out the current length of data per loop iteration).
+ delta = min(cursize, amt - cursize)
+ data.write(self.fp.read(delta))
+ if data.tell() >= amt:
+ return data.getvalue()
+ cursize += delta
+ if data.tell() < cursize:
+ raise IncompleteRead(data.getvalue(), amt - data.tell())
def _safe_readinto(self, b):
"""Same as _safe_read, but for reading into a buffer."""
diff --git a/Lib/test/test_httplib.py b/Lib/test/test_httplib.py
index 77152cf64565e0..89ec5f6f1c5383 100644
--- a/Lib/test/test_httplib.py
+++ b/Lib/test/test_httplib.py
@@ -1226,6 +1226,72 @@ def run_server():
thread.join()
self.assertEqual(result, b"proxied data\n")
+ def test_large_content_length(self):
+ serv = socket.create_server((HOST, 0))
+ self.addCleanup(serv.close)
+
+ def run_server():
+ [conn, address] = serv.accept()
+ with conn:
+ while conn.recv(1024):
+ conn.sendall(
+ b"HTTP/1.1 200 Ok\r\n"
+ b"Content-Length: %d\r\n"
+ b"\r\n" % size)
+ conn.sendall(b'A' * (size//3))
+ conn.sendall(b'B' * (size - size//3))
+
+ thread = threading.Thread(target=run_server)
+ thread.start()
+ self.addCleanup(thread.join, 1.0)
+
+ conn = client.HTTPConnection(*serv.getsockname())
+ try:
+ for w in range(15, 27):
+ size = 1 << w
+ conn.request("GET", "/")
+ with conn.getresponse() as response:
+ self.assertEqual(len(response.read()), size)
+ finally:
+ conn.close()
+ thread.join(1.0)
+
+ def test_large_content_length_truncated(self):
+ serv = socket.create_server((HOST, 0))
+ self.addCleanup(serv.close)
+
+ def run_server():
+ while True:
+ [conn, address] = serv.accept()
+ with conn:
+ conn.recv(1024)
+ if not size:
+ break
+ conn.sendall(
+ b"HTTP/1.1 200 Ok\r\n"
+ b"Content-Length: %d\r\n"
+ b"\r\n"
+ b"Text" % size)
+
+ thread = threading.Thread(target=run_server)
+ thread.start()
+ self.addCleanup(thread.join, 1.0)
+
+ conn = client.HTTPConnection(*serv.getsockname())
+ try:
+ for w in range(18, 65):
+ size = 1 << w
+ conn.request("GET", "/")
+ with conn.getresponse() as response:
+ self.assertRaises(client.IncompleteRead, response.read)
+ conn.close()
+ finally:
+ conn.close()
+ size = 0
+ conn.request("GET", "/")
+ conn.close()
+ thread.join(1.0)
+
def test_putrequest_override_domain_validation(self):
"""
It should be possible to override the default validation
diff --git a/Misc/NEWS.d/next/Security/2024-05-23-11-47-48.gh-issue-119451.qkJe9-.rst b/Misc/NEWS.d/next/Security/2024-05-23-11-47-48.gh-issue-119451.qkJe9-.rst
new file mode 100644
index 00000000000000..6d6f25cd2f8bf7
--- /dev/null
+++ b/Misc/NEWS.d/next/Security/2024-05-23-11-47-48.gh-issue-119451.qkJe9-.rst
@@ -0,0 +1,5 @@
+Fix a potential memory denial of service in the :mod:`http.client` module.
+When connecting to a malicious server, it could cause
+an arbitrary amount of memory to be allocated.
+This could have led to symptoms including a :exc:`MemoryError`, swapping, out
+of memory (OOM) killed processes or containers, or even system crashes.

View File

@@ -1,160 +0,0 @@
From e99059d800b741504ef18693803927a0dc062be4 Mon Sep 17 00:00:00 2001
From: Serhiy Storchaka <storchaka@gmail.com>
Date: Mon, 1 Dec 2025 17:28:15 +0200
Subject: [PATCH] [3.10] gh-119342: Fix a potential denial of service in
plistlib (GH-119343)
Reading a specially prepared small Plist file could cause OOM because file's
read(n) preallocates a bytes object for reading the specified amount of
data. Now plistlib reads large data by chunks, therefore the upper limit of
consumed memory is proportional to the size of the input file.
(cherry picked from commit 694922cf40aa3a28f898b5f5ee08b71b4922df70)
Co-authored-by: Serhiy Storchaka <storchaka@gmail.com>
---
Lib/plistlib.py | 31 ++++++++++------
Lib/test/test_plistlib.py | 37 +++++++++++++++++--
...-05-21-22-11-31.gh-issue-119342.BTFj4Z.rst | 5 +++
3 files changed, 59 insertions(+), 14 deletions(-)
create mode 100644 Misc/NEWS.d/next/Security/2024-05-21-22-11-31.gh-issue-119342.BTFj4Z.rst
diff --git a/Lib/plistlib.py b/Lib/plistlib.py
index d6c997efe9c5f5..c80dfee02a3335 100644
--- a/Lib/plistlib.py
+++ b/Lib/plistlib.py
@@ -73,6 +73,9 @@
PlistFormat = enum.Enum('PlistFormat', 'FMT_XML FMT_BINARY', module=__name__)
globals().update(PlistFormat.__members__)
+# Data larger than this will be read in chunks, to prevent extreme
+# overallocation.
+_MIN_READ_BUF_SIZE = 1 << 20
class UID:
def __init__(self, data):
@@ -499,12 +502,24 @@ def _get_size(self, tokenL):
return tokenL
+ def _read(self, size):
+ cursize = min(size, _MIN_READ_BUF_SIZE)
+ data = self._fp.read(cursize)
+ while True:
+ if len(data) != cursize:
+ raise InvalidFileException
+ if cursize == size:
+ return data
+ delta = min(cursize, size - cursize)
+ data += self._fp.read(delta)
+ cursize += delta
+
def _read_ints(self, n, size):
- data = self._fp.read(size * n)
+ data = self._read(size * n)
if size in _BINARY_FORMAT:
return struct.unpack(f'>{n}{_BINARY_FORMAT[size]}', data)
else:
- if not size or len(data) != size * n:
+ if not size:
raise InvalidFileException()
return tuple(int.from_bytes(data[i: i + size], 'big')
for i in range(0, size * n, size))
@@ -561,22 +576,16 @@ def _read_object(self, ref):
elif tokenH == 0x40: # data
s = self._get_size(tokenL)
- result = self._fp.read(s)
- if len(result) != s:
- raise InvalidFileException()
+ result = self._read(s)
elif tokenH == 0x50: # ascii string
s = self._get_size(tokenL)
- data = self._fp.read(s)
- if len(data) != s:
- raise InvalidFileException()
+ data = self._read(s)
result = data.decode('ascii')
elif tokenH == 0x60: # unicode string
s = self._get_size(tokenL) * 2
- data = self._fp.read(s)
- if len(data) != s:
- raise InvalidFileException()
+ data = self._read(s)
result = data.decode('utf-16be')
elif tokenH == 0x80: # UID
diff --git a/Lib/test/test_plistlib.py b/Lib/test/test_plistlib.py
index ef96c6ceda21a2..d3836991d212cd 100644
--- a/Lib/test/test_plistlib.py
+++ b/Lib/test/test_plistlib.py
@@ -838,8 +838,7 @@ def test_xml_plist_with_entity_decl(self):
class TestBinaryPlistlib(unittest.TestCase):
- @staticmethod
- def decode(*objects, offset_size=1, ref_size=1):
+ def build(self, *objects, offset_size=1, ref_size=1):
data = [b'bplist00']
offset = 8
offsets = []
@@ -851,7 +850,11 @@ def decode(*objects, offset_size=1, ref_size=1):
len(objects), 0, offset)
data.extend(offsets)
data.append(tail)
- return plistlib.loads(b''.join(data), fmt=plistlib.FMT_BINARY)
+ return b''.join(data)
+
+ def decode(self, *objects, offset_size=1, ref_size=1):
+ data = self.build(*objects, offset_size=offset_size, ref_size=ref_size)
+ return plistlib.loads(data, fmt=plistlib.FMT_BINARY)
def test_nonstandard_refs_size(self):
# Issue #21538: Refs and offsets are 24-bit integers
@@ -959,6 +962,34 @@ def test_invalid_binary(self):
with self.assertRaises(plistlib.InvalidFileException):
plistlib.loads(b'bplist00' + data, fmt=plistlib.FMT_BINARY)
+ def test_truncated_large_data(self):
+ self.addCleanup(os_helper.unlink, os_helper.TESTFN)
+ def check(data):
+ with open(os_helper.TESTFN, 'wb') as f:
+ f.write(data)
+ # buffered file
+ with open(os_helper.TESTFN, 'rb') as f:
+ with self.assertRaises(plistlib.InvalidFileException):
+ plistlib.load(f, fmt=plistlib.FMT_BINARY)
+ # unbuffered file
+ with open(os_helper.TESTFN, 'rb', buffering=0) as f:
+ with self.assertRaises(plistlib.InvalidFileException):
+ plistlib.load(f, fmt=plistlib.FMT_BINARY)
+ for w in range(20, 64):
+ s = 1 << w
+ # data
+ check(self.build(b'\x4f\x13' + s.to_bytes(8, 'big')))
+ # ascii string
+ check(self.build(b'\x5f\x13' + s.to_bytes(8, 'big')))
+ # unicode string
+ check(self.build(b'\x6f\x13' + s.to_bytes(8, 'big')))
+ # array
+ check(self.build(b'\xaf\x13' + s.to_bytes(8, 'big')))
+ # dict
+ check(self.build(b'\xdf\x13' + s.to_bytes(8, 'big')))
+ # number of objects
+ check(b'bplist00' + struct.pack('>6xBBQQQ', 1, 1, s, 0, 8))
+
class TestKeyedArchive(unittest.TestCase):
def test_keyed_archive_data(self):
diff --git a/Misc/NEWS.d/next/Security/2024-05-21-22-11-31.gh-issue-119342.BTFj4Z.rst b/Misc/NEWS.d/next/Security/2024-05-21-22-11-31.gh-issue-119342.BTFj4Z.rst
new file mode 100644
index 00000000000000..04fd8faca4cf7e
--- /dev/null
+++ b/Misc/NEWS.d/next/Security/2024-05-21-22-11-31.gh-issue-119342.BTFj4Z.rst
@@ -0,0 +1,5 @@
+Fix a potential memory denial of service in the :mod:`plistlib` module.
+When reading a Plist file received from untrusted source, it could cause
+an arbitrary amount of memory to be allocated.
+This could have led to symptoms including a :exc:`MemoryError`, swapping, out
+of memory (OOM) killed processes or containers, or even system crashes.

View File

@@ -8,27 +8,19 @@ Subject: [PATCH] [3.10] gh-143925: Reject control characters in data: URL
Co-authored-by: Seth Michael Larson <seth@python.org>
---
Lib/test/test_urllib.py | 8 ++++++++
Lib/test/test_urllib.py | 7 +++++++
Lib/urllib/request.py | 5 +++++
Misc/NEWS.d/next/Security/2026-01-16-11-51-19.gh-issue-143925.mrtcHW.rst | 1 +
3 files changed, 14 insertions(+)
3 files changed, 13 insertions(+)
create mode 100644 Misc/NEWS.d/next/Security/2026-01-16-11-51-19.gh-issue-143925.mrtcHW.rst
Index: Python-3.10.19/Lib/test/test_urllib.py
Index: Python-3.10.20/Lib/test/test_urllib.py
===================================================================
--- Python-3.10.19.orig/Lib/test/test_urllib.py 2026-02-12 01:05:56.127447144 +0100
+++ Python-3.10.19/Lib/test/test_urllib.py 2026-02-12 01:08:02.226352573 +0100
@@ -11,6 +11,7 @@
from test import support
from test.support import os_helper
from test.support import warnings_helper
+from test.support import control_characters_c0
import os
try:
import ssl
@@ -683,6 +684,13 @@
# missing padding character
self.assertRaises(ValueError,urllib.request.urlopen,'data:;base64,Cg=')
--- Python-3.10.20.orig/Lib/test/test_urllib.py 2026-03-05 19:39:02.061358156 +0100
+++ Python-3.10.20/Lib/test/test_urllib.py 2026-03-05 23:19:43.575732909 +0100
@@ -607,6 +607,13 @@
"https://localhost", cafile="/nonexistent/path", context=context
)
+ def test_invalid_mediatype(self):
+ for c0 in control_characters_c0():
@@ -38,15 +30,15 @@ Index: Python-3.10.19/Lib/test/test_urllib.py
+ self.assertRaises(ValueError,urllib.request.urlopen,
+ f'data:text/html{c0};base64,ZGF0YQ==')
class urlretrieve_FileTests(unittest.TestCase):
"""Test urllib.urlretrieve() on local files"""
Index: Python-3.10.19/Lib/urllib/request.py
class urlopen_DataTests(unittest.TestCase):
"""Test urlopen() opening a data URL."""
Index: Python-3.10.20/Lib/urllib/request.py
===================================================================
--- Python-3.10.19.orig/Lib/urllib/request.py 2026-02-12 01:05:56.627830069 +0100
+++ Python-3.10.19/Lib/urllib/request.py 2026-02-12 01:08:02.226810828 +0100
@@ -1654,6 +1654,11 @@
scheme, data = url.split(":",1)
mediatype, data = data.split(",",1)
--- Python-3.10.20.orig/Lib/urllib/request.py 2026-03-05 19:39:02.551702670 +0100
+++ Python-3.10.20/Lib/urllib/request.py 2026-03-05 23:19:43.576415166 +0100
@@ -1659,6 +1659,11 @@
raise ValueError(
"Control characters not allowed in data: mediatype")
+ # Disallow control characters within mediatype.
+ if re.search(r"[\x00-\x1F\x7F]", mediatype):
@@ -56,9 +48,9 @@ Index: Python-3.10.19/Lib/urllib/request.py
# even base64 encoded data URLs might be quoted so unquote in any case:
data = unquote_to_bytes(data)
if mediatype.endswith(";base64"):
Index: Python-3.10.19/Misc/NEWS.d/next/Security/2026-01-16-11-51-19.gh-issue-143925.mrtcHW.rst
Index: Python-3.10.20/Misc/NEWS.d/next/Security/2026-01-16-11-51-19.gh-issue-143925.mrtcHW.rst
===================================================================
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ Python-3.10.19/Misc/NEWS.d/next/Security/2026-01-16-11-51-19.gh-issue-143925.mrtcHW.rst 2026-02-12 01:08:02.227192287 +0100
+++ Python-3.10.20/Misc/NEWS.d/next/Security/2026-01-16-11-51-19.gh-issue-143925.mrtcHW.rst 2026-03-05 23:19:43.576850667 +0100
@@ -0,0 +1 @@
+Reject control characters in ``data:`` URL media types.

View File

@@ -9,10 +9,10 @@ Subject: [PATCH 1/2] Add 'test.support' fixture for C0 control characters
Misc/NEWS.d/next/Security/2026-01-16-11-41-06.gh-issue-143921.AeCOor.rst | 1 +
3 files changed, 10 insertions(+), 1 deletion(-)
Index: Python-3.10.19/Lib/imaplib.py
Index: Python-3.10.20/Lib/imaplib.py
===================================================================
--- Python-3.10.19.orig/Lib/imaplib.py 2026-02-12 01:05:53.821319313 +0100
+++ Python-3.10.19/Lib/imaplib.py 2026-02-12 01:06:28.558652908 +0100
--- Python-3.10.20.orig/Lib/imaplib.py 2026-03-05 19:38:59.446918283 +0100
+++ Python-3.10.20/Lib/imaplib.py 2026-03-05 23:19:20.515035897 +0100
@@ -132,7 +132,7 @@
# We compile these in _mode_xxx.
_Literal = br'.*{(?P<size>\d+)}$'
@@ -31,10 +31,10 @@ Index: Python-3.10.19/Lib/imaplib.py
data = data + b' ' + arg
literal = self.literal
Index: Python-3.10.19/Lib/test/test_imaplib.py
Index: Python-3.10.20/Lib/test/test_imaplib.py
===================================================================
--- Python-3.10.19.orig/Lib/test/test_imaplib.py 2026-02-12 01:05:55.293033311 +0100
+++ Python-3.10.19/Lib/test/test_imaplib.py 2026-02-12 01:07:45.387053336 +0100
--- Python-3.10.20.orig/Lib/test/test_imaplib.py 2026-03-05 19:39:01.155920382 +0100
+++ Python-3.10.20/Lib/test/test_imaplib.py 2026-03-05 23:19:20.517235411 +0100
@@ -538,6 +538,12 @@
self.assertEqual(data[0], b'Returned to authenticated state. (Success)')
self.assertEqual(client.state, 'AUTH')
@@ -48,9 +48,9 @@ Index: Python-3.10.19/Lib/test/test_imaplib.py
class NewIMAPTests(NewIMAPTestsMixin, unittest.TestCase):
imap_class = imaplib.IMAP4
Index: Python-3.10.19/Misc/NEWS.d/next/Security/2026-01-16-11-41-06.gh-issue-143921.AeCOor.rst
Index: Python-3.10.20/Misc/NEWS.d/next/Security/2026-01-16-11-41-06.gh-issue-143921.AeCOor.rst
===================================================================
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ Python-3.10.19/Misc/NEWS.d/next/Security/2026-01-16-11-41-06.gh-issue-143921.AeCOor.rst 2026-02-12 01:06:28.559224837 +0100
+++ Python-3.10.20/Misc/NEWS.d/next/Security/2026-01-16-11-41-06.gh-issue-143921.AeCOor.rst 2026-03-05 23:19:20.517573599 +0100
@@ -0,0 +1 @@
+Reject control characters in IMAP commands.

View File

@@ -9,10 +9,10 @@ Subject: [PATCH 1/2] Add 'test.support' fixture for C0 control characters
Misc/NEWS.d/next/Security/2026-01-16-11-43-47.gh-issue-143923.DuytMe.rst | 1 +
3 files changed, 11 insertions(+)
Index: Python-3.10.19/Lib/poplib.py
Index: Python-3.10.20/Lib/poplib.py
===================================================================
--- Python-3.10.19.orig/Lib/poplib.py 2026-02-12 01:05:54.262197434 +0100
+++ Python-3.10.19/Lib/poplib.py 2026-02-12 01:12:02.945762019 +0100
--- Python-3.10.20.orig/Lib/poplib.py 2026-03-05 19:38:59.939747453 +0100
+++ Python-3.10.20/Lib/poplib.py 2026-03-05 23:21:23.043850896 +0100
@@ -122,6 +122,8 @@
def _putcmd(self, line):
if self._debugging: print('*cmd*', repr(line))
@@ -22,10 +22,10 @@ Index: Python-3.10.19/Lib/poplib.py
self._putline(line)
Index: Python-3.10.19/Lib/test/test_poplib.py
Index: Python-3.10.20/Lib/test/test_poplib.py
===================================================================
--- Python-3.10.19.orig/Lib/test/test_poplib.py 2026-02-12 01:05:55.796995175 +0100
+++ Python-3.10.19/Lib/test/test_poplib.py 2026-02-12 01:12:32.837694637 +0100
--- Python-3.10.20.orig/Lib/test/test_poplib.py 2026-03-05 19:39:01.686377763 +0100
+++ Python-3.10.20/Lib/test/test_poplib.py 2026-03-05 23:21:23.044538262 +0100
@@ -15,6 +15,7 @@
from test.support import hashlib_helper
from test.support import socket_helper
@@ -48,9 +48,9 @@ Index: Python-3.10.19/Lib/test/test_poplib.py
@requires_ssl
def test_stls_capa(self):
capa = self.client.capa()
Index: Python-3.10.19/Misc/NEWS.d/next/Security/2026-01-16-11-43-47.gh-issue-143923.DuytMe.rst
Index: Python-3.10.20/Misc/NEWS.d/next/Security/2026-01-16-11-43-47.gh-issue-143923.DuytMe.rst
===================================================================
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ Python-3.10.19/Misc/NEWS.d/next/Security/2026-01-16-11-43-47.gh-issue-143923.DuytMe.rst 2026-02-12 01:12:02.946199975 +0100
+++ Python-3.10.20/Misc/NEWS.d/next/Security/2026-01-16-11-43-47.gh-issue-143923.DuytMe.rst 2026-03-05 23:21:23.044905845 +0100
@@ -0,0 +1 @@
+Reject control characters in POP3 commands.

View File

@@ -1,359 +0,0 @@
From 20044636f0d9a802c42f907934c69d46e4019a0c Mon Sep 17 00:00:00 2001
From: Serhiy Storchaka <storchaka@gmail.com>
Date: Fri, 31 Oct 2025 15:49:51 +0200
Subject: [PATCH] [3.10] gh-136065: Fix quadratic complexity in
os.path.expandvars() (GH-134952) (cherry picked from commit
f029e8db626ddc6e3a3beea4eff511a71aaceb5c)
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Co-authored-by: Serhiy Storchaka <storchaka@gmail.com>
Co-authored-by: Łukasz Langa <lukasz@langa.pl>
---
Lib/ntpath.py | 126 ++++++------------
Lib/posixpath.py | 43 +++---
Lib/test/test_genericpath.py | 14 ++
Lib/test/test_ntpath.py | 20 ++-
...-05-30-22-33-27.gh-issue-136065.bu337o.rst | 1 +
5 files changed, 93 insertions(+), 111 deletions(-)
create mode 100644 Misc/NEWS.d/next/Security/2025-05-30-22-33-27.gh-issue-136065.bu337o.rst
diff --git a/Lib/ntpath.py b/Lib/ntpath.py
index 9b0cca44727fd5..bd2b4e289c17b9 100644
--- a/Lib/ntpath.py
+++ b/Lib/ntpath.py
@@ -374,17 +374,23 @@ def expanduser(path):
# XXX With COMMAND.COM you can use any characters in a variable name,
# XXX except '^|<>='.
+_varpattern = r"'[^']*'?|%(%|[^%]*%?)|\$(\$|[-\w]+|\{[^}]*\}?)"
+_varsub = None
+_varsubb = None
+
def expandvars(path):
"""Expand shell variables of the forms $var, ${var} and %var%.
Unknown variables are left unchanged."""
path = os.fspath(path)
+ global _varsub, _varsubb
if isinstance(path, bytes):
if b'$' not in path and b'%' not in path:
return path
- import string
- varchars = bytes(string.ascii_letters + string.digits + '_-', 'ascii')
- quote = b'\''
+ if not _varsubb:
+ import re
+ _varsubb = re.compile(_varpattern.encode(), re.ASCII).sub
+ sub = _varsubb
percent = b'%'
brace = b'{'
rbrace = b'}'
@@ -393,94 +399,44 @@ def expandvars(path):
else:
if '$' not in path and '%' not in path:
return path
- import string
- varchars = string.ascii_letters + string.digits + '_-'
- quote = '\''
+ if not _varsub:
+ import re
+ _varsub = re.compile(_varpattern, re.ASCII).sub
+ sub = _varsub
percent = '%'
brace = '{'
rbrace = '}'
dollar = '$'
environ = os.environ
- res = path[:0]
- index = 0
- pathlen = len(path)
- while index < pathlen:
- c = path[index:index+1]
- if c == quote: # no expansion within single quotes
- path = path[index + 1:]
- pathlen = len(path)
- try:
- index = path.index(c)
- res += c + path[:index + 1]
- except ValueError:
- res += c + path
- index = pathlen - 1
- elif c == percent: # variable or '%'
- if path[index + 1:index + 2] == percent:
- res += c
- index += 1
- else:
- path = path[index+1:]
- pathlen = len(path)
- try:
- index = path.index(percent)
- except ValueError:
- res += percent + path
- index = pathlen - 1
- else:
- var = path[:index]
- try:
- if environ is None:
- value = os.fsencode(os.environ[os.fsdecode(var)])
- else:
- value = environ[var]
- except KeyError:
- value = percent + var + percent
- res += value
- elif c == dollar: # variable or '$$'
- if path[index + 1:index + 2] == dollar:
- res += c
- index += 1
- elif path[index + 1:index + 2] == brace:
- path = path[index+2:]
- pathlen = len(path)
- try:
- index = path.index(rbrace)
- except ValueError:
- res += dollar + brace + path
- index = pathlen - 1
- else:
- var = path[:index]
- try:
- if environ is None:
- value = os.fsencode(os.environ[os.fsdecode(var)])
- else:
- value = environ[var]
- except KeyError:
- value = dollar + brace + var + rbrace
- res += value
- else:
- var = path[:0]
- index += 1
- c = path[index:index + 1]
- while c and c in varchars:
- var += c
- index += 1
- c = path[index:index + 1]
- try:
- if environ is None:
- value = os.fsencode(os.environ[os.fsdecode(var)])
- else:
- value = environ[var]
- except KeyError:
- value = dollar + var
- res += value
- if c:
- index -= 1
+
+ def repl(m):
+ lastindex = m.lastindex
+ if lastindex is None:
+ return m[0]
+ name = m[lastindex]
+ if lastindex == 1:
+ if name == percent:
+ return name
+ if not name.endswith(percent):
+ return m[0]
+ name = name[:-1]
else:
- res += c
- index += 1
- return res
+ if name == dollar:
+ return name
+ if name.startswith(brace):
+ if not name.endswith(rbrace):
+ return m[0]
+ name = name[1:-1]
+
+ try:
+ if environ is None:
+ return os.fsencode(os.environ[os.fsdecode(name)])
+ else:
+ return environ[name]
+ except KeyError:
+ return m[0]
+
+ return sub(repl, path)
# Normalize a path, e.g. A//B, A/./B and A/foo/../B all become A\B.
diff --git a/Lib/posixpath.py b/Lib/posixpath.py
index b8dd563ada3880..75020eef477b5e 100644
--- a/Lib/posixpath.py
+++ b/Lib/posixpath.py
@@ -279,42 +279,41 @@ def expanduser(path):
# This expands the forms $variable and ${variable} only.
# Non-existent variables are left unchanged.
-_varprog = None
-_varprogb = None
+_varpattern = r'\$(\w+|\{[^}]*\}?)'
+_varsub = None
+_varsubb = None
def expandvars(path):
"""Expand shell variables of form $var and ${var}. Unknown variables
are left unchanged."""
path = os.fspath(path)
- global _varprog, _varprogb
+ global _varsub, _varsubb
if isinstance(path, bytes):
if b'$' not in path:
return path
- if not _varprogb:
+ if not _varsubb:
import re
- _varprogb = re.compile(br'\$(\w+|\{[^}]*\})', re.ASCII)
- search = _varprogb.search
+ _varsubb = re.compile(_varpattern.encode(), re.ASCII).sub
+ sub = _varsubb
start = b'{'
end = b'}'
environ = getattr(os, 'environb', None)
else:
if '$' not in path:
return path
- if not _varprog:
+ if not _varsub:
import re
- _varprog = re.compile(r'\$(\w+|\{[^}]*\})', re.ASCII)
- search = _varprog.search
+ _varsub = re.compile(_varpattern, re.ASCII).sub
+ sub = _varsub
start = '{'
end = '}'
environ = os.environ
- i = 0
- while True:
- m = search(path, i)
- if not m:
- break
- i, j = m.span(0)
- name = m.group(1)
- if name.startswith(start) and name.endswith(end):
+
+ def repl(m):
+ name = m[1]
+ if name.startswith(start):
+ if not name.endswith(end):
+ return m[0]
name = name[1:-1]
try:
if environ is None:
@@ -322,13 +321,11 @@ def expandvars(path):
else:
value = environ[name]
except KeyError:
- i = j
+ return m[0]
else:
- tail = path[j:]
- path = path[:i] + value
- i = len(path)
- path += tail
- return path
+ return value
+
+ return sub(repl, path)
# Normalize a path, e.g. A//B, A/./B and A/foo/../B all become A/B.
diff --git a/Lib/test/test_genericpath.py b/Lib/test/test_genericpath.py
index 1ff7f75ad3e614..b0a13265c98b4e 100644
--- a/Lib/test/test_genericpath.py
+++ b/Lib/test/test_genericpath.py
@@ -7,6 +7,7 @@
import sys
import unittest
import warnings
+from test import support
from test.support import os_helper
from test.support import warnings_helper
from test.support.script_helper import assert_python_ok
@@ -430,6 +431,19 @@ def check(value, expected):
os.fsencode('$bar%s bar' % nonascii))
check(b'$spam}bar', os.fsencode('%s}bar' % nonascii))
+ @support.requires_resource('cpu')
+ def test_expandvars_large(self):
+ expandvars = self.pathmodule.expandvars
+ with os_helper.EnvironmentVarGuard() as env:
+ env.clear()
+ env["A"] = "B"
+ n = 100_000
+ self.assertEqual(expandvars('$A'*n), 'B'*n)
+ self.assertEqual(expandvars('${A}'*n), 'B'*n)
+ self.assertEqual(expandvars('$A!'*n), 'B!'*n)
+ self.assertEqual(expandvars('${A}A'*n), 'BA'*n)
+ self.assertEqual(expandvars('${'*10*n), '${'*10*n)
+
def test_abspath(self):
self.assertIn("foo", self.pathmodule.abspath("foo"))
with warnings.catch_warnings():
diff --git a/Lib/test/test_ntpath.py b/Lib/test/test_ntpath.py
index f790f771f2fb6d..161e57d62a06d3 100644
--- a/Lib/test/test_ntpath.py
+++ b/Lib/test/test_ntpath.py
@@ -5,8 +5,8 @@
import unittest
import warnings
from ntpath import ALLOW_MISSING
+from test import support
from test.support import os_helper
-from test.support import TestFailed
from test.support.os_helper import FakePath
from test import test_genericpath
from tempfile import TemporaryFile
@@ -56,7 +56,7 @@ def tester(fn, wantResult):
fn = fn.replace("\\", "\\\\")
gotResult = eval(fn)
if wantResult != gotResult and _norm(wantResult) != _norm(gotResult):
- raise TestFailed("%s should return: %s but returned: %s" \
+ raise support.TestFailed("%s should return: %s but returned: %s" \
%(str(fn), str(wantResult), str(gotResult)))
# then with bytes
@@ -72,7 +72,7 @@ def tester(fn, wantResult):
warnings.simplefilter("ignore", DeprecationWarning)
gotResult = eval(fn)
if _norm(wantResult) != _norm(gotResult):
- raise TestFailed("%s should return: %s but returned: %s" \
+ raise support.TestFailed("%s should return: %s but returned: %s" \
%(str(fn), str(wantResult), repr(gotResult)))
@@ -689,6 +689,19 @@ def check(value, expected):
check('%spam%bar', '%sbar' % nonascii)
check('%{}%bar'.format(nonascii), 'ham%sbar' % nonascii)
+ @support.requires_resource('cpu')
+ def test_expandvars_large(self):
+ expandvars = ntpath.expandvars
+ with os_helper.EnvironmentVarGuard() as env:
+ env.clear()
+ env["A"] = "B"
+ n = 100_000
+ self.assertEqual(expandvars('%A%'*n), 'B'*n)
+ self.assertEqual(expandvars('%A%A'*n), 'BA'*n)
+ self.assertEqual(expandvars("''"*n + '%%'), "''"*n + '%')
+ self.assertEqual(expandvars("%%"*n), "%"*n)
+ self.assertEqual(expandvars("$$"*n), "$"*n)
+
def test_expanduser(self):
tester('ntpath.expanduser("test")', 'test')
@@ -923,6 +936,7 @@ def test_nt_helpers(self):
self.assertIsInstance(b_final_path, bytes)
self.assertGreater(len(b_final_path), 0)
+
class NtCommonTest(test_genericpath.CommonTest, unittest.TestCase):
pathmodule = ntpath
attributes = ['relpath']
diff --git a/Misc/NEWS.d/next/Security/2025-05-30-22-33-27.gh-issue-136065.bu337o.rst b/Misc/NEWS.d/next/Security/2025-05-30-22-33-27.gh-issue-136065.bu337o.rst
new file mode 100644
index 00000000000000..1d152bb5318380
--- /dev/null
+++ b/Misc/NEWS.d/next/Security/2025-05-30-22-33-27.gh-issue-136065.bu337o.rst
@@ -0,0 +1 @@
+Fix quadratic complexity in :func:`os.path.expandvars`.

View File

@@ -1,184 +0,0 @@
From 57c5ecd7e61fbb24e7de76eafd95332bd0ae4dea Mon Sep 17 00:00:00 2001
From: Seth Michael Larson <seth@python.org>
Date: Tue, 20 Jan 2026 15:23:42 -0600
Subject: [PATCH] [3.10] gh-143919: Reject control characters in http cookies
(cherry picked from commit 95746b3a13a985787ef53b977129041971ed7f70)
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Co-authored-by: Seth Michael Larson <seth@python.org>
Co-authored-by: Bartosz Sławecki <bartosz@ilikepython.com>
Co-authored-by: sobolevn <mail@sobolevn.me>
---
Doc/library/http.cookies.rst | 4 +-
Lib/http/cookies.py | 25 +++++++--
Lib/test/test_http_cookies.py | 52 +++++++++++++++++--
...-01-16-11-13-15.gh-issue-143919.kchwZV.rst | 1 +
4 files changed, 73 insertions(+), 9 deletions(-)
create mode 100644 Misc/NEWS.d/next/Security/2026-01-16-11-13-15.gh-issue-143919.kchwZV.rst
diff --git a/Doc/library/http.cookies.rst b/Doc/library/http.cookies.rst
index a2c1eb00d8b33d..4cb563c230ea5e 100644
--- a/Doc/library/http.cookies.rst
+++ b/Doc/library/http.cookies.rst
@@ -270,9 +270,9 @@ The following example demonstrates how to use the :mod:`http.cookies` module.
Set-Cookie: chips=ahoy
Set-Cookie: vienna=finger
>>> C = cookies.SimpleCookie()
- >>> C.load('keebler="E=everybody; L=\\"Loves\\"; fudge=\\012;";')
+ >>> C.load('keebler="E=everybody; L=\\"Loves\\"; fudge=;";')
>>> print(C)
- Set-Cookie: keebler="E=everybody; L=\"Loves\"; fudge=\012;"
+ Set-Cookie: keebler="E=everybody; L=\"Loves\"; fudge=;"
>>> C = cookies.SimpleCookie()
>>> C["oreo"] = "doublestuff"
>>> C["oreo"]["path"] = "/"
diff --git a/Lib/http/cookies.py b/Lib/http/cookies.py
index 2c1f021d0abede..5cfa7a8072c7f7 100644
--- a/Lib/http/cookies.py
+++ b/Lib/http/cookies.py
@@ -87,9 +87,9 @@
such trickeries do not confuse it.
>>> C = cookies.SimpleCookie()
- >>> C.load('keebler="E=everybody; L=\\"Loves\\"; fudge=\\012;";')
+ >>> C.load('keebler="E=everybody; L=\\"Loves\\"; fudge=;";')
>>> print(C)
- Set-Cookie: keebler="E=everybody; L=\"Loves\"; fudge=\012;"
+ Set-Cookie: keebler="E=everybody; L=\"Loves\"; fudge=;"
Each element of the Cookie also supports all of the RFC 2109
Cookie attributes. Here's an example which sets the Path
@@ -170,6 +170,15 @@ class CookieError(Exception):
})
_is_legal_key = re.compile('[%s]+' % re.escape(_LegalChars)).fullmatch
+_control_character_re = re.compile(r'[\x00-\x1F\x7F]')
+
+
+def _has_control_character(*val):
+ """Detects control characters within a value.
+ Supports any type, as header values can be any type.
+ """
+ return any(_control_character_re.search(str(v)) for v in val)
+
def _quote(str):
r"""Quote a string for use in a cookie header.
@@ -292,12 +301,16 @@ def __setitem__(self, K, V):
K = K.lower()
if not K in self._reserved:
raise CookieError("Invalid attribute %r" % (K,))
+ if _has_control_character(K, V):
+ raise CookieError(f"Control characters are not allowed in cookies {K!r} {V!r}")
dict.__setitem__(self, K, V)
def setdefault(self, key, val=None):
key = key.lower()
if key not in self._reserved:
raise CookieError("Invalid attribute %r" % (key,))
+ if _has_control_character(key, val):
+ raise CookieError("Control characters are not allowed in cookies %r %r" % (key, val,))
return dict.setdefault(self, key, val)
def __eq__(self, morsel):
@@ -333,6 +346,9 @@ def set(self, key, val, coded_val):
raise CookieError('Attempt to set a reserved key %r' % (key,))
if not _is_legal_key(key):
raise CookieError('Illegal key %r' % (key,))
+ if _has_control_character(key, val, coded_val):
+ raise CookieError(
+ "Control characters are not allowed in cookies %r %r %r" % (key, val, coded_val,))
# It's a good key, so save it.
self._key = key
@@ -484,7 +500,10 @@ def output(self, attrs=None, header="Set-Cookie:", sep="\015\012"):
result = []
items = sorted(self.items())
for key, value in items:
- result.append(value.output(attrs, header))
+ value_output = value.output(attrs, header)
+ if _has_control_character(value_output):
+ raise CookieError("Control characters are not allowed in cookies")
+ result.append(value_output)
return sep.join(result)
__str__ = output
diff --git a/Lib/test/test_http_cookies.py b/Lib/test/test_http_cookies.py
index 644e75cd5b742e..1f2c049fa811fa 100644
--- a/Lib/test/test_http_cookies.py
+++ b/Lib/test/test_http_cookies.py
@@ -17,10 +17,10 @@ def test_basic(self):
'repr': "<SimpleCookie: chips='ahoy' vienna='finger'>",
'output': 'Set-Cookie: chips=ahoy\nSet-Cookie: vienna=finger'},
- {'data': 'keebler="E=mc2; L=\\"Loves\\"; fudge=\\012;"',
- 'dict': {'keebler' : 'E=mc2; L="Loves"; fudge=\012;'},
- 'repr': '''<SimpleCookie: keebler='E=mc2; L="Loves"; fudge=\\n;'>''',
- 'output': 'Set-Cookie: keebler="E=mc2; L=\\"Loves\\"; fudge=\\012;"'},
+ {'data': 'keebler="E=mc2; L=\\"Loves\\"; fudge=;"',
+ 'dict': {'keebler' : 'E=mc2; L="Loves"; fudge=;'},
+ 'repr': '''<SimpleCookie: keebler='E=mc2; L="Loves"; fudge=;'>''',
+ 'output': 'Set-Cookie: keebler="E=mc2; L=\\"Loves\\"; fudge=;"'},
# Check illegal cookies that have an '=' char in an unquoted value
{'data': 'keebler=E=mc2',
@@ -517,6 +517,50 @@ def test_repr(self):
r'Set-Cookie: key=coded_val; '
r'expires=\w+, \d+ \w+ \d+ \d+:\d+:\d+ \w+')
+ def test_control_characters(self):
+ for c0 in support.control_characters_c0():
+ morsel = cookies.Morsel()
+
+ # .__setitem__()
+ with self.assertRaises(cookies.CookieError):
+ morsel[c0] = "val"
+ with self.assertRaises(cookies.CookieError):
+ morsel["path"] = c0
+
+ # .setdefault()
+ with self.assertRaises(cookies.CookieError):
+ morsel.setdefault("path", c0)
+ with self.assertRaises(cookies.CookieError):
+ morsel.setdefault(c0, "val")
+
+ # .set()
+ with self.assertRaises(cookies.CookieError):
+ morsel.set(c0, "val", "coded-value")
+ with self.assertRaises(cookies.CookieError):
+ morsel.set("path", c0, "coded-value")
+ with self.assertRaises(cookies.CookieError):
+ morsel.set("path", "val", c0)
+
+ def test_control_characters_output(self):
+ # Tests that even if the internals of Morsel are modified
+ # that a call to .output() has control character safeguards.
+ for c0 in support.control_characters_c0():
+ morsel = cookies.Morsel()
+ morsel.set("key", "value", "coded-value")
+ morsel._key = c0 # Override private variable.
+ cookie = cookies.SimpleCookie()
+ cookie["cookie"] = morsel
+ with self.assertRaises(cookies.CookieError):
+ cookie.output()
+
+ morsel = cookies.Morsel()
+ morsel.set("key", "value", "coded-value")
+ morsel._coded_value = c0 # Override private variable.
+ cookie = cookies.SimpleCookie()
+ cookie["cookie"] = morsel
+ with self.assertRaises(cookies.CookieError):
+ cookie.output()
+
def test_main():
run_unittest(CookieTests, MorselTests)
run_doctest(cookies)
diff --git a/Misc/NEWS.d/next/Security/2026-01-16-11-13-15.gh-issue-143919.kchwZV.rst b/Misc/NEWS.d/next/Security/2026-01-16-11-13-15.gh-issue-143919.kchwZV.rst
new file mode 100644
index 00000000000000..788c3e4ac2ebf7
--- /dev/null
+++ b/Misc/NEWS.d/next/Security/2026-01-16-11-13-15.gh-issue-143919.kchwZV.rst
@@ -0,0 +1 @@
+Reject control characters in :class:`http.cookies.Morsel` fields and values.

View File

@@ -1,97 +0,0 @@
From 123bfbbe9074ef7fa28e1e7b25575665296560fa Mon Sep 17 00:00:00 2001
From: "Gregory P. Smith" <68491+gpshead@users.noreply.github.com>
Date: Sat, 17 Jan 2026 10:23:57 -0800
Subject: [PATCH] [3.10] gh-143916: Reject control characters in
wsgiref.headers.Headers (GH-143917) (GH-143973)
gh-143916: Reject control characters in wsgiref.headers.Headers (GH-143917)
* Add 'test.support' fixture for C0 control characters
* gh-143916: Reject control characters in wsgiref.headers.Headers
(cherry picked from commit f7fceed79ca1bceae8dbe5ba5bc8928564da7211)
(cherry picked from commit 22e4d55285cee52bc4dbe061324e5f30bd4dee58)
Co-authored-by: Gregory P. Smith <68491+gpshead@users.noreply.github.com>
Co-authored-by: Seth Michael Larson <seth@python.org>
---
Lib/test/support/__init__.py | 7 +++++++
Lib/test/test_wsgiref.py | 12 +++++++++++-
Lib/wsgiref/headers.py | 3 +++
.../2026-01-16-11-07-36.gh-issue-143916.dpWeOD.rst | 2 ++
4 files changed, 23 insertions(+), 1 deletion(-)
create mode 100644 Misc/NEWS.d/next/Security/2026-01-16-11-07-36.gh-issue-143916.dpWeOD.rst
diff --git a/Lib/test/support/__init__.py b/Lib/test/support/__init__.py
index 0d3b9634f10248..d0492fe1914343 100644
--- a/Lib/test/support/__init__.py
+++ b/Lib/test/support/__init__.py
@@ -2157,3 +2157,10 @@ def adjust_int_max_str_digits(max_digits):
yield
finally:
sys.set_int_max_str_digits(current)
+
+
+def control_characters_c0() -> list[str]:
+ """Returns a list of C0 control characters as strings.
+ C0 control characters defined as the byte range 0x00-0x1F, and 0x7F.
+ """
+ return [chr(c) for c in range(0x00, 0x20)] + ["\x7F"]
diff --git a/Lib/test/test_wsgiref.py b/Lib/test/test_wsgiref.py
index 42094f467731d4..01ca51ba458587 100644
--- a/Lib/test/test_wsgiref.py
+++ b/Lib/test/test_wsgiref.py
@@ -1,6 +1,6 @@
from unittest import mock
from test import support
-from test.support import socket_helper
+from test.support import socket_helper, control_characters_c0
from test.support import warnings_helper
from test.test_httpservers import NoLogRequestHandler
from unittest import TestCase
@@ -527,6 +527,16 @@ def testExtras(self):
'\r\n'
)
+ def testRaisesControlCharacters(self):
+ headers = Headers()
+ for c0 in control_characters_c0():
+ self.assertRaises(ValueError, headers.__setitem__, f"key{c0}", "val")
+ self.assertRaises(ValueError, headers.__setitem__, "key", f"val{c0}")
+ self.assertRaises(ValueError, headers.add_header, f"key{c0}", "val", param="param")
+ self.assertRaises(ValueError, headers.add_header, "key", f"val{c0}", param="param")
+ self.assertRaises(ValueError, headers.add_header, "key", "val", param=f"param{c0}")
+
+
class ErrorHandler(BaseCGIHandler):
"""Simple handler subclass for testing BaseHandler"""
diff --git a/Lib/wsgiref/headers.py b/Lib/wsgiref/headers.py
index fab851c5a44430..fd98e85d75492b 100644
--- a/Lib/wsgiref/headers.py
+++ b/Lib/wsgiref/headers.py
@@ -9,6 +9,7 @@
# existence of which force quoting of the parameter value.
import re
tspecials = re.compile(r'[ \(\)<>@,;:\\"/\[\]\?=]')
+_control_chars_re = re.compile(r'[\x00-\x1F\x7F]')
def _formatparam(param, value=None, quote=1):
"""Convenience function to format and return a key=value pair.
@@ -41,6 +42,8 @@ def __init__(self, headers=None):
def _convert_string_type(self, value):
"""Convert/check value type."""
if type(value) is str:
+ if _control_chars_re.search(value):
+ raise ValueError("Control characters not allowed in headers")
return value
raise AssertionError("Header names/values must be"
" of type str (got {0})".format(repr(value)))
diff --git a/Misc/NEWS.d/next/Security/2026-01-16-11-07-36.gh-issue-143916.dpWeOD.rst b/Misc/NEWS.d/next/Security/2026-01-16-11-07-36.gh-issue-143916.dpWeOD.rst
new file mode 100644
index 00000000000000..44bd0b27059f94
--- /dev/null
+++ b/Misc/NEWS.d/next/Security/2026-01-16-11-07-36.gh-issue-143916.dpWeOD.rst
@@ -0,0 +1,2 @@
+Reject C0 control characters within wsgiref.headers.Headers fields, values,
+and parameters.

Binary file not shown.

File diff suppressed because one or more lines are too long

BIN
Python-3.10.20.tar.xz LFS Normal file

Binary file not shown.

File diff suppressed because one or more lines are too long

View File

@@ -3,10 +3,10 @@
Misc/NEWS | 2 +-
2 files changed, 1 insertion(+), 4 deletions(-)
Index: Python-3.10.19/Doc/using/configure.rst
Index: Python-3.10.20/Doc/using/configure.rst
===================================================================
--- Python-3.10.19.orig/Doc/using/configure.rst 2025-10-09 17:25:03.000000000 +0200
+++ Python-3.10.19/Doc/using/configure.rst 2025-12-19 23:10:08.779794344 +0100
--- Python-3.10.20.orig/Doc/using/configure.rst 2026-03-03 01:49:35.000000000 +0100
+++ Python-3.10.20/Doc/using/configure.rst 2026-03-05 19:41:57.289556663 +0100
@@ -42,7 +42,6 @@
See :data:`sys.int_info.bits_per_digit <sys.int_info>`.
@@ -29,11 +29,11 @@ Index: Python-3.10.19/Doc/using/configure.rst
.. cmdoption:: --enable-framework=INSTALLDIR
Create a Python.framework rather than a traditional Unix install. Optional
Index: Python-3.10.19/Misc/NEWS
Index: Python-3.10.20/Misc/NEWS
===================================================================
--- Python-3.10.19.orig/Misc/NEWS 2025-10-09 17:25:03.000000000 +0200
+++ Python-3.10.19/Misc/NEWS 2025-12-19 23:10:08.784479751 +0100
@@ -4018,7 +4018,7 @@
--- Python-3.10.20.orig/Misc/NEWS 2026-03-03 01:49:35.000000000 +0100
+++ Python-3.10.20/Misc/NEWS 2026-03-05 19:41:57.302556681 +0100
@@ -4112,7 +4112,7 @@
-----
- bpo-43795: The list in :ref:`stable-abi-list` now shows the public name

View File

@@ -1,3 +1,92 @@
-------------------------------------------------------------------
Thu Mar 5 18:38:39 UTC 2026 - Matej Cepl <mcepl@cepl.eu>
- Update to 3.10.20:
- Security
- gh-144125: BytesGenerator will now refuse to serialize
(write) headers that are unsafely folded or delimited; see
verify_generated_headers. (Contributed by Bas Bloemsaat and
Petr Viktorin in gh-121650).
- gh-143935: Fixed a bug in the folding of comments when
flattening an email message using a modern email policy.
Comments consisting of a very long sequence of non-foldable
characters could trigger a forced line wrap that omitted
the required leading space on the continuation line,
causing the remainder of the comment to be interpreted as
a new header field. This enabled header injection with
carefully crafted inputs (bsc#1257029 CVE-2025-11468).
- gh-143925: Reject control characters in data: URL media
types.
- gh-143919: Reject control characters in http.cookies.Morsel
fields and values (bsc#1257031, CVE-2026-0672).
- gh-143916: Reject C0 control characters within
wsgiref.headers.Headers fields, values, and parameters
(bsc#1257042, CVE-2026-0865).
- gh-142145: Remove quadratic behavior in xml.minidom node ID
cache clearing. In order to do this without breaking
existing users, we also add the ownerDocument attribute to
xml.dom.minidom elements and attributes created by directly
instantiating the Element or Attr class. Note that this way
of creating nodes is not supported; creator functions like
xml.dom.Document.documentElement() should be used instead
(bsc#1254997, CVE-2025-12084).
- gh-137836: Add support of the “plaintext” element, RAWTEXT
elements “xmp”, “iframe”, “noembed” and “noframes”, and
optionally RAWTEXT element “noscript” in
html.parser.HTMLParser.
- gh-136063: email.message: ensure linear complexity for
legacy HTTP parameters parsing. Patch by Bénédikt Tran.
- gh-136065: Fix quadratic complexity in
os.path.expandvars() (bsc#1252974, CVE-2025-6075).
- gh-119451: Fix a potential memory denial of service in the
http.client module. When connecting to a malicious server,
it could cause an arbitrary amount of memory to be
allocated. This could have led to symptoms including
a MemoryError, swapping, out of memory (OOM) killed
processes or containers, or even system crashes
(CVE-2025-13836, bsc#1254400).
- gh-119452: Fix a potential memory denial of service in the
http.server module. When a malicious user is connected to
the CGI server on Windows, it could cause an arbitrary
amount of memory to be allocated. This could have led to
symptoms including a MemoryError, swapping, out of memory
(OOM) killed processes or containers, or even system
crashes.
- gh-119342: Fix a potential memory denial of service in the
plistlib module. When reading a Plist file received from
untrusted source, it could cause an arbitrary amount of
memory to be allocated. This could have led to symptoms
including a MemoryError, swapping, out of memory (OOM)
killed processes or containers, or even system crashes
(bsc#1254401, CVE-2025-13837).
- Library
- gh-144833: Fixed a use-after-free in ssl when SSL_new()
returns NULL in newPySSLSocket(). The error was reported
via a dangling pointer after the object had already been
freed.
- gh-144363: Update bundled libexpat to 2.7.4
- gh-90949: Add SetAllocTrackerActivationThreshold() and
SetAllocTrackerMaximumAmplification() to xmlparser objects
to prevent use of disproportional amounts of dynamic memory
from within an Expat parser. Patch by Bénédikt Tran.
- Core and Builtins
- gh-120384: Fix an array out of bounds crash in
list_ass_subscript, which could be invoked via some
specificly tailored input: including concurrent
modification of a list object, where one thread assigns
a slice and another clears it.
- gh-120298: Fix use-after free in list_richcompare_impl
which can be invoked via some specificly tailored evil
input.
- Remove upstreamed patches:
- CVE-2025-11468-email-hdr-fold-comment.patch
- CVE-2025-12084-minidom-quad-search.patch
- CVE-2025-13836-http-resp-cont-len.patch
- CVE-2025-13837-plistlib-mailicious-length.patch
- CVE-2025-6075-expandvars-perf-degrad.patch
- CVE-2026-0672-http-hdr-inject-cookie-Morsel.patch
- CVE-2026-0865-wsgiref-ctrl-chars.patch
-------------------------------------------------------------------
Wed Feb 11 23:49:49 CET 2026 - Matej Cepl <mcepl@suse.com>

View File

@@ -108,7 +108,7 @@ Obsoletes: python39%{?1:-%{1}}
# _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.10.19
Version: 3.10.20
Release: 0
Summary: Python 3 Interpreter
License: Python-2.0

View File

@@ -73,10 +73,10 @@
Doc/tutorial/stdlib.rst | 2
72 files changed, 458 insertions(+), 427 deletions(-)
Index: Python-3.10.19/Doc/c-api/bytearray.rst
Index: Python-3.10.20/Doc/c-api/bytearray.rst
===================================================================
--- Python-3.10.19.orig/Doc/c-api/bytearray.rst 2025-10-09 17:25:03.000000000 +0200
+++ Python-3.10.19/Doc/c-api/bytearray.rst 2025-12-19 23:10:15.391446431 +0100
--- Python-3.10.20.orig/Doc/c-api/bytearray.rst 2026-03-05 19:42:16.336584040 +0100
+++ Python-3.10.20/Doc/c-api/bytearray.rst 2026-03-05 19:42:18.969673759 +0100
@@ -5,7 +5,7 @@
Byte Array Objects
------------------
@@ -86,10 +86,10 @@ Index: Python-3.10.19/Doc/c-api/bytearray.rst
.. c:type:: PyByteArrayObject
Index: Python-3.10.19/Doc/c-api/bytes.rst
Index: Python-3.10.20/Doc/c-api/bytes.rst
===================================================================
--- Python-3.10.19.orig/Doc/c-api/bytes.rst 2025-10-09 17:25:03.000000000 +0200
+++ Python-3.10.19/Doc/c-api/bytes.rst 2025-12-19 23:10:15.391922542 +0100
--- Python-3.10.20.orig/Doc/c-api/bytes.rst 2026-03-05 19:42:16.336584040 +0100
+++ Python-3.10.20/Doc/c-api/bytes.rst 2026-03-05 19:42:18.970100765 +0100
@@ -8,7 +8,7 @@
These functions raise :exc:`TypeError` when expecting a bytes parameter and
called with a non-bytes parameter.
@@ -99,10 +99,10 @@ Index: Python-3.10.19/Doc/c-api/bytes.rst
.. c:type:: PyBytesObject
Index: Python-3.10.19/Doc/c-api/capsule.rst
Index: Python-3.10.20/Doc/c-api/capsule.rst
===================================================================
--- Python-3.10.19.orig/Doc/c-api/capsule.rst 2025-10-09 17:25:03.000000000 +0200
+++ Python-3.10.19/Doc/c-api/capsule.rst 2025-12-19 23:10:15.392109858 +0100
--- Python-3.10.20.orig/Doc/c-api/capsule.rst 2026-03-05 19:42:16.336584040 +0100
+++ Python-3.10.20/Doc/c-api/capsule.rst 2026-03-05 19:42:18.970312835 +0100
@@ -5,7 +5,7 @@
Capsules
--------
@@ -112,10 +112,10 @@ Index: Python-3.10.19/Doc/c-api/capsule.rst
Refer to :ref:`using-capsules` for more information on using these objects.
Index: Python-3.10.19/Doc/c-api/complex.rst
Index: Python-3.10.20/Doc/c-api/complex.rst
===================================================================
--- Python-3.10.19.orig/Doc/c-api/complex.rst 2025-10-09 17:25:03.000000000 +0200
+++ Python-3.10.19/Doc/c-api/complex.rst 2025-12-19 23:10:15.392289421 +0100
--- Python-3.10.20.orig/Doc/c-api/complex.rst 2026-03-05 19:42:16.336584040 +0100
+++ Python-3.10.20/Doc/c-api/complex.rst 2026-03-05 19:42:18.970503093 +0100
@@ -5,7 +5,7 @@
Complex Number Objects
----------------------
@@ -125,10 +125,10 @@ Index: Python-3.10.19/Doc/c-api/complex.rst
Python's complex number objects are implemented as two distinct types when
viewed from the C API: one is the Python object exposed to Python programs, and
Index: Python-3.10.19/Doc/c-api/concrete.rst
Index: Python-3.10.20/Doc/c-api/concrete.rst
===================================================================
--- Python-3.10.19.orig/Doc/c-api/concrete.rst 2025-10-09 17:25:03.000000000 +0200
+++ Python-3.10.19/Doc/c-api/concrete.rst 2025-12-19 23:10:15.392466051 +0100
--- Python-3.10.20.orig/Doc/c-api/concrete.rst 2026-03-05 19:42:16.336584040 +0100
+++ Python-3.10.20/Doc/c-api/concrete.rst 2026-03-05 19:42:18.970750049 +0100
@@ -40,7 +40,7 @@
Numeric Objects
===============
@@ -156,10 +156,10 @@ Index: Python-3.10.19/Doc/c-api/concrete.rst
.. toctree::
Index: Python-3.10.19/Doc/c-api/dict.rst
Index: Python-3.10.20/Doc/c-api/dict.rst
===================================================================
--- Python-3.10.19.orig/Doc/c-api/dict.rst 2025-10-09 17:25:03.000000000 +0200
+++ Python-3.10.19/Doc/c-api/dict.rst 2025-12-19 23:10:15.392652110 +0100
--- Python-3.10.20.orig/Doc/c-api/dict.rst 2026-03-05 19:42:16.336584040 +0100
+++ Python-3.10.20/Doc/c-api/dict.rst 2026-03-05 19:42:18.970944416 +0100
@@ -5,7 +5,7 @@
Dictionary Objects
------------------
@@ -178,10 +178,10 @@ Index: Python-3.10.19/Doc/c-api/dict.rst
Return the number of items in the dictionary. This is equivalent to
``len(p)`` on a dictionary.
Index: Python-3.10.19/Doc/c-api/exceptions.rst
Index: Python-3.10.20/Doc/c-api/exceptions.rst
===================================================================
--- Python-3.10.19.orig/Doc/c-api/exceptions.rst 2025-10-09 17:25:03.000000000 +0200
+++ Python-3.10.19/Doc/c-api/exceptions.rst 2025-12-19 23:10:15.392896207 +0100
--- Python-3.10.20.orig/Doc/c-api/exceptions.rst 2026-03-05 19:42:16.336584040 +0100
+++ Python-3.10.20/Doc/c-api/exceptions.rst 2026-03-05 19:42:18.971230595 +0100
@@ -503,7 +503,7 @@
.. c:function:: int PyErr_CheckSignals()
@@ -209,10 +209,10 @@ Index: Python-3.10.19/Doc/c-api/exceptions.rst
single: KeyboardInterrupt (built-in exception)
Simulate the effect of a signal arriving. The next time
Index: Python-3.10.19/Doc/c-api/file.rst
Index: Python-3.10.20/Doc/c-api/file.rst
===================================================================
--- Python-3.10.19.orig/Doc/c-api/file.rst 2025-10-09 17:25:03.000000000 +0200
+++ Python-3.10.19/Doc/c-api/file.rst 2025-12-19 23:10:15.393159161 +0100
--- Python-3.10.20.orig/Doc/c-api/file.rst 2026-03-05 19:42:16.336584040 +0100
+++ Python-3.10.20/Doc/c-api/file.rst 2026-03-05 19:42:18.971537043 +0100
@@ -5,7 +5,7 @@
File Objects
------------
@@ -222,10 +222,10 @@ Index: Python-3.10.19/Doc/c-api/file.rst
These APIs are a minimal emulation of the Python 2 C API for built-in file
objects, which used to rely on the buffered I/O (:c:expr:`FILE*`) support
Index: Python-3.10.19/Doc/c-api/float.rst
Index: Python-3.10.20/Doc/c-api/float.rst
===================================================================
--- Python-3.10.19.orig/Doc/c-api/float.rst 2025-10-09 17:25:03.000000000 +0200
+++ Python-3.10.19/Doc/c-api/float.rst 2025-12-19 23:10:15.393330204 +0100
--- Python-3.10.20.orig/Doc/c-api/float.rst 2026-03-05 19:42:16.336584040 +0100
+++ Python-3.10.20/Doc/c-api/float.rst 2026-03-05 19:42:18.971720008 +0100
@@ -5,7 +5,7 @@
Floating Point Objects
----------------------
@@ -235,10 +235,10 @@ Index: Python-3.10.19/Doc/c-api/float.rst
.. c:type:: PyFloatObject
Index: Python-3.10.19/Doc/c-api/function.rst
Index: Python-3.10.20/Doc/c-api/function.rst
===================================================================
--- Python-3.10.19.orig/Doc/c-api/function.rst 2025-10-09 17:25:03.000000000 +0200
+++ Python-3.10.19/Doc/c-api/function.rst 2025-12-19 23:10:15.393493494 +0100
--- Python-3.10.20.orig/Doc/c-api/function.rst 2026-03-05 19:42:16.337584041 +0100
+++ Python-3.10.20/Doc/c-api/function.rst 2026-03-05 19:42:18.971899246 +0100
@@ -5,7 +5,7 @@
Function Objects
----------------
@@ -248,10 +248,10 @@ Index: Python-3.10.19/Doc/c-api/function.rst
There are a few functions specific to Python functions.
Index: Python-3.10.19/Doc/c-api/import.rst
Index: Python-3.10.20/Doc/c-api/import.rst
===================================================================
--- Python-3.10.19.orig/Doc/c-api/import.rst 2025-10-09 17:25:03.000000000 +0200
+++ Python-3.10.19/Doc/c-api/import.rst 2025-12-19 23:10:15.393679483 +0100
--- Python-3.10.20.orig/Doc/c-api/import.rst 2026-03-05 19:42:16.337584041 +0100
+++ Python-3.10.20/Doc/c-api/import.rst 2026-03-05 19:42:18.972099725 +0100
@@ -41,7 +41,7 @@
.. c:function:: PyObject* PyImport_ImportModuleEx(const char *name, PyObject *globals, PyObject *locals, PyObject *fromlist)
@@ -270,10 +270,10 @@ Index: Python-3.10.19/Doc/c-api/import.rst
Given a module name (possibly of the form ``package.module``) and a code object
read from a Python bytecode file or obtained from the built-in function
Index: Python-3.10.19/Doc/c-api/init.rst
Index: Python-3.10.20/Doc/c-api/init.rst
===================================================================
--- Python-3.10.19.orig/Doc/c-api/init.rst 2025-10-09 17:25:03.000000000 +0200
+++ Python-3.10.19/Doc/c-api/init.rst 2025-12-19 23:10:15.393955078 +0100
--- Python-3.10.20.orig/Doc/c-api/init.rst 2026-03-05 19:42:16.337584041 +0100
+++ Python-3.10.20/Doc/c-api/init.rst 2026-03-05 19:42:18.972397676 +0100
@@ -233,9 +233,9 @@
single: PyEval_InitThreads()
single: modules (in module sys)
@@ -309,10 +309,10 @@ Index: Python-3.10.19/Doc/c-api/init.rst
single: stdout (in module sys)
single: stderr (in module sys)
single: stdin (in module sys)
Index: Python-3.10.19/Doc/c-api/intro.rst
Index: Python-3.10.20/Doc/c-api/intro.rst
===================================================================
--- Python-3.10.19.orig/Doc/c-api/intro.rst 2025-10-09 17:25:03.000000000 +0200
+++ Python-3.10.19/Doc/c-api/intro.rst 2025-12-19 23:10:15.394470650 +0100
--- Python-3.10.20.orig/Doc/c-api/intro.rst 2026-03-05 19:42:16.337584041 +0100
+++ Python-3.10.20/Doc/c-api/intro.rst 2026-03-05 19:42:18.972771231 +0100
@@ -226,7 +226,7 @@
Objects, Types and Reference Counts
===================================
@@ -335,10 +335,10 @@ Index: Python-3.10.19/Doc/c-api/intro.rst
triple: module; search; path
single: path (in module sys)
Index: Python-3.10.19/Doc/c-api/list.rst
Index: Python-3.10.20/Doc/c-api/list.rst
===================================================================
--- Python-3.10.19.orig/Doc/c-api/list.rst 2025-10-09 17:25:03.000000000 +0200
+++ Python-3.10.19/Doc/c-api/list.rst 2025-12-19 23:10:15.394763148 +0100
--- Python-3.10.20.orig/Doc/c-api/list.rst 2026-03-05 19:42:16.337584041 +0100
+++ Python-3.10.20/Doc/c-api/list.rst 2026-03-05 19:42:18.973088189 +0100
@@ -5,7 +5,7 @@
List Objects
------------
@@ -366,10 +366,10 @@ Index: Python-3.10.19/Doc/c-api/list.rst
Return a new tuple object containing the contents of *list*; equivalent to
``tuple(list)``.
Index: Python-3.10.19/Doc/c-api/long.rst
Index: Python-3.10.20/Doc/c-api/long.rst
===================================================================
--- Python-3.10.19.orig/Doc/c-api/long.rst 2025-10-09 17:25:03.000000000 +0200
+++ Python-3.10.19/Doc/c-api/long.rst 2025-12-19 23:10:15.394948159 +0100
--- Python-3.10.20.orig/Doc/c-api/long.rst 2026-03-05 19:42:16.337584041 +0100
+++ Python-3.10.20/Doc/c-api/long.rst 2026-03-05 19:42:18.973340364 +0100
@@ -5,8 +5,8 @@
Integer Objects
---------------
@@ -381,10 +381,10 @@ Index: Python-3.10.19/Doc/c-api/long.rst
All integers are implemented as "long" integer objects of arbitrary size.
Index: Python-3.10.19/Doc/c-api/mapping.rst
Index: Python-3.10.20/Doc/c-api/mapping.rst
===================================================================
--- Python-3.10.19.orig/Doc/c-api/mapping.rst 2025-10-09 17:25:03.000000000 +0200
+++ Python-3.10.19/Doc/c-api/mapping.rst 2025-12-19 23:10:15.395138967 +0100
--- Python-3.10.20.orig/Doc/c-api/mapping.rst 2026-03-05 19:42:16.337584041 +0100
+++ Python-3.10.20/Doc/c-api/mapping.rst 2026-03-05 19:42:18.973549118 +0100
@@ -20,7 +20,7 @@
.. c:function:: Py_ssize_t PyMapping_Size(PyObject *o)
Py_ssize_t PyMapping_Length(PyObject *o)
@@ -394,10 +394,10 @@ Index: Python-3.10.19/Doc/c-api/mapping.rst
Returns the number of keys in object *o* on success, and ``-1`` on failure.
This is equivalent to the Python expression ``len(o)``.
Index: Python-3.10.19/Doc/c-api/memoryview.rst
Index: Python-3.10.20/Doc/c-api/memoryview.rst
===================================================================
--- Python-3.10.19.orig/Doc/c-api/memoryview.rst 2025-10-09 17:25:03.000000000 +0200
+++ Python-3.10.19/Doc/c-api/memoryview.rst 2025-12-19 23:10:15.395300231 +0100
--- Python-3.10.20.orig/Doc/c-api/memoryview.rst 2026-03-05 19:42:16.337584041 +0100
+++ Python-3.10.20/Doc/c-api/memoryview.rst 2026-03-05 19:42:18.973728286 +0100
@@ -3,7 +3,7 @@
.. _memoryview-objects:
@@ -407,10 +407,10 @@ Index: Python-3.10.19/Doc/c-api/memoryview.rst
MemoryView objects
------------------
Index: Python-3.10.19/Doc/c-api/method.rst
Index: Python-3.10.20/Doc/c-api/method.rst
===================================================================
--- Python-3.10.19.orig/Doc/c-api/method.rst 2025-10-09 17:25:03.000000000 +0200
+++ Python-3.10.19/Doc/c-api/method.rst 2025-12-19 23:10:15.395505706 +0100
--- Python-3.10.20.orig/Doc/c-api/method.rst 2026-03-05 19:42:16.337584041 +0100
+++ Python-3.10.20/Doc/c-api/method.rst 2026-03-05 19:42:18.973936919 +0100
@@ -5,7 +5,7 @@
Instance Method Objects
-----------------------
@@ -429,10 +429,10 @@ Index: Python-3.10.19/Doc/c-api/method.rst
Methods are bound function objects. Methods are always bound to an instance of
a user-defined class. Unbound methods (methods bound to a class object) are
Index: Python-3.10.19/Doc/c-api/module.rst
Index: Python-3.10.20/Doc/c-api/module.rst
===================================================================
--- Python-3.10.19.orig/Doc/c-api/module.rst 2025-10-09 17:25:03.000000000 +0200
+++ Python-3.10.19/Doc/c-api/module.rst 2025-12-19 23:10:15.395739397 +0100
--- Python-3.10.20.orig/Doc/c-api/module.rst 2026-03-05 19:42:16.337584041 +0100
+++ Python-3.10.20/Doc/c-api/module.rst 2026-03-05 19:42:18.974150622 +0100
@@ -5,7 +5,7 @@
Module Objects
--------------
@@ -442,10 +442,10 @@ Index: Python-3.10.19/Doc/c-api/module.rst
.. c:var:: PyTypeObject PyModule_Type
Index: Python-3.10.19/Doc/c-api/none.rst
Index: Python-3.10.20/Doc/c-api/none.rst
===================================================================
--- Python-3.10.19.orig/Doc/c-api/none.rst 2025-10-09 17:25:03.000000000 +0200
+++ Python-3.10.19/Doc/c-api/none.rst 2025-12-19 23:10:15.395955557 +0100
--- Python-3.10.20.orig/Doc/c-api/none.rst 2026-03-05 19:42:16.337584041 +0100
+++ Python-3.10.20/Doc/c-api/none.rst 2026-03-05 19:42:18.974386076 +0100
@@ -5,7 +5,7 @@
The ``None`` Object
-------------------
@@ -455,10 +455,10 @@ Index: Python-3.10.19/Doc/c-api/none.rst
Note that the :c:type:`PyTypeObject` for ``None`` is not directly exposed in the
Python/C API. Since ``None`` is a singleton, testing for object identity (using
Index: Python-3.10.19/Doc/c-api/number.rst
Index: Python-3.10.20/Doc/c-api/number.rst
===================================================================
--- Python-3.10.19.orig/Doc/c-api/number.rst 2025-10-09 17:25:03.000000000 +0200
+++ Python-3.10.19/Doc/c-api/number.rst 2025-12-19 23:10:15.396155514 +0100
--- Python-3.10.20.orig/Doc/c-api/number.rst 2026-03-05 19:42:16.337584041 +0100
+++ Python-3.10.20/Doc/c-api/number.rst 2026-03-05 19:42:18.974581886 +0100
@@ -64,7 +64,7 @@
.. c:function:: PyObject* PyNumber_Divmod(PyObject *o1, PyObject *o2)
@@ -513,10 +513,10 @@ Index: Python-3.10.19/Doc/c-api/number.rst
Returns the *o* converted to a float object on success, or ``NULL`` on failure.
This is the equivalent of the Python expression ``float(o)``.
Index: Python-3.10.19/Doc/c-api/object.rst
Index: Python-3.10.20/Doc/c-api/object.rst
===================================================================
--- Python-3.10.19.orig/Doc/c-api/object.rst 2025-10-09 17:25:03.000000000 +0200
+++ Python-3.10.19/Doc/c-api/object.rst 2025-12-19 23:10:15.396357217 +0100
--- Python-3.10.20.orig/Doc/c-api/object.rst 2026-03-05 19:42:16.337584041 +0100
+++ Python-3.10.20/Doc/c-api/object.rst 2026-03-05 19:42:18.974799656 +0100
@@ -172,7 +172,7 @@
.. c:function:: PyObject* PyObject_Repr(PyObject *o)
@@ -571,10 +571,10 @@ Index: Python-3.10.19/Doc/c-api/object.rst
Return the length of object *o*. If the object *o* provides either the sequence
and mapping protocols, the sequence length is returned. On error, ``-1`` is
Index: Python-3.10.19/Doc/c-api/sequence.rst
Index: Python-3.10.20/Doc/c-api/sequence.rst
===================================================================
--- Python-3.10.19.orig/Doc/c-api/sequence.rst 2025-10-09 17:25:03.000000000 +0200
+++ Python-3.10.19/Doc/c-api/sequence.rst 2025-12-19 23:10:15.396594610 +0100
--- Python-3.10.20.orig/Doc/c-api/sequence.rst 2026-03-05 19:42:16.337584041 +0100
+++ Python-3.10.20/Doc/c-api/sequence.rst 2026-03-05 19:42:18.975049317 +0100
@@ -18,7 +18,7 @@
.. c:function:: Py_ssize_t PySequence_Size(PyObject *o)
Py_ssize_t PySequence_Length(PyObject *o)
@@ -593,10 +593,10 @@ Index: Python-3.10.19/Doc/c-api/sequence.rst
Return a tuple object with the same contents as the sequence or iterable *o*,
or ``NULL`` on failure. If *o* is a tuple, a new reference will be returned,
Index: Python-3.10.19/Doc/c-api/set.rst
Index: Python-3.10.20/Doc/c-api/set.rst
===================================================================
--- Python-3.10.19.orig/Doc/c-api/set.rst 2025-10-09 17:25:03.000000000 +0200
+++ Python-3.10.19/Doc/c-api/set.rst 2025-12-19 23:10:15.396771519 +0100
--- Python-3.10.20.orig/Doc/c-api/set.rst 2026-03-05 19:42:16.337584041 +0100
+++ Python-3.10.20/Doc/c-api/set.rst 2026-03-05 19:42:18.975306692 +0100
@@ -9,8 +9,8 @@
@@ -617,10 +617,10 @@ Index: Python-3.10.19/Doc/c-api/set.rst
Return the length of a :class:`set` or :class:`frozenset` object. Equivalent to
``len(anyset)``. Raises a :exc:`PyExc_SystemError` if *anyset* is not a
Index: Python-3.10.19/Doc/c-api/structures.rst
Index: Python-3.10.20/Doc/c-api/structures.rst
===================================================================
--- Python-3.10.19.orig/Doc/c-api/structures.rst 2025-10-09 17:25:03.000000000 +0200
+++ Python-3.10.19/Doc/c-api/structures.rst 2025-12-19 23:10:15.396945495 +0100
--- Python-3.10.20.orig/Doc/c-api/structures.rst 2026-03-05 19:42:16.337584041 +0100
+++ Python-3.10.20/Doc/c-api/structures.rst 2026-03-05 19:42:18.975635963 +0100
@@ -351,7 +351,7 @@
.. data:: METH_CLASS
@@ -639,10 +639,10 @@ Index: Python-3.10.19/Doc/c-api/structures.rst
The method will be passed ``NULL`` as the first parameter rather than an
instance of the type. This is used to create *static methods*, similar to
Index: Python-3.10.19/Doc/c-api/tuple.rst
Index: Python-3.10.20/Doc/c-api/tuple.rst
===================================================================
--- Python-3.10.19.orig/Doc/c-api/tuple.rst 2025-10-09 17:25:03.000000000 +0200
+++ Python-3.10.19/Doc/c-api/tuple.rst 2025-12-19 23:10:15.397144544 +0100
--- Python-3.10.20.orig/Doc/c-api/tuple.rst 2026-03-05 19:42:16.337584041 +0100
+++ Python-3.10.20/Doc/c-api/tuple.rst 2026-03-05 19:42:18.975888880 +0100
@@ -5,7 +5,7 @@
Tuple Objects
-------------
@@ -652,10 +652,10 @@ Index: Python-3.10.19/Doc/c-api/tuple.rst
.. c:type:: PyTupleObject
Index: Python-3.10.19/Doc/c-api/type.rst
Index: Python-3.10.20/Doc/c-api/type.rst
===================================================================
--- Python-3.10.19.orig/Doc/c-api/type.rst 2025-10-09 17:25:03.000000000 +0200
+++ Python-3.10.19/Doc/c-api/type.rst 2025-12-19 23:10:15.397329764 +0100
--- Python-3.10.20.orig/Doc/c-api/type.rst 2026-03-05 19:42:16.337584041 +0100
+++ Python-3.10.20/Doc/c-api/type.rst 2026-03-05 19:42:18.976188766 +0100
@@ -5,7 +5,7 @@
Type Objects
------------
@@ -665,10 +665,10 @@ Index: Python-3.10.19/Doc/c-api/type.rst
.. c:type:: PyTypeObject
Index: Python-3.10.19/Doc/c-api/typeobj.rst
Index: Python-3.10.20/Doc/c-api/typeobj.rst
===================================================================
--- Python-3.10.19.orig/Doc/c-api/typeobj.rst 2025-10-09 17:25:03.000000000 +0200
+++ Python-3.10.19/Doc/c-api/typeobj.rst 2025-12-19 23:10:15.397446400 +0100
--- Python-3.10.20.orig/Doc/c-api/typeobj.rst 2026-03-05 19:42:16.337584041 +0100
+++ Python-3.10.20/Doc/c-api/typeobj.rst 2026-03-05 19:42:18.976565316 +0100
@@ -803,7 +803,7 @@
.. c:member:: reprfunc PyTypeObject.tp_repr
@@ -687,10 +687,10 @@ Index: Python-3.10.19/Doc/c-api/typeobj.rst
An optional pointer to a function that implements the built-in function
:func:`hash`.
Index: Python-3.10.19/Doc/conf.py
Index: Python-3.10.20/Doc/conf.py
===================================================================
--- Python-3.10.19.orig/Doc/conf.py 2025-10-09 17:25:03.000000000 +0200
+++ Python-3.10.19/Doc/conf.py 2025-12-19 23:10:15.398083707 +0100
--- Python-3.10.20.orig/Doc/conf.py 2026-03-05 19:42:16.337584041 +0100
+++ Python-3.10.20/Doc/conf.py 2026-03-05 19:42:18.977099103 +0100
@@ -61,6 +61,11 @@
# Avoid a warning with Sphinx >= 2.0
master_doc = 'contents'
@@ -703,10 +703,10 @@ Index: Python-3.10.19/Doc/conf.py
# Options for HTML output
# -----------------------
Index: Python-3.10.19/Doc/extending/newtypes.rst
Index: Python-3.10.20/Doc/extending/newtypes.rst
===================================================================
--- Python-3.10.19.orig/Doc/extending/newtypes.rst 2025-10-09 17:25:03.000000000 +0200
+++ Python-3.10.19/Doc/extending/newtypes.rst 2025-12-19 23:10:15.398298470 +0100
--- Python-3.10.20.orig/Doc/extending/newtypes.rst 2026-03-05 19:42:16.337584041 +0100
+++ Python-3.10.20/Doc/extending/newtypes.rst 2026-03-05 19:42:18.977417513 +0100
@@ -149,7 +149,7 @@
.. index::
@@ -716,10 +716,10 @@ Index: Python-3.10.19/Doc/extending/newtypes.rst
Object Presentation
-------------------
Index: Python-3.10.19/Doc/library/_thread.rst
Index: Python-3.10.20/Doc/library/_thread.rst
===================================================================
--- Python-3.10.19.orig/Doc/library/_thread.rst 2025-10-09 17:25:03.000000000 +0200
+++ Python-3.10.19/Doc/library/_thread.rst 2025-12-19 23:10:15.398608428 +0100
--- Python-3.10.20.orig/Doc/library/_thread.rst 2026-03-05 19:42:16.337584041 +0100
+++ Python-3.10.20/Doc/library/_thread.rst 2026-03-05 19:42:18.977812839 +0100
@@ -204,7 +204,7 @@
**Caveats:**
@@ -729,10 +729,10 @@ Index: Python-3.10.19/Doc/library/_thread.rst
* Threads interact strangely with interrupts: the :exc:`KeyboardInterrupt`
exception will be received by an arbitrary thread. (When the :mod:`signal`
Index: Python-3.10.19/Doc/library/binascii.rst
Index: Python-3.10.20/Doc/library/binascii.rst
===================================================================
--- Python-3.10.19.orig/Doc/library/binascii.rst 2025-10-09 17:25:03.000000000 +0200
+++ Python-3.10.19/Doc/library/binascii.rst 2025-12-19 23:10:15.398847287 +0100
--- Python-3.10.20.orig/Doc/library/binascii.rst 2026-03-05 19:42:16.337584041 +0100
+++ Python-3.10.20/Doc/library/binascii.rst 2026-03-05 19:42:18.978168049 +0100
@@ -6,9 +6,9 @@
representations.
@@ -746,10 +746,10 @@ Index: Python-3.10.19/Doc/library/binascii.rst
--------------
Index: Python-3.10.19/Doc/library/cmath.rst
Index: Python-3.10.20/Doc/library/cmath.rst
===================================================================
--- Python-3.10.19.orig/Doc/library/cmath.rst 2025-10-09 17:25:03.000000000 +0200
+++ Python-3.10.19/Doc/library/cmath.rst 2025-12-19 23:10:15.399084959 +0100
--- Python-3.10.20.orig/Doc/library/cmath.rst 2026-03-05 19:42:16.337584041 +0100
+++ Python-3.10.20/Doc/library/cmath.rst 2026-03-05 19:42:18.978445211 +0100
@@ -301,7 +301,7 @@
.. versionadded:: 3.6
@@ -759,10 +759,10 @@ Index: Python-3.10.19/Doc/library/cmath.rst
Note that the selection of functions is similar, but not identical, to that in
module :mod:`math`. The reason for having two modules is that some users aren't
Index: Python-3.10.19/Doc/library/copy.rst
Index: Python-3.10.20/Doc/library/copy.rst
===================================================================
--- Python-3.10.19.orig/Doc/library/copy.rst 2025-10-09 17:25:03.000000000 +0200
+++ Python-3.10.19/Doc/library/copy.rst 2025-12-19 23:10:15.399270528 +0100
--- Python-3.10.20.orig/Doc/library/copy.rst 2026-03-05 19:42:16.337584041 +0100
+++ Python-3.10.20/Doc/library/copy.rst 2026-03-05 19:42:18.978728956 +0100
@@ -68,7 +68,7 @@
of lists by assigning a slice of the entire list, for example,
``copied_list = original_list[:]``.
@@ -772,10 +772,10 @@ Index: Python-3.10.19/Doc/library/copy.rst
Classes can use the same interfaces to control copying that they use to control
pickling. See the description of module :mod:`pickle` for information on these
Index: Python-3.10.19/Doc/library/copyreg.rst
Index: Python-3.10.20/Doc/library/copyreg.rst
===================================================================
--- Python-3.10.19.orig/Doc/library/copyreg.rst 2025-10-09 17:25:03.000000000 +0200
+++ Python-3.10.19/Doc/library/copyreg.rst 2025-12-19 23:10:15.399461755 +0100
--- Python-3.10.20.orig/Doc/library/copyreg.rst 2026-03-05 19:42:16.337584041 +0100
+++ Python-3.10.20/Doc/library/copyreg.rst 2026-03-05 19:42:18.978924325 +0100
@@ -7,8 +7,8 @@
**Source code:** :source:`Lib/copyreg.py`
@@ -787,10 +787,10 @@ Index: Python-3.10.19/Doc/library/copyreg.rst
--------------
Index: Python-3.10.19/Doc/library/dis.rst
Index: Python-3.10.20/Doc/library/dis.rst
===================================================================
--- Python-3.10.19.orig/Doc/library/dis.rst 2025-10-09 17:25:03.000000000 +0200
+++ Python-3.10.19/Doc/library/dis.rst 2025-12-19 23:10:15.399767732 +0100
--- Python-3.10.20.orig/Doc/library/dis.rst 2026-03-05 19:42:16.337584041 +0100
+++ Python-3.10.20/Doc/library/dis.rst 2026-03-05 19:42:18.979174547 +0100
@@ -1207,7 +1207,7 @@
.. opcode:: BUILD_SLICE (argc)
@@ -800,10 +800,10 @@ Index: Python-3.10.19/Doc/library/dis.rst
Pushes a slice object on the stack. *argc* must be 2 or 3. If it is 2,
``slice(TOS1, TOS)`` is pushed; if it is 3, ``slice(TOS2, TOS1, TOS)`` is
Index: Python-3.10.19/Doc/library/email.compat32-message.rst
Index: Python-3.10.20/Doc/library/email.compat32-message.rst
===================================================================
--- Python-3.10.19.orig/Doc/library/email.compat32-message.rst 2025-10-09 17:25:03.000000000 +0200
+++ Python-3.10.19/Doc/library/email.compat32-message.rst 2025-12-19 23:10:15.400042699 +0100
--- Python-3.10.20.orig/Doc/library/email.compat32-message.rst 2026-03-05 19:42:16.337584041 +0100
+++ Python-3.10.20/Doc/library/email.compat32-message.rst 2026-03-05 19:42:18.979546769 +0100
@@ -7,6 +7,7 @@
:synopsis: The base class representing email messages in a fashion
backward compatible with Python 3.2
@@ -812,10 +812,10 @@ Index: Python-3.10.19/Doc/library/email.compat32-message.rst
The :class:`Message` class is very similar to the
Index: Python-3.10.19/Doc/library/exceptions.rst
Index: Python-3.10.20/Doc/library/exceptions.rst
===================================================================
--- Python-3.10.19.orig/Doc/library/exceptions.rst 2025-10-09 17:25:03.000000000 +0200
+++ Python-3.10.19/Doc/library/exceptions.rst 2025-12-19 23:10:15.400305095 +0100
--- Python-3.10.20.orig/Doc/library/exceptions.rst 2026-03-05 19:42:16.337584041 +0100
+++ Python-3.10.20/Doc/library/exceptions.rst 2026-03-05 19:42:18.979875649 +0100
@@ -4,8 +4,8 @@
===================
@@ -854,10 +854,10 @@ Index: Python-3.10.19/Doc/library/exceptions.rst
This exception is raised when a system function returns a system-related
error, including I/O failures such as "file not found" or "disk full"
Index: Python-3.10.19/Doc/library/fnmatch.rst
Index: Python-3.10.20/Doc/library/fnmatch.rst
===================================================================
--- Python-3.10.19.orig/Doc/library/fnmatch.rst 2025-10-09 17:25:03.000000000 +0200
+++ Python-3.10.19/Doc/library/fnmatch.rst 2025-12-19 23:10:15.400595567 +0100
--- Python-3.10.20.orig/Doc/library/fnmatch.rst 2026-03-05 19:42:16.337584041 +0100
+++ Python-3.10.20/Doc/library/fnmatch.rst 2026-03-05 19:42:18.980208527 +0100
@@ -8,7 +8,7 @@
.. index:: single: filenames; wildcard expansion
@@ -876,10 +876,10 @@ Index: Python-3.10.19/Doc/library/fnmatch.rst
Note that the filename separator (``'/'`` on Unix) is *not* special to this
module. See module :mod:`glob` for pathname expansion (:mod:`glob` uses
Index: Python-3.10.19/Doc/library/functions.rst
Index: Python-3.10.20/Doc/library/functions.rst
===================================================================
--- Python-3.10.19.orig/Doc/library/functions.rst 2025-10-09 17:25:03.000000000 +0200
+++ Python-3.10.19/Doc/library/functions.rst 2025-12-19 23:10:15.400828071 +0100
--- Python-3.10.20.orig/Doc/library/functions.rst 2026-03-05 19:42:16.337584041 +0100
+++ Python-3.10.20/Doc/library/functions.rst 2026-03-05 19:42:18.980496911 +0100
@@ -548,7 +548,7 @@
Raises an :ref:`auditing event <auditing>` ``exec`` with the code object
as the argument. Code compilation events may also be raised.
@@ -918,10 +918,10 @@ Index: Python-3.10.19/Doc/library/functions.rst
.. note::
Index: Python-3.10.19/Doc/library/http.client.rst
Index: Python-3.10.20/Doc/library/http.client.rst
===================================================================
--- Python-3.10.19.orig/Doc/library/http.client.rst 2025-10-09 17:25:03.000000000 +0200
+++ Python-3.10.19/Doc/library/http.client.rst 2025-12-19 23:10:15.401177908 +0100
--- Python-3.10.20.orig/Doc/library/http.client.rst 2026-03-05 19:42:16.337584041 +0100
+++ Python-3.10.20/Doc/library/http.client.rst 2026-03-05 19:42:18.980925559 +0100
@@ -10,7 +10,7 @@
pair: HTTP; protocol
single: HTTP; http.client (standard module)
@@ -931,10 +931,10 @@ Index: Python-3.10.19/Doc/library/http.client.rst
--------------
Index: Python-3.10.19/Doc/library/imp.rst
Index: Python-3.10.20/Doc/library/imp.rst
===================================================================
--- Python-3.10.19.orig/Doc/library/imp.rst 2025-10-09 17:25:03.000000000 +0200
+++ Python-3.10.19/Doc/library/imp.rst 2025-12-19 23:10:15.401419561 +0100
--- Python-3.10.20.orig/Doc/library/imp.rst 2026-03-05 19:42:16.337584041 +0100
+++ Python-3.10.20/Doc/library/imp.rst 2026-03-05 19:42:18.981246615 +0100
@@ -10,7 +10,7 @@
.. deprecated:: 3.4
The :mod:`imp` module is deprecated in favor of :mod:`importlib`.
@@ -944,10 +944,10 @@ Index: Python-3.10.19/Doc/library/imp.rst
--------------
Index: Python-3.10.19/Doc/library/internet.rst
Index: Python-3.10.20/Doc/library/internet.rst
===================================================================
--- Python-3.10.19.orig/Doc/library/internet.rst 2025-10-09 17:25:03.000000000 +0200
+++ Python-3.10.19/Doc/library/internet.rst 2025-12-19 23:10:15.401643543 +0100
--- Python-3.10.20.orig/Doc/library/internet.rst 2026-03-05 19:42:16.337584041 +0100
+++ Python-3.10.20/Doc/library/internet.rst 2026-03-05 19:42:18.981489052 +0100
@@ -9,7 +9,7 @@
single: Internet
single: World Wide Web
@@ -957,10 +957,10 @@ Index: Python-3.10.19/Doc/library/internet.rst
The modules described in this chapter implement internet protocols and support
for related technology. They are all implemented in Python. Most of these
Index: Python-3.10.19/Doc/library/locale.rst
Index: Python-3.10.20/Doc/library/locale.rst
===================================================================
--- Python-3.10.19.orig/Doc/library/locale.rst 2025-10-09 17:25:03.000000000 +0200
+++ Python-3.10.19/Doc/library/locale.rst 2025-12-19 23:10:15.401831697 +0100
--- Python-3.10.20.orig/Doc/library/locale.rst 2026-03-05 19:42:16.337584041 +0100
+++ Python-3.10.20/Doc/library/locale.rst 2026-03-05 19:42:18.981763630 +0100
@@ -16,7 +16,7 @@
certain cultural issues in an application, without requiring the programmer to
know all the specifics of each country where the software is executed.
@@ -979,10 +979,10 @@ Index: Python-3.10.19/Doc/library/locale.rst
Locale category for the character type functions. Depending on the settings of
this category, the functions of module :mod:`string` dealing with case change
Index: Python-3.10.19/Doc/library/marshal.rst
Index: Python-3.10.20/Doc/library/marshal.rst
===================================================================
--- Python-3.10.19.orig/Doc/library/marshal.rst 2025-10-09 17:25:03.000000000 +0200
+++ Python-3.10.19/Doc/library/marshal.rst 2025-12-19 23:10:15.402080194 +0100
--- Python-3.10.20.orig/Doc/library/marshal.rst 2026-03-05 19:42:16.337584041 +0100
+++ Python-3.10.20/Doc/library/marshal.rst 2026-03-05 19:42:18.982052574 +0100
@@ -15,8 +15,8 @@
rarely does). [#]_
@@ -994,11 +994,11 @@ Index: Python-3.10.19/Doc/library/marshal.rst
This is not a general "persistence" module. For general persistence and
transfer of Python objects through RPC calls, see the modules :mod:`pickle` and
Index: Python-3.10.19/Doc/library/os.path.rst
Index: Python-3.10.20/Doc/library/os.path.rst
===================================================================
--- Python-3.10.19.orig/Doc/library/os.path.rst 2025-10-09 17:25:03.000000000 +0200
+++ Python-3.10.19/Doc/library/os.path.rst 2025-12-19 23:10:15.402271561 +0100
@@ -159,7 +159,7 @@
--- Python-3.10.20.orig/Doc/library/os.path.rst 2026-03-05 19:42:16.337584041 +0100
+++ Python-3.10.20/Doc/library/os.path.rst 2026-03-05 19:42:18.982385091 +0100
@@ -161,7 +161,7 @@
On Unix and Windows, return the argument with an initial component of ``~`` or
``~user`` replaced by that *user*'s home directory.
@@ -1007,10 +1007,10 @@ Index: Python-3.10.19/Doc/library/os.path.rst
On Unix, an initial ``~`` is replaced by the environment variable :envvar:`HOME`
if it is set; otherwise the current user's home directory is looked up in the
Index: Python-3.10.19/Doc/library/os.rst
Index: Python-3.10.20/Doc/library/os.rst
===================================================================
--- Python-3.10.19.orig/Doc/library/os.rst 2025-10-09 17:25:03.000000000 +0200
+++ Python-3.10.19/Doc/library/os.rst 2025-12-19 23:10:15.402446375 +0100
--- Python-3.10.20.orig/Doc/library/os.rst 2026-03-05 19:42:16.337584041 +0100
+++ Python-3.10.20/Doc/library/os.rst 2026-03-05 19:42:18.982587843 +0100
@@ -1136,7 +1136,7 @@
.. function:: openpty()
@@ -1029,10 +1029,10 @@ Index: Python-3.10.19/Doc/library/os.rst
Example::
Index: Python-3.10.19/Doc/library/pdb.rst
Index: Python-3.10.20/Doc/library/pdb.rst
===================================================================
--- Python-3.10.19.orig/Doc/library/pdb.rst 2025-10-09 17:25:03.000000000 +0200
+++ Python-3.10.19/Doc/library/pdb.rst 2025-12-19 23:10:15.403432541 +0100
--- Python-3.10.20.orig/Doc/library/pdb.rst 2026-03-05 19:42:16.337584041 +0100
+++ Python-3.10.20/Doc/library/pdb.rst 2026-03-05 19:42:18.983778239 +0100
@@ -20,8 +20,8 @@
.. index::
@@ -1044,10 +1044,10 @@ Index: Python-3.10.19/Doc/library/pdb.rst
The debugger is extensible -- it is actually defined as the class :class:`Pdb`.
This is currently undocumented but easily understood by reading the source. The
Index: Python-3.10.19/Doc/library/posix.rst
Index: Python-3.10.20/Doc/library/posix.rst
===================================================================
--- Python-3.10.19.orig/Doc/library/posix.rst 2025-10-09 17:25:03.000000000 +0200
+++ Python-3.10.19/Doc/library/posix.rst 2025-12-19 23:10:15.403681946 +0100
--- Python-3.10.20.orig/Doc/library/posix.rst 2026-03-05 19:42:16.337584041 +0100
+++ Python-3.10.20/Doc/library/posix.rst 2026-03-05 19:42:18.984101268 +0100
@@ -11,7 +11,7 @@
standardized by the C Standard and the POSIX standard (a thinly disguised Unix
interface).
@@ -1057,10 +1057,10 @@ Index: Python-3.10.19/Doc/library/posix.rst
**Do not import this module directly.** Instead, import the module :mod:`os`,
which provides a *portable* version of this interface. On Unix, the :mod:`os`
Index: Python-3.10.19/Doc/library/pprint.rst
Index: Python-3.10.20/Doc/library/pprint.rst
===================================================================
--- Python-3.10.19.orig/Doc/library/pprint.rst 2025-10-09 17:25:03.000000000 +0200
+++ Python-3.10.19/Doc/library/pprint.rst 2025-12-19 23:10:15.403862208 +0100
--- Python-3.10.20.orig/Doc/library/pprint.rst 2026-03-05 19:42:16.337584041 +0100
+++ Python-3.10.20/Doc/library/pprint.rst 2026-03-05 19:42:18.984325922 +0100
@@ -171,7 +171,7 @@
.. function:: isreadable(object)
@@ -1079,10 +1079,10 @@ Index: Python-3.10.19/Doc/library/pprint.rst
Determine if the formatted representation of the object is "readable," or can be
used to reconstruct the value using :func:`eval`. Note that this returns
Index: Python-3.10.19/Doc/library/pwd.rst
Index: Python-3.10.20/Doc/library/pwd.rst
===================================================================
--- Python-3.10.19.orig/Doc/library/pwd.rst 2025-10-09 17:25:03.000000000 +0200
+++ Python-3.10.19/Doc/library/pwd.rst 2025-12-19 23:10:15.404074457 +0100
--- Python-3.10.20.orig/Doc/library/pwd.rst 2026-03-05 19:42:16.337584041 +0100
+++ Python-3.10.20/Doc/library/pwd.rst 2026-03-05 19:42:18.984577957 +0100
@@ -37,7 +37,7 @@
.. note::
@@ -1092,10 +1092,10 @@ Index: Python-3.10.19/Doc/library/pwd.rst
In traditional Unix the field ``pw_passwd`` usually contains a password
encrypted with a DES derived algorithm (see module :mod:`crypt`). However most
Index: Python-3.10.19/Doc/library/pyexpat.rst
Index: Python-3.10.20/Doc/library/pyexpat.rst
===================================================================
--- Python-3.10.19.orig/Doc/library/pyexpat.rst 2025-10-09 17:25:03.000000000 +0200
+++ Python-3.10.19/Doc/library/pyexpat.rst 2025-12-19 23:10:15.404269595 +0100
--- Python-3.10.20.orig/Doc/library/pyexpat.rst 2026-03-05 19:42:16.337584041 +0100
+++ Python-3.10.20/Doc/library/pyexpat.rst 2026-03-05 19:42:18.984818931 +0100
@@ -33,7 +33,7 @@
parser, the handler functions are called for the character data and markup in
the XML document.
@@ -1105,10 +1105,10 @@ Index: Python-3.10.19/Doc/library/pyexpat.rst
This module uses the :mod:`pyexpat` module to provide access to the Expat
parser. Direct use of the :mod:`pyexpat` module is deprecated.
Index: Python-3.10.19/Doc/library/runpy.rst
Index: Python-3.10.20/Doc/library/runpy.rst
===================================================================
--- Python-3.10.19.orig/Doc/library/runpy.rst 2025-10-09 17:25:03.000000000 +0200
+++ Python-3.10.19/Doc/library/runpy.rst 2025-12-19 23:10:15.404446365 +0100
--- Python-3.10.20.orig/Doc/library/runpy.rst 2026-03-05 19:42:16.337584041 +0100
+++ Python-3.10.20/Doc/library/runpy.rst 2026-03-05 19:42:18.985177187 +0100
@@ -30,7 +30,7 @@
.. function:: run_module(mod_name, init_globals=None, run_name=None, alter_sys=False)
@@ -1127,10 +1127,10 @@ Index: Python-3.10.19/Doc/library/runpy.rst
Execute the code at the named filesystem location and return the resulting
module globals dictionary. As with a script name supplied to the CPython
Index: Python-3.10.19/Doc/library/shelve.rst
Index: Python-3.10.20/Doc/library/shelve.rst
===================================================================
--- Python-3.10.19.orig/Doc/library/shelve.rst 2025-10-09 17:25:03.000000000 +0200
+++ Python-3.10.19/Doc/library/shelve.rst 2025-12-19 23:10:15.404878127 +0100
--- Python-3.10.20.orig/Doc/library/shelve.rst 2026-03-05 19:42:16.337584041 +0100
+++ Python-3.10.20/Doc/library/shelve.rst 2026-03-05 19:42:18.985415677 +0100
@@ -6,7 +6,7 @@
**Source code:** :source:`Lib/shelve.py`
@@ -1151,10 +1151,10 @@ Index: Python-3.10.19/Doc/library/shelve.rst
* The choice of which database package will be used (such as :mod:`dbm.ndbm` or
:mod:`dbm.gnu`) depends on which interface is available. Therefore it is not
Index: Python-3.10.19/Doc/library/site.rst
Index: Python-3.10.20/Doc/library/site.rst
===================================================================
--- Python-3.10.19.orig/Doc/library/site.rst 2025-10-09 17:25:03.000000000 +0200
+++ Python-3.10.19/Doc/library/site.rst 2025-12-19 23:10:15.405113354 +0100
--- Python-3.10.20.orig/Doc/library/site.rst 2026-03-05 19:42:16.337584041 +0100
+++ Python-3.10.20/Doc/library/site.rst 2026-03-05 19:42:18.985669245 +0100
@@ -51,7 +51,7 @@
.. index::
@@ -1182,10 +1182,10 @@ Index: Python-3.10.19/Doc/library/site.rst
After this, an attempt is made to import a module named :mod:`usercustomize`,
which can perform arbitrary user-specific customizations, if
Index: Python-3.10.19/Doc/library/socket.rst
Index: Python-3.10.20/Doc/library/socket.rst
===================================================================
--- Python-3.10.19.orig/Doc/library/socket.rst 2025-10-09 17:25:03.000000000 +0200
+++ Python-3.10.19/Doc/library/socket.rst 2025-12-19 23:10:15.405446360 +0100
--- Python-3.10.20.orig/Doc/library/socket.rst 2026-03-05 19:42:16.337584041 +0100
+++ Python-3.10.20/Doc/library/socket.rst 2026-03-05 19:42:18.986046306 +0100
@@ -16,7 +16,7 @@
Some behavior may be platform dependent, since calls are made to the operating
system socket APIs.
@@ -1204,10 +1204,10 @@ Index: Python-3.10.19/Doc/library/socket.rst
Set the value of the given socket option (see the Unix manual page
:manpage:`setsockopt(2)`). The needed symbolic constants are defined in the
Index: Python-3.10.19/Doc/library/stdtypes.rst
Index: Python-3.10.20/Doc/library/stdtypes.rst
===================================================================
--- Python-3.10.19.orig/Doc/library/stdtypes.rst 2025-10-09 17:25:03.000000000 +0200
+++ Python-3.10.19/Doc/library/stdtypes.rst 2025-12-19 23:10:15.406446355 +0100
--- Python-3.10.20.orig/Doc/library/stdtypes.rst 2026-03-05 19:42:16.337584041 +0100
+++ Python-3.10.20/Doc/library/stdtypes.rst 2026-03-05 19:42:18.986972964 +0100
@@ -32,8 +32,8 @@
===================
@@ -1583,10 +1583,10 @@ Index: Python-3.10.19/Doc/library/stdtypes.rst
Type objects represent the various object types. An object's type is accessed
by the built-in function :func:`type`. There are no special operations on
Index: Python-3.10.19/Doc/library/sys.rst
Index: Python-3.10.20/Doc/library/sys.rst
===================================================================
--- Python-3.10.19.orig/Doc/library/sys.rst 2025-10-09 17:25:03.000000000 +0200
+++ Python-3.10.19/Doc/library/sys.rst 2025-12-19 23:10:15.406880072 +0100
--- Python-3.10.20.orig/Doc/library/sys.rst 2026-03-05 19:42:16.337584041 +0100
+++ Python-3.10.20/Doc/library/sys.rst 2026-03-05 19:42:18.987990342 +0100
@@ -398,7 +398,7 @@
an except clause." For any stack frame, only information about the exception
being currently handled is accessible.
@@ -1596,10 +1596,10 @@ Index: Python-3.10.19/Doc/library/sys.rst
If no exception is being handled anywhere on the stack, a tuple containing
three ``None`` values is returned. Otherwise, the values returned are
Index: Python-3.10.19/Doc/library/traceback.rst
Index: Python-3.10.20/Doc/library/traceback.rst
===================================================================
--- Python-3.10.19.orig/Doc/library/traceback.rst 2025-10-09 17:25:03.000000000 +0200
+++ Python-3.10.19/Doc/library/traceback.rst 2025-12-19 23:10:15.407220202 +0100
--- Python-3.10.20.orig/Doc/library/traceback.rst 2026-03-05 19:42:16.337584041 +0100
+++ Python-3.10.20/Doc/library/traceback.rst 2026-03-05 19:42:18.988443998 +0100
@@ -14,7 +14,7 @@
stack traces under program control, such as in a "wrapper" around the
interpreter.
@@ -1609,10 +1609,10 @@ Index: Python-3.10.19/Doc/library/traceback.rst
The module uses traceback objects --- this is the object type that is stored in
the :data:`sys.last_traceback` variable and returned as the third item from
Index: Python-3.10.19/Doc/library/types.rst
Index: Python-3.10.20/Doc/library/types.rst
===================================================================
--- Python-3.10.19.orig/Doc/library/types.rst 2025-10-09 17:25:03.000000000 +0200
+++ Python-3.10.19/Doc/library/types.rst 2025-12-19 23:10:15.407463391 +0100
--- Python-3.10.20.orig/Doc/library/types.rst 2026-03-05 19:42:16.337584041 +0100
+++ Python-3.10.20/Doc/library/types.rst 2026-03-05 19:42:18.988791784 +0100
@@ -146,7 +146,7 @@
.. class:: CodeType(**kwargs)
@@ -1622,10 +1622,10 @@ Index: Python-3.10.19/Doc/library/types.rst
The type for code objects such as returned by :func:`compile`.
Index: Python-3.10.19/Doc/reference/compound_stmts.rst
Index: Python-3.10.20/Doc/reference/compound_stmts.rst
===================================================================
--- Python-3.10.19.orig/Doc/reference/compound_stmts.rst 2025-10-09 17:25:03.000000000 +0200
+++ Python-3.10.19/Doc/reference/compound_stmts.rst 2025-12-19 23:10:15.407774397 +0100
--- Python-3.10.20.orig/Doc/reference/compound_stmts.rst 2026-03-05 19:42:16.337584041 +0100
+++ Python-3.10.20/Doc/reference/compound_stmts.rst 2026-03-05 19:42:18.989240841 +0100
@@ -84,9 +84,9 @@
============================
@@ -1855,10 +1855,10 @@ Index: Python-3.10.19/Doc/reference/compound_stmts.rst
.. _`async with`:
The :keyword:`!async with` statement
Index: Python-3.10.19/Doc/reference/datamodel.rst
Index: Python-3.10.20/Doc/reference/datamodel.rst
===================================================================
--- Python-3.10.19.orig/Doc/reference/datamodel.rst 2025-10-09 17:25:03.000000000 +0200
+++ Python-3.10.19/Doc/reference/datamodel.rst 2025-12-19 23:10:15.408446345 +0100
--- Python-3.10.20.orig/Doc/reference/datamodel.rst 2026-03-05 19:42:16.337584041 +0100
+++ Python-3.10.20/Doc/reference/datamodel.rst 2026-03-05 19:42:18.989869737 +0100
@@ -21,8 +21,8 @@
represented by objects.)
@@ -2371,10 +2371,10 @@ Index: Python-3.10.19/Doc/reference/datamodel.rst
single: context manager
Typical uses of context managers include saving and restoring various kinds of
Index: Python-3.10.19/Doc/reference/executionmodel.rst
Index: Python-3.10.20/Doc/reference/executionmodel.rst
===================================================================
--- Python-3.10.19.orig/Doc/reference/executionmodel.rst 2025-10-09 17:25:03.000000000 +0200
+++ Python-3.10.19/Doc/reference/executionmodel.rst 2025-12-19 23:10:15.408910164 +0100
--- Python-3.10.20.orig/Doc/reference/executionmodel.rst 2026-03-05 19:42:16.337584041 +0100
+++ Python-3.10.20/Doc/reference/executionmodel.rst 2026-03-05 19:42:18.990617928 +0100
@@ -151,7 +151,7 @@
:exc:`SyntaxError` is raised at compile time if the given name does not
exist in any enclosing function scope.
@@ -2384,10 +2384,10 @@ Index: Python-3.10.19/Doc/reference/executionmodel.rst
The namespace for a module is automatically created the first time a module is
imported. The main module for a script is always called :mod:`__main__`.
Index: Python-3.10.19/Doc/reference/expressions.rst
Index: Python-3.10.20/Doc/reference/expressions.rst
===================================================================
--- Python-3.10.19.orig/Doc/reference/expressions.rst 2025-10-09 17:25:03.000000000 +0200
+++ Python-3.10.19/Doc/reference/expressions.rst 2025-12-19 23:10:15.409155938 +0100
--- Python-3.10.20.orig/Doc/reference/expressions.rst 2026-03-05 19:42:16.337584041 +0100
+++ Python-3.10.20/Doc/reference/expressions.rst 2026-03-05 19:42:18.990933533 +0100
@@ -71,7 +71,7 @@
for lexical definition and section :ref:`naming` for documentation of naming and
binding.
@@ -2794,10 +2794,10 @@ Index: Python-3.10.19/Doc/reference/expressions.rst
Except when part of a list or set display, an expression list
containing at least one comma yields a tuple. The length of
Index: Python-3.10.19/Doc/reference/simple_stmts.rst
Index: Python-3.10.20/Doc/reference/simple_stmts.rst
===================================================================
--- Python-3.10.19.orig/Doc/reference/simple_stmts.rst 2025-10-09 17:25:03.000000000 +0200
+++ Python-3.10.19/Doc/reference/simple_stmts.rst 2025-12-19 23:10:15.409656983 +0100
--- Python-3.10.20.orig/Doc/reference/simple_stmts.rst 2026-03-05 19:42:16.337584041 +0100
+++ Python-3.10.20/Doc/reference/simple_stmts.rst 2026-03-05 19:42:18.991596393 +0100
@@ -53,8 +53,8 @@
expression).
@@ -3039,10 +3039,10 @@ Index: Python-3.10.19/Doc/reference/simple_stmts.rst
single: , (comma); identifier list
.. productionlist:: python-grammar
Index: Python-3.10.19/Doc/reference/toplevel_components.rst
Index: Python-3.10.20/Doc/reference/toplevel_components.rst
===================================================================
--- Python-3.10.19.orig/Doc/reference/toplevel_components.rst 2025-10-09 17:25:03.000000000 +0200
+++ Python-3.10.19/Doc/reference/toplevel_components.rst 2025-12-19 23:10:15.409991385 +0100
--- Python-3.10.20.orig/Doc/reference/toplevel_components.rst 2026-03-05 19:42:16.337584041 +0100
+++ Python-3.10.20/Doc/reference/toplevel_components.rst 2026-03-05 19:42:18.991994343 +0100
@@ -21,9 +21,9 @@
.. index:: single: program
@@ -3074,10 +3074,10 @@ Index: Python-3.10.19/Doc/reference/toplevel_components.rst
:func:`eval` is used for expression input. It ignores leading whitespace. The
string argument to :func:`eval` must have the following form:
Index: Python-3.10.19/Doc/tools/extensions/pyspecific.py
Index: Python-3.10.20/Doc/tools/extensions/pyspecific.py
===================================================================
--- Python-3.10.19.orig/Doc/tools/extensions/pyspecific.py 2025-10-09 17:25:03.000000000 +0200
+++ Python-3.10.19/Doc/tools/extensions/pyspecific.py 2025-12-19 23:10:15.410328302 +0100
--- Python-3.10.20.orig/Doc/tools/extensions/pyspecific.py 2026-03-05 19:42:16.337584041 +0100
+++ Python-3.10.20/Doc/tools/extensions/pyspecific.py 2026-03-05 19:42:18.992268971 +0100
@@ -644,6 +644,30 @@
node.replace_self(table)
@@ -3117,10 +3117,10 @@ Index: Python-3.10.19/Doc/tools/extensions/pyspecific.py
app.connect('doctree-resolved', process_audit_events)
app.connect('env-merge-info', audit_events_merge)
app.connect('env-purge-doc', audit_events_purge)
Index: Python-3.10.19/Doc/tutorial/classes.rst
Index: Python-3.10.20/Doc/tutorial/classes.rst
===================================================================
--- Python-3.10.19.orig/Doc/tutorial/classes.rst 2025-10-09 17:25:03.000000000 +0200
+++ Python-3.10.19/Doc/tutorial/classes.rst 2025-12-19 23:10:15.410720534 +0100
--- Python-3.10.20.orig/Doc/tutorial/classes.rst 2026-03-05 19:42:16.337584041 +0100
+++ Python-3.10.20/Doc/tutorial/classes.rst 2026-03-05 19:42:18.992758014 +0100
@@ -344,7 +344,7 @@
However, in the following discussion, we'll use the term method exclusively to
mean methods of class instance objects, unless explicitly stated otherwise.)
@@ -3130,10 +3130,10 @@ Index: Python-3.10.19/Doc/tutorial/classes.rst
Valid method names of an instance object depend on its class. By definition,
all attributes of a class that are function objects define corresponding
Index: Python-3.10.19/Doc/tutorial/controlflow.rst
Index: Python-3.10.20/Doc/tutorial/controlflow.rst
===================================================================
--- Python-3.10.19.orig/Doc/tutorial/controlflow.rst 2025-10-09 17:25:03.000000000 +0200
+++ Python-3.10.19/Doc/tutorial/controlflow.rst 2025-12-19 23:10:15.411043971 +0100
--- Python-3.10.20.orig/Doc/tutorial/controlflow.rst 2026-03-05 19:42:16.337584041 +0100
+++ Python-3.10.20/Doc/tutorial/controlflow.rst 2026-03-05 19:42:18.993212891 +0100
@@ -46,7 +46,7 @@
==========================
@@ -3143,10 +3143,10 @@ Index: Python-3.10.19/Doc/tutorial/controlflow.rst
The :keyword:`for` statement in Python differs a bit from what you may be used
to in C or Pascal. Rather than always iterating over an arithmetic progression
Index: Python-3.10.19/Doc/tutorial/inputoutput.rst
Index: Python-3.10.20/Doc/tutorial/inputoutput.rst
===================================================================
--- Python-3.10.19.orig/Doc/tutorial/inputoutput.rst 2025-10-09 17:25:03.000000000 +0200
+++ Python-3.10.19/Doc/tutorial/inputoutput.rst 2025-12-19 23:10:15.411308183 +0100
--- Python-3.10.20.orig/Doc/tutorial/inputoutput.rst 2026-03-05 19:42:16.337584041 +0100
+++ Python-3.10.20/Doc/tutorial/inputoutput.rst 2026-03-05 19:42:18.993527254 +0100
@@ -285,8 +285,8 @@
=========================
@@ -3167,10 +3167,10 @@ Index: Python-3.10.19/Doc/tutorial/inputoutput.rst
Strings can easily be written to and read from a file. Numbers take a bit more
effort, since the :meth:`read` method only returns strings, which will have to
Index: Python-3.10.19/Doc/tutorial/modules.rst
Index: Python-3.10.20/Doc/tutorial/modules.rst
===================================================================
--- Python-3.10.19.orig/Doc/tutorial/modules.rst 2025-10-09 17:25:03.000000000 +0200
+++ Python-3.10.19/Doc/tutorial/modules.rst 2025-12-19 23:10:15.411539499 +0100
--- Python-3.10.20.orig/Doc/tutorial/modules.rst 2026-03-05 19:42:16.337584041 +0100
+++ Python-3.10.20/Doc/tutorial/modules.rst 2026-03-05 19:42:18.993796923 +0100
@@ -260,7 +260,7 @@
Standard Modules
================
@@ -3189,10 +3189,10 @@ Index: Python-3.10.19/Doc/tutorial/modules.rst
:func:`dir` does not list the names of built-in functions and variables. If you
want a list of those, they are defined in the standard module
Index: Python-3.10.19/Doc/tutorial/stdlib.rst
Index: Python-3.10.20/Doc/tutorial/stdlib.rst
===================================================================
--- Python-3.10.19.orig/Doc/tutorial/stdlib.rst 2025-10-09 17:25:03.000000000 +0200
+++ Python-3.10.19/Doc/tutorial/stdlib.rst 2025-12-19 23:10:15.411769907 +0100
--- Python-3.10.20.orig/Doc/tutorial/stdlib.rst 2026-03-05 19:42:16.337584041 +0100
+++ Python-3.10.20/Doc/tutorial/stdlib.rst 2026-03-05 19:42:18.994160168 +0100
@@ -24,7 +24,7 @@
will keep :func:`os.open` from shadowing the built-in :func:`open` function which
operates much differently.

View File

@@ -27,17 +27,19 @@ Co-authored-by: Sebastian Pipping <sebastian@pipping.org>
1 file changed, 9 insertions(+), 14 deletions(-)
create mode 100644 Misc/NEWS.d/next/Library/2022-02-20-21-03-31.bpo-46811.8BxgdQ.rst
--- a/Lib/test/test_minidom.py
+++ b/Lib/test/test_minidom.py
@@ -6,7 +6,6 @@ import io
Index: Python-3.10.20/Lib/test/test_minidom.py
===================================================================
--- Python-3.10.20.orig/Lib/test/test_minidom.py 2026-03-05 19:39:01.567696516 +0100
+++ Python-3.10.20/Lib/test/test_minidom.py 2026-03-05 19:42:02.323563898 +0100
@@ -7,7 +7,6 @@
from test import support
import unittest
-import pyexpat
import xml.dom.minidom
from xml.dom.minidom import parse, Attr, Node, Document, parseString
@@ -1163,13 +1162,11 @@ class MinidomTest(unittest.TestCase):
from xml.dom.minidom import parse, Attr, Node, Document, Element, parseString
@@ -1194,13 +1193,11 @@
# Verify that character decoding errors raise exceptions instead
# of crashing
@@ -56,7 +58,7 @@ Co-authored-by: Sebastian Pipping <sebastian@pipping.org>
b'<fran\xe7ais>Comment \xe7a va ? Tr\xe8s bien ?</fran\xe7ais>')
doc.unlink()
@@ -1631,12 +1628,10 @@ class MinidomTest(unittest.TestCase):
@@ -1662,12 +1659,10 @@
self.confirm(doc2.namespaceURI == xml.dom.EMPTY_NAMESPACE)
def testExceptionOnSpacesInXMLNSValue(self):