|
Packit |
562c7a |
# mode: run
|
|
Packit |
562c7a |
# tag: pep492, asyncfor, await
|
|
Packit |
562c7a |
|
|
Packit |
562c7a |
import sys
|
|
Packit |
562c7a |
|
|
Packit |
562c7a |
if sys.version_info >= (3, 5, 0, 'beta'):
|
|
Packit |
562c7a |
# pass Cython implemented AsyncIter() into a Python async-for loop
|
|
Packit |
562c7a |
__doc__ = u"""
|
|
Packit |
562c7a |
>>> def test_py35(AsyncIterClass):
|
|
Packit |
562c7a |
... buffer = []
|
|
Packit |
562c7a |
... async def coro():
|
|
Packit |
562c7a |
... async for i1, i2 in AsyncIterClass(1):
|
|
Packit |
562c7a |
... buffer.append(i1 + i2)
|
|
Packit |
562c7a |
... return coro, buffer
|
|
Packit |
562c7a |
|
|
Packit |
562c7a |
>>> testfunc, buffer = test_py35(AsyncIterOld if sys.version_info < (3, 5, 2) else AsyncIter)
|
|
Packit |
562c7a |
>>> buffer
|
|
Packit |
562c7a |
[]
|
|
Packit |
562c7a |
|
|
Packit |
562c7a |
>>> yielded, _ = run_async(testfunc(), check_type=False)
|
|
Packit |
562c7a |
>>> yielded == [i * 100 for i in range(1, 11)] or yielded
|
|
Packit |
562c7a |
True
|
|
Packit |
562c7a |
>>> buffer == [i*2 for i in range(1, 101)] or buffer
|
|
Packit |
562c7a |
True
|
|
Packit |
562c7a |
"""
|
|
Packit |
562c7a |
|
|
Packit |
562c7a |
|
|
Packit |
562c7a |
cdef class AsyncYieldFrom:
|
|
Packit |
562c7a |
cdef object obj
|
|
Packit |
562c7a |
def __init__(self, obj):
|
|
Packit |
562c7a |
self.obj = obj
|
|
Packit |
562c7a |
|
|
Packit |
562c7a |
def __await__(self):
|
|
Packit |
562c7a |
yield from self.obj
|
|
Packit |
562c7a |
|
|
Packit |
562c7a |
|
|
Packit |
562c7a |
cdef class AsyncYield:
|
|
Packit |
562c7a |
cdef object value
|
|
Packit |
562c7a |
def __init__(self, value):
|
|
Packit |
562c7a |
self.value = value
|
|
Packit |
562c7a |
|
|
Packit |
562c7a |
def __await__(self):
|
|
Packit |
562c7a |
yield self.value
|
|
Packit |
562c7a |
|
|
Packit |
562c7a |
|
|
Packit |
562c7a |
def run_async(coro, check_type='coroutine'):
|
|
Packit |
562c7a |
if check_type:
|
|
Packit |
562c7a |
assert coro.__class__.__name__ == check_type, \
|
|
Packit |
562c7a |
'type(%s) != %s' % (coro.__class__, check_type)
|
|
Packit |
562c7a |
|
|
Packit |
562c7a |
buffer = []
|
|
Packit |
562c7a |
result = None
|
|
Packit |
562c7a |
while True:
|
|
Packit |
562c7a |
try:
|
|
Packit |
562c7a |
buffer.append(coro.send(None))
|
|
Packit |
562c7a |
except StopIteration as ex:
|
|
Packit |
562c7a |
result = ex.args[0] if ex.args else None
|
|
Packit |
562c7a |
break
|
|
Packit |
562c7a |
return buffer, result
|
|
Packit |
562c7a |
|
|
Packit |
562c7a |
|
|
Packit |
562c7a |
cdef class AsyncIter:
|
|
Packit |
562c7a |
cdef long i
|
|
Packit |
562c7a |
cdef long aiter_calls
|
|
Packit |
562c7a |
cdef long max_iter_calls
|
|
Packit |
562c7a |
|
|
Packit |
562c7a |
def __init__(self, long max_iter_calls=1):
|
|
Packit |
562c7a |
self.i = 0
|
|
Packit |
562c7a |
self.aiter_calls = 0
|
|
Packit |
562c7a |
self.max_iter_calls = max_iter_calls
|
|
Packit |
562c7a |
|
|
Packit |
562c7a |
def __aiter__(self):
|
|
Packit |
562c7a |
self.aiter_calls += 1
|
|
Packit |
562c7a |
return self
|
|
Packit |
562c7a |
|
|
Packit |
562c7a |
async def __anext__(self):
|
|
Packit |
562c7a |
self.i += 1
|
|
Packit |
562c7a |
assert self.aiter_calls <= self.max_iter_calls
|
|
Packit |
562c7a |
|
|
Packit |
562c7a |
if not (self.i % 10):
|
|
Packit |
562c7a |
await AsyncYield(self.i * 10)
|
|
Packit |
562c7a |
|
|
Packit |
562c7a |
if self.i > 100:
|
|
Packit |
562c7a |
raise StopAsyncIteration
|
|
Packit |
562c7a |
|
|
Packit |
562c7a |
return self.i, self.i
|
|
Packit |
562c7a |
|
|
Packit |
562c7a |
|
|
Packit |
562c7a |
cdef class AsyncIterOld(AsyncIter):
|
|
Packit |
562c7a |
"""
|
|
Packit |
562c7a |
Same as AsyncIter, but with the old async-def interface for __aiter__().
|
|
Packit |
562c7a |
"""
|
|
Packit |
562c7a |
async def __aiter__(self):
|
|
Packit |
562c7a |
self.aiter_calls += 1
|
|
Packit |
562c7a |
return self
|
|
Packit |
562c7a |
|
|
Packit |
562c7a |
|
|
Packit |
562c7a |
def test_for_1():
|
|
Packit |
562c7a |
"""
|
|
Packit |
562c7a |
>>> testfunc, buffer = test_for_1()
|
|
Packit |
562c7a |
>>> buffer
|
|
Packit |
562c7a |
[]
|
|
Packit |
562c7a |
>>> yielded, _ = run_async(testfunc())
|
|
Packit |
562c7a |
>>> yielded == [i * 100 for i in range(1, 11)] or yielded
|
|
Packit |
562c7a |
True
|
|
Packit |
562c7a |
>>> buffer == [i*2 for i in range(1, 101)] or buffer
|
|
Packit |
562c7a |
True
|
|
Packit |
562c7a |
"""
|
|
Packit |
562c7a |
buffer = []
|
|
Packit |
562c7a |
async def test1():
|
|
Packit |
562c7a |
async for i1, i2 in AsyncIter(1):
|
|
Packit |
562c7a |
buffer.append(i1 + i2)
|
|
Packit |
562c7a |
return test1, buffer
|
|
Packit |
562c7a |
|
|
Packit |
562c7a |
|
|
Packit |
562c7a |
def test_for_2():
|
|
Packit |
562c7a |
"""
|
|
Packit |
562c7a |
>>> testfunc, buffer = test_for_2()
|
|
Packit |
562c7a |
>>> buffer
|
|
Packit |
562c7a |
[]
|
|
Packit |
562c7a |
>>> yielded, _ = run_async(testfunc())
|
|
Packit |
562c7a |
>>> yielded == [100, 200] or yielded
|
|
Packit |
562c7a |
True
|
|
Packit |
562c7a |
>>> buffer == [i for i in range(1, 21)] + ['end'] or buffer
|
|
Packit |
562c7a |
True
|
|
Packit |
562c7a |
"""
|
|
Packit |
562c7a |
buffer = []
|
|
Packit |
562c7a |
async def test2():
|
|
Packit |
562c7a |
nonlocal buffer
|
|
Packit |
562c7a |
async for i in AsyncIter(2):
|
|
Packit |
562c7a |
buffer.append(i[0])
|
|
Packit |
562c7a |
if i[0] == 20:
|
|
Packit |
562c7a |
break
|
|
Packit |
562c7a |
else:
|
|
Packit |
562c7a |
buffer.append('what?')
|
|
Packit |
562c7a |
buffer.append('end')
|
|
Packit |
562c7a |
return test2, buffer
|
|
Packit |
562c7a |
|
|
Packit |
562c7a |
|
|
Packit |
562c7a |
|
|
Packit |
562c7a |
def test_for_3():
|
|
Packit |
562c7a |
"""
|
|
Packit |
562c7a |
>>> testfunc, buffer = test_for_3()
|
|
Packit |
562c7a |
>>> buffer
|
|
Packit |
562c7a |
[]
|
|
Packit |
562c7a |
>>> yielded, _ = run_async(testfunc())
|
|
Packit |
562c7a |
>>> yielded == [i * 100 for i in range(1, 11)] or yielded
|
|
Packit |
562c7a |
True
|
|
Packit |
562c7a |
>>> buffer == [i for i in range(1, 21)] + ['what?', 'end'] or buffer
|
|
Packit |
562c7a |
True
|
|
Packit |
562c7a |
"""
|
|
Packit |
562c7a |
buffer = []
|
|
Packit |
562c7a |
async def test3():
|
|
Packit |
562c7a |
nonlocal buffer
|
|
Packit |
562c7a |
async for i in AsyncIter(3):
|
|
Packit |
562c7a |
if i[0] > 20:
|
|
Packit |
562c7a |
continue
|
|
Packit |
562c7a |
buffer.append(i[0])
|
|
Packit |
562c7a |
else:
|
|
Packit |
562c7a |
buffer.append('what?')
|
|
Packit |
562c7a |
buffer.append('end')
|
|
Packit |
562c7a |
return test3, buffer
|
|
Packit |
562c7a |
|
|
Packit |
562c7a |
|
|
Packit |
562c7a |
cdef class NonAwaitableFromAnext:
|
|
Packit |
562c7a |
def __aiter__(self):
|
|
Packit |
562c7a |
return self
|
|
Packit |
562c7a |
|
|
Packit |
562c7a |
def __anext__(self):
|
|
Packit |
562c7a |
return 123
|
|
Packit |
562c7a |
|
|
Packit |
562c7a |
|
|
Packit |
562c7a |
def test_broken_anext():
|
|
Packit |
562c7a |
"""
|
|
Packit |
562c7a |
>>> testfunc = test_broken_anext()
|
|
Packit |
562c7a |
>>> try: run_async(testfunc())
|
|
Packit |
562c7a |
... except TypeError as exc:
|
|
Packit |
562c7a |
... assert ' int' in str(exc)
|
|
Packit |
562c7a |
... else:
|
|
Packit |
562c7a |
... print("NOT RAISED!")
|
|
Packit |
562c7a |
"""
|
|
Packit |
562c7a |
async def foo():
|
|
Packit |
562c7a |
async for i in NonAwaitableFromAnext():
|
|
Packit |
562c7a |
print('never going to happen')
|
|
Packit |
562c7a |
return foo
|
|
Packit |
562c7a |
|
|
Packit |
562c7a |
|
|
Packit |
562c7a |
cdef class Manager:
|
|
Packit |
562c7a |
cdef readonly list counter
|
|
Packit |
562c7a |
def __init__(self, counter):
|
|
Packit |
562c7a |
self.counter = counter
|
|
Packit |
562c7a |
|
|
Packit |
562c7a |
async def __aenter__(self):
|
|
Packit |
562c7a |
self.counter[0] += 10000
|
|
Packit |
562c7a |
|
|
Packit |
562c7a |
async def __aexit__(self, *args):
|
|
Packit |
562c7a |
self.counter[0] += 100000
|
|
Packit |
562c7a |
|
|
Packit |
562c7a |
|
|
Packit |
562c7a |
cdef class Iterable:
|
|
Packit |
562c7a |
cdef long i
|
|
Packit |
562c7a |
def __init__(self):
|
|
Packit |
562c7a |
self.i = 0
|
|
Packit |
562c7a |
|
|
Packit |
562c7a |
def __aiter__(self):
|
|
Packit |
562c7a |
return self
|
|
Packit |
562c7a |
|
|
Packit |
562c7a |
async def __anext__(self):
|
|
Packit |
562c7a |
if self.i > 10:
|
|
Packit |
562c7a |
raise StopAsyncIteration
|
|
Packit |
562c7a |
self.i += 1
|
|
Packit |
562c7a |
return self.i
|
|
Packit |
562c7a |
|
|
Packit |
562c7a |
|
|
Packit |
562c7a |
def test_with_for():
|
|
Packit |
562c7a |
"""
|
|
Packit |
562c7a |
>>> test_with_for()
|
|
Packit |
562c7a |
111011
|
|
Packit |
562c7a |
333033
|
|
Packit |
562c7a |
20555255
|
|
Packit |
562c7a |
"""
|
|
Packit |
562c7a |
I = [0]
|
|
Packit |
562c7a |
|
|
Packit |
562c7a |
manager = Manager(I)
|
|
Packit |
562c7a |
iterable = Iterable()
|
|
Packit |
562c7a |
mrefs_before = sys.getrefcount(manager)
|
|
Packit |
562c7a |
irefs_before = sys.getrefcount(iterable)
|
|
Packit |
562c7a |
|
|
Packit |
562c7a |
async def main():
|
|
Packit |
562c7a |
async with manager:
|
|
Packit |
562c7a |
async for i in iterable:
|
|
Packit |
562c7a |
I[0] += 1
|
|
Packit |
562c7a |
I[0] += 1000
|
|
Packit |
562c7a |
|
|
Packit |
562c7a |
run_async(main())
|
|
Packit |
562c7a |
print(I[0])
|
|
Packit |
562c7a |
|
|
Packit |
562c7a |
assert sys.getrefcount(manager) == mrefs_before
|
|
Packit |
562c7a |
assert sys.getrefcount(iterable) == irefs_before
|
|
Packit |
562c7a |
|
|
Packit |
562c7a |
##############
|
|
Packit |
562c7a |
|
|
Packit |
562c7a |
async def main():
|
|
Packit |
562c7a |
nonlocal I
|
|
Packit |
562c7a |
|
|
Packit |
562c7a |
async with Manager(I):
|
|
Packit |
562c7a |
async for i in Iterable():
|
|
Packit |
562c7a |
I[0] += 1
|
|
Packit |
562c7a |
I[0] += 1000
|
|
Packit |
562c7a |
|
|
Packit |
562c7a |
async with Manager(I):
|
|
Packit |
562c7a |
async for i in Iterable():
|
|
Packit |
562c7a |
I[0] += 1
|
|
Packit |
562c7a |
I[0] += 1000
|
|
Packit |
562c7a |
|
|
Packit |
562c7a |
run_async(main())
|
|
Packit |
562c7a |
print(I[0])
|
|
Packit |
562c7a |
|
|
Packit |
562c7a |
##############
|
|
Packit |
562c7a |
|
|
Packit |
562c7a |
async def main():
|
|
Packit |
562c7a |
async with Manager(I):
|
|
Packit |
562c7a |
I[0] += 100
|
|
Packit |
562c7a |
async for i in Iterable():
|
|
Packit |
562c7a |
I[0] += 1
|
|
Packit |
562c7a |
else:
|
|
Packit |
562c7a |
I[0] += 10000000
|
|
Packit |
562c7a |
I[0] += 1000
|
|
Packit |
562c7a |
|
|
Packit |
562c7a |
async with Manager(I):
|
|
Packit |
562c7a |
I[0] += 100
|
|
Packit |
562c7a |
async for i in Iterable():
|
|
Packit |
562c7a |
I[0] += 1
|
|
Packit |
562c7a |
else:
|
|
Packit |
562c7a |
I[0] += 10000000
|
|
Packit |
562c7a |
I[0] += 1000
|
|
Packit |
562c7a |
|
|
Packit |
562c7a |
run_async(main())
|
|
Packit |
562c7a |
print(I[0])
|
|
Packit |
562c7a |
|
|
Packit |
562c7a |
|
|
Packit |
562c7a |
# old-style pre-3.5.2 AIter protocol - no longer supported
|
|
Packit |
562c7a |
#cdef class AI_old:
|
|
Packit |
562c7a |
# async def __aiter__(self):
|
|
Packit |
562c7a |
# 1/0
|
|
Packit |
562c7a |
|
|
Packit |
562c7a |
|
|
Packit |
562c7a |
cdef class AI_new:
|
|
Packit |
562c7a |
def __aiter__(self):
|
|
Packit |
562c7a |
1/0
|
|
Packit |
562c7a |
|
|
Packit |
562c7a |
|
|
Packit |
562c7a |
def test_aiter_raises(AI):
|
|
Packit |
562c7a |
"""
|
|
Packit |
562c7a |
#>>> test_aiter_raises(AI_old)
|
|
Packit |
562c7a |
#RAISED
|
|
Packit |
562c7a |
#0
|
|
Packit |
562c7a |
>>> test_aiter_raises(AI_new)
|
|
Packit |
562c7a |
RAISED
|
|
Packit |
562c7a |
0
|
|
Packit |
562c7a |
"""
|
|
Packit |
562c7a |
CNT = 0
|
|
Packit |
562c7a |
|
|
Packit |
562c7a |
async def foo():
|
|
Packit |
562c7a |
nonlocal CNT
|
|
Packit |
562c7a |
async for i in AI():
|
|
Packit |
562c7a |
CNT += 1
|
|
Packit |
562c7a |
CNT += 10
|
|
Packit |
562c7a |
|
|
Packit |
562c7a |
try:
|
|
Packit |
562c7a |
run_async(foo())
|
|
Packit |
562c7a |
except ZeroDivisionError:
|
|
Packit |
562c7a |
print("RAISED")
|
|
Packit |
562c7a |
else:
|
|
Packit |
562c7a |
print("NOT RAISED")
|
|
Packit |
562c7a |
return CNT
|