Skip to content

Commit f9bb106

Browse files
committed
Add tests for issue gh-74956
1 parent 32c37fe commit f9bb106

File tree

1 file changed

+117
-0
lines changed

1 file changed

+117
-0
lines changed

Lib/test/test_asyncgen.py

Lines changed: 117 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1695,6 +1695,32 @@ async def run():
16951695

16961696
self.loop.run_until_complete(run())
16971697

1698+
def test_send_exhausted(self):
1699+
"""
1700+
Test the behaviour of an exhausted async generator
1701+
"""
1702+
1703+
async def run():
1704+
# test exhausted generator
1705+
async def gen():
1706+
yield 1
1707+
1708+
g = gen()
1709+
[f async for f in g]
1710+
1711+
# an exhausted generator behaves like this:
1712+
1713+
with self.assertRaises(StopAsyncIteration):
1714+
r = await g.asend(None)
1715+
with self.assertRaises(StopAsyncIteration):
1716+
r = await g.__anext__()
1717+
1718+
# The following behaviour may be undefined:
1719+
r = await g.athrow(EOFError)
1720+
assert r is None
1721+
1722+
self.loop.run_until_complete(run())
1723+
16981724

16991725
class TestUnawaitedWarnings(unittest.TestCase):
17001726
def test_asend(self):
@@ -1728,6 +1754,97 @@ async def gen():
17281754
gc_collect()
17291755

17301756

1757+
class TestIssueGH74956(unittest.TestCase):
1758+
# simultanous use of generator by different coroutines is not
1759+
# allowed.
1760+
# https://github.com/python/cpython/issues/74956
1761+
1762+
def setUp(self):
1763+
self.loop = asyncio.new_event_loop()
1764+
asyncio.set_event_loop(None)
1765+
1766+
def tearDown(self):
1767+
self.loop.close()
1768+
self.loop = None
1769+
asyncio.set_event_loop_policy(None)
1770+
1771+
def test_simultaneous_asend(self):
1772+
"""
1773+
Verify that simultaneous use of generator by different coroutines is not
1774+
permitted
1775+
"""
1776+
1777+
async def run():
1778+
async def consumer():
1779+
while True:
1780+
await sleep(0)
1781+
yield
1782+
1783+
agenerator = consumer()
1784+
await agenerator.asend(None)
1785+
fa = asyncio.create_task(agenerator.asend("A"))
1786+
fb = asyncio.create_task(agenerator.asend("B"))
1787+
await fa
1788+
with self.assertRaises(RuntimeError) as err:
1789+
await fb
1790+
assert "already running" in str(err.exception)
1791+
1792+
agenerator = consumer()
1793+
await agenerator.asend(None)
1794+
fa = asyncio.create_task(agenerator.asend("A"))
1795+
fb = asyncio.create_task(agenerator.athrow(EOFError))
1796+
await fa
1797+
with self.assertRaises(RuntimeError) as err:
1798+
await fb
1799+
assert "already running" in str(err.exception)
1800+
1801+
await agenerator.asend(None)
1802+
fa = asyncio.create_task(agenerator.asend("A"))
1803+
fb = asyncio.create_task(agenerator.aclose())
1804+
await fa
1805+
with self.assertRaises(RuntimeError) as err:
1806+
await fb
1807+
assert "already running" in str(err.exception)
1808+
1809+
self.loop.run_until_complete(run())
1810+
1811+
def test_ag_running(self):
1812+
"""
1813+
Verify that as_running transitions correctly in
1814+
an async generator
1815+
"""
1816+
state = 0
1817+
1818+
async def agen():
1819+
nonlocal state
1820+
state = 1
1821+
await asyncio.sleep(0)
1822+
state = 2
1823+
value = yield "foo"
1824+
state = value
1825+
1826+
a = agen()
1827+
assert a.ag_running is False
1828+
# start it running
1829+
coro = a.asend(None)
1830+
assert state == 0
1831+
coro.send(None)
1832+
assert state == 1
1833+
assert a.ag_running is True
1834+
1835+
# wake it from sleep and have it yield
1836+
with self.assertRaises(StopIteration) as v:
1837+
coro.send(None)
1838+
assert v.exception.value == "foo"
1839+
assert state == 2
1840+
assert a.ag_running is False
1841+
1842+
# finish it
1843+
coro = a.asend("bar")
1844+
self.assertRaises(StopAsyncIteration, coro.send, None)
1845+
assert a.ag_running is False
1846+
assert state == "bar"
1847+
17311848

17321849
if __name__ == "__main__":
17331850
unittest.main()

0 commit comments

Comments
 (0)