Skip to content
Merged
Changes from 1 commit
Commits
Show all changes
18 commits
Select commit Hold shift + click to select a range
3006d6e
fix proactor error hang
graingert Aug 31, 2026
eb09595
gh-127057: Re-arm proactor datagram read loop after a recoverable OSE…
graingert Aug 31, 2026
8a50451
Merge branches 'fix-proactor-udp-connreset' and 'fix-proactor-error-h…
graingert Sep 1, 2026
f1c27aa
unignore error port unreachable in proactor
graingert Sep 1, 2026
60187dd
Merge branch 'main' into fix-proactor-error-hang
graingert Sep 4, 2026
d57cb23
fix DatagramTransport when errror_recieved calls sendto
graingert Sep 4, 2026
bb80478
Merge branch 'main' of github.com:python/cpython into fix-proactor-er…
graingert Sep 5, 2026
99dd5a1
Merge branch 'fix-proactor-error-hang' into unignore-error-port-unrea…
graingert Sep 5, 2026
bad71a2
Merge branch 'main' of github.com:python/cpython into unignore-error-…
graingert Sep 16, 2026
5c71eb7
Apply suggestion from @graingert
graingert Sep 16, 2026
08e2a39
remove test_datagram_write_error_resumes_paused_protocol_from_callback
graingert Sep 16, 2026
b6eb862
Apply suggestion from @graingert
graingert Sep 16, 2026
96e0119
Merge branch 'main' into unignore-error-port-unreachable-in-proactor
graingert Sep 18, 2026
8dc75b4
Merge branch 'main' into unignore-error-port-unreachable-in-proactor
graingert Sep 30, 2026
d426aa2
Merge branch 'main' into unignore-error-port-unreachable-in-proactor
graingert Oct 5, 2026
37f3e94
Merge branch 'main' into unignore-error-port-unreachable-in-proactor
graingert Oct 7, 2026
cccedb8
Merge branch 'main' into unignore-error-port-unreachable-in-proactor
graingert Oct 19, 2026
74d7f75
shorten news
graingert Oct 19, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
Merge branch 'main' of github.com:python/cpython into fix-proactor-er…
…ror-hang

# Conflicts:
#	Lib/test/test_asyncio/test_events.py
  • Loading branch information
graingert committed Sep 5, 2026
commit bb80478c626d5ea17b2ec831c252b5dadd1cf525
54 changes: 54 additions & 0 deletions Lib/test/test_asyncio/test_events.py
Original file line number Diff line number Diff line change
Expand Up @@ -1712,6 +1712,60 @@ def error_received(self, exc):
unhandled,
f'unhandled exception in the write loop: {unhandled}')

def test_datagram_recvfrom_connection_reset_recovers(self):
# gh-127057: a UDP socket that sent a datagram to an address that
# wasn't listening can raise ConnectionResetError on a later
# receive. The transport must keep working afterwards.
loop = self.loop

class Protocol(asyncio.DatagramProtocol):
def connection_made(self, transport):
self.transport = transport
self.errors = []
self.received = []
self.datagram_received_event = loop.create_future()

def error_received(self, exc):
self.errors.append(exc)

def datagram_received(self, data, addr):
self.received.append(data)
if not self.datagram_received_event.done():
self.datagram_received_event.set_result(None)

sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
sock.setblocking(False)
sock.bind(('127.0.0.1', 0))
addr = sock.getsockname()

# Bind and immediately close a second socket to get an address
# that is guaranteed not to be listening.
closed = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
closed.bind(('127.0.0.1', 0))
closed_addr = closed.getsockname()
closed.close()

# Trigger the error before the socket is wrapped in a transport,
# so that the first read raises synchronously.
sock.sendto(b'x', closed_addr)

transport, protocol = loop.run_until_complete(
loop.create_datagram_endpoint(Protocol, sock=sock))

transport.sendto(b'ping', addr)
loop.run_until_complete(asyncio.wait_for(
protocol.datagram_received_event, support.SHORT_TIMEOUT))
self.assertEqual(protocol.received, [b'ping'])

if sys.platform == 'win32':
# Other platforms don't report ICMP errors on an
# unconnected UDP socket.
self.assertEqual(len(protocol.errors), 1)
self.assertIsInstance(protocol.errors[0], ConnectionResetError)

transport.close()
test_utils.run_briefly(loop)

def test_internal_fds(self):
loop = self.create_event_loop()
if not isinstance(loop, selector_events.BaseSelectorEventLoop):
Expand Down
Loading
You are viewing a condensed version of this merge commit. You can view the full changes here.