diff --git a/Lib/test/test_asyncgen.py b/Lib/test/test_asyncgen.py index 4961170b74..c3257b5d78 100644 --- a/Lib/test/test_asyncgen.py +++ b/Lib/test/test_asyncgen.py @@ -1,10 +1,7 @@ import inspect -import sys import types import unittest -from unittest import mock - from test.support import import_module asyncio = import_module("asyncio") @@ -136,24 +133,6 @@ class AsyncGenTest(unittest.TestCase): break return res - def async_iterate(g): - res = [] - while True: - try: - g.__anext__().__next__() - except StopAsyncIteration: - res.append('STOP') - break - except StopIteration as ex: - if ex.args: - res.append(ex.args[0]) - else: - res.append('EMPTY StopIteration') - break - except Exception as ex: - res.append(str(type(ex))) - return res - sync_gen_result = sync_iterate(sync_gen) async_gen_result = async_iterate(async_gen) self.assertEqual(sync_gen_result, async_gen_result) @@ -179,19 +158,22 @@ class AsyncGenTest(unittest.TestCase): g = gen() ai = g.__aiter__() - self.assertEqual(ai.__anext__().__next__(), ('result',)) + + an = ai.__anext__() + self.assertEqual(an.__next__(), ('result',)) try: - ai.__anext__().__next__() + an.__next__() except StopIteration as ex: self.assertEqual(ex.args[0], 123) else: self.fail('StopIteration was not raised') - self.assertEqual(ai.__anext__().__next__(), ('result',)) + an = ai.__anext__() + self.assertEqual(an.__next__(), ('result',)) try: - ai.__anext__().__next__() + an.__next__() except StopAsyncIteration as ex: self.assertFalse(ex.args) else: @@ -215,10 +197,11 @@ class AsyncGenTest(unittest.TestCase): g = gen() ai = g.__aiter__() - self.assertEqual(ai.__anext__().__next__(), ('result',)) + an = ai.__anext__() + self.assertEqual(an.__next__(), ('result',)) try: - ai.__anext__().__next__() + an.__next__() except StopIteration as ex: self.assertEqual(ex.args[0], 123) else: @@ -246,6 +229,7 @@ class AsyncGenTest(unittest.TestCase): 'async generator.*StopIteration'): to_list(gen()) + @unittest.skip("TODO: RUSTPYTHON") def test_async_gen_exception_07(self): def sync_gen(): try: @@ -390,6 +374,7 @@ class AsyncGenAsyncioTest(unittest.TestCase): def tearDown(self): self.loop.close() self.loop = None + asyncio.set_event_loop_policy(None) async def to_list(self, gen): res = [] @@ -400,9 +385,9 @@ class AsyncGenAsyncioTest(unittest.TestCase): def test_async_gen_asyncio_01(self): async def gen(): yield 1 - await asyncio.sleep(0.01, loop=self.loop) + await asyncio.sleep(0.01) yield 2 - await asyncio.sleep(0.01, loop=self.loop) + await asyncio.sleep(0.01) return yield 3 @@ -412,7 +397,7 @@ class AsyncGenAsyncioTest(unittest.TestCase): def test_async_gen_asyncio_02(self): async def gen(): yield 1 - await asyncio.sleep(0.01, loop=self.loop) + await asyncio.sleep(0.01) yield 2 1 / 0 yield 3 @@ -426,7 +411,7 @@ class AsyncGenAsyncioTest(unittest.TestCase): class Gen: async def __aiter__(self): yield 1 - await asyncio.sleep(0.01, loop=loop) + await asyncio.sleep(0.01) yield 2 res = loop.run_until_complete(self.to_list(Gen())) @@ -435,13 +420,13 @@ class AsyncGenAsyncioTest(unittest.TestCase): def test_async_gen_asyncio_anext_04(self): async def foo(): yield 1 - await asyncio.sleep(0.01, loop=self.loop) + await asyncio.sleep(0.01) try: yield 2 yield 3 except ZeroDivisionError: yield 1000 - await asyncio.sleep(0.01, loop=self.loop) + await asyncio.sleep(0.01) yield 4 async def run1(): @@ -592,7 +577,7 @@ class AsyncGenAsyncioTest(unittest.TestCase): yield 1 1 / 0 finally: - await asyncio.sleep(0.01, loop=self.loop) + await asyncio.sleep(0.01) yield 12 async def run(): @@ -615,8 +600,8 @@ class AsyncGenAsyncioTest(unittest.TestCase): yield 1 1 / 0 finally: - await asyncio.sleep(0.01, loop=self.loop) - await asyncio.sleep(0.01, loop=self.loop) + await asyncio.sleep(0.01) + await asyncio.sleep(0.01) DONE += 1 DONE += 1000 @@ -642,8 +627,8 @@ class AsyncGenAsyncioTest(unittest.TestCase): DONE += 1000 yield 2 finally: - await asyncio.sleep(0.01, loop=self.loop) - await asyncio.sleep(0.01, loop=self.loop) + await asyncio.sleep(0.01) + await asyncio.sleep(0.01) DONE += 1 DONE += 1000 @@ -651,18 +636,14 @@ class AsyncGenAsyncioTest(unittest.TestCase): gen = foo() it = gen.__aiter__() self.assertEqual(await it.__anext__(), 1) - t = self.loop.create_task(it.__anext__()) - await asyncio.sleep(0.01, loop=self.loop) await gen.aclose() - return t - t = self.loop.run_until_complete(run()) + self.loop.run_until_complete(run()) self.assertEqual(DONE, 1) # Silence ResourceWarnings fut.cancel() - t.cancel() - self.loop.run_until_complete(asyncio.sleep(0.01, loop=self.loop)) + self.loop.run_until_complete(asyncio.sleep(0.01)) def test_async_gen_asyncio_gc_aclose_09(self): DONE = 0 @@ -673,8 +654,8 @@ class AsyncGenAsyncioTest(unittest.TestCase): while True: yield 1 finally: - await asyncio.sleep(0.01, loop=self.loop) - await asyncio.sleep(0.01, loop=self.loop) + await asyncio.sleep(0.01) + await asyncio.sleep(0.01) DONE = 1 async def run(): @@ -683,7 +664,7 @@ class AsyncGenAsyncioTest(unittest.TestCase): await g.__anext__() del g - await asyncio.sleep(0.1, loop=self.loop) + await asyncio.sleep(0.1) self.loop.run_until_complete(run()) self.assertEqual(DONE, 1) @@ -758,6 +739,33 @@ class AsyncGenAsyncioTest(unittest.TestCase): self.loop.run_until_complete(run()) self.assertEqual(DONE, 10) + def test_async_gen_asyncio_aclose_12(self): + DONE = 0 + + async def target(): + await asyncio.sleep(0.01) + 1 / 0 + + async def foo(): + nonlocal DONE + task = asyncio.create_task(target()) + try: + yield 1 + finally: + try: + await task + except ZeroDivisionError: + DONE = 1 + + async def run(): + gen = foo() + it = gen.__aiter__() + await it.__anext__() + await gen.aclose() + + self.loop.run_until_complete(run()) + self.assertEqual(DONE, 1) + def test_async_gen_asyncio_asend_01(self): DONE = 0 @@ -774,15 +782,15 @@ class AsyncGenAsyncioTest(unittest.TestCase): async def gen(): nonlocal DONE try: - await asyncio.sleep(0.01, loop=self.loop) + await asyncio.sleep(0.01) v = yield 1 - await asyncio.sleep(0.01, loop=self.loop) + await asyncio.sleep(0.01) yield v * 2 - await asyncio.sleep(0.01, loop=self.loop) + await asyncio.sleep(0.01) return finally: - await asyncio.sleep(0.01, loop=self.loop) - await asyncio.sleep(0.01, loop=self.loop) + await asyncio.sleep(0.01) + await asyncio.sleep(0.01) DONE = 1 async def run(): @@ -804,20 +812,20 @@ class AsyncGenAsyncioTest(unittest.TestCase): DONE = 0 async def sleep_n_crash(delay): - await asyncio.sleep(delay, loop=self.loop) + await asyncio.sleep(delay) 1 / 0 async def gen(): nonlocal DONE try: - await asyncio.sleep(0.01, loop=self.loop) + await asyncio.sleep(0.01) v = yield 1 await sleep_n_crash(0.01) DONE += 1000 yield v * 2 finally: - await asyncio.sleep(0.01, loop=self.loop) - await asyncio.sleep(0.01, loop=self.loop) + await asyncio.sleep(0.01) + await asyncio.sleep(0.01) DONE = 1 async def run(): @@ -836,7 +844,7 @@ class AsyncGenAsyncioTest(unittest.TestCase): DONE = 0 async def sleep_n_crash(delay): - fut = asyncio.ensure_future(asyncio.sleep(delay, loop=self.loop), + fut = asyncio.ensure_future(asyncio.sleep(delay), loop=self.loop) self.loop.call_later(delay / 2, lambda: fut.cancel()) return await fut @@ -844,14 +852,14 @@ class AsyncGenAsyncioTest(unittest.TestCase): async def gen(): nonlocal DONE try: - await asyncio.sleep(0.01, loop=self.loop) + await asyncio.sleep(0.01) v = yield 1 await sleep_n_crash(0.01) DONE += 1000 yield v * 2 finally: - await asyncio.sleep(0.01, loop=self.loop) - await asyncio.sleep(0.01, loop=self.loop) + await asyncio.sleep(0.01) + await asyncio.sleep(0.01) DONE = 1 async def run(): @@ -890,18 +898,18 @@ class AsyncGenAsyncioTest(unittest.TestCase): async def gen(): nonlocal DONE try: - await asyncio.sleep(0.01, loop=self.loop) + await asyncio.sleep(0.01) try: v = yield 1 except FooEr: v = 1000 - await asyncio.sleep(0.01, loop=self.loop) + await asyncio.sleep(0.01) yield v * 2 - await asyncio.sleep(0.01, loop=self.loop) + await asyncio.sleep(0.01) # return finally: - await asyncio.sleep(0.01, loop=self.loop) - await asyncio.sleep(0.01, loop=self.loop) + await asyncio.sleep(0.01) + await asyncio.sleep(0.01) DONE = 1 async def run(): @@ -926,7 +934,7 @@ class AsyncGenAsyncioTest(unittest.TestCase): pass async def sleep_n_crash(delay): - fut = asyncio.ensure_future(asyncio.sleep(delay, loop=self.loop), + fut = asyncio.ensure_future(asyncio.sleep(delay), loop=self.loop) self.loop.call_later(delay / 2, lambda: fut.cancel()) return await fut @@ -934,17 +942,17 @@ class AsyncGenAsyncioTest(unittest.TestCase): async def gen(): nonlocal DONE try: - await asyncio.sleep(0.01, loop=self.loop) + await asyncio.sleep(0.01) try: v = yield 1 except FooEr: await sleep_n_crash(0.01) yield v * 2 - await asyncio.sleep(0.01, loop=self.loop) + await asyncio.sleep(0.01) # return finally: - await asyncio.sleep(0.01, loop=self.loop) - await asyncio.sleep(0.01, loop=self.loop) + await asyncio.sleep(0.01) + await asyncio.sleep(0.01) DONE = 1 async def run(): @@ -1043,10 +1051,10 @@ class AsyncGenAsyncioTest(unittest.TestCase): async def waiter(timeout): nonlocal finalized try: - await asyncio.sleep(timeout, loop=self.loop) + await asyncio.sleep(timeout) yield 1 finally: - await asyncio.sleep(0, loop=self.loop) + await asyncio.sleep(0) finalized += 1 async def wait(): @@ -1056,48 +1064,152 @@ class AsyncGenAsyncioTest(unittest.TestCase): t1 = self.loop.create_task(wait()) t2 = self.loop.create_task(wait()) - self.loop.run_until_complete(asyncio.sleep(0.1, loop=self.loop)) - - self.loop.run_until_complete(self.loop.shutdown_asyncgens()) - self.assertEqual(finalized, 2) + self.loop.run_until_complete(asyncio.sleep(0.1)) # Silence warnings t1.cancel() t2.cancel() - self.loop.run_until_complete(asyncio.sleep(0.1, loop=self.loop)) - def test_async_gen_asyncio_shutdown_02(self): - logged = 0 + with self.assertRaises(asyncio.CancelledError): + self.loop.run_until_complete(t1) + with self.assertRaises(asyncio.CancelledError): + self.loop.run_until_complete(t2) - def logger(loop, context): - nonlocal logged - self.assertIn('asyncgen', context) - expected = 'an error occurred during closing of asynchronous' - if expected in context['message']: - logged += 1 - - async def waiter(timeout): - try: - await asyncio.sleep(timeout, loop=self.loop) - yield 1 - finally: - 1 / 0 - - async def wait(): - async for _ in waiter(1): - pass - - t = self.loop.create_task(wait()) - self.loop.run_until_complete(asyncio.sleep(0.1, loop=self.loop)) - - self.loop.set_exception_handler(logger) self.loop.run_until_complete(self.loop.shutdown_asyncgens()) - self.assertEqual(logged, 1) + self.assertEqual(finalized, 2) + + # TODO: RUSTPYTHON: async for gen expression compilation + # def test_async_gen_expression_01(self): + # async def arange(n): + # for i in range(n): + # await asyncio.sleep(0.01) + # yield i + + # def make_arange(n): + # # This syntax is legal starting with Python 3.7 + # return (i * 2 async for i in arange(n)) + + # async def run(): + # return [i async for i in make_arange(10)] + + # res = self.loop.run_until_complete(run()) + # self.assertEqual(res, [i * 2 for i in range(10)]) + + # def test_async_gen_expression_02(self): + # async def wrap(n): + # await asyncio.sleep(0.01) + # return n + + # def make_arange(n): + # # This syntax is legal starting with Python 3.7 + # return (i * 2 for i in range(n) if await wrap(i)) + + # async def run(): + # return [i async for i in make_arange(10)] + + # res = self.loop.run_until_complete(run()) + # self.assertEqual(res, [i * 2 for i in range(1, 10)]) + + def test_asyncgen_nonstarted_hooks_are_cancellable(self): + # See https://bugs.python.org/issue38013 + messages = [] + + def exception_handler(loop, context): + messages.append(context) + + async def async_iterate(): + yield 1 + yield 2 + + async def main(): + loop = asyncio.get_running_loop() + loop.set_exception_handler(exception_handler) + + async for i in async_iterate(): + break + + asyncio.run(main()) + + self.assertEqual([], messages) + + def test_async_gen_await_same_anext_coro_twice(self): + async def async_iterate(): + yield 1 + yield 2 + + async def run(): + it = async_iterate() + nxt = it.__anext__() + await nxt + with self.assertRaisesRegex( + RuntimeError, + r"cannot reuse already awaited __anext__\(\)/asend\(\)" + ): + await nxt + + await it.aclose() # prevent unfinished iterator warning + + self.loop.run_until_complete(run()) + + def test_async_gen_await_same_aclose_coro_twice(self): + async def async_iterate(): + yield 1 + yield 2 + + async def run(): + it = async_iterate() + nxt = it.aclose() + await nxt + with self.assertRaisesRegex( + RuntimeError, + r"cannot reuse already awaited aclose\(\)/athrow\(\)" + ): + await nxt + + self.loop.run_until_complete(run()) + + def test_async_gen_aclose_twice_with_different_coros(self): + # Regression test for https://bugs.python.org/issue39606 + async def async_iterate(): + yield 1 + yield 2 + + async def run(): + it = async_iterate() + await it.aclose() + await it.aclose() + + self.loop.run_until_complete(run()) + + def test_async_gen_aclose_after_exhaustion(self): + # Regression test for https://bugs.python.org/issue39606 + async def async_iterate(): + yield 1 + yield 2 + + async def run(): + it = async_iterate() + async for _ in it: + pass + await it.aclose() + + self.loop.run_until_complete(run()) + + def test_async_gen_aclose_compatible_with_get_stack(self): + async def async_generator(): + yield object() + + async def run(): + ag = async_generator() + asyncio.create_task(ag.aclose()) + tasks = asyncio.all_tasks() + for task in tasks: + # No AttributeError raised + task.get_stack() + + self.loop.run_until_complete(run()) - # Silence warnings - t.cancel() - self.loop.run_until_complete(asyncio.sleep(0.1, loop=self.loop)) if __name__ == "__main__": unittest.main()