xiio

really simple async runtime
git clone https://git.ce9e.org/xiio.git

commit
d39fb2b7a1d88a6447fe62d7206fea21e836dabe
parent
6b9965a49151195a363b7eb06f53a6379e1102ea
Author
Tobias Bengfort <tobias.bengfort@posteo.de>
Date
2026-02-26 18:34
allow to pause execution

The first step is to move the blocking call out of the function. To do
that, we pause execution by using the `yield` keyword. This turns our
function into a generator function. The separate `run()` function will
do the blocking call and resume the generator function once that is
done. The special `StopIteration` exception is raised when the generator
function returns.

Diffstat

M tests.py 14 ++++++++------
A xiio.py 15 +++++++++++++++

2 files changed, 23 insertions, 6 deletions


diff --git a/tests.py b/tests.py

@@ -3,6 +3,8 @@ import time
    3     3 import unittest
    4     4 from unittest import mock
    5     5 
   -1     6 import xiio
   -1     7 
    6     8 
    7     9 class XiioTestCase(unittest.TestCase):
    8    10     @contextlib.contextmanager
@@ -18,11 +20,11 @@ class XiioTestCase(unittest.TestCase):
   18    20 class TestRun(XiioTestCase):
   19    21     def test_sleep(self):
   20    22         def foo():
   21    -1             time.sleep(0.1)
   -1    23             yield 0.1
   22    24             return 'Hello World'
   23    25 
   24    26         with self.assert_duration(0.1):
   25    -1             result = foo()
   -1    27             result = xiio.run(foo())
   26    28         self.assertEqual(result, 'Hello World')
   27    29 
   28    30     def test_runs_cleanup_on_error_while_paused(self):
@@ -30,13 +32,13 @@ class TestRun(XiioTestCase):
   30    32 
   31    33         def foo():
   32    34             try:
   33    -1                 time.sleep(0.1)
   -1    35                 yield 0.1
   34    36             finally:
   35    37                 stack.append(1)
   36    38 
   37    39         with mock.patch('time.sleep', side_effect=KeyboardInterrupt):
   38    40             with self.assertRaises(KeyboardInterrupt):
   39    -1                 foo()
   -1    41                 xiio.run(foo())
   40    42         self.assertEqual(stack, [1])
   41    43 
   42    44     def test_waits_for_cleanup(self):
@@ -44,8 +46,8 @@ class TestRun(XiioTestCase):
   44    46             try:
   45    47                 raise ValueError
   46    48             finally:
   47    -1                 time.sleep(0.1)
   -1    49                 yield 0.1
   48    50 
   49    51         with self.assertRaises(ValueError):
   50    52             with self.assert_duration(0.1):
   51    -1                 foo()
   -1    53                 xiio.run(foo())

diff --git a/xiio.py b/xiio.py

@@ -0,0 +1,15 @@
   -1     1 import time
   -1     2 
   -1     3 
   -1     4 def run(gen):
   -1     5     try:
   -1     6         timeout = next(gen)
   -1     7         while True:
   -1     8             try:
   -1     9                 time.sleep(timeout)
   -1    10             except BaseException as e:
   -1    11                 timeout = gen.throw(e)
   -1    12             else:
   -1    13                 timeout = next(gen)
   -1    14     except StopIteration as e:
   -1    15         return e.value