@@ -1771,32 +1771,54 @@ def tearDown(self):
1771
1771
def test_simultaneous_asend (self ):
1772
1772
"""
1773
1773
Verify that simultaneous use of generator by different coroutines is not
1774
- permitted
1774
+ permitted. We use Tasks to achieve this, where one task is suspended
1775
+ in a `asyncio.sleep()` call inside the generator (during an `asend()` call),
1776
+ and the other task attempts
1777
+ to do an `asend()`, (or `athrow()`, or `aclose()`) on the generator.
1775
1778
"""
1776
1779
1777
- async def run ():
1780
+
1781
+ async def run_collision (op , * args ):
1782
+ # Two tasks are created and scheduled. The first will sleep inside the
1783
+ # `asend()` and the other will then attempt a second operation and fail.
1784
+
1778
1785
async def consumer ():
1779
1786
while True :
1787
+ # task fa will sleep here, and another task will try to iterate
1788
+ # the generator
1780
1789
await asyncio .sleep (0 )
1781
1790
if (yield ) is None :
1782
1791
break
1783
1792
1793
+ # create and start the generator
1794
+ agenerator = consumer ()
1795
+ await agenerator .asend (None )
1796
+
1797
+ # start the first asend() task
1798
+ fa = asyncio .create_task (agenerator .asend ("A" ))
1799
+
1800
+ # start the second task, which should fail (asend, athrow, aclose)
1801
+ method = getattr (agenerator , op )
1802
+ fb = asyncio .create_task (method (* args ))
1803
+
1804
+ # first asend should succeed
1805
+ await fa
1806
+
1807
+ # second operation should fail
1808
+ with self .assertRaises (RuntimeError ) as err :
1809
+ await fb
1810
+ assert "already running" in str (err .exception )
1811
+
1812
+ # cleanup partially run generator
1813
+ with self .assertRaises (StopAsyncIteration ):
1814
+ await agenerator .asend (None ) # close it
1815
+
1816
+ async def run ():
1784
1817
# try different combinations of asend, athrow, aclose
1785
1818
# which are clashing with an asend which is already running
1786
1819
# (and awaiting sleep(0))
1787
1820
for op , args in [("asend" , ["A" ]), ("athrow" , [EOFError ]), ("aclose" , [])]:
1788
- agenerator = consumer ()
1789
- await agenerator .asend (None ) # start it
1790
- # fa will hit sleep and then fb will run
1791
- fa = asyncio .create_task (agenerator .asend ("A" ))
1792
- coro = getattr (agenerator , op )(* args )
1793
- fb = asyncio .create_task (coro )
1794
- await fa
1795
- with self .assertRaises (RuntimeError ) as err :
1796
- await fb
1797
- assert "already running" in str (err .exception )
1798
- with self .assertRaises (StopAsyncIteration ):
1799
- await agenerator .asend (None ) # close it
1821
+ await run_collision (op , * args )
1800
1822
1801
1823
self .loop .run_until_complete (run ())
1802
1824
0 commit comments