summaryrefslogtreecommitdiff
path: root/t/test_functionality.py
diff options
context:
space:
mode:
authorbd <bdunahu@operationnull.com>2025-07-21 13:25:56 -0600
committerbd <bdunahu@operationnull.com>2025-07-21 13:25:56 -0600
commit487c77a96504c0178581a7a4bb7e9cd66783548f (patch)
tree67bb104ce5fe7238546001a47a85b8aaafc042a1 /t/test_functionality.py
parent83e88319b72df01fa70e6bf3a020ab745cdef661 (diff)
Update comments reflecting on asyncio.gather and task groups
Diffstat (limited to 't/test_functionality.py')
-rw-r--r--t/test_functionality.py79
1 files changed, 58 insertions, 21 deletions
diff --git a/t/test_functionality.py b/t/test_functionality.py
index 63863cf..75f0137 100644
--- a/t/test_functionality.py
+++ b/t/test_functionality.py
@@ -3,6 +3,10 @@ import asyncio
import threading
+class TerminateTaskGroup(Exception):
+ '''Exception raised to terminate a task group.'''
+
+
class BasicUsage(utils.AergiaUnitTestCase):
def test_asyncless(self):
@@ -55,7 +59,10 @@ class BasicUsage(utils.AergiaUnitTestCase):
self.assertFuncContains('b', [self.expected_samples(delay * 3)],
samples)
- # TODO samples from gather all execution time, should we trace this?
+ # the gather function is technically waiting for all tasks to finish.
+ # This might be seen as unintuitive though I don't want to bias the
+ # results by adding logic to add artificial consistency.
+ # profiling does not mean obscuring implementation details.
self.assertFuncContains('a', [self.expected_samples(delay)], samples)
def test_subthread_task(self):
@@ -75,7 +82,7 @@ class BasicUsage(utils.AergiaUnitTestCase):
self.assertFuncContains('c', [], samples)
self.assertFuncContains('b', [self.expected_samples(delay * 3)],
samples)
- # TODO samples from gather all execution time, should we trace this?
+ # see comment on `test_simultaneous_tasks'.
self.assertFuncContains('a', [self.expected_samples(delay)], samples)
def test_eager_task(self):
@@ -92,6 +99,31 @@ class BasicUsage(utils.AergiaUnitTestCase):
samples = self.Aergia.get_samples()
self.assertFuncContains('a', [self.expected_samples(delay)], samples)
+ def test_async_eager_scheduled_woven(self):
+ d1 = 0.2
+ d2 = 0.3
+ d3 = 0.2
+ d4 = 0.1
+
+ async def a():
+ await asyncio.sleep(d1)
+ proc = await asyncio.create_subprocess_shell(f'sleep {d2}')
+ await proc.communicate()
+ await asyncio.sleep(d3)
+ proc = await asyncio.create_subprocess_shell(f'sleep {d4}')
+ await proc.communicate()
+
+ self.Aergia.start()
+ asyncio.run(a())
+ self.Aergia.stop()
+
+ samples = self.Aergia.get_samples()
+ self.assertFuncContains('a', [self.expected_samples(d1),
+ self.expected_samples(d2),
+ self.expected_samples(d3),
+ self.expected_samples(d4),
+ ], samples)
+
def test_async_generator(self):
delay = 0.2
num_times = 10
@@ -111,8 +143,8 @@ class BasicUsage(utils.AergiaUnitTestCase):
self.Aergia.stop()
samples = self.Aergia.get_samples()
- # TODO can we make these results more intuitive?
- # async generators also do not work at all with yappi.
+ # TODO I do not think async generators report correctly.
+ # also does not work at all with yappi.
# doing so would be unique to this profiler.
# self.assertFuncContains('b',
@@ -142,8 +174,8 @@ class BasicUsage(utils.AergiaUnitTestCase):
self.Aergia.stop()
samples = self.Aergia.get_samples()
- # TODO can we make these results more intuitive?
- # async generators also do not work at all with yappi.
+ # TODO I do not think async generators report correctly.
+ # also does not work at all with yappi.
# doing so would be unique to this profiler.
self.assertFuncContains('b', [], samples)
@@ -192,28 +224,32 @@ class BasicUsage(utils.AergiaUnitTestCase):
self.assertFuncContains('d', [self.expected_samples(d1)], samples)
self.assertFuncContains('c', [self.expected_samples(d2)], samples)
self.assertFuncContains('b', [self.expected_samples(d3)], samples)
- # TODO where does this come from?
+ # the task group is technically waiting for all tasks to finish.
+ # same as task.gather
+ # This might be seen as unintuitive, (especially considering how
+ # the next test works), though I don't want to bias the results
+ # by adding logic to add artificial consistency.
+ # Both are reporting correctly.
self.assertFuncContains('a', [self.expected_samples(d2)], samples)
def test_task_groups_cancel(self):
d1 = 0.1
- d2 = 0.2
- d3 = 0.3
- async def d(): await asyncio.sleep(d1)
+ d2 = 0.3
+ d3 = 0.2
+ async def d(): raise TerminateTaskGroup
- async def c():
- await asyncio.sleep(d2)
- 1 / 0 # crash
+ async def c(): await asyncio.sleep(d1)
- async def b(): await asyncio.sleep(d3)
+ async def b(): await asyncio.sleep(d2)
async def a():
try:
async with asyncio.TaskGroup() as tg:
- tg.create_task(d())
tg.create_task(c())
tg.create_task(b())
- except:
+ await asyncio.sleep(d3)
+ tg.create_task(d())
+ except* TerminateTaskGroup:
pass
self.Aergia.start()
@@ -222,8 +258,9 @@ class BasicUsage(utils.AergiaUnitTestCase):
samples = self.Aergia.get_samples()
- self.assertFuncContains('d', [self.expected_samples(d1)], samples)
- self.assertFuncContains('c', [self.expected_samples(d2)], samples)
- self.assertFuncContains('b', [self.expected_samples(d2)], samples)
- # TODO where does this come from?
- self.assertFuncContains('a', [self.expected_samples(d2)], samples)
+ self.assertFuncContains('d', [], samples)
+ self.assertFuncContains('c', [self.expected_samples(d1)], samples)
+ self.assertFuncContains('b', [self.expected_samples(d3)], samples)
+ # this time is attached to the sleep call itself. Aergia's print
+ # function would confirm this!
+ self.assertFuncContains('a', [self.expected_samples(d3)], samples)