| 
									
										
										
										
											2022-03-30 15:15:06 +03:00
										 |  |  | import _thread | 
					
						
							| 
									
										
										
										
											2017-12-14 09:42:21 -05:00
										 |  |  | import asyncio | 
					
						
							| 
									
										
										
										
											2022-03-24 21:51:16 +02:00
										 |  |  | import contextvars | 
					
						
							|  |  |  | import re | 
					
						
							| 
									
										
										
										
											2022-04-25 16:56:20 +01:00
										 |  |  | import signal | 
					
						
							| 
									
										
										
										
											2023-10-12 07:13:57 -07:00
										 |  |  | import sys | 
					
						
							| 
									
										
										
										
											2022-03-30 15:15:06 +03:00
										 |  |  | import threading | 
					
						
							| 
									
										
										
										
											2017-12-14 09:42:21 -05:00
										 |  |  | import unittest | 
					
						
							| 
									
										
										
										
											2022-07-28 21:17:54 +05:30
										 |  |  | from test.test_asyncio import utils as test_utils | 
					
						
							| 
									
										
										
										
											2017-12-14 09:42:21 -05:00
										 |  |  | from unittest import mock | 
					
						
							| 
									
										
										
										
											2022-04-25 16:56:20 +01:00
										 |  |  | from unittest.mock import patch | 
					
						
							| 
									
										
										
										
											2017-12-14 09:42:21 -05:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-02-10 14:57:20 +02:00
										 |  |  | def tearDownModule(): | 
					
						
							|  |  |  |     asyncio.set_event_loop_policy(None) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-03-30 15:15:06 +03:00
										 |  |  | def interrupt_self(): | 
					
						
							|  |  |  |     _thread.interrupt_main() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-12-14 09:42:21 -05:00
										 |  |  | class TestPolicy(asyncio.AbstractEventLoopPolicy): | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def __init__(self, loop_factory): | 
					
						
							|  |  |  |         self.loop_factory = loop_factory | 
					
						
							|  |  |  |         self.loop = None | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def get_event_loop(self): | 
					
						
							|  |  |  |         # shouldn't ever be called by asyncio.run() | 
					
						
							|  |  |  |         raise RuntimeError | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def new_event_loop(self): | 
					
						
							|  |  |  |         return self.loop_factory() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def set_event_loop(self, loop): | 
					
						
							|  |  |  |         if loop is not None: | 
					
						
							|  |  |  |             # we want to check if the loop is closed | 
					
						
							|  |  |  |             # in BaseTest.tearDown | 
					
						
							|  |  |  |             self.loop = loop | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | class BaseTest(unittest.TestCase): | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def new_loop(self): | 
					
						
							|  |  |  |         loop = asyncio.BaseEventLoop() | 
					
						
							|  |  |  |         loop._process_events = mock.Mock() | 
					
						
							| 
									
										
										
										
											2022-06-15 20:11:47 +05:30
										 |  |  |         # Mock waking event loop from select | 
					
						
							|  |  |  |         loop._write_to_self = mock.Mock() | 
					
						
							|  |  |  |         loop._write_to_self.return_value = None | 
					
						
							| 
									
										
										
										
											2017-12-14 09:42:21 -05:00
										 |  |  |         loop._selector = mock.Mock() | 
					
						
							|  |  |  |         loop._selector.select.return_value = () | 
					
						
							|  |  |  |         loop.shutdown_ag_run = False | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         async def shutdown_asyncgens(): | 
					
						
							|  |  |  |             loop.shutdown_ag_run = True | 
					
						
							|  |  |  |         loop.shutdown_asyncgens = shutdown_asyncgens | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         return loop | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def setUp(self): | 
					
						
							|  |  |  |         super().setUp() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         policy = TestPolicy(self.new_loop) | 
					
						
							|  |  |  |         asyncio.set_event_loop_policy(policy) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def tearDown(self): | 
					
						
							|  |  |  |         policy = asyncio.get_event_loop_policy() | 
					
						
							|  |  |  |         if policy.loop is not None: | 
					
						
							|  |  |  |             self.assertTrue(policy.loop.is_closed()) | 
					
						
							|  |  |  |             self.assertTrue(policy.loop.shutdown_ag_run) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         asyncio.set_event_loop_policy(None) | 
					
						
							|  |  |  |         super().tearDown() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | class RunTests(BaseTest): | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def test_asyncio_run_return(self): | 
					
						
							|  |  |  |         async def main(): | 
					
						
							|  |  |  |             await asyncio.sleep(0) | 
					
						
							|  |  |  |             return 42 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         self.assertEqual(asyncio.run(main()), 42) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def test_asyncio_run_raises(self): | 
					
						
							|  |  |  |         async def main(): | 
					
						
							|  |  |  |             await asyncio.sleep(0) | 
					
						
							|  |  |  |             raise ValueError('spam') | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         with self.assertRaisesRegex(ValueError, 'spam'): | 
					
						
							|  |  |  |             asyncio.run(main()) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def test_asyncio_run_only_coro(self): | 
					
						
							|  |  |  |         for o in {1, lambda: None}: | 
					
						
							|  |  |  |             with self.subTest(obj=o), \ | 
					
						
							|  |  |  |                     self.assertRaisesRegex(ValueError, | 
					
						
							|  |  |  |                                            'a coroutine was expected'): | 
					
						
							|  |  |  |                 asyncio.run(o) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def test_asyncio_run_debug(self): | 
					
						
							|  |  |  |         async def main(expected): | 
					
						
							|  |  |  |             loop = asyncio.get_event_loop() | 
					
						
							|  |  |  |             self.assertIs(loop.get_debug(), expected) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-08-21 16:55:09 +09:00
										 |  |  |         asyncio.run(main(False), debug=False) | 
					
						
							| 
									
										
										
										
											2017-12-14 09:42:21 -05:00
										 |  |  |         asyncio.run(main(True), debug=True) | 
					
						
							| 
									
										
										
										
											2020-09-02 21:54:46 -07:00
										 |  |  |         with mock.patch('asyncio.coroutines._is_debug_mode', lambda: True): | 
					
						
							|  |  |  |             asyncio.run(main(True)) | 
					
						
							|  |  |  |             asyncio.run(main(False), debug=False) | 
					
						
							| 
									
										
										
										
											2023-08-21 16:55:09 +09:00
										 |  |  |         with mock.patch('asyncio.coroutines._is_debug_mode', lambda: False): | 
					
						
							|  |  |  |             asyncio.run(main(True), debug=True) | 
					
						
							|  |  |  |             asyncio.run(main(False)) | 
					
						
							| 
									
										
										
										
											2017-12-14 09:42:21 -05:00
										 |  |  | 
 | 
					
						
							|  |  |  |     def test_asyncio_run_from_running_loop(self): | 
					
						
							|  |  |  |         async def main(): | 
					
						
							|  |  |  |             coro = main() | 
					
						
							|  |  |  |             try: | 
					
						
							|  |  |  |                 asyncio.run(coro) | 
					
						
							|  |  |  |             finally: | 
					
						
							|  |  |  |                 coro.close()  # Suppress ResourceWarning | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         with self.assertRaisesRegex(RuntimeError, | 
					
						
							|  |  |  |                                     'cannot be called from a running'): | 
					
						
							|  |  |  |             asyncio.run(main()) | 
					
						
							| 
									
										
										
										
											2018-01-21 14:56:59 -05:00
										 |  |  | 
 | 
					
						
							|  |  |  |     def test_asyncio_run_cancels_hanging_tasks(self): | 
					
						
							|  |  |  |         lo_task = None | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         async def leftover(): | 
					
						
							|  |  |  |             await asyncio.sleep(0.1) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         async def main(): | 
					
						
							|  |  |  |             nonlocal lo_task | 
					
						
							|  |  |  |             lo_task = asyncio.create_task(leftover()) | 
					
						
							|  |  |  |             return 123 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         self.assertEqual(asyncio.run(main()), 123) | 
					
						
							|  |  |  |         self.assertTrue(lo_task.done()) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def test_asyncio_run_reports_hanging_tasks_errors(self): | 
					
						
							|  |  |  |         lo_task = None | 
					
						
							|  |  |  |         call_exc_handler_mock = mock.Mock() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         async def leftover(): | 
					
						
							|  |  |  |             try: | 
					
						
							|  |  |  |                 await asyncio.sleep(0.1) | 
					
						
							|  |  |  |             except asyncio.CancelledError: | 
					
						
							|  |  |  |                 1 / 0 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         async def main(): | 
					
						
							|  |  |  |             loop = asyncio.get_running_loop() | 
					
						
							|  |  |  |             loop.call_exception_handler = call_exc_handler_mock | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             nonlocal lo_task | 
					
						
							|  |  |  |             lo_task = asyncio.create_task(leftover()) | 
					
						
							|  |  |  |             return 123 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         self.assertEqual(asyncio.run(main()), 123) | 
					
						
							|  |  |  |         self.assertTrue(lo_task.done()) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         call_exc_handler_mock.assert_called_with({ | 
					
						
							|  |  |  |             'message': test_utils.MockPattern(r'asyncio.run.*shutdown'), | 
					
						
							|  |  |  |             'task': lo_task, | 
					
						
							|  |  |  |             'exception': test_utils.MockInstanceOf(ZeroDivisionError) | 
					
						
							|  |  |  |         }) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def test_asyncio_run_closes_gens_after_hanging_tasks_errors(self): | 
					
						
							|  |  |  |         spinner = None | 
					
						
							|  |  |  |         lazyboy = None | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         class FancyExit(Exception): | 
					
						
							|  |  |  |             pass | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         async def fidget(): | 
					
						
							|  |  |  |             while True: | 
					
						
							|  |  |  |                 yield 1 | 
					
						
							|  |  |  |                 await asyncio.sleep(1) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         async def spin(): | 
					
						
							|  |  |  |             nonlocal spinner | 
					
						
							|  |  |  |             spinner = fidget() | 
					
						
							|  |  |  |             try: | 
					
						
							|  |  |  |                 async for the_meaning_of_life in spinner:  # NoQA | 
					
						
							|  |  |  |                     pass | 
					
						
							|  |  |  |             except asyncio.CancelledError: | 
					
						
							|  |  |  |                 1 / 0 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         async def main(): | 
					
						
							|  |  |  |             loop = asyncio.get_running_loop() | 
					
						
							|  |  |  |             loop.call_exception_handler = mock.Mock() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             nonlocal lazyboy | 
					
						
							|  |  |  |             lazyboy = asyncio.create_task(spin()) | 
					
						
							|  |  |  |             raise FancyExit | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         with self.assertRaises(FancyExit): | 
					
						
							|  |  |  |             asyncio.run(main()) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         self.assertTrue(lazyboy.done()) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         self.assertIsNone(spinner.ag_frame) | 
					
						
							|  |  |  |         self.assertFalse(spinner.ag_running) | 
					
						
							| 
									
										
										
										
											2022-01-22 14:06:27 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-07-06 20:48:21 +05:30
										 |  |  |     def test_asyncio_run_set_event_loop(self): | 
					
						
							|  |  |  |         #See https://github.com/python/cpython/issues/93896 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         async def main(): | 
					
						
							|  |  |  |             await asyncio.sleep(0) | 
					
						
							|  |  |  |             return 42 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         policy = asyncio.get_event_loop_policy() | 
					
						
							|  |  |  |         policy.set_event_loop = mock.Mock() | 
					
						
							|  |  |  |         asyncio.run(main()) | 
					
						
							|  |  |  |         self.assertTrue(policy.set_event_loop.called) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-07-28 21:17:54 +05:30
										 |  |  |     def test_asyncio_run_without_uncancel(self): | 
					
						
							|  |  |  |         # See https://github.com/python/cpython/issues/95097 | 
					
						
							|  |  |  |         class Task: | 
					
						
							|  |  |  |             def __init__(self, loop, coro, **kwargs): | 
					
						
							|  |  |  |                 self._task = asyncio.Task(coro, loop=loop, **kwargs) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             def cancel(self, *args, **kwargs): | 
					
						
							|  |  |  |                 return self._task.cancel(*args, **kwargs) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             def add_done_callback(self, *args, **kwargs): | 
					
						
							|  |  |  |                 return self._task.add_done_callback(*args, **kwargs) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             def remove_done_callback(self, *args, **kwargs): | 
					
						
							|  |  |  |                 return self._task.remove_done_callback(*args, **kwargs) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             @property | 
					
						
							|  |  |  |             def _asyncio_future_blocking(self): | 
					
						
							|  |  |  |                 return self._task._asyncio_future_blocking | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             def result(self, *args, **kwargs): | 
					
						
							|  |  |  |                 return self._task.result(*args, **kwargs) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             def done(self, *args, **kwargs): | 
					
						
							|  |  |  |                 return self._task.done(*args, **kwargs) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             def cancelled(self, *args, **kwargs): | 
					
						
							|  |  |  |                 return self._task.cancelled(*args, **kwargs) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             def exception(self, *args, **kwargs): | 
					
						
							|  |  |  |                 return self._task.exception(*args, **kwargs) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             def get_loop(self, *args, **kwargs): | 
					
						
							|  |  |  |                 return self._task.get_loop(*args, **kwargs) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-06-13 11:36:40 +05:30
										 |  |  |             def set_name(self, *args, **kwargs): | 
					
						
							|  |  |  |                 return self._task.set_name(*args, **kwargs) | 
					
						
							| 
									
										
										
										
											2022-07-28 21:17:54 +05:30
										 |  |  | 
 | 
					
						
							|  |  |  |         async def main(): | 
					
						
							|  |  |  |             interrupt_self() | 
					
						
							|  |  |  |             await asyncio.Event().wait() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         def new_event_loop(): | 
					
						
							|  |  |  |             loop = self.new_loop() | 
					
						
							|  |  |  |             loop.set_task_factory(Task) | 
					
						
							|  |  |  |             return loop | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         asyncio.set_event_loop_policy(TestPolicy(new_event_loop)) | 
					
						
							|  |  |  |         with self.assertRaises(asyncio.CancelledError): | 
					
						
							|  |  |  |             asyncio.run(main()) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-11-14 23:48:51 +05:30
										 |  |  |     def test_asyncio_run_loop_factory(self): | 
					
						
							|  |  |  |         factory = mock.Mock() | 
					
						
							|  |  |  |         loop = factory.return_value = self.new_loop() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         async def main(): | 
					
						
							|  |  |  |             self.assertEqual(asyncio.get_running_loop(), loop) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         asyncio.run(main(), loop_factory=factory) | 
					
						
							|  |  |  |         factory.assert_called_once_with() | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-10-12 07:13:57 -07:00
										 |  |  |     def test_loop_factory_default_event_loop(self): | 
					
						
							|  |  |  |         async def main(): | 
					
						
							|  |  |  |             if sys.platform == "win32": | 
					
						
							|  |  |  |                 self.assertIsInstance(asyncio.get_running_loop(), asyncio.ProactorEventLoop) | 
					
						
							|  |  |  |             else: | 
					
						
							|  |  |  |                 self.assertIsInstance(asyncio.get_running_loop(), asyncio.SelectorEventLoop) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         asyncio.run(main(), loop_factory=asyncio.EventLoop) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-01-22 14:06:27 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-03-24 21:51:16 +02:00
										 |  |  | class RunnerTests(BaseTest): | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def test_non_debug(self): | 
					
						
							|  |  |  |         with asyncio.Runner(debug=False) as runner: | 
					
						
							|  |  |  |             self.assertFalse(runner.get_loop().get_debug()) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def test_debug(self): | 
					
						
							|  |  |  |         with asyncio.Runner(debug=True) as runner: | 
					
						
							|  |  |  |             self.assertTrue(runner.get_loop().get_debug()) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def test_custom_factory(self): | 
					
						
							|  |  |  |         loop = mock.Mock() | 
					
						
							| 
									
										
										
										
											2022-03-26 00:26:23 +02:00
										 |  |  |         with asyncio.Runner(loop_factory=lambda: loop) as runner: | 
					
						
							| 
									
										
										
										
											2022-03-24 21:51:16 +02:00
										 |  |  |             self.assertIs(runner.get_loop(), loop) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def test_run(self): | 
					
						
							|  |  |  |         async def f(): | 
					
						
							|  |  |  |             await asyncio.sleep(0) | 
					
						
							|  |  |  |             return 'done' | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         with asyncio.Runner() as runner: | 
					
						
							|  |  |  |             self.assertEqual('done', runner.run(f())) | 
					
						
							|  |  |  |             loop = runner.get_loop() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         with self.assertRaisesRegex( | 
					
						
							|  |  |  |             RuntimeError, | 
					
						
							|  |  |  |             "Runner is closed" | 
					
						
							|  |  |  |         ): | 
					
						
							|  |  |  |             runner.get_loop() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         self.assertTrue(loop.is_closed()) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def test_run_non_coro(self): | 
					
						
							|  |  |  |         with asyncio.Runner() as runner: | 
					
						
							|  |  |  |             with self.assertRaisesRegex( | 
					
						
							|  |  |  |                 ValueError, | 
					
						
							|  |  |  |                 "a coroutine was expected" | 
					
						
							|  |  |  |             ): | 
					
						
							|  |  |  |                 runner.run(123) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def test_run_future(self): | 
					
						
							|  |  |  |         with asyncio.Runner() as runner: | 
					
						
							|  |  |  |             with self.assertRaisesRegex( | 
					
						
							|  |  |  |                 ValueError, | 
					
						
							|  |  |  |                 "a coroutine was expected" | 
					
						
							|  |  |  |             ): | 
					
						
							|  |  |  |                 fut = runner.get_loop().create_future() | 
					
						
							|  |  |  |                 runner.run(fut) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def test_explicit_close(self): | 
					
						
							|  |  |  |         runner = asyncio.Runner() | 
					
						
							|  |  |  |         loop = runner.get_loop() | 
					
						
							|  |  |  |         runner.close() | 
					
						
							|  |  |  |         with self.assertRaisesRegex( | 
					
						
							|  |  |  |                 RuntimeError, | 
					
						
							|  |  |  |                 "Runner is closed" | 
					
						
							|  |  |  |         ): | 
					
						
							|  |  |  |             runner.get_loop() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         self.assertTrue(loop.is_closed()) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def test_double_close(self): | 
					
						
							|  |  |  |         runner = asyncio.Runner() | 
					
						
							|  |  |  |         loop = runner.get_loop() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         runner.close() | 
					
						
							|  |  |  |         self.assertTrue(loop.is_closed()) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         # the second call is no-op | 
					
						
							|  |  |  |         runner.close() | 
					
						
							|  |  |  |         self.assertTrue(loop.is_closed()) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def test_second_with_block_raises(self): | 
					
						
							|  |  |  |         ret = [] | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         async def f(arg): | 
					
						
							|  |  |  |             ret.append(arg) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         runner = asyncio.Runner() | 
					
						
							|  |  |  |         with runner: | 
					
						
							|  |  |  |             runner.run(f(1)) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         with self.assertRaisesRegex( | 
					
						
							|  |  |  |             RuntimeError, | 
					
						
							|  |  |  |             "Runner is closed" | 
					
						
							|  |  |  |         ): | 
					
						
							|  |  |  |             with runner: | 
					
						
							|  |  |  |                 runner.run(f(2)) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         self.assertEqual([1], ret) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def test_run_keeps_context(self): | 
					
						
							|  |  |  |         cvar = contextvars.ContextVar("cvar", default=-1) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         async def f(val): | 
					
						
							|  |  |  |             old = cvar.get() | 
					
						
							|  |  |  |             await asyncio.sleep(0) | 
					
						
							|  |  |  |             cvar.set(val) | 
					
						
							|  |  |  |             return old | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         async def get_context(): | 
					
						
							|  |  |  |             return contextvars.copy_context() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         with asyncio.Runner() as runner: | 
					
						
							|  |  |  |             self.assertEqual(-1, runner.run(f(1))) | 
					
						
							|  |  |  |             self.assertEqual(1, runner.run(f(2))) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-03-25 19:59:29 +02:00
										 |  |  |             self.assertEqual(2, runner.run(get_context()).get(cvar)) | 
					
						
							| 
									
										
										
										
											2022-03-24 21:51:16 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-03-30 15:15:06 +03:00
										 |  |  |     def test_recursive_run(self): | 
					
						
							| 
									
										
										
										
											2022-03-24 21:51:16 +02:00
										 |  |  |         async def g(): | 
					
						
							|  |  |  |             pass | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         async def f(): | 
					
						
							|  |  |  |             runner.run(g()) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         with asyncio.Runner() as runner: | 
					
						
							|  |  |  |             with self.assertWarnsRegex( | 
					
						
							|  |  |  |                 RuntimeWarning, | 
					
						
							|  |  |  |                 "coroutine .+ was never awaited", | 
					
						
							|  |  |  |             ): | 
					
						
							|  |  |  |                 with self.assertRaisesRegex( | 
					
						
							|  |  |  |                     RuntimeError, | 
					
						
							|  |  |  |                     re.escape( | 
					
						
							|  |  |  |                         "Runner.run() cannot be called from a running event loop" | 
					
						
							|  |  |  |                     ), | 
					
						
							|  |  |  |                 ): | 
					
						
							|  |  |  |                     runner.run(f()) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-03-30 15:15:06 +03:00
										 |  |  |     def test_interrupt_call_soon(self): | 
					
						
							|  |  |  |         # The only case when task is not suspended by waiting a future | 
					
						
							|  |  |  |         # or another task | 
					
						
							|  |  |  |         assert threading.current_thread() is threading.main_thread() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         async def coro(): | 
					
						
							|  |  |  |             with self.assertRaises(asyncio.CancelledError): | 
					
						
							|  |  |  |                 while True: | 
					
						
							|  |  |  |                     await asyncio.sleep(0) | 
					
						
							|  |  |  |             raise asyncio.CancelledError() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         with asyncio.Runner() as runner: | 
					
						
							|  |  |  |             runner.get_loop().call_later(0.1, interrupt_self) | 
					
						
							|  |  |  |             with self.assertRaises(KeyboardInterrupt): | 
					
						
							|  |  |  |                 runner.run(coro()) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def test_interrupt_wait(self): | 
					
						
							|  |  |  |         # interrupting when waiting a future cancels both future and main task | 
					
						
							|  |  |  |         assert threading.current_thread() is threading.main_thread() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         async def coro(fut): | 
					
						
							|  |  |  |             with self.assertRaises(asyncio.CancelledError): | 
					
						
							|  |  |  |                 await fut | 
					
						
							|  |  |  |             raise asyncio.CancelledError() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         with asyncio.Runner() as runner: | 
					
						
							|  |  |  |             fut = runner.get_loop().create_future() | 
					
						
							|  |  |  |             runner.get_loop().call_later(0.1, interrupt_self) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             with self.assertRaises(KeyboardInterrupt): | 
					
						
							|  |  |  |                 runner.run(coro(fut)) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             self.assertTrue(fut.cancelled()) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def test_interrupt_cancelled_task(self): | 
					
						
							|  |  |  |         # interrupting cancelled main task doesn't raise KeyboardInterrupt | 
					
						
							|  |  |  |         assert threading.current_thread() is threading.main_thread() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         async def subtask(task): | 
					
						
							|  |  |  |             await asyncio.sleep(0) | 
					
						
							|  |  |  |             task.cancel() | 
					
						
							|  |  |  |             interrupt_self() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         async def coro(): | 
					
						
							|  |  |  |             asyncio.create_task(subtask(asyncio.current_task())) | 
					
						
							|  |  |  |             await asyncio.sleep(10) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         with asyncio.Runner() as runner: | 
					
						
							|  |  |  |             with self.assertRaises(asyncio.CancelledError): | 
					
						
							|  |  |  |                 runner.run(coro()) | 
					
						
							| 
									
										
										
										
											2022-05-25 18:34:14 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-04-25 16:56:20 +01:00
										 |  |  |     def test_signal_install_not_supported_ok(self): | 
					
						
							| 
									
										
										
										
											2022-05-25 18:34:14 +03:00
										 |  |  |         # signal.signal() can throw if the "main thread" doesn't have signals enabled | 
					
						
							| 
									
										
										
										
											2022-04-25 16:56:20 +01:00
										 |  |  |         assert threading.current_thread() is threading.main_thread() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         async def coro(): | 
					
						
							|  |  |  |             pass | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         with asyncio.Runner() as runner: | 
					
						
							|  |  |  |             with patch.object( | 
					
						
							|  |  |  |                 signal, | 
					
						
							|  |  |  |                 "signal", | 
					
						
							|  |  |  |                 side_effect=ValueError( | 
					
						
							|  |  |  |                     "signal only works in main thread of the main interpreter" | 
					
						
							|  |  |  |                 ) | 
					
						
							|  |  |  |             ): | 
					
						
							|  |  |  |                 runner.run(coro()) | 
					
						
							| 
									
										
										
										
											2022-03-30 15:15:06 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-08-15 22:32:47 +05:30
										 |  |  |     def test_set_event_loop_called_once(self): | 
					
						
							|  |  |  |         # See https://github.com/python/cpython/issues/95736 | 
					
						
							|  |  |  |         async def coro(): | 
					
						
							|  |  |  |             pass | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         policy = asyncio.get_event_loop_policy() | 
					
						
							|  |  |  |         policy.set_event_loop = mock.Mock() | 
					
						
							|  |  |  |         runner = asyncio.Runner() | 
					
						
							|  |  |  |         runner.run(coro()) | 
					
						
							|  |  |  |         runner.run(coro()) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         self.assertEqual(1, policy.set_event_loop.call_count) | 
					
						
							|  |  |  |         runner.close() | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-12-23 17:07:52 -08:00
										 |  |  |     def test_no_repr_is_call_on_the_task_result(self): | 
					
						
							|  |  |  |         # See https://github.com/python/cpython/issues/112559. | 
					
						
							|  |  |  |         class MyResult: | 
					
						
							|  |  |  |             def __init__(self): | 
					
						
							|  |  |  |                 self.repr_count = 0 | 
					
						
							|  |  |  |             def __repr__(self): | 
					
						
							|  |  |  |                 self.repr_count += 1 | 
					
						
							|  |  |  |                 return super().__repr__() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         async def coro(): | 
					
						
							|  |  |  |             return MyResult() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         with asyncio.Runner() as runner: | 
					
						
							|  |  |  |             result = runner.run(coro()) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         self.assertEqual(0, result.repr_count) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-03-24 21:51:16 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-01-22 14:06:27 +03:00
										 |  |  | if __name__ == '__main__': | 
					
						
							|  |  |  |     unittest.main() |