From 770530679e89b06f33655b34a8c466ed906842fe Mon Sep 17 00:00:00 2001 From: Thomas Grainger Date: Tue, 31 Oct 2023 15:03:54 -0700 Subject: gh-110774: allow setting the Runner(loop_factory=...) from IsolatedAsyncioTestCase (#110776) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Ɓukasz Langa Co-authored-by: Carol Willing --- Doc/library/unittest.rst | 8 ++++++++ Lib/test/test_unittest/test_async_case.py | 14 ++++++++++++++ Lib/unittest/async_case.py | 7 +++++-- .../Library/2023-10-12-15-16-44.gh-issue-110774.AdCb5A.rst | 1 + 4 files changed, 28 insertions(+), 2 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2023-10-12-15-16-44.gh-issue-110774.AdCb5A.rst diff --git a/Doc/library/unittest.rst b/Doc/library/unittest.rst index 21abc58..c90c554 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 a465103..ba1ab83 100644 --- a/Lib/test/test_unittest/test_async_case.py +++ b/Lib/test/test_unittest/test_async_case.py @@ -484,5 +484,19 @@ class TestAsyncCase(unittest.TestCase): 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 bd2a471..63ff6a5 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 @@ class IsolatedAsyncioTestCase(TestCase): 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 0000000..a5a9fed --- /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` -- cgit v0.12