Skip to content

Commit f691177

Browse files
authored
Merge branch '3.13' into backport-5c20517-3.13
2 parents 56caf8e + fc9b015 commit f691177

29 files changed

Lines changed: 480 additions & 48 deletions

‎.github/workflows/build.yml‎

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -303,7 +303,7 @@ jobs:
303303
# Keep 1.1.1w in our list despite it being upstream EOL and otherwise
304304
# unsupported as it most resembles other 1.1.1-work-a-like ssl APIs
305305
# supported by important vendors such as AWS-LC.
306-
openssl_ver: [1.1.1w, 3.0.22, 3.4.7, 3.5.8, 3.6.4]
306+
openssl_ver: [1.1.1w, 3.4.8, 3.5.9, 3.6.5]
307307
# See Tools/ssl/make_ssl_data.py for notes on adding a new version
308308
env:
309309
OPENSSL_VER: ${{ matrix.openssl_ver }}
@@ -378,7 +378,7 @@ jobs:
378378
needs: build-context
379379
if: needs.build-context.outputs.run-ubuntu == 'true'
380380
env:
381-
OPENSSL_VER: 3.5.8
381+
OPENSSL_VER: 3.5.9
382382
PYTHONSTRICTEXTENSIONBUILD: 1
383383
steps:
384384
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
@@ -485,7 +485,7 @@ jobs:
485485
matrix:
486486
os: [ubuntu-24.04]
487487
env:
488-
OPENSSL_VER: 3.5.8
488+
OPENSSL_VER: 3.5.9
489489
PYTHONSTRICTEXTENSIONBUILD: 1
490490
ASAN_OPTIONS: detect_leaks=0:allocator_may_return_null=1:handle_segv=0
491491
steps:

‎.github/workflows/reusable-ubuntu.yml‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ jobs:
2525
matrix:
2626
os: [ubuntu-24.04, ubuntu-24.04-arm]
2727
env:
28-
OPENSSL_VER: 3.5.8
28+
OPENSSL_VER: 3.5.9
2929
PYTHONSTRICTEXTENSIONBUILD: 1
3030
TERM: linux
3131
steps:

‎Doc/library/subprocess.rst‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -239,8 +239,8 @@ underlying :class:`Popen` interface can be used directly.
239239

240240
.. attribute:: returncode
241241

242-
Exit status of the child process. If the process exited due to a
243-
signal, this will be the negative signal number.
242+
Exit status of the child process, an integer. If the process
243+
exited due to a signal, this will be the negative signal number.
244244

245245
.. attribute:: cmd
246246

‎Lib/asyncio/proactor_events.py‎

Lines changed: 36 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -105,8 +105,9 @@ def close(self):
105105
if self._closing:
106106
return
107107
self._closing = True
108-
self._conn_lost += 1
109108
if not self._buffer and self._write_fut is None:
109+
# Nothing left to flush: no more data will be sent.
110+
self._conn_lost += 1
110111
self._loop.call_soon(self._call_connection_lost, None)
111112
if self._read_fut is not None:
112113
self._read_fut.cancel()
@@ -386,6 +387,7 @@ def _loop_writing(self, f=None, data=None):
386387
self._buffer = None
387388
if not data:
388389
if self._closing:
390+
self._conn_lost += 1
389391
self._loop.call_soon(self._call_connection_lost, None)
390392
if self._eof_written:
391393
self._sock.shutdown(socket.SHUT_WR)
@@ -480,6 +482,11 @@ def get_write_buffer_size(self):
480482
def abort(self):
481483
self._force_close(None)
482484

485+
def _force_close(self, exc):
486+
# The base class drops the buffer; the size is tracked separately.
487+
self._buffer_size = 0
488+
super()._force_close(exc)
489+
483490
def sendto(self, data, addr=None):
484491
if not isinstance(data, (bytes, bytearray, memoryview)):
485492
raise TypeError('data argument must be bytes-like object (%r)',
@@ -509,6 +516,8 @@ def sendto(self, data, addr=None):
509516
def _loop_writing(self, fut=None):
510517
try:
511518
if self._conn_lost:
519+
# No more data will be sent: either everything buffered has
520+
# already been flushed, or _force_close() dropped it.
512521
return
513522

514523
assert fut is self._write_fut
@@ -517,9 +526,10 @@ def _loop_writing(self, fut=None):
517526
# We are in a _loop_writing() done callback, get the result
518527
fut.result()
519528

520-
if not self._buffer or (self._conn_lost and self._address):
521-
# The connection has been closed
529+
if not self._buffer:
530+
# Everything buffered has been sent
522531
if self._closing:
532+
self._conn_lost += 1
523533
self._loop.call_soon(self._call_connection_lost, None)
524534
return
525535

@@ -534,6 +544,27 @@ def _loop_writing(self, fut=None):
534544
addr=addr)
535545
except OSError as exc:
536546
self._protocol.error_received(exc)
547+
# error_received() is arbitrary protocol code: it may have sent
548+
# (scheduling a write of its own, directly or via call_soon()),
549+
# closed, or aborted the transport.
550+
if self._buffer or self._closing:
551+
# Either data is still queued, or a close() is waiting on
552+
# the write loop to drain it and call connection_lost().
553+
# This write failed, so there is no completion callback
554+
# pending to re-enter the loop -- schedule one (gh-156698).
555+
def write_next():
556+
# error_received() may have scheduled a write of its own,
557+
# directly or with call_soon(); its completion callback
558+
# will drain the rest of the buffer.
559+
if self._write_fut is None:
560+
self._loop_writing()
561+
562+
self._loop.call_soon(write_next)
563+
else:
564+
# Nothing left to write, so a paused protocol has to be
565+
# resumed here: the next entry into _loop_writing() returns
566+
# early on an empty buffer without doing it.
567+
self._maybe_resume_protocol()
537568
except Exception as exc:
538569
self._fatal_error(exc, 'Fatal write error on datagram transport')
539570
else:
@@ -543,28 +574,20 @@ def _loop_writing(self, fut=None):
543574
def _loop_reading(self, fut=None):
544575
data = None
545576
try:
546-
if self._conn_lost:
577+
if self._closing:
547578
return
548579

549-
assert self._read_fut is fut or (self._read_fut is None and
550-
self._closing)
580+
assert self._read_fut is fut
551581

552582
self._read_fut = None
553583
if fut is not None:
554584
res = fut.result()
555585

556-
if self._closing:
557-
# since close() has been called we ignore any read data
558-
data = None
559-
return
560-
561586
if self._address is not None:
562587
data, addr = res, self._address
563588
else:
564589
data, addr = res
565590

566-
if self._conn_lost:
567-
return
568591
if self._address is not None:
569592
self._read_fut = self._loop._proactor.recv(self._sock,
570593
self.max_size)

‎Lib/asyncio/tasks.py‎

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -118,11 +118,20 @@ def __init__(self, coro, *, loop=None, name=None, context=None,
118118
self._coro = coro
119119
if context is None:
120120
self._context = contextvars.copy_context()
121+
elif not isinstance(context, contextvars.Context):
122+
# gh-157301: the passed value must be a contextvars.Context
123+
self._log_destroy_pending = False
124+
raise TypeError('a contextvars.Context was expected, '
125+
f'got {type(context).__name__}')
121126
else:
122127
self._context = context
123128

124129
if eager_start and self._loop.is_running():
125-
self.__eager_start()
130+
try:
131+
self.__eager_start()
132+
except:
133+
self._log_destroy_pending = False
134+
raise
126135
else:
127136
self._loop.call_soon(self.__step, context=self._context)
128137
_register_task(self)

‎Lib/logging/handlers.py‎

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -882,7 +882,11 @@ def __init__(self, address=('localhost', SYSLOG_UDP_PORT),
882882
self.facility = facility
883883
self.socktype = socktype
884884
self.socket = None
885-
self.createSocket()
885+
# The address is resolved again when emitting an event.
886+
try:
887+
self.createSocket()
888+
except socket.gaierror:
889+
pass
886890

887891
def _connect_unixsocket(self, address):
888892
use_socktype = self.socktype

‎Lib/subprocess.py‎

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -143,16 +143,16 @@ def __init__(self, returncode, cmd, output=None, stderr=None):
143143
self.stderr = stderr
144144

145145
def __str__(self):
146-
if self.returncode and self.returncode < 0:
146+
if isinstance(self.returncode, int) and self.returncode < 0:
147147
try:
148148
return "Command '%s' died with %r." % (
149149
self.cmd, signal.Signals(-self.returncode))
150150
except ValueError:
151151
return "Command '%s' died with unknown signal %d." % (
152152
self.cmd, -self.returncode)
153153
else:
154-
return "Command '%s' returned non-zero exit status %d." % (
155-
self.cmd, self.returncode)
154+
return (f"Command '{self.cmd}' returned non-zero "
155+
f"exit status {self.returncode}.")
156156

157157
@property
158158
def stdout(self):

0 commit comments

Comments
 (0)