Skip to content

Commit e0e52c7

Browse files
authored
Merge branch '3.11' into backport-120384-3.11
2 parents de70708 + 88f3f5b commit e0e52c7

33 files changed

+1529
-469
lines changed

.github/workflows/build_msi.yml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ concurrency:
3333
jobs:
3434
build_win32:
3535
name: 'Windows (x86) Installer'
36-
runs-on: windows-latest
36+
runs-on: windows-2022
3737
timeout-minutes: 60
3838
steps:
3939
- uses: actions/checkout@v4
@@ -42,7 +42,7 @@ jobs:
4242

4343
build_win_amd64:
4444
name: 'Windows (x64) Installer'
45-
runs-on: windows-latest
45+
runs-on: windows-2022
4646
timeout-minutes: 60
4747
steps:
4848
- uses: actions/checkout@v4
@@ -51,7 +51,7 @@ jobs:
5151

5252
build_win_arm64:
5353
name: 'Windows (ARM64) Installer'
54-
runs-on: windows-latest
54+
runs-on: windows-2022
5555
timeout-minutes: 60
5656
steps:
5757
- uses: actions/checkout@v4

.github/workflows/reusable-macos.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ jobs:
2424
matrix:
2525
os: [
2626
"macos-14", # M1
27-
"macos-13", # Intel
27+
"macos-15-intel", # Intel
2828
]
2929
runs-on: ${{ matrix.os }}
3030
steps:

.github/workflows/reusable-windows.yml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ on:
99
jobs:
1010
build_win32:
1111
name: 'build and test (x86)'
12-
runs-on: windows-latest
12+
runs-on: windows-2022
1313
timeout-minutes: 60
1414
env:
1515
IncludeUwp: 'true'
@@ -24,7 +24,7 @@ jobs:
2424

2525
build_win_amd64:
2626
name: 'build and test (x64)'
27-
runs-on: windows-latest
27+
runs-on: windows-2022
2828
timeout-minutes: 60
2929
env:
3030
IncludeUwp: 'true'
@@ -41,7 +41,7 @@ jobs:
4141

4242
build_win_arm64:
4343
name: 'build (arm64)'
44-
runs-on: windows-latest
44+
runs-on: windows-2022
4545
timeout-minutes: 60
4646
env:
4747
IncludeUwp: 'true'

Doc/tools/templates/download.html

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -20,14 +20,6 @@ <h1>Download Python {{ release }} Documentation</h1>
2020

2121
<table class="docutils">
2222
<tr><th>Format</th><th>Packed as .zip</th><th>Packed as .tar.bz2</th></tr>
23-
<tr><td>PDF (US-Letter paper size)</td>
24-
<td><a href="{{ dlbase }}/python-{{ release }}-docs-pdf-letter.zip">Download</a> (ca. 13 MiB)</td>
25-
<td><a href="{{ dlbase }}/python-{{ release }}-docs-pdf-letter.tar.bz2">Download</a> (ca. 13 MiB)</td>
26-
</tr>
27-
<tr><td>PDF (A4 paper size)</td>
28-
<td><a href="{{ dlbase }}/python-{{ release }}-docs-pdf-a4.zip">Download</a> (ca. 13 MiB)</td>
29-
<td><a href="{{ dlbase }}/python-{{ release }}-docs-pdf-a4.tar.bz2">Download</a> (ca. 13 MiB)</td>
30-
</tr>
3123
<tr><td>HTML</td>
3224
<td><a href="{{ dlbase }}/python-{{ release }}-docs-html.zip">Download</a> (ca. 9 MiB)</td>
3325
<td><a href="{{ dlbase }}/python-{{ release }}-docs-html.tar.bz2">Download</a> (ca. 6 MiB)</td>
@@ -44,6 +36,18 @@ <h1>Download Python {{ release }} Documentation</h1>
4436

4537
<p>These archives contain all the content in the documentation.</p>
4638

39+
<p>
40+
We no longer provide updates to the pre-built PDFs of the documentation.
41+
The previously-built archives are still available and may be of use:
42+
<a href="{{ dlbase }}/python-{{ release }}-docs-pdf-a4.zip">A4 PDF (.zip archive)</a>;
43+
<a href="{{ dlbase }}/python-{{ release }}-docs-pdf-a4.tar.bz2">A4 PDF (.tar.bz2 archive)</a>;
44+
<a href="{{ dlbase }}/python-{{ release }}-docs-pdf-letter.zip">US-Letter PDF (.zip archive)</a>;
45+
<a href="{{ dlbase }}/python-{{ release }}-docs-pdf-letter.tar.bz2">US-Letter PDF (.tar.bz2 archive)</a>.
46+
To build a PDF archive, follow the instructions in the
47+
<a href="https://devguide.python.org/documentation/start-documenting/#building-the-documentation">Developer's Guide</a>
48+
and run <code>make dist-pdf</code> in the <code>Doc/</code> directory of a copy of the CPython repository.
49+
</p>
50+
4751

4852
<h2>Unpacking</h2>
4953

Include/patchlevel.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,12 +18,12 @@
1818
/*--start constants--*/
1919
#define PY_MAJOR_VERSION 3
2020
#define PY_MINOR_VERSION 11
21-
#define PY_MICRO_VERSION 13
21+
#define PY_MICRO_VERSION 14
2222
#define PY_RELEASE_LEVEL PY_RELEASE_LEVEL_FINAL
2323
#define PY_RELEASE_SERIAL 0
2424

2525
/* Version as a string */
26-
#define PY_VERSION "3.11.13+"
26+
#define PY_VERSION "3.11.14+"
2727
/*--end constants--*/
2828

2929
/* Version as a single 4-byte hex number, e.g. 0x010502B2 == 1.5.2b2.

Lib/html/parser.py

Lines changed: 45 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -110,6 +110,7 @@ class HTMLParser(_markupbase.ParserBase):
110110
"""
111111

112112
CDATA_CONTENT_ELEMENTS = ("script", "style")
113+
RCDATA_CONTENT_ELEMENTS = ("textarea", "title")
113114

114115
def __init__(self, *, convert_charrefs=True):
115116
"""Initialize and reset this instance.
@@ -126,6 +127,8 @@ def reset(self):
126127
self.lasttag = '???'
127128
self.interesting = interesting_normal
128129
self.cdata_elem = None
130+
self._support_cdata = True
131+
self._escapable = True
129132
_markupbase.ParserBase.reset(self)
130133

131134
def feed(self, data):
@@ -147,14 +150,33 @@ def get_starttag_text(self):
147150
"""Return full source of start tag: '<...>'."""
148151
return self.__starttag_text
149152

150-
def set_cdata_mode(self, elem):
153+
def set_cdata_mode(self, elem, *, escapable=False):
151154
self.cdata_elem = elem.lower()
152-
self.interesting = re.compile(r'</%s(?=[\t\n\r\f />])' % self.cdata_elem,
153-
re.IGNORECASE|re.ASCII)
155+
self._escapable = escapable
156+
if escapable and not self.convert_charrefs:
157+
self.interesting = re.compile(r'&|</%s(?=[\t\n\r\f />])' % self.cdata_elem,
158+
re.IGNORECASE|re.ASCII)
159+
else:
160+
self.interesting = re.compile(r'</%s(?=[\t\n\r\f />])' % self.cdata_elem,
161+
re.IGNORECASE|re.ASCII)
154162

155163
def clear_cdata_mode(self):
156164
self.interesting = interesting_normal
157165
self.cdata_elem = None
166+
self._escapable = True
167+
168+
def _set_support_cdata(self, flag=True):
169+
"""Enable or disable support of the CDATA sections.
170+
If enabled, "<[CDATA[" starts a CDATA section which ends with "]]>".
171+
If disabled, "<[CDATA[" starts a bogus comments which ends with ">".
172+
173+
This method is not called by default. Its purpose is to be called
174+
in custom handle_starttag() and handle_endtag() methods, with
175+
value that depends on the adjusted current node.
176+
See https://html.spec.whatwg.org/multipage/parsing.html#markup-declaration-open-state
177+
for details.
178+
"""
179+
self._support_cdata = flag
158180

159181
# Internal -- handle data as far as reasonable. May leave state
160182
# and data to be processed by a subsequent call. If 'end' is
@@ -187,7 +209,7 @@ def goahead(self, end):
187209
break
188210
j = n
189211
if i < j:
190-
if self.convert_charrefs and not self.cdata_elem:
212+
if self.convert_charrefs and self._escapable:
191213
self.handle_data(unescape(rawdata[i:j]))
192214
else:
193215
self.handle_data(rawdata[i:j])
@@ -230,7 +252,7 @@ def goahead(self, end):
230252
j -= len(suffix)
231253
break
232254
self.handle_comment(rawdata[i+4:j])
233-
elif startswith("<![CDATA[", i):
255+
elif startswith("<![CDATA[", i) and self._support_cdata:
234256
self.unknown_decl(rawdata[i+3:])
235257
elif rawdata[i:i+9].lower() == '<!doctype':
236258
self.handle_decl(rawdata[i+2:])
@@ -289,7 +311,7 @@ def goahead(self, end):
289311
assert 0, "interesting.search() lied"
290312
# end while
291313
if end and i < n:
292-
if self.convert_charrefs and not self.cdata_elem:
314+
if self.convert_charrefs and self._escapable:
293315
self.handle_data(unescape(rawdata[i:n]))
294316
else:
295317
self.handle_data(rawdata[i:n])
@@ -306,15 +328,28 @@ def parse_html_declaration(self, i):
306328
if rawdata[i:i+4] == '<!--':
307329
# this case is actually already handled in goahead()
308330
return self.parse_comment(i)
309-
elif rawdata[i:i+3] == '<![':
310-
return self.parse_marked_section(i)
331+
elif rawdata[i:i+9] == '<![CDATA[' and self._support_cdata:
332+
j = rawdata.find(']]>', i+9)
333+
if j < 0:
334+
return -1
335+
self.unknown_decl(rawdata[i+3: j])
336+
return j + 3
311337
elif rawdata[i:i+9].lower() == '<!doctype':
312338
# find the closing >
313339
gtpos = rawdata.find('>', i+9)
314340
if gtpos == -1:
315341
return -1
316342
self.handle_decl(rawdata[i+2:gtpos])
317343
return gtpos+1
344+
elif rawdata[i:i+3] == '<![':
345+
j = rawdata.find('>', i+3)
346+
if j < 0:
347+
return -1
348+
if rawdata[j-1] == ']':
349+
self.unknown_decl(rawdata[i+3: j-1])
350+
else:
351+
self.handle_comment(rawdata[i+2: j])
352+
return j + 1
318353
else:
319354
return self.parse_bogus_comment(i)
320355

@@ -401,6 +436,8 @@ def parse_starttag(self, i):
401436
self.handle_starttag(tag, attrs)
402437
if tag in self.CDATA_CONTENT_ELEMENTS:
403438
self.set_cdata_mode(tag)
439+
elif tag in self.RCDATA_CONTENT_ELEMENTS:
440+
self.set_cdata_mode(tag, escapable=True)
404441
return endpos
405442

406443
# Internal -- check to see if we have a complete starttag; return end

Lib/pydoc_data/topics.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
# -*- coding: utf-8 -*-
2-
# Autogenerated by Sphinx on Tue Jun 3 19:38:08 2025
2+
# Autogenerated by Sphinx on Thu Oct 9 18:16:46 2025
33
# as part of the release process.
44
topics = {'assert': 'The "assert" statement\n'
55
'**********************\n'

Lib/tarfile.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1614,6 +1614,9 @@ def _block(self, count):
16141614
"""Round up a byte count by BLOCKSIZE and return it,
16151615
e.g. _block(834) => 1024.
16161616
"""
1617+
# Only non-negative offsets are allowed
1618+
if count < 0:
1619+
raise InvalidHeaderError("invalid offset")
16171620
blocks, remainder = divmod(count, BLOCKSIZE)
16181621
if remainder:
16191622
blocks += 1

Lib/test/support/__init__.py

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -304,6 +304,16 @@ def requires(resource, msg=None):
304304
if resource == 'gui' and not _is_gui_available():
305305
raise ResourceDenied(_is_gui_available.reason)
306306

307+
def _get_kernel_version(sysname="Linux"):
308+
import platform
309+
if platform.system() != sysname:
310+
return None
311+
version_txt = platform.release().split('-', 1)[0]
312+
try:
313+
return tuple(map(int, version_txt.split('.')))
314+
except ValueError:
315+
return None
316+
307317
def _requires_unix_version(sysname, min_version):
308318
"""Decorator raising SkipTest if the OS is `sysname` and the version is less
309319
than `min_version`.

Lib/test/test___all__.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,12 @@ def check_all(self, modname):
8080
self.assertEqual(keys, all_set, "in module {}".format(modname))
8181

8282
def walk_modules(self, basedir, modpath):
83+
if modpath == 'distutils.':
84+
# gh-135374: when setuptools is installed, it now replaces
85+
# 'distutils' with its own version.
86+
# In a security-fix only branch of CPython,
87+
# skip the __all__ test rather than deal with the fallout.
88+
return
8389
for fn in sorted(os.listdir(basedir)):
8490
path = os.path.join(basedir, fn)
8591
if os.path.isdir(path):

0 commit comments

Comments
 (0)