- commit
- 782851e16a4988987e94d22388efb84d2ab988ac
- parent
- 0df8fb90d90a5f881d9815ac411c82c769ee5a00
- Author
- Tobias Bengfort <tobias.bengfort@posteo.de>
- Date
- 2026-02-27 00:46
add timeout() Just a higher level abstraction on top of TaskGroup.
Diffstat
| M | README.md | 15 | ++++++++------- |
| M | tests.py | 28 | ++++++++++++++++++++++++++++ |
| M | xiio.py | 23 | +++++++++++++++++++++++ |
3 files changed, 59 insertions, 7 deletions
diff --git a/README.md b/README.md
@@ -19,13 +19,14 @@ async def greet(name): 19 19 20 20 21 21 async def main():22 -1 name1 = (await xiio.read(sys.stdin, 32)).decode()23 -1 name2 = (await xiio.read(sys.stdin, 32)).decode()24 -125 -1 await xiio.gather([26 -1 greet(name1),27 -1 greet(name2),28 -1 ])-1 22 async with xiio.timeout(10): -1 23 name1 = (await xiio.read(sys.stdin, 32)).decode() -1 24 name2 = (await xiio.read(sys.stdin, 32)).decode() -1 25 -1 26 await xiio.gather([ -1 27 greet(name1), -1 28 greet(name2), -1 29 ]) 29 30 30 31 31 32 xiio.run(main())
diff --git a/tests.py b/tests.py
@@ -241,6 +241,34 @@ class TestGather(XiioTestCase): 241 241 self.assertEqual(stack, [1]) 242 242 243 243 -1 244 class TestTimeout(XiioTestCase): -1 245 def test_timeout_finish(self): -1 246 async def foo(): -1 247 async with xiio.timeout(1): -1 248 await xiio.sleep(0.2) -1 249 return 1 -1 250 -1 251 with self.assert_duration(0.2): -1 252 result = xiio.run(foo()) -1 253 self.assertEqual(result, 1) -1 254 -1 255 async def test_timeout_throw(self): -1 256 with self.assertRaises(TimeoutError): -1 257 with self.assert_duration(0.1): -1 258 async with xiio.timeout(0.1): -1 259 await xiio.sleep(0.3) -1 260 -1 261 async def test_timeout_no_throw(self): -1 262 with self.assert_duration(0.1): -1 263 async with xiio.timeout(0.1, throw=False): -1 264 await xiio.sleep(0.3) -1 265 -1 266 async def test_timeout_none(self): -1 267 with self.assert_duration(0.1): -1 268 async with xiio.timeout(None): -1 269 await xiio.sleep(0.1) -1 270 -1 271 244 272 class TestRun(XiioTestCase): 245 273 def test_sleep(self): 246 274 async def foo():
diff --git a/xiio.py b/xiio.py
@@ -1,8 +1,10 @@ -1 1 import contextlib 1 2 import math 2 3 import os 3 4 import selectors 4 5 import time 5 6 import typing -1 7 from collections.abc import AsyncGenerator 6 8 from collections.abc import Coroutine 7 9 from collections.abc import Generator 8 10 from selectors import EVENT_READ as READ @@ -222,6 +224,27 @@ async def gather(coros: list[Coro[T]]) -> list[T]: 222 224 return [typing.cast(T, task.result) for task in tasks] 223 225 224 226 -1 227 @contextlib.asynccontextmanager -1 228 async def timeout( -1 229 seconds: float | None, *, throw: bool = True -1 230 ) -> AsyncGenerator[None, None]: -1 231 if seconds is None: -1 232 yield -1 233 else: -1 234 async def _timeout() -> typing.NoReturn: -1 235 await sleep(seconds) -1 236 raise TimeoutError -1 237 -1 238 try: -1 239 async with TaskGroup() as tg: -1 240 task = tg.add_task(_timeout()) -1 241 yield -1 242 task.cancel() -1 243 except TimeoutError: -1 244 if throw: -1 245 raise -1 246 -1 247 225 248 def run(coro: Coro[T]) -> T: 226 249 task = Task(coro.__await__()) 227 250 try: