From 8d36cd53289580f1d6f9425aa8cad1264df58c24 Mon Sep 17 00:00:00 2001 From: sobolevn Date: Sun, 19 May 2024 13:06:25 +0300 Subject: [PATCH 1/3] gh-119121: Fix and test `async.staggered.staggered_race` --- Lib/asyncio/staggered.py | 3 +- Lib/test/test_asyncio/test_staggered.py | 93 +++++++++++++++++++ ...-05-19-13-05-59.gh-issue-119121.P1gnh1.rst | 2 + 3 files changed, 96 insertions(+), 2 deletions(-) create mode 100644 Lib/test/test_asyncio/test_staggered.py create mode 100644 Misc/NEWS.d/next/Library/2024-05-19-13-05-59.gh-issue-119121.P1gnh1.rst diff --git a/Lib/asyncio/staggered.py b/Lib/asyncio/staggered.py index e180cde0243b15..c3a7441a7b091d 100644 --- a/Lib/asyncio/staggered.py +++ b/Lib/asyncio/staggered.py @@ -69,8 +69,7 @@ async def staggered_race(coro_fns, delay, *, loop=None): exceptions = [] running_tasks = [] - async def run_one_coro( - previous_failed: typing.Optional[locks.Event]) -> None: + async def run_one_coro(previous_failed) -> None: # Wait for the previous task to finish, or for delay seconds if previous_failed is not None: with contextlib.suppress(exceptions_mod.TimeoutError): diff --git a/Lib/test/test_asyncio/test_staggered.py b/Lib/test/test_asyncio/test_staggered.py new file mode 100644 index 00000000000000..16273b77f9c9c4 --- /dev/null +++ b/Lib/test/test_asyncio/test_staggered.py @@ -0,0 +1,93 @@ +import asyncio +import unittest +from asyncio.staggered import staggered_race + + +def tearDownModule(): + asyncio.set_event_loop_policy(None) + + +class StaggeredTests(unittest.IsolatedAsyncioTestCase): + async def test_empty(self): + winner, index, excs = await staggered_race( + [], + delay=None, + ) + + self.assertEqual(winner, None) + self.assertEqual(index, None) + self.assertEqual(excs, []) + + async def test_one_successful(self): + async def coro(index): + return f'Res: {index}' + + winner, index, excs = await staggered_race( + [ + lambda: coro(0), + lambda: coro(1), + ], + delay=None, + ) + + self.assertEqual(winner, 'Res: 0') + self.assertEqual(index, 0) + self.assertEqual(excs, [None]) + + async def test_first_error_second_successful(self): + async def coro(index): + if index == 0: + raise ValueError(index) + return f'Res: {index}' + + winner, index, excs = await staggered_race( + [ + lambda: coro(0), + lambda: coro(1), + ], + delay=None, + ) + + self.assertEqual(winner, 'Res: 1') + self.assertEqual(index, 1) + self.assertEqual(len(excs), 2) + self.assertIsInstance(excs[0], ValueError) + self.assertEqual(excs[1], None) + + async def test_first_timeout_second_successful(self): + async def coro(index): + if index == 0: + await asyncio.sleep(10) # much bigger than delay + return f'Res: {index}' + + winner, index, excs = await staggered_race( + [ + lambda: coro(0), + lambda: coro(1), + ], + delay=0.1, + ) + + self.assertEqual(winner, 'Res: 1') + self.assertEqual(index, 1) + self.assertEqual(len(excs), 2) + self.assertIsInstance(excs[0], asyncio.CancelledError) + self.assertEqual(excs[1], None) + + async def test_none_successful(self): + async def coro(index): + raise ValueError(index) + + winner, index, excs = await staggered_race( + [ + lambda: coro(0), + lambda: coro(1), + ], + delay=None, + ) + + self.assertEqual(winner, None) + self.assertEqual(index, None) + self.assertEqual(len(excs), 2) + self.assertIsInstance(excs[0], ValueError) + self.assertIsInstance(excs[1], ValueError) diff --git a/Misc/NEWS.d/next/Library/2024-05-19-13-05-59.gh-issue-119121.P1gnh1.rst b/Misc/NEWS.d/next/Library/2024-05-19-13-05-59.gh-issue-119121.P1gnh1.rst new file mode 100644 index 00000000000000..fd562ea4f73317 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2024-05-19-13-05-59.gh-issue-119121.P1gnh1.rst @@ -0,0 +1,2 @@ +Fix a NameError happening in ``asyncio.staggered.staggered_race``. This +function is now tested. From 3d7737b80854c2cbb5659eec70f8131a44627296 Mon Sep 17 00:00:00 2001 From: sobolevn Date: Sun, 19 May 2024 13:14:11 +0300 Subject: [PATCH 2/3] Add a guard for WASI / etc --- Lib/test/test_asyncio/test_staggered.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Lib/test/test_asyncio/test_staggered.py b/Lib/test/test_asyncio/test_staggered.py index 16273b77f9c9c4..06fa5c776480f1 100644 --- a/Lib/test/test_asyncio/test_staggered.py +++ b/Lib/test/test_asyncio/test_staggered.py @@ -2,6 +2,10 @@ import unittest from asyncio.staggered import staggered_race +from test import support + +support.requires_working_socket(module=True) + def tearDownModule(): asyncio.set_event_loop_policy(None) From 688734987c5a71cdebda38562c71b47e0c8547dd Mon Sep 17 00:00:00 2001 From: sobolevn Date: Mon, 20 May 2024 13:24:49 +0300 Subject: [PATCH 3/3] Address review --- Lib/test/test_asyncio/test_staggered.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/Lib/test/test_asyncio/test_staggered.py b/Lib/test/test_asyncio/test_staggered.py index 06fa5c776480f1..e6e32f7dbbbcba 100644 --- a/Lib/test/test_asyncio/test_staggered.py +++ b/Lib/test/test_asyncio/test_staggered.py @@ -18,8 +18,8 @@ async def test_empty(self): delay=None, ) - self.assertEqual(winner, None) - self.assertEqual(index, None) + self.assertIs(winner, None) + self.assertIs(index, None) self.assertEqual(excs, []) async def test_one_successful(self): @@ -56,7 +56,7 @@ async def coro(index): self.assertEqual(index, 1) self.assertEqual(len(excs), 2) self.assertIsInstance(excs[0], ValueError) - self.assertEqual(excs[1], None) + self.assertIs(excs[1], None) async def test_first_timeout_second_successful(self): async def coro(index): @@ -76,7 +76,7 @@ async def coro(index): self.assertEqual(index, 1) self.assertEqual(len(excs), 2) self.assertIsInstance(excs[0], asyncio.CancelledError) - self.assertEqual(excs[1], None) + self.assertIs(excs[1], None) async def test_none_successful(self): async def coro(index): @@ -90,8 +90,8 @@ async def coro(index): delay=None, ) - self.assertEqual(winner, None) - self.assertEqual(index, None) + self.assertIs(winner, None) + self.assertIs(index, None) self.assertEqual(len(excs), 2) self.assertIsInstance(excs[0], ValueError) self.assertIsInstance(excs[1], ValueError)