Skip to content

Commit f3b14a4

Browse files
generatedunixname1734921407115435meta-codesync[bot]
authored andcommitted
Sync pre-release CPython 3.15 branch from GitHub (2026-08-31)
Summary: Imported python/cpython `3.15.0rc1+dev` from upstream rev [`b93576a`](https://www.github.com/python/cpython/commit/b93576a2b66d98ec8fe2bf64de6fd27a7851e1ed) (committed 2026-08-31 19:05:08+00:00). # Commit Info - Base: (`3.15.0rc1+dev`) - [`5136a68`](https://www.github.com/python/cpython/commit/5136a686beda8566da8592b90cea4b8e734724b6) (commit date: 2026-08-30 18:20:30+00:00) - Imported: (`3.15.0rc1+dev`) - [`b93576a`](https://www.github.com/python/cpython/commit/b93576a2b66d98ec8fe2bf64de6fd27a7851e1ed) (commit date: 2026-08-31 19:05:08+00:00) # Noteworthy file changes - Low-signal files (6 added, 1 removed) (NEWS.d, docs, .github) Complete list of added/removed files: https://www.internalfb.com/intern/everpaste/?color=0&handle=GL-nlisr4yDjBMgDALm7qp6M0e4Obr0LAAAz Reviewed By: itamaro Differential Revision: D118238648 fbshipit-source-id: 13acc96c08b89681b084230f61a5d8c4191292cd
1 parent cd57cc6 commit f3b14a4

33 files changed

Lines changed: 709 additions & 257 deletions

Doc/library/mimetypes.rst

Lines changed: 12 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -201,8 +201,8 @@ than one MIME-type database; it provides an interface similar to the one of the
201201
.. class:: MimeTypes(filenames=(), strict=True)
202202

203203
This class represents a MIME-types database. By default, it provides access to
204-
the same database as the rest of this module. The initial database is a copy of
205-
that provided by the module, and may be extended by loading additional
204+
the same database as the rest of this module. The initial database is created from
205+
Python's built-in MIME type tables. It may be extended by loading additional
206206
:file:`mime.types`\ -style files into the database using the :meth:`read` or
207207
:meth:`readfp` methods. The mapping dictionaries may also be cleared before
208208
loading additional data if the default data is not desired.
@@ -216,30 +216,32 @@ than one MIME-type database; it provides an interface similar to the one of the
216216
Dictionary mapping suffixes to suffixes. This is used to allow recognition of
217217
encoded files for which the encoding and the type are indicated by the same
218218
extension. For example, the :file:`.tgz` extension is mapped to :file:`.tar.gz`
219-
to allow the encoding and type to be recognized separately. This is initially a
220-
copy of the global :data:`suffix_map` defined in the module.
219+
to allow the encoding and type to be recognized separately.
220+
This is initialized with some predefined values.
221221

222222

223223
.. attribute:: MimeTypes.encodings_map
224224

225-
Dictionary mapping filename extensions to encoding types. This is initially a
226-
copy of the global :data:`encodings_map` defined in the module.
225+
Dictionary mapping filename extensions to encoding types.
226+
This is initialized with some predefined values.
227227

228228

229229
.. attribute:: MimeTypes.types_map
230230

231231
Tuple containing two dictionaries, mapping filename extensions to MIME types:
232232
the first dictionary is for the non-standards types and the second one is for
233-
the standard types. They are initialized by :data:`common_types` and
234-
:data:`types_map`.
233+
the standard types.
234+
They are initialized with some predefined values and MIME type
235+
information loaded from files specified by the *filenames* argument.
235236

236237

237238
.. attribute:: MimeTypes.types_map_inv
238239

239240
Tuple containing two dictionaries, mapping MIME types to a list of filename
240241
extensions: the first dictionary is for the non-standards types and the
241-
second one is for the standard types. They are initialized by
242-
:data:`common_types` and :data:`types_map`.
242+
second one is for the standard types.
243+
They are initialized with some predefined values and MIME type
244+
information loaded from files specified by the *filenames* argument.
243245

244246

245247
.. method:: MimeTypes.guess_extension(type, strict=True)

Doc/library/tarfile.rst

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1107,6 +1107,10 @@ reused in custom filters:
11071107
paths (in case the name is absolute
11081108
even after stripping slashes, e.g. ``C:/foo`` on Windows).
11091109
This raises :class:`~tarfile.AbsolutePathError`.
1110+
- Normalize filenames (:attr:`TarInfo.name`) that contain ``..`` components
1111+
using :func:`os.path.normpath`.
1112+
Note that this removes internal ``..`` components, which may change the
1113+
meaning of the name if it traverses symbolic links.
11101114
- :ref:`Refuse <tarfile-extraction-refuse>` to extract files whose absolute
11111115
path (after following symlinks) would end up outside the destination.
11121116
This raises :class:`~tarfile.OutsideDestinationError`.
@@ -1115,6 +1119,10 @@ reused in custom filters:
11151119

11161120
Return the modified ``TarInfo`` member.
11171121

1122+
.. versionchanged:: next
1123+
1124+
Filenames containing ``..`` components are now normalized.
1125+
11181126
.. function:: data_filter(member, path)
11191127

11201128
Implements the ``'data'`` filter.

Doc/library/xml.dom.minidom.rst

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -264,6 +264,11 @@ rules apply:
264264
* :attr:`~xml.dom.Document.strictErrorChecking` and
265265
:attr:`~xml.dom.Attr.specified` are always ``False``.
266266

267+
* :meth:`~xml.dom.Element.removeAttribute` and
268+
:meth:`~xml.dom.Element.removeAttributeNS` raise
269+
:exc:`~xml.dom.NotFoundErr` if there is no matching attribute,
270+
while the DOM specifies that this has no effect.
271+
267272
The following interfaces have no implementation in :mod:`!xml.dom.minidom`:
268273

269274
* :class:`DOMTimeStamp`

Doc/library/xml.dom.rst

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -153,6 +153,11 @@ Objects in the DOM
153153

154154
The definitive documentation for the DOM is the DOM specification from the W3C.
155155

156+
The names documented in this section are DOM interfaces.
157+
With the exception of :class:`Node` and the exception classes,
158+
they are not provided by the :mod:`!xml.dom` module itself,
159+
but by concrete DOM implementations, such as :mod:`xml.dom.minidom`.
160+
156161
Note that DOM attributes may also be manipulated as nodes instead of as simple
157162
strings. It is fairly rare that you must do this, however, so this usage is not
158163
yet documented.
@@ -461,23 +466,23 @@ for each node type are:
461466
.. method:: Node.insertBefore(newChild, refChild)
462467

463468
Insert a new child node before an existing child. It must be the case that
464-
*refChild* is a child of this node; if not, :exc:`ValueError` is raised.
469+
*refChild* is a child of this node; if not, :exc:`NotFoundErr` is raised.
465470
*newChild* is returned. If *refChild* is ``None``, it inserts *newChild* at the
466471
end of the children's list.
467472

468473

469474
.. method:: Node.removeChild(oldChild)
470475

471476
Remove a child node. *oldChild* must be a child of this node; if not,
472-
:exc:`ValueError` is raised. *oldChild* is returned on success. If *oldChild*
477+
:exc:`NotFoundErr` is raised. *oldChild* is returned on success. If *oldChild*
473478
will not be used further, its :meth:`~xml.dom.minidom.Node.unlink` method
474479
should be called.
475480

476481

477482
.. method:: Node.replaceChild(newChild, oldChild)
478483

479484
Replace an existing node with a new node. It must be the case that *oldChild*
480-
is a child of this node; if not, :exc:`ValueError` is raised.
485+
is a child of this node; if not, :exc:`NotFoundErr` is raised.
481486

482487

483488
.. method:: Node.normalize()
@@ -826,8 +831,7 @@ of that class.
826831

827832
.. method:: Element.removeAttribute(name)
828833

829-
Remove an attribute by name. If there is no matching attribute, a
830-
:exc:`NotFoundErr` is raised.
834+
Remove an attribute by name.
831835

832836

833837
.. method:: Element.removeAttributeNode(oldAttr)
@@ -838,8 +842,7 @@ of that class.
838842

839843
.. method:: Element.removeAttributeNS(namespaceURI, localName)
840844

841-
Remove an attribute by name. Note that it uses a localName, not a qname. No
842-
exception is raised if there is no matching attribute.
845+
Remove an attribute by name. Note that it uses a localName, not a qname.
843846

844847

845848
.. method:: Element.setAttribute(name, value)

Include/internal/pycore_pystate.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -360,6 +360,10 @@ struct PyInterpreterView {
360360
PyAPI_FUNC(Py_ssize_t) _PyInterpreterState_GuardCountdown(PyInterpreterState *interp);
361361
PyAPI_FUNC(PyInterpreterState *) _PyInterpreterGuard_GetInterpreter(PyInterpreterGuard *guard);
362362

363+
extern int _PyInterpreterGuard_TryAcquire(PyInterpreterState *interp,
364+
PyInterpreterGuard *guard);
365+
extern void _PyInterpreterGuard_Release(PyInterpreterGuard *guard);
366+
363367
#ifdef __cplusplus
364368
}
365369
#endif

Include/internal/pycore_tracemalloc.h

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -44,9 +44,10 @@ struct
4444
__attribute__((packed))
4545
#endif
4646
tracemalloc_frame {
47-
/* filename cannot be NULL: "<unknown>" is used if the Python frame
48-
filename is NULL */
49-
PyObject *filename;
47+
/* Interned NUL terminated UTF-8 (surrogatepass) string.
48+
Cannot be NULL: "<unknown>" is used if the Python frame filename
49+
cannot be captured. */
50+
const char *filename;
5051
unsigned int lineno;
5152
};
5253

@@ -85,7 +86,7 @@ struct _tracemalloc_runtime_state {
8586
Protected by TABLES_LOCK(). */
8687
size_t peak_traced_memory;
8788
/* Hash table used as a set to intern filenames:
88-
PyObject* => PyObject*.
89+
char* (NUL terminated UTF-8 string) => NULL.
8990
Protected by the TABLES_LOCK(). */
9091
_Py_hashtable_t *filenames;
9192
/* Buffer to store a new traceback in traceback_new().

Lib/asyncio/graph.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,8 @@ def _build_graph_for_future(
5858
while coro is not None:
5959
if hasattr(coro, 'cr_await'):
6060
# A native coroutine or duck-type compatible iterator
61-
st.append(FrameCallGraphEntry(coro.cr_frame))
61+
if coro.cr_frame is not None:
62+
st.append(FrameCallGraphEntry(coro.cr_frame))
6263
coro = coro.cr_await
6364
elif hasattr(coro, 'ag_await'):
6465
# A native async generator or duck-type compatible iterator

Lib/netrc.py

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -48,11 +48,12 @@ def _read_char(self):
4848
def get_token(self):
4949
if self.pushback:
5050
return self.pushback.pop(0)
51-
token = ""
51+
token = None
5252
fiter = iter(self._read_char, "")
5353
for ch in fiter:
5454
if ch in self.whitespace:
5555
continue
56+
token = ""
5657
if ch == '"':
5758
for ch in fiter:
5859
if ch == '"':
@@ -96,9 +97,9 @@ def _parse(self, file, fp, default_netrc):
9697
# Look for a machine, default, or macdef top-level keyword
9798
saved_lineno = lexer.lineno
9899
tt = lexer.get_token()
99-
if not tt:
100+
if tt is None:
100101
break
101-
elif tt[0] == '#':
102+
elif tt.startswith('#'):
102103
if lexer.lineno == saved_lineno and len(tt) == 1:
103104
lexer.instream.readline()
104105
continue
@@ -135,20 +136,20 @@ def _parse(self, file, fp, default_netrc):
135136
while 1:
136137
prev_lineno = lexer.lineno
137138
tt = lexer.get_token()
138-
if tt.startswith('#'):
139+
if tt is not None and tt.startswith('#'):
139140
if lexer.lineno == prev_lineno:
140141
lexer.instream.readline()
141142
continue
142-
if tt in {'', 'machine', 'default', 'macdef'}:
143+
if tt in {None, 'machine', 'default', 'macdef'}:
143144
self.hosts[entryname] = (login, account, password)
144145
lexer.push_token(tt)
145146
break
146147
elif tt == 'login' or tt == 'user':
147-
login = lexer.get_token()
148+
login = lexer.get_token() or ''
148149
elif tt == 'account':
149-
account = lexer.get_token()
150+
account = lexer.get_token() or ''
150151
elif tt == 'password':
151-
password = lexer.get_token()
152+
password = lexer.get_token() or ''
152153
else:
153154
raise NetrcParseError("bad follower token %r" % tt,
154155
file, lexer.lineno)

Lib/tarfile.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -833,6 +833,13 @@ def _get_filtered_attrs(member, dest_path, for_data=True):
833833
# For example, 'C:/foo' on Windows.
834834
raise AbsolutePathError(member)
835835
# Ensure we stay in the destination
836+
if '..' in name.replace(os.sep, '/').split('/'):
837+
# Directories are created from the name as given, so a name that
838+
# leaves the destination part-way through would create them
839+
# outside it even if the resolved path stays inside.
840+
normalized = os.path.normpath(name)
841+
if normalized != name:
842+
name = new_attrs['name'] = normalized
836843
target_path = os.path.realpath(os.path.join(dest_path, name),
837844
strict=os.path.ALLOW_MISSING)
838845
if os.path.commonpath([target_path, dest_path]) != dest_path:

Lib/test/support/os_helper.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -434,7 +434,10 @@ def _rmtree_inner(path):
434434
file=sys.__stderr__)
435435
mode = 0
436436
if stat.S_ISDIR(mode):
437-
_waitfor(_rmtree_inner, fullname, waitall=True)
437+
# Do not follow junctions, which os.lstat() reports
438+
# as directories.
439+
if not os.path.isjunction(fullname):
440+
_waitfor(_rmtree_inner, fullname, waitall=True)
438441
_force_run(fullname, os.rmdir, fullname)
439442
else:
440443
_force_run(fullname, os.unlink, fullname)

0 commit comments

Comments
 (0)