gh-110774: allow setting the Runner(loop_factory=...) from IsolatedAsyncioTestCase (#110776)

https://github.com/python/cpython/commit/770530679e89b06f33655b34a8c466ed906... commit: 770530679e89b06f33655b34a8c466ed906842fe branch: main author: Thomas Grainger <tagrain@gmail.com> committer: gvanrossum <gvanrossum@gmail.com> date: 2023-10-31T15:03:54-07:00 summary: gh-110774: allow setting the Runner(loop_factory=...) from IsolatedAsyncioTestCase (#110776) Co-authored-by: Łukasz Langa <lukasz@langa.pl> Co-authored-by: Carol Willing <carolcode@willingconsulting.com> files: A Misc/NEWS.d/next/Library/2023-10-12-15-16-44.gh-issue-110774.AdCb5A.rst M Doc/library/unittest.rst M Lib/test/test_unittest/test_async_case.py M Lib/unittest/async_case.py diff --git a/Doc/library/unittest.rst b/Doc/library/unittest.rst index 21abc583f853a..c90c554591e74 100644 --- a/Doc/library/unittest.rst +++ b/Doc/library/unittest.rst @@ -1571,6 +1571,14 @@ Test cases .. versionadded:: 3.8 + .. attribute:: loop_factory + + The *loop_factory* passed to :class:`asyncio.Runner`. Override + in subclasses with :class:`asyncio.EventLoop` to avoid using the + asyncio policy system. + + .. versionadded:: 3.13 + .. coroutinemethod:: asyncSetUp() Method called to prepare the test fixture. This is called after :meth:`setUp`. diff --git a/Lib/test/test_unittest/test_async_case.py b/Lib/test/test_unittest/test_async_case.py index a465103b59b6e..ba1ab838cd4a2 100644 --- a/Lib/test/test_unittest/test_async_case.py +++ b/Lib/test/test_unittest/test_async_case.py @@ -484,5 +484,19 @@ async def test_demo1(self): result = test.run() self.assertTrue(result.wasSuccessful()) + def test_loop_factory(self): + asyncio.set_event_loop_policy(None) + + class TestCase1(unittest.IsolatedAsyncioTestCase): + loop_factory = asyncio.EventLoop + + async def test_demo1(self): + pass + + test = TestCase1('test_demo1') + result = test.run() + self.assertTrue(result.wasSuccessful()) + self.assertIsNone(support.maybe_get_event_loop_policy()) + if __name__ == "__main__": unittest.main() diff --git a/Lib/unittest/async_case.py b/Lib/unittest/async_case.py index bd2a471156065..63ff6a5d1f8b6 100644 --- a/Lib/unittest/async_case.py +++ b/Lib/unittest/async_case.py @@ -25,12 +25,15 @@ class IsolatedAsyncioTestCase(TestCase): # them inside the same task. # Note: the test case modifies event loop policy if the policy was not instantiated - # yet. + # yet, unless loop_factory=asyncio.EventLoop is set. # asyncio.get_event_loop_policy() creates a default policy on demand but never # returns None # I believe this is not an issue in user level tests but python itself for testing # should reset a policy in every test module # by calling asyncio.set_event_loop_policy(None) in tearDownModule() + # or set loop_factory=asyncio.EventLoop + + loop_factory = None def __init__(self, methodName='runTest'): super().__init__(methodName) @@ -118,7 +121,7 @@ def _callMaybeAsync(self, func, /, *args, **kwargs): def _setupAsyncioRunner(self): assert self._asyncioRunner is None, 'asyncio runner is already initialized' - runner = asyncio.Runner(debug=True) + runner = asyncio.Runner(debug=True, loop_factory=self.loop_factory) self._asyncioRunner = runner def _tearDownAsyncioRunner(self): diff --git a/Misc/NEWS.d/next/Library/2023-10-12-15-16-44.gh-issue-110774.AdCb5A.rst b/Misc/NEWS.d/next/Library/2023-10-12-15-16-44.gh-issue-110774.AdCb5A.rst new file mode 100644 index 0000000000000..a5a9fed11864d --- /dev/null +++ b/Misc/NEWS.d/next/Library/2023-10-12-15-16-44.gh-issue-110774.AdCb5A.rst @@ -0,0 +1 @@ +Support setting the :class:`asyncio.Runner` loop_factory kwarg in :class:`unittest.IsolatedAsyncioTestCase`
participants (1)
-
gvanrossum