mirror of
https://github.com/python/cpython.git
synced 2025-10-07 15:42:02 +00:00
Issue #28003: Implement PEP 525 -- Asynchronous Generators.
This commit is contained in:
parent
b96ef55d49
commit
eb6364557f
27 changed files with 2189 additions and 96 deletions
823
Lib/test/test_asyncgen.py
Normal file
823
Lib/test/test_asyncgen.py
Normal file
|
@ -0,0 +1,823 @@
|
|||
import asyncio
|
||||
import inspect
|
||||
import sys
|
||||
import types
|
||||
import unittest
|
||||
|
||||
from unittest import mock
|
||||
|
||||
|
||||
class AwaitException(Exception):
|
||||
pass
|
||||
|
||||
|
||||
@types.coroutine
|
||||
def awaitable(*, throw=False):
|
||||
if throw:
|
||||
yield ('throw',)
|
||||
else:
|
||||
yield ('result',)
|
||||
|
||||
|
||||
def run_until_complete(coro):
|
||||
exc = False
|
||||
while True:
|
||||
try:
|
||||
if exc:
|
||||
exc = False
|
||||
fut = coro.throw(AwaitException)
|
||||
else:
|
||||
fut = coro.send(None)
|
||||
except StopIteration as ex:
|
||||
return ex.args[0]
|
||||
|
||||
if fut == ('throw',):
|
||||
exc = True
|
||||
|
||||
|
||||
def to_list(gen):
|
||||
async def iterate():
|
||||
res = []
|
||||
async for i in gen:
|
||||
res.append(i)
|
||||
return res
|
||||
|
||||
return run_until_complete(iterate())
|
||||
|
||||
|
||||
class AsyncGenSyntaxTest(unittest.TestCase):
|
||||
|
||||
def test_async_gen_syntax_01(self):
|
||||
code = '''async def foo():
|
||||
await abc
|
||||
yield from 123
|
||||
'''
|
||||
|
||||
with self.assertRaisesRegex(SyntaxError, 'yield from.*inside async'):
|
||||
exec(code, {}, {})
|
||||
|
||||
def test_async_gen_syntax_02(self):
|
||||
code = '''async def foo():
|
||||
yield from 123
|
||||
'''
|
||||
|
||||
with self.assertRaisesRegex(SyntaxError, 'yield from.*inside async'):
|
||||
exec(code, {}, {})
|
||||
|
||||
def test_async_gen_syntax_03(self):
|
||||
code = '''async def foo():
|
||||
await abc
|
||||
yield
|
||||
return 123
|
||||
'''
|
||||
|
||||
with self.assertRaisesRegex(SyntaxError, 'return.*value.*async gen'):
|
||||
exec(code, {}, {})
|
||||
|
||||
def test_async_gen_syntax_04(self):
|
||||
code = '''async def foo():
|
||||
yield
|
||||
return 123
|
||||
'''
|
||||
|
||||
with self.assertRaisesRegex(SyntaxError, 'return.*value.*async gen'):
|
||||
exec(code, {}, {})
|
||||
|
||||
def test_async_gen_syntax_05(self):
|
||||
code = '''async def foo():
|
||||
if 0:
|
||||
yield
|
||||
return 12
|
||||
'''
|
||||
|
||||
with self.assertRaisesRegex(SyntaxError, 'return.*value.*async gen'):
|
||||
exec(code, {}, {})
|
||||
|
||||
|
||||
class AsyncGenTest(unittest.TestCase):
|
||||
|
||||
def compare_generators(self, sync_gen, async_gen):
|
||||
def sync_iterate(g):
|
||||
res = []
|
||||
while True:
|
||||
try:
|
||||
res.append(g.__next__())
|
||||
except StopIteration:
|
||||
res.append('STOP')
|
||||
break
|
||||
except Exception as ex:
|
||||
res.append(str(type(ex)))
|
||||
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)
|
||||
return async_gen_result
|
||||
|
||||
def test_async_gen_iteration_01(self):
|
||||
async def gen():
|
||||
await awaitable()
|
||||
a = yield 123
|
||||
self.assertIs(a, None)
|
||||
await awaitable()
|
||||
yield 456
|
||||
await awaitable()
|
||||
yield 789
|
||||
|
||||
self.assertEqual(to_list(gen()), [123, 456, 789])
|
||||
|
||||
def test_async_gen_iteration_02(self):
|
||||
async def gen():
|
||||
await awaitable()
|
||||
yield 123
|
||||
await awaitable()
|
||||
|
||||
g = gen()
|
||||
ai = g.__aiter__()
|
||||
self.assertEqual(ai.__anext__().__next__(), ('result',))
|
||||
|
||||
try:
|
||||
ai.__anext__().__next__()
|
||||
except StopIteration as ex:
|
||||
self.assertEqual(ex.args[0], 123)
|
||||
else:
|
||||
self.fail('StopIteration was not raised')
|
||||
|
||||
self.assertEqual(ai.__anext__().__next__(), ('result',))
|
||||
|
||||
try:
|
||||
ai.__anext__().__next__()
|
||||
except StopAsyncIteration as ex:
|
||||
self.assertFalse(ex.args)
|
||||
else:
|
||||
self.fail('StopAsyncIteration was not raised')
|
||||
|
||||
def test_async_gen_exception_03(self):
|
||||
async def gen():
|
||||
await awaitable()
|
||||
yield 123
|
||||
await awaitable(throw=True)
|
||||
yield 456
|
||||
|
||||
with self.assertRaises(AwaitException):
|
||||
to_list(gen())
|
||||
|
||||
def test_async_gen_exception_04(self):
|
||||
async def gen():
|
||||
await awaitable()
|
||||
yield 123
|
||||
1 / 0
|
||||
|
||||
g = gen()
|
||||
ai = g.__aiter__()
|
||||
self.assertEqual(ai.__anext__().__next__(), ('result',))
|
||||
|
||||
try:
|
||||
ai.__anext__().__next__()
|
||||
except StopIteration as ex:
|
||||
self.assertEqual(ex.args[0], 123)
|
||||
else:
|
||||
self.fail('StopIteration was not raised')
|
||||
|
||||
with self.assertRaises(ZeroDivisionError):
|
||||
ai.__anext__().__next__()
|
||||
|
||||
def test_async_gen_exception_05(self):
|
||||
async def gen():
|
||||
yield 123
|
||||
raise StopAsyncIteration
|
||||
|
||||
with self.assertRaisesRegex(RuntimeError,
|
||||
'async generator.*StopAsyncIteration'):
|
||||
to_list(gen())
|
||||
|
||||
def test_async_gen_exception_06(self):
|
||||
async def gen():
|
||||
yield 123
|
||||
raise StopIteration
|
||||
|
||||
with self.assertRaisesRegex(RuntimeError,
|
||||
'async generator.*StopIteration'):
|
||||
to_list(gen())
|
||||
|
||||
def test_async_gen_exception_07(self):
|
||||
def sync_gen():
|
||||
try:
|
||||
yield 1
|
||||
1 / 0
|
||||
finally:
|
||||
yield 2
|
||||
yield 3
|
||||
|
||||
yield 100
|
||||
|
||||
async def async_gen():
|
||||
try:
|
||||
yield 1
|
||||
1 / 0
|
||||
finally:
|
||||
yield 2
|
||||
yield 3
|
||||
|
||||
yield 100
|
||||
|
||||
self.compare_generators(sync_gen(), async_gen())
|
||||
|
||||
def test_async_gen_exception_08(self):
|
||||
def sync_gen():
|
||||
try:
|
||||
yield 1
|
||||
finally:
|
||||
yield 2
|
||||
1 / 0
|
||||
yield 3
|
||||
|
||||
yield 100
|
||||
|
||||
async def async_gen():
|
||||
try:
|
||||
yield 1
|
||||
await awaitable()
|
||||
finally:
|
||||
await awaitable()
|
||||
yield 2
|
||||
1 / 0
|
||||
yield 3
|
||||
|
||||
yield 100
|
||||
|
||||
self.compare_generators(sync_gen(), async_gen())
|
||||
|
||||
def test_async_gen_exception_09(self):
|
||||
def sync_gen():
|
||||
try:
|
||||
yield 1
|
||||
1 / 0
|
||||
finally:
|
||||
yield 2
|
||||
yield 3
|
||||
|
||||
yield 100
|
||||
|
||||
async def async_gen():
|
||||
try:
|
||||
await awaitable()
|
||||
yield 1
|
||||
1 / 0
|
||||
finally:
|
||||
yield 2
|
||||
await awaitable()
|
||||
yield 3
|
||||
|
||||
yield 100
|
||||
|
||||
self.compare_generators(sync_gen(), async_gen())
|
||||
|
||||
def test_async_gen_exception_10(self):
|
||||
async def gen():
|
||||
yield 123
|
||||
with self.assertRaisesRegex(TypeError,
|
||||
"non-None value .* async generator"):
|
||||
gen().__anext__().send(100)
|
||||
|
||||
def test_async_gen_api_01(self):
|
||||
async def gen():
|
||||
yield 123
|
||||
|
||||
g = gen()
|
||||
|
||||
self.assertEqual(g.__name__, 'gen')
|
||||
g.__name__ = '123'
|
||||
self.assertEqual(g.__name__, '123')
|
||||
|
||||
self.assertIn('.gen', g.__qualname__)
|
||||
g.__qualname__ = '123'
|
||||
self.assertEqual(g.__qualname__, '123')
|
||||
|
||||
self.assertIsNone(g.ag_await)
|
||||
self.assertIsInstance(g.ag_frame, types.FrameType)
|
||||
self.assertFalse(g.ag_running)
|
||||
self.assertIsInstance(g.ag_code, types.CodeType)
|
||||
|
||||
self.assertTrue(inspect.isawaitable(g.aclose()))
|
||||
|
||||
|
||||
class AsyncGenAsyncioTest(unittest.TestCase):
|
||||
|
||||
def setUp(self):
|
||||
self.loop = asyncio.new_event_loop()
|
||||
asyncio.set_event_loop(None)
|
||||
|
||||
def tearDown(self):
|
||||
self.loop.close()
|
||||
self.loop = None
|
||||
|
||||
async def to_list(self, gen):
|
||||
res = []
|
||||
async for i in gen:
|
||||
res.append(i)
|
||||
return res
|
||||
|
||||
def test_async_gen_asyncio_01(self):
|
||||
async def gen():
|
||||
yield 1
|
||||
await asyncio.sleep(0.01, loop=self.loop)
|
||||
yield 2
|
||||
await asyncio.sleep(0.01, loop=self.loop)
|
||||
return
|
||||
yield 3
|
||||
|
||||
res = self.loop.run_until_complete(self.to_list(gen()))
|
||||
self.assertEqual(res, [1, 2])
|
||||
|
||||
def test_async_gen_asyncio_02(self):
|
||||
async def gen():
|
||||
yield 1
|
||||
await asyncio.sleep(0.01, loop=self.loop)
|
||||
yield 2
|
||||
1 / 0
|
||||
yield 3
|
||||
|
||||
with self.assertRaises(ZeroDivisionError):
|
||||
self.loop.run_until_complete(self.to_list(gen()))
|
||||
|
||||
def test_async_gen_asyncio_03(self):
|
||||
loop = self.loop
|
||||
|
||||
class Gen:
|
||||
async def __aiter__(self):
|
||||
yield 1
|
||||
await asyncio.sleep(0.01, loop=loop)
|
||||
yield 2
|
||||
|
||||
res = loop.run_until_complete(self.to_list(Gen()))
|
||||
self.assertEqual(res, [1, 2])
|
||||
|
||||
def test_async_gen_asyncio_anext_04(self):
|
||||
async def foo():
|
||||
yield 1
|
||||
await asyncio.sleep(0.01, loop=self.loop)
|
||||
try:
|
||||
yield 2
|
||||
yield 3
|
||||
except ZeroDivisionError:
|
||||
yield 1000
|
||||
await asyncio.sleep(0.01, loop=self.loop)
|
||||
yield 4
|
||||
|
||||
async def run1():
|
||||
it = foo().__aiter__()
|
||||
|
||||
self.assertEqual(await it.__anext__(), 1)
|
||||
self.assertEqual(await it.__anext__(), 2)
|
||||
self.assertEqual(await it.__anext__(), 3)
|
||||
self.assertEqual(await it.__anext__(), 4)
|
||||
with self.assertRaises(StopAsyncIteration):
|
||||
await it.__anext__()
|
||||
with self.assertRaises(StopAsyncIteration):
|
||||
await it.__anext__()
|
||||
|
||||
async def run2():
|
||||
it = foo().__aiter__()
|
||||
|
||||
self.assertEqual(await it.__anext__(), 1)
|
||||
self.assertEqual(await it.__anext__(), 2)
|
||||
try:
|
||||
it.__anext__().throw(ZeroDivisionError)
|
||||
except StopIteration as ex:
|
||||
self.assertEqual(ex.args[0], 1000)
|
||||
else:
|
||||
self.fail('StopIteration was not raised')
|
||||
self.assertEqual(await it.__anext__(), 4)
|
||||
with self.assertRaises(StopAsyncIteration):
|
||||
await it.__anext__()
|
||||
|
||||
self.loop.run_until_complete(run1())
|
||||
self.loop.run_until_complete(run2())
|
||||
|
||||
def test_async_gen_asyncio_anext_05(self):
|
||||
async def foo():
|
||||
v = yield 1
|
||||
v = yield v
|
||||
yield v * 100
|
||||
|
||||
async def run():
|
||||
it = foo().__aiter__()
|
||||
|
||||
try:
|
||||
it.__anext__().send(None)
|
||||
except StopIteration as ex:
|
||||
self.assertEqual(ex.args[0], 1)
|
||||
else:
|
||||
self.fail('StopIteration was not raised')
|
||||
|
||||
try:
|
||||
it.__anext__().send(10)
|
||||
except StopIteration as ex:
|
||||
self.assertEqual(ex.args[0], 10)
|
||||
else:
|
||||
self.fail('StopIteration was not raised')
|
||||
|
||||
try:
|
||||
it.__anext__().send(12)
|
||||
except StopIteration as ex:
|
||||
self.assertEqual(ex.args[0], 1200)
|
||||
else:
|
||||
self.fail('StopIteration was not raised')
|
||||
|
||||
with self.assertRaises(StopAsyncIteration):
|
||||
await it.__anext__()
|
||||
|
||||
self.loop.run_until_complete(run())
|
||||
|
||||
def test_async_gen_asyncio_aclose_06(self):
|
||||
async def foo():
|
||||
try:
|
||||
yield 1
|
||||
1 / 0
|
||||
finally:
|
||||
await asyncio.sleep(0.01, loop=self.loop)
|
||||
yield 12
|
||||
|
||||
async def run():
|
||||
gen = foo()
|
||||
it = gen.__aiter__()
|
||||
await it.__anext__()
|
||||
await gen.aclose()
|
||||
|
||||
with self.assertRaisesRegex(
|
||||
RuntimeError,
|
||||
"async generator ignored GeneratorExit"):
|
||||
self.loop.run_until_complete(run())
|
||||
|
||||
def test_async_gen_asyncio_aclose_07(self):
|
||||
DONE = 0
|
||||
|
||||
async def foo():
|
||||
nonlocal DONE
|
||||
try:
|
||||
yield 1
|
||||
1 / 0
|
||||
finally:
|
||||
await asyncio.sleep(0.01, loop=self.loop)
|
||||
await asyncio.sleep(0.01, loop=self.loop)
|
||||
DONE += 1
|
||||
DONE += 1000
|
||||
|
||||
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_aclose_08(self):
|
||||
DONE = 0
|
||||
|
||||
fut = asyncio.Future(loop=self.loop)
|
||||
|
||||
async def foo():
|
||||
nonlocal DONE
|
||||
try:
|
||||
yield 1
|
||||
await fut
|
||||
DONE += 1000
|
||||
yield 2
|
||||
finally:
|
||||
await asyncio.sleep(0.01, loop=self.loop)
|
||||
await asyncio.sleep(0.01, loop=self.loop)
|
||||
DONE += 1
|
||||
DONE += 1000
|
||||
|
||||
async def run():
|
||||
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.assertEqual(DONE, 1)
|
||||
|
||||
# Silence ResourceWarnings
|
||||
fut.cancel()
|
||||
t.cancel()
|
||||
self.loop.run_until_complete(asyncio.sleep(0.01, loop=self.loop))
|
||||
|
||||
def test_async_gen_asyncio_gc_aclose_09(self):
|
||||
DONE = 0
|
||||
|
||||
async def gen():
|
||||
nonlocal DONE
|
||||
try:
|
||||
while True:
|
||||
yield 1
|
||||
finally:
|
||||
await asyncio.sleep(0.01, loop=self.loop)
|
||||
await asyncio.sleep(0.01, loop=self.loop)
|
||||
DONE = 1
|
||||
|
||||
async def run():
|
||||
g = gen()
|
||||
await g.__anext__()
|
||||
await g.__anext__()
|
||||
del g
|
||||
|
||||
await asyncio.sleep(0.1, loop=self.loop)
|
||||
|
||||
self.loop.run_until_complete(run())
|
||||
self.assertEqual(DONE, 1)
|
||||
|
||||
def test_async_gen_asyncio_asend_01(self):
|
||||
DONE = 0
|
||||
|
||||
# Sanity check:
|
||||
def sgen():
|
||||
v = yield 1
|
||||
yield v * 2
|
||||
sg = sgen()
|
||||
v = sg.send(None)
|
||||
self.assertEqual(v, 1)
|
||||
v = sg.send(100)
|
||||
self.assertEqual(v, 200)
|
||||
|
||||
async def gen():
|
||||
nonlocal DONE
|
||||
try:
|
||||
await asyncio.sleep(0.01, loop=self.loop)
|
||||
v = yield 1
|
||||
await asyncio.sleep(0.01, loop=self.loop)
|
||||
yield v * 2
|
||||
await asyncio.sleep(0.01, loop=self.loop)
|
||||
return
|
||||
finally:
|
||||
await asyncio.sleep(0.01, loop=self.loop)
|
||||
await asyncio.sleep(0.01, loop=self.loop)
|
||||
DONE = 1
|
||||
|
||||
async def run():
|
||||
g = gen()
|
||||
|
||||
v = await g.asend(None)
|
||||
self.assertEqual(v, 1)
|
||||
|
||||
v = await g.asend(100)
|
||||
self.assertEqual(v, 200)
|
||||
|
||||
with self.assertRaises(StopAsyncIteration):
|
||||
await g.asend(None)
|
||||
|
||||
self.loop.run_until_complete(run())
|
||||
self.assertEqual(DONE, 1)
|
||||
|
||||
def test_async_gen_asyncio_asend_02(self):
|
||||
DONE = 0
|
||||
|
||||
async def sleep_n_crash(delay):
|
||||
await asyncio.sleep(delay, loop=self.loop)
|
||||
1 / 0
|
||||
|
||||
async def gen():
|
||||
nonlocal DONE
|
||||
try:
|
||||
await asyncio.sleep(0.01, loop=self.loop)
|
||||
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)
|
||||
DONE = 1
|
||||
|
||||
async def run():
|
||||
g = gen()
|
||||
|
||||
v = await g.asend(None)
|
||||
self.assertEqual(v, 1)
|
||||
|
||||
await g.asend(100)
|
||||
|
||||
with self.assertRaises(ZeroDivisionError):
|
||||
self.loop.run_until_complete(run())
|
||||
self.assertEqual(DONE, 1)
|
||||
|
||||
def test_async_gen_asyncio_asend_03(self):
|
||||
DONE = 0
|
||||
|
||||
async def sleep_n_crash(delay):
|
||||
fut = asyncio.ensure_future(asyncio.sleep(delay, loop=self.loop),
|
||||
loop=self.loop)
|
||||
self.loop.call_later(delay / 2, lambda: fut.cancel())
|
||||
return await fut
|
||||
|
||||
async def gen():
|
||||
nonlocal DONE
|
||||
try:
|
||||
await asyncio.sleep(0.01, loop=self.loop)
|
||||
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)
|
||||
DONE = 1
|
||||
|
||||
async def run():
|
||||
g = gen()
|
||||
|
||||
v = await g.asend(None)
|
||||
self.assertEqual(v, 1)
|
||||
|
||||
await g.asend(100)
|
||||
|
||||
with self.assertRaises(asyncio.CancelledError):
|
||||
self.loop.run_until_complete(run())
|
||||
self.assertEqual(DONE, 1)
|
||||
|
||||
def test_async_gen_asyncio_athrow_01(self):
|
||||
DONE = 0
|
||||
|
||||
class FooEr(Exception):
|
||||
pass
|
||||
|
||||
# Sanity check:
|
||||
def sgen():
|
||||
try:
|
||||
v = yield 1
|
||||
except FooEr:
|
||||
v = 1000
|
||||
yield v * 2
|
||||
sg = sgen()
|
||||
v = sg.send(None)
|
||||
self.assertEqual(v, 1)
|
||||
v = sg.throw(FooEr)
|
||||
self.assertEqual(v, 2000)
|
||||
with self.assertRaises(StopIteration):
|
||||
sg.send(None)
|
||||
|
||||
async def gen():
|
||||
nonlocal DONE
|
||||
try:
|
||||
await asyncio.sleep(0.01, loop=self.loop)
|
||||
try:
|
||||
v = yield 1
|
||||
except FooEr:
|
||||
v = 1000
|
||||
await asyncio.sleep(0.01, loop=self.loop)
|
||||
yield v * 2
|
||||
await asyncio.sleep(0.01, loop=self.loop)
|
||||
# return
|
||||
finally:
|
||||
await asyncio.sleep(0.01, loop=self.loop)
|
||||
await asyncio.sleep(0.01, loop=self.loop)
|
||||
DONE = 1
|
||||
|
||||
async def run():
|
||||
g = gen()
|
||||
|
||||
v = await g.asend(None)
|
||||
self.assertEqual(v, 1)
|
||||
|
||||
v = await g.athrow(FooEr)
|
||||
self.assertEqual(v, 2000)
|
||||
|
||||
with self.assertRaises(StopAsyncIteration):
|
||||
await g.asend(None)
|
||||
|
||||
self.loop.run_until_complete(run())
|
||||
self.assertEqual(DONE, 1)
|
||||
|
||||
def test_async_gen_asyncio_athrow_02(self):
|
||||
DONE = 0
|
||||
|
||||
class FooEr(Exception):
|
||||
pass
|
||||
|
||||
async def sleep_n_crash(delay):
|
||||
fut = asyncio.ensure_future(asyncio.sleep(delay, loop=self.loop),
|
||||
loop=self.loop)
|
||||
self.loop.call_later(delay / 2, lambda: fut.cancel())
|
||||
return await fut
|
||||
|
||||
async def gen():
|
||||
nonlocal DONE
|
||||
try:
|
||||
await asyncio.sleep(0.01, loop=self.loop)
|
||||
try:
|
||||
v = yield 1
|
||||
except FooEr:
|
||||
await sleep_n_crash(0.01)
|
||||
yield v * 2
|
||||
await asyncio.sleep(0.01, loop=self.loop)
|
||||
# return
|
||||
finally:
|
||||
await asyncio.sleep(0.01, loop=self.loop)
|
||||
await asyncio.sleep(0.01, loop=self.loop)
|
||||
DONE = 1
|
||||
|
||||
async def run():
|
||||
g = gen()
|
||||
|
||||
v = await g.asend(None)
|
||||
self.assertEqual(v, 1)
|
||||
|
||||
try:
|
||||
await g.athrow(FooEr)
|
||||
except asyncio.CancelledError:
|
||||
self.assertEqual(DONE, 1)
|
||||
raise
|
||||
else:
|
||||
self.fail('CancelledError was not raised')
|
||||
|
||||
with self.assertRaises(asyncio.CancelledError):
|
||||
self.loop.run_until_complete(run())
|
||||
self.assertEqual(DONE, 1)
|
||||
|
||||
def test_async_gen_asyncio_shutdown_01(self):
|
||||
finalized = 0
|
||||
|
||||
async def waiter(timeout):
|
||||
nonlocal finalized
|
||||
try:
|
||||
await asyncio.sleep(timeout, loop=self.loop)
|
||||
yield 1
|
||||
finally:
|
||||
await asyncio.sleep(0, loop=self.loop)
|
||||
finalized += 1
|
||||
|
||||
async def wait():
|
||||
async for _ in waiter(1):
|
||||
pass
|
||||
|
||||
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)
|
||||
|
||||
# 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
|
||||
|
||||
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)
|
||||
|
||||
# Silence warnings
|
||||
t.cancel()
|
||||
self.loop.run_until_complete(asyncio.sleep(0.1, loop=self.loop))
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
Loading…
Add table
Add a link
Reference in a new issue