Skip to content

Commit 3479737

Browse files
authored
Merge branch 'main' into enhancement-bpo-42861
2 parents 2e13267 + 4572903 commit 3479737

26 files changed

Lines changed: 303 additions & 102 deletions

.github/workflows/build.yml

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -554,7 +554,6 @@ jobs:
554554
- Thread
555555
free-threading:
556556
- false
557-
- true
558557
sanitizer:
559558
- TSan
560559
include:
@@ -566,6 +565,17 @@ jobs:
566565
sanitizer: ${{ matrix.sanitizer }}
567566
free-threading: ${{ matrix.free-threading }}
568567

568+
# XXX: Temporarily allow this job to fail to not block PRs.
569+
build-san-free-threading:
570+
# ${{ '' } is a hack to nest jobs under the same sidebar category.
571+
name: Sanitizers${{ '' }} # zizmor: ignore[obfuscation]
572+
needs: build-context
573+
if: needs.build-context.outputs.run-ubuntu == 'true'
574+
uses: ./.github/workflows/reusable-san.yml
575+
with:
576+
sanitizer: TSan
577+
free-threading: true
578+
569579
cross-build-linux:
570580
name: Cross build Linux
571581
runs-on: ubuntu-26.04
@@ -669,6 +679,7 @@ jobs:
669679
- test-hypothesis
670680
- build-asan
671681
- build-san
682+
- build-san-free-threading
672683
- cross-build-linux
673684
- cifuzz
674685
if: always()
@@ -680,6 +691,7 @@ jobs:
680691
allowed-failures: >-
681692
build-android,
682693
build-emscripten,
694+
build-san-free-threading,
683695
build-windows-msi,
684696
build-ubuntu-ssltests,
685697
test-hypothesis,

Doc/deprecations/pending-removal-in-3.21.rst

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,3 +23,8 @@ Pending removal in Python 3.21
2323
* Soft-deprecated since Python 3.15, using ``'F'`` and ``'D'`` type codes are now
2424
deprecated. These codes will be removed in Python 3.21. Use instead
2525
two-letter forms ``'Zf'`` and ``'Zd'``.
26+
27+
* :mod:`tempfile`:
28+
29+
* ``tempfile._TemporaryFileWrapper`` will be removed in Python 3.21. Use the
30+
public :class:`tempfile.TemporaryFileWrapper` instead.

Doc/library/string.rst

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -971,7 +971,8 @@ attributes:
971971

972972
Alternatively, you can provide the entire regular expression pattern by
973973
overriding the class attribute *pattern*. If you do this, the value must be a
974-
regular expression object with four named capturing groups. The capturing
974+
regular expression pattern string, or a compiled regular expression
975+
object, with four named capturing groups. The capturing
975976
groups correspond to the rules given above, along with the invalid placeholder
976977
rule:
977978

Doc/library/sys.rst

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2240,8 +2240,9 @@ always available. Unless explicitly noted otherwise, all variables are read-only
22402240

22412241
The name of the lock implementation:
22422242

2243-
* ``"semaphore"``: a lock uses a semaphore
2244-
* ``"mutex+cond"``: a lock uses a mutex and a condition variable
2243+
* ``"semaphore"``: a lock uses a semaphore (Python 3.14 and older)
2244+
* ``"mutex+cond"``: a lock uses a mutex and a condition variable (Python 3.14 and older)
2245+
* ``"pymutex"``: a lock uses the :c:type:`PyMutex` implementation (Python 3.15 and newer)
22452246
* ``None`` if this information is unknown
22462247

22472248
.. attribute:: thread_info.version

Doc/library/tempfile.rst

Lines changed: 40 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -14,10 +14,11 @@
1414

1515
This module creates temporary files and directories. It works on all
1616
supported platforms. :class:`TemporaryFile`, :class:`NamedTemporaryFile`,
17-
:class:`TemporaryDirectory`, and :class:`SpooledTemporaryFile` are high-level
18-
interfaces which provide automatic cleanup and can be used as
19-
:term:`context managers <context manager>`. :func:`mkstemp` and
20-
:func:`mkdtemp` are lower-level functions which require manual cleanup.
17+
:class:`TemporaryFileWrapper`, :class:`TemporaryDirectory`, and
18+
:class:`SpooledTemporaryFile` are high-level interfaces which provide
19+
automatic cleanup and can be used as :term:`context managers
20+
<context manager>`. :func:`mkstemp` and :func:`mkdtemp` are lower-level
21+
functions which require manual cleanup.
2122

2223
All the user-callable functions and constructors take additional arguments which
2324
allow direct control over the location and name of temporary files and
@@ -84,13 +85,13 @@ The module defines the following user-callable items:
8485
:func:`TemporaryFile` with *delete* and *delete_on_close* parameters that
8586
determine whether and how the named file should be automatically deleted.
8687

87-
The returned object is always a :term:`file-like object` whose :attr:`!file`
88-
attribute is the underlying true file object. This file-like object
89-
can be used in a :keyword:`with` statement, just like a normal file. The
90-
name of the temporary file can be retrieved from the :attr:`!name` attribute
91-
of the returned file-like object. On Unix, unlike with the
92-
:func:`TemporaryFile`, the directory entry does not get unlinked immediately
93-
after the file creation.
88+
The returned object is always a :class:`TemporaryFileWrapper` instance
89+
(a :term:`file-like object`) whose :attr:`~TemporaryFileWrapper.file` attribute is the underlying
90+
true file object. This file-like object can be used in a :keyword:`with`
91+
statement, just like a normal file. The name of the temporary file can be
92+
retrieved from the :attr:`!name` attribute of the returned file-like object.
93+
On Unix, unlike with the :func:`TemporaryFile`, the directory entry does not
94+
get unlinked immediately after the file creation.
9495

9596
If *delete* is true (the default) and *delete_on_close* is true (the
9697
default), the file is deleted as soon as it is closed. If *delete* is true
@@ -140,6 +141,34 @@ The module defines the following user-callable items:
140141
.. versionchanged:: 3.12
141142
Added *delete_on_close* parameter.
142143

144+
.. class:: TemporaryFileWrapper(file, name, delete=True, delete_on_close=True)
145+
146+
A mutable wrapper returned by :func:`NamedTemporaryFile`. It wraps the
147+
underlying file object, delegating attribute access to it, and ensures
148+
the temporary file is deleted when appropriate.
149+
150+
.. attribute:: file
151+
152+
The underlying :term:`file-like object`.
153+
154+
.. attribute:: name
155+
156+
The file name of the temporary file.
157+
158+
.. method:: close()
159+
160+
Close the temporary file, possibly deleting it depending on the
161+
*delete* and *delete_on_close* arguments passed to
162+
:func:`NamedTemporaryFile`.
163+
164+
.. note::
165+
166+
``tempfile._TemporaryFileWrapper`` is kept as a backwards compatible
167+
deprecated alias for this class.
168+
It will be removed in Python 3.21
169+
170+
.. versionadded:: next
171+
143172

144173
.. class:: SpooledTemporaryFile(max_size=0, mode='w+b', buffering=-1, encoding=None, newline=None, suffix=None, prefix=None, dir=None, *, errors=None)
145174

Doc/whatsnew/3.16.rst

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -596,6 +596,13 @@ New deprecations
596596
two-letter forms ``'Zf'`` and ``'Zd'``.
597597
(Contributed by Sergey B Kirpichev in :gh:`121249`.)
598598

599+
* :mod:`tempfile`
600+
601+
* The private ``tempfile._TemporaryFileWrapper`` name is deprecated
602+
and is slated for removal in Python 3.21.
603+
Use the new public :class:`tempfile.TemporaryFileWrapper` instead,
604+
which is the return type of :func:`tempfile.NamedTemporaryFile`.
605+
599606
.. Add deprecations above alphabetically, not here at the end.
600607
601608
.. include:: ../deprecations/pending-removal-in-3.17.rst

Lib/asyncio/base_events.py

Lines changed: 20 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1219,21 +1219,26 @@ async def _create_connection_transport(
12191219
ssl_handshake_timeout=None,
12201220
ssl_shutdown_timeout=None, context=None):
12211221

1222-
sock.setblocking(False)
1223-
context = context if context is not None else contextvars.copy_context()
1224-
1225-
protocol = protocol_factory()
1226-
waiter = self.create_future()
1227-
if ssl:
1228-
sslcontext = None if isinstance(ssl, bool) else ssl
1229-
transport = self._make_ssl_transport(
1230-
sock, protocol, sslcontext, waiter,
1231-
server_side=server_side, server_hostname=server_hostname,
1232-
ssl_handshake_timeout=ssl_handshake_timeout,
1233-
ssl_shutdown_timeout=ssl_shutdown_timeout,
1234-
context=context)
1235-
else:
1236-
transport = self._make_socket_transport(sock, protocol, waiter, context=context)
1222+
try:
1223+
sock.setblocking(False)
1224+
context = context if context is not None else contextvars.copy_context()
1225+
1226+
protocol = protocol_factory()
1227+
waiter = self.create_future()
1228+
if ssl:
1229+
sslcontext = None if isinstance(ssl, bool) else ssl
1230+
transport = self._make_ssl_transport(
1231+
sock, protocol, sslcontext, waiter,
1232+
server_side=server_side, server_hostname=server_hostname,
1233+
ssl_handshake_timeout=ssl_handshake_timeout,
1234+
ssl_shutdown_timeout=ssl_shutdown_timeout,
1235+
context=context)
1236+
else:
1237+
transport = self._make_socket_transport(sock, protocol, waiter, context=context)
1238+
except:
1239+
# gh-153133: close the socket if the transport is never created.
1240+
sock.close()
1241+
raise
12371242

12381243
try:
12391244
await waiter

Lib/string/__init__.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,14 @@ def __init_subclass__(cls):
8383
def _compile_pattern(cls):
8484
import re # deferred import, for performance
8585

86+
# `pattern` may be the `_TemplatePattern` sentinel (not yet compiled), an
87+
# already-compiled regular expression object (as documented), or a string
88+
# regular expression. An already-compiled object is returned as-is; the
89+
# other two are compiled and cached back on the class.
8690
pattern = cls.__dict__.get('pattern', _TemplatePattern)
91+
if isinstance(pattern, re.Pattern):
92+
# re.compile() rejects flags on an already-compiled pattern.
93+
return pattern
8794
if pattern is _TemplatePattern:
8895
delim = re.escape(cls.delimiter)
8996
id = cls.idpattern

Lib/tempfile.py

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@
3131
"TMP_MAX", "gettempprefix", # constants
3232
"tempdir", "gettempdir",
3333
"gettempprefixb", "gettempdirb",
34+
"TemporaryFileWrapper",
3435
]
3536

3637

@@ -484,7 +485,7 @@ def __del__(self):
484485
_warnings.warn(self.warn_message, ResourceWarning)
485486

486487

487-
class _TemporaryFileWrapper:
488+
class TemporaryFileWrapper:
488489
"""Temporary file wrapper
489490
490491
This class provides a wrapper around files opened for
@@ -555,6 +556,19 @@ def __iter__(self):
555556
for line in self.file:
556557
yield line
557558

559+
def __getattr__(name):
560+
if name == "_TemporaryFileWrapper":
561+
_warnings._deprecated(
562+
"tempfile._TemporaryFileWrapper",
563+
message=(
564+
"{name!r} is deprecated and slated for removal in Python {remove}. "
565+
"Use tempfile.TemporaryFileWrapper instead."
566+
),
567+
remove=(3, 21),
568+
)
569+
return TemporaryFileWrapper
570+
raise AttributeError(f"module {__name__!r} has no attribute {name!r}")
571+
558572
def NamedTemporaryFile(mode='w+b', buffering=-1, encoding=None,
559573
newline=None, suffix=None, prefix=None,
560574
dir=None, delete=True, *, errors=None,
@@ -607,7 +621,7 @@ def opener(*args):
607621
raw = getattr(file, 'buffer', file)
608622
raw = getattr(raw, 'raw', raw)
609623
raw.name = name
610-
return _TemporaryFileWrapper(file, name, delete, delete_on_close)
624+
return TemporaryFileWrapper(file, name, delete, delete_on_close)
611625
except:
612626
file.close()
613627
raise

Lib/test/test_array.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,11 @@ def __init__(self, typecode, newarg=None):
3131

3232
class MiscTest(unittest.TestCase):
3333

34+
def test_array_type_importable(self):
35+
from array import ArrayType
36+
37+
self.assertIs(array.array, ArrayType)
38+
3439
def test_array_is_sequence(self):
3540
self.assertIsInstance(array.array("B"), collections.abc.MutableSequence)
3641
self.assertIsInstance(array.array("B"), collections.abc.Reversible)

0 commit comments

Comments
 (0)