mirror of
https://github.com/python/cpython.git
synced 2025-07-16 15:55:18 +00:00

- Add requires_fork and requires_subprocess to more tests - Skip extension import tests if dlopen is not available - Don't assume that _testcapi is a shared extension - Skip a lot of socket tests that don't work on Emscripten - Skip mmap tests, mmap emulation is incomplete - venv does not work yet - Cannot get libc from executable The "entire" test suite is now passing on Emscripten with EMSDK from git head (91 suites are skipped).
1677 lines
47 KiB
Python
1677 lines
47 KiB
Python
import inspect
|
|
import types
|
|
import unittest
|
|
import contextlib
|
|
|
|
from test.support.import_helper import import_module
|
|
from test.support import gc_collect, requires_working_socket
|
|
asyncio = import_module("asyncio")
|
|
|
|
|
|
requires_working_socket(module=True)
|
|
|
|
_no_default = object()
|
|
|
|
|
|
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())
|
|
|
|
|
|
def py_anext(iterator, default=_no_default):
|
|
"""Pure-Python implementation of anext() for testing purposes.
|
|
|
|
Closely matches the builtin anext() C implementation.
|
|
Can be used to compare the built-in implementation of the inner
|
|
coroutines machinery to C-implementation of __anext__() and send()
|
|
or throw() on the returned generator.
|
|
"""
|
|
|
|
try:
|
|
__anext__ = type(iterator).__anext__
|
|
except AttributeError:
|
|
raise TypeError(f'{iterator!r} is not an async iterator')
|
|
|
|
if default is _no_default:
|
|
return __anext__(iterator)
|
|
|
|
async def anext_impl():
|
|
try:
|
|
# The C code is way more low-level than this, as it implements
|
|
# all methods of the iterator protocol. In this implementation
|
|
# we're relying on higher-level coroutine concepts, but that's
|
|
# exactly what we want -- crosstest pure-Python high-level
|
|
# implementation and low-level C anext() iterators.
|
|
return await __anext__(iterator)
|
|
except StopAsyncIteration:
|
|
return default
|
|
|
|
return anext_impl()
|
|
|
|
|
|
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:
|
|
an = g.__anext__()
|
|
try:
|
|
while True:
|
|
try:
|
|
an.__next__()
|
|
except StopIteration as ex:
|
|
if ex.args:
|
|
res.append(ex.args[0])
|
|
break
|
|
else:
|
|
res.append('EMPTY StopIteration')
|
|
break
|
|
except StopAsyncIteration:
|
|
raise
|
|
except Exception as ex:
|
|
res.append(str(type(ex)))
|
|
break
|
|
except StopAsyncIteration:
|
|
res.append('STOP')
|
|
break
|
|
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__()
|
|
|
|
an = ai.__anext__()
|
|
self.assertEqual(an.__next__(), ('result',))
|
|
|
|
try:
|
|
an.__next__()
|
|
except StopIteration as ex:
|
|
self.assertEqual(ex.args[0], 123)
|
|
else:
|
|
self.fail('StopIteration was not raised')
|
|
|
|
an = ai.__anext__()
|
|
self.assertEqual(an.__next__(), ('result',))
|
|
|
|
try:
|
|
an.__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__()
|
|
an = ai.__anext__()
|
|
self.assertEqual(an.__next__(), ('result',))
|
|
|
|
try:
|
|
an.__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_exception_11(self):
|
|
def sync_gen():
|
|
yield 10
|
|
yield 20
|
|
|
|
def sync_gen_wrapper():
|
|
yield 1
|
|
sg = sync_gen()
|
|
sg.send(None)
|
|
try:
|
|
sg.throw(GeneratorExit())
|
|
except GeneratorExit:
|
|
yield 2
|
|
yield 3
|
|
|
|
async def async_gen():
|
|
yield 10
|
|
yield 20
|
|
|
|
async def async_gen_wrapper():
|
|
yield 1
|
|
asg = async_gen()
|
|
await asg.asend(None)
|
|
try:
|
|
await asg.athrow(GeneratorExit())
|
|
except GeneratorExit:
|
|
yield 2
|
|
yield 3
|
|
|
|
self.compare_generators(sync_gen_wrapper(), async_gen_wrapper())
|
|
|
|
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
|
|
asyncio.set_event_loop_policy(None)
|
|
|
|
def check_async_iterator_anext(self, ait_class):
|
|
with self.subTest(anext="pure-Python"):
|
|
self._check_async_iterator_anext(ait_class, py_anext)
|
|
with self.subTest(anext="builtin"):
|
|
self._check_async_iterator_anext(ait_class, anext)
|
|
|
|
def _check_async_iterator_anext(self, ait_class, anext):
|
|
g = ait_class()
|
|
async def consume():
|
|
results = []
|
|
results.append(await anext(g))
|
|
results.append(await anext(g))
|
|
results.append(await anext(g, 'buckle my shoe'))
|
|
return results
|
|
res = self.loop.run_until_complete(consume())
|
|
self.assertEqual(res, [1, 2, 'buckle my shoe'])
|
|
with self.assertRaises(StopAsyncIteration):
|
|
self.loop.run_until_complete(consume())
|
|
|
|
async def test_2():
|
|
g1 = ait_class()
|
|
self.assertEqual(await anext(g1), 1)
|
|
self.assertEqual(await anext(g1), 2)
|
|
with self.assertRaises(StopAsyncIteration):
|
|
await anext(g1)
|
|
with self.assertRaises(StopAsyncIteration):
|
|
await anext(g1)
|
|
|
|
g2 = ait_class()
|
|
self.assertEqual(await anext(g2, "default"), 1)
|
|
self.assertEqual(await anext(g2, "default"), 2)
|
|
self.assertEqual(await anext(g2, "default"), "default")
|
|
self.assertEqual(await anext(g2, "default"), "default")
|
|
|
|
return "completed"
|
|
|
|
result = self.loop.run_until_complete(test_2())
|
|
self.assertEqual(result, "completed")
|
|
|
|
def test_send():
|
|
p = ait_class()
|
|
obj = anext(p, "completed")
|
|
with self.assertRaises(StopIteration):
|
|
with contextlib.closing(obj.__await__()) as g:
|
|
g.send(None)
|
|
|
|
test_send()
|
|
|
|
async def test_throw():
|
|
p = ait_class()
|
|
obj = anext(p, "completed")
|
|
self.assertRaises(SyntaxError, obj.throw, SyntaxError)
|
|
return "completed"
|
|
|
|
result = self.loop.run_until_complete(test_throw())
|
|
self.assertEqual(result, "completed")
|
|
|
|
def test_async_generator_anext(self):
|
|
async def agen():
|
|
yield 1
|
|
yield 2
|
|
self.check_async_iterator_anext(agen)
|
|
|
|
def test_python_async_iterator_anext(self):
|
|
class MyAsyncIter:
|
|
"""Asynchronously yield 1, then 2."""
|
|
def __init__(self):
|
|
self.yielded = 0
|
|
def __aiter__(self):
|
|
return self
|
|
async def __anext__(self):
|
|
if self.yielded >= 2:
|
|
raise StopAsyncIteration()
|
|
else:
|
|
self.yielded += 1
|
|
return self.yielded
|
|
self.check_async_iterator_anext(MyAsyncIter)
|
|
|
|
def test_python_async_iterator_types_coroutine_anext(self):
|
|
import types
|
|
class MyAsyncIterWithTypesCoro:
|
|
"""Asynchronously yield 1, then 2."""
|
|
def __init__(self):
|
|
self.yielded = 0
|
|
def __aiter__(self):
|
|
return self
|
|
@types.coroutine
|
|
def __anext__(self):
|
|
if False:
|
|
yield "this is a generator-based coroutine"
|
|
if self.yielded >= 2:
|
|
raise StopAsyncIteration()
|
|
else:
|
|
self.yielded += 1
|
|
return self.yielded
|
|
self.check_async_iterator_anext(MyAsyncIterWithTypesCoro)
|
|
|
|
def test_async_gen_aiter(self):
|
|
async def gen():
|
|
yield 1
|
|
yield 2
|
|
g = gen()
|
|
async def consume():
|
|
return [i async for i in aiter(g)]
|
|
res = self.loop.run_until_complete(consume())
|
|
self.assertEqual(res, [1, 2])
|
|
|
|
def test_async_gen_aiter_class(self):
|
|
results = []
|
|
class Gen:
|
|
async def __aiter__(self):
|
|
yield 1
|
|
yield 2
|
|
g = Gen()
|
|
async def consume():
|
|
ait = aiter(g)
|
|
while True:
|
|
try:
|
|
results.append(await anext(ait))
|
|
except StopAsyncIteration:
|
|
break
|
|
self.loop.run_until_complete(consume())
|
|
self.assertEqual(results, [1, 2])
|
|
|
|
def test_aiter_idempotent(self):
|
|
async def gen():
|
|
yield 1
|
|
applied_once = aiter(gen())
|
|
applied_twice = aiter(applied_once)
|
|
self.assertIs(applied_once, applied_twice)
|
|
|
|
def test_anext_bad_args(self):
|
|
async def gen():
|
|
yield 1
|
|
async def call_with_too_few_args():
|
|
await anext()
|
|
async def call_with_too_many_args():
|
|
await anext(gen(), 1, 3)
|
|
async def call_with_wrong_type_args():
|
|
await anext(1, gen())
|
|
async def call_with_kwarg():
|
|
await anext(aiterator=gen())
|
|
with self.assertRaises(TypeError):
|
|
self.loop.run_until_complete(call_with_too_few_args())
|
|
with self.assertRaises(TypeError):
|
|
self.loop.run_until_complete(call_with_too_many_args())
|
|
with self.assertRaises(TypeError):
|
|
self.loop.run_until_complete(call_with_wrong_type_args())
|
|
with self.assertRaises(TypeError):
|
|
self.loop.run_until_complete(call_with_kwarg())
|
|
|
|
def test_anext_bad_await(self):
|
|
async def bad_awaitable():
|
|
class BadAwaitable:
|
|
def __await__(self):
|
|
return 42
|
|
class MyAsyncIter:
|
|
def __aiter__(self):
|
|
return self
|
|
def __anext__(self):
|
|
return BadAwaitable()
|
|
regex = r"__await__.*iterator"
|
|
awaitable = anext(MyAsyncIter(), "default")
|
|
with self.assertRaisesRegex(TypeError, regex):
|
|
await awaitable
|
|
awaitable = anext(MyAsyncIter())
|
|
with self.assertRaisesRegex(TypeError, regex):
|
|
await awaitable
|
|
return "completed"
|
|
result = self.loop.run_until_complete(bad_awaitable())
|
|
self.assertEqual(result, "completed")
|
|
|
|
async def check_anext_returning_iterator(self, aiter_class):
|
|
awaitable = anext(aiter_class(), "default")
|
|
with self.assertRaises(TypeError):
|
|
await awaitable
|
|
awaitable = anext(aiter_class())
|
|
with self.assertRaises(TypeError):
|
|
await awaitable
|
|
return "completed"
|
|
|
|
def test_anext_return_iterator(self):
|
|
class WithIterAnext:
|
|
def __aiter__(self):
|
|
return self
|
|
def __anext__(self):
|
|
return iter("abc")
|
|
result = self.loop.run_until_complete(self.check_anext_returning_iterator(WithIterAnext))
|
|
self.assertEqual(result, "completed")
|
|
|
|
def test_anext_return_generator(self):
|
|
class WithGenAnext:
|
|
def __aiter__(self):
|
|
return self
|
|
def __anext__(self):
|
|
yield
|
|
result = self.loop.run_until_complete(self.check_anext_returning_iterator(WithGenAnext))
|
|
self.assertEqual(result, "completed")
|
|
|
|
def test_anext_await_raises(self):
|
|
class RaisingAwaitable:
|
|
def __await__(self):
|
|
raise ZeroDivisionError()
|
|
yield
|
|
class WithRaisingAwaitableAnext:
|
|
def __aiter__(self):
|
|
return self
|
|
def __anext__(self):
|
|
return RaisingAwaitable()
|
|
async def do_test():
|
|
awaitable = anext(WithRaisingAwaitableAnext())
|
|
with self.assertRaises(ZeroDivisionError):
|
|
await awaitable
|
|
awaitable = anext(WithRaisingAwaitableAnext(), "default")
|
|
with self.assertRaises(ZeroDivisionError):
|
|
await awaitable
|
|
return "completed"
|
|
result = self.loop.run_until_complete(do_test())
|
|
self.assertEqual(result, "completed")
|
|
|
|
def test_anext_iter(self):
|
|
@types.coroutine
|
|
def _async_yield(v):
|
|
return (yield v)
|
|
|
|
class MyError(Exception):
|
|
pass
|
|
|
|
async def agenfn():
|
|
try:
|
|
await _async_yield(1)
|
|
except MyError:
|
|
await _async_yield(2)
|
|
return
|
|
yield
|
|
|
|
def test1(anext):
|
|
agen = agenfn()
|
|
with contextlib.closing(anext(agen, "default").__await__()) as g:
|
|
self.assertEqual(g.send(None), 1)
|
|
self.assertEqual(g.throw(MyError, MyError(), None), 2)
|
|
try:
|
|
g.send(None)
|
|
except StopIteration as e:
|
|
err = e
|
|
else:
|
|
self.fail('StopIteration was not raised')
|
|
self.assertEqual(err.value, "default")
|
|
|
|
def test2(anext):
|
|
agen = agenfn()
|
|
with contextlib.closing(anext(agen, "default").__await__()) as g:
|
|
self.assertEqual(g.send(None), 1)
|
|
self.assertEqual(g.throw(MyError, MyError(), None), 2)
|
|
with self.assertRaises(MyError):
|
|
g.throw(MyError, MyError(), None)
|
|
|
|
def test3(anext):
|
|
agen = agenfn()
|
|
with contextlib.closing(anext(agen, "default").__await__()) as g:
|
|
self.assertEqual(g.send(None), 1)
|
|
g.close()
|
|
with self.assertRaisesRegex(RuntimeError, 'cannot reuse'):
|
|
self.assertEqual(g.send(None), 1)
|
|
|
|
def test4(anext):
|
|
@types.coroutine
|
|
def _async_yield(v):
|
|
yield v * 10
|
|
return (yield (v * 10 + 1))
|
|
|
|
async def agenfn():
|
|
try:
|
|
await _async_yield(1)
|
|
except MyError:
|
|
await _async_yield(2)
|
|
return
|
|
yield
|
|
|
|
agen = agenfn()
|
|
with contextlib.closing(anext(agen, "default").__await__()) as g:
|
|
self.assertEqual(g.send(None), 10)
|
|
self.assertEqual(g.throw(MyError, MyError(), None), 20)
|
|
with self.assertRaisesRegex(MyError, 'val'):
|
|
g.throw(MyError, MyError('val'), None)
|
|
|
|
def test5(anext):
|
|
@types.coroutine
|
|
def _async_yield(v):
|
|
yield v * 10
|
|
return (yield (v * 10 + 1))
|
|
|
|
async def agenfn():
|
|
try:
|
|
await _async_yield(1)
|
|
except MyError:
|
|
return
|
|
yield 'aaa'
|
|
|
|
agen = agenfn()
|
|
with contextlib.closing(anext(agen, "default").__await__()) as g:
|
|
self.assertEqual(g.send(None), 10)
|
|
with self.assertRaisesRegex(StopIteration, 'default'):
|
|
g.throw(MyError, MyError(), None)
|
|
|
|
def test6(anext):
|
|
@types.coroutine
|
|
def _async_yield(v):
|
|
yield v * 10
|
|
return (yield (v * 10 + 1))
|
|
|
|
async def agenfn():
|
|
await _async_yield(1)
|
|
yield 'aaa'
|
|
|
|
agen = agenfn()
|
|
with contextlib.closing(anext(agen, "default").__await__()) as g:
|
|
with self.assertRaises(MyError):
|
|
g.throw(MyError, MyError(), None)
|
|
|
|
def run_test(test):
|
|
with self.subTest('pure-Python anext()'):
|
|
test(py_anext)
|
|
with self.subTest('builtin anext()'):
|
|
test(anext)
|
|
|
|
run_test(test1)
|
|
run_test(test2)
|
|
run_test(test3)
|
|
run_test(test4)
|
|
run_test(test5)
|
|
run_test(test6)
|
|
|
|
def test_aiter_bad_args(self):
|
|
async def gen():
|
|
yield 1
|
|
async def call_with_too_few_args():
|
|
await aiter()
|
|
async def call_with_too_many_args():
|
|
await aiter(gen(), 1)
|
|
async def call_with_wrong_type_arg():
|
|
await aiter(1)
|
|
with self.assertRaises(TypeError):
|
|
self.loop.run_until_complete(call_with_too_few_args())
|
|
with self.assertRaises(TypeError):
|
|
self.loop.run_until_complete(call_with_too_many_args())
|
|
with self.assertRaises(TypeError):
|
|
self.loop.run_until_complete(call_with_wrong_type_arg())
|
|
|
|
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)
|
|
yield 2
|
|
await asyncio.sleep(0.01)
|
|
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)
|
|
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)
|
|
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)
|
|
try:
|
|
yield 2
|
|
yield 3
|
|
except ZeroDivisionError:
|
|
yield 1000
|
|
await asyncio.sleep(0.01)
|
|
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_anext_06(self):
|
|
DONE = 0
|
|
|
|
# test synchronous generators
|
|
def foo():
|
|
try:
|
|
yield
|
|
except:
|
|
pass
|
|
g = foo()
|
|
g.send(None)
|
|
with self.assertRaises(StopIteration):
|
|
g.send(None)
|
|
|
|
# now with asynchronous generators
|
|
|
|
async def gen():
|
|
nonlocal DONE
|
|
try:
|
|
yield
|
|
except:
|
|
pass
|
|
DONE = 1
|
|
|
|
async def run():
|
|
nonlocal DONE
|
|
g = gen()
|
|
await g.asend(None)
|
|
with self.assertRaises(StopAsyncIteration):
|
|
await g.asend(None)
|
|
DONE += 10
|
|
|
|
self.loop.run_until_complete(run())
|
|
self.assertEqual(DONE, 11)
|
|
|
|
def test_async_gen_asyncio_anext_tuple(self):
|
|
async def foo():
|
|
try:
|
|
yield (1,)
|
|
except ZeroDivisionError:
|
|
yield (2,)
|
|
|
|
async def run():
|
|
it = foo().__aiter__()
|
|
|
|
self.assertEqual(await it.__anext__(), (1,))
|
|
with self.assertRaises(StopIteration) as cm:
|
|
it.__anext__().throw(ZeroDivisionError)
|
|
self.assertEqual(cm.exception.args[0], (2,))
|
|
with self.assertRaises(StopAsyncIteration):
|
|
await it.__anext__()
|
|
|
|
self.loop.run_until_complete(run())
|
|
|
|
def test_async_gen_asyncio_anext_stopiteration(self):
|
|
async def foo():
|
|
try:
|
|
yield StopIteration(1)
|
|
except ZeroDivisionError:
|
|
yield StopIteration(3)
|
|
|
|
async def run():
|
|
it = foo().__aiter__()
|
|
|
|
v = await it.__anext__()
|
|
self.assertIsInstance(v, StopIteration)
|
|
self.assertEqual(v.value, 1)
|
|
with self.assertRaises(StopIteration) as cm:
|
|
it.__anext__().throw(ZeroDivisionError)
|
|
v = cm.exception.args[0]
|
|
self.assertIsInstance(v, StopIteration)
|
|
self.assertEqual(v.value, 3)
|
|
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)
|
|
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)
|
|
await asyncio.sleep(0.01)
|
|
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)
|
|
await asyncio.sleep(0.01)
|
|
DONE += 1
|
|
DONE += 1000
|
|
|
|
async def run():
|
|
gen = foo()
|
|
it = gen.__aiter__()
|
|
self.assertEqual(await it.__anext__(), 1)
|
|
await gen.aclose()
|
|
|
|
self.loop.run_until_complete(run())
|
|
self.assertEqual(DONE, 1)
|
|
|
|
# Silence ResourceWarnings
|
|
fut.cancel()
|
|
self.loop.run_until_complete(asyncio.sleep(0.01))
|
|
|
|
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)
|
|
await asyncio.sleep(0.01)
|
|
DONE = 1
|
|
|
|
async def run():
|
|
g = gen()
|
|
await g.__anext__()
|
|
await g.__anext__()
|
|
del g
|
|
gc_collect() # For PyPy or other GCs.
|
|
|
|
await asyncio.sleep(0.1)
|
|
|
|
self.loop.run_until_complete(run())
|
|
self.assertEqual(DONE, 1)
|
|
|
|
def test_async_gen_asyncio_aclose_10(self):
|
|
DONE = 0
|
|
|
|
# test synchronous generators
|
|
def foo():
|
|
try:
|
|
yield
|
|
except:
|
|
pass
|
|
g = foo()
|
|
g.send(None)
|
|
g.close()
|
|
|
|
# now with asynchronous generators
|
|
|
|
async def gen():
|
|
nonlocal DONE
|
|
try:
|
|
yield
|
|
except:
|
|
pass
|
|
DONE = 1
|
|
|
|
async def run():
|
|
nonlocal DONE
|
|
g = gen()
|
|
await g.asend(None)
|
|
await g.aclose()
|
|
DONE += 10
|
|
|
|
self.loop.run_until_complete(run())
|
|
self.assertEqual(DONE, 11)
|
|
|
|
def test_async_gen_asyncio_aclose_11(self):
|
|
DONE = 0
|
|
|
|
# test synchronous generators
|
|
def foo():
|
|
try:
|
|
yield
|
|
except:
|
|
pass
|
|
yield
|
|
g = foo()
|
|
g.send(None)
|
|
with self.assertRaisesRegex(RuntimeError, 'ignored GeneratorExit'):
|
|
g.close()
|
|
|
|
# now with asynchronous generators
|
|
|
|
async def gen():
|
|
nonlocal DONE
|
|
try:
|
|
yield
|
|
except:
|
|
pass
|
|
yield
|
|
DONE += 1
|
|
|
|
async def run():
|
|
nonlocal DONE
|
|
g = gen()
|
|
await g.asend(None)
|
|
with self.assertRaisesRegex(RuntimeError, 'ignored GeneratorExit'):
|
|
await g.aclose()
|
|
DONE += 10
|
|
|
|
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
|
|
|
|
# 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)
|
|
v = yield 1
|
|
await asyncio.sleep(0.01)
|
|
yield v * 2
|
|
await asyncio.sleep(0.01)
|
|
return
|
|
finally:
|
|
await asyncio.sleep(0.01)
|
|
await asyncio.sleep(0.01)
|
|
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)
|
|
1 / 0
|
|
|
|
async def gen():
|
|
nonlocal DONE
|
|
try:
|
|
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)
|
|
await asyncio.sleep(0.01)
|
|
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)
|
|
self.loop.call_later(delay / 2, lambda: fut.cancel())
|
|
return await fut
|
|
|
|
async def gen():
|
|
nonlocal DONE
|
|
try:
|
|
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)
|
|
await asyncio.sleep(0.01)
|
|
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)
|
|
try:
|
|
v = yield 1
|
|
except FooEr:
|
|
v = 1000
|
|
await asyncio.sleep(0.01)
|
|
yield v * 2
|
|
await asyncio.sleep(0.01)
|
|
# return
|
|
finally:
|
|
await asyncio.sleep(0.01)
|
|
await asyncio.sleep(0.01)
|
|
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)
|
|
self.loop.call_later(delay / 2, lambda: fut.cancel())
|
|
return await fut
|
|
|
|
async def gen():
|
|
nonlocal DONE
|
|
try:
|
|
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)
|
|
# return
|
|
finally:
|
|
await asyncio.sleep(0.01)
|
|
await asyncio.sleep(0.01)
|
|
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_athrow_03(self):
|
|
DONE = 0
|
|
|
|
# test synchronous generators
|
|
def foo():
|
|
try:
|
|
yield
|
|
except:
|
|
pass
|
|
g = foo()
|
|
g.send(None)
|
|
with self.assertRaises(StopIteration):
|
|
g.throw(ValueError)
|
|
|
|
# now with asynchronous generators
|
|
|
|
async def gen():
|
|
nonlocal DONE
|
|
try:
|
|
yield
|
|
except:
|
|
pass
|
|
DONE = 1
|
|
|
|
async def run():
|
|
nonlocal DONE
|
|
g = gen()
|
|
await g.asend(None)
|
|
with self.assertRaises(StopAsyncIteration):
|
|
await g.athrow(ValueError)
|
|
DONE += 10
|
|
|
|
self.loop.run_until_complete(run())
|
|
self.assertEqual(DONE, 11)
|
|
|
|
def test_async_gen_asyncio_athrow_tuple(self):
|
|
async def gen():
|
|
try:
|
|
yield 1
|
|
except ZeroDivisionError:
|
|
yield (2,)
|
|
|
|
async def run():
|
|
g = gen()
|
|
v = await g.asend(None)
|
|
self.assertEqual(v, 1)
|
|
v = await g.athrow(ZeroDivisionError)
|
|
self.assertEqual(v, (2,))
|
|
with self.assertRaises(StopAsyncIteration):
|
|
await g.asend(None)
|
|
|
|
self.loop.run_until_complete(run())
|
|
|
|
def test_async_gen_asyncio_athrow_stopiteration(self):
|
|
async def gen():
|
|
try:
|
|
yield 1
|
|
except ZeroDivisionError:
|
|
yield StopIteration(2)
|
|
|
|
async def run():
|
|
g = gen()
|
|
v = await g.asend(None)
|
|
self.assertEqual(v, 1)
|
|
v = await g.athrow(ZeroDivisionError)
|
|
self.assertIsInstance(v, StopIteration)
|
|
self.assertEqual(v.value, 2)
|
|
with self.assertRaises(StopAsyncIteration):
|
|
await g.asend(None)
|
|
|
|
self.loop.run_until_complete(run())
|
|
|
|
def test_async_gen_asyncio_shutdown_01(self):
|
|
finalized = 0
|
|
|
|
async def waiter(timeout):
|
|
nonlocal finalized
|
|
try:
|
|
await asyncio.sleep(timeout)
|
|
yield 1
|
|
finally:
|
|
await asyncio.sleep(0)
|
|
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))
|
|
|
|
# Silence warnings
|
|
t1.cancel()
|
|
t2.cancel()
|
|
|
|
with self.assertRaises(asyncio.CancelledError):
|
|
self.loop.run_until_complete(t1)
|
|
with self.assertRaises(asyncio.CancelledError):
|
|
self.loop.run_until_complete(t2)
|
|
|
|
self.loop.run_until_complete(self.loop.shutdown_asyncgens())
|
|
|
|
self.assertEqual(finalized, 2)
|
|
|
|
def test_async_gen_asyncio_shutdown_02(self):
|
|
messages = []
|
|
|
|
def exception_handler(loop, context):
|
|
messages.append(context)
|
|
|
|
async def async_iterate():
|
|
yield 1
|
|
yield 2
|
|
|
|
it = async_iterate()
|
|
async def main():
|
|
loop = asyncio.get_running_loop()
|
|
loop.set_exception_handler(exception_handler)
|
|
|
|
async for i in it:
|
|
break
|
|
|
|
asyncio.run(main())
|
|
|
|
self.assertEqual(messages, [])
|
|
|
|
def test_async_gen_asyncio_shutdown_exception_01(self):
|
|
messages = []
|
|
|
|
def exception_handler(loop, context):
|
|
messages.append(context)
|
|
|
|
async def async_iterate():
|
|
try:
|
|
yield 1
|
|
yield 2
|
|
finally:
|
|
1/0
|
|
|
|
it = async_iterate()
|
|
async def main():
|
|
loop = asyncio.get_running_loop()
|
|
loop.set_exception_handler(exception_handler)
|
|
|
|
async for i in it:
|
|
break
|
|
|
|
asyncio.run(main())
|
|
|
|
message, = messages
|
|
self.assertEqual(message['asyncgen'], it)
|
|
self.assertIsInstance(message['exception'], ZeroDivisionError)
|
|
self.assertIn('an error occurred during closing of asynchronous generator',
|
|
message['message'])
|
|
|
|
def test_async_gen_asyncio_shutdown_exception_02(self):
|
|
messages = []
|
|
|
|
def exception_handler(loop, context):
|
|
messages.append(context)
|
|
|
|
async def async_iterate():
|
|
try:
|
|
yield 1
|
|
yield 2
|
|
finally:
|
|
1/0
|
|
|
|
async def main():
|
|
loop = asyncio.get_running_loop()
|
|
loop.set_exception_handler(exception_handler)
|
|
|
|
async for i in async_iterate():
|
|
break
|
|
gc_collect()
|
|
|
|
asyncio.run(main())
|
|
|
|
message, = messages
|
|
self.assertIsInstance(message['exception'], ZeroDivisionError)
|
|
self.assertIn('unhandled exception during asyncio.run() shutdown',
|
|
message['message'])
|
|
|
|
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())
|
|
|
|
|
|
if __name__ == "__main__":
|
|
unittest.main()
|