diff --git a/docs/source/reference/changelog.rst b/docs/source/reference/changelog.rst index 198baf68..21d6a391 100644 --- a/docs/source/reference/changelog.rst +++ b/docs/source/reference/changelog.rst @@ -2,6 +2,10 @@ Changelog ========= +0.23.7 (UNRELEASED) +=================== +- Silence deprecation warnings about unclosed event loops that occurred with certain CPython patch releases `#817 `_ + 0.23.6 (2024-03-19) =================== - Fix compatibility with pytest 8.2 `#800 `_ diff --git a/pytest_asyncio/plugin.py b/pytest_asyncio/plugin.py index b2c5c59e..7dbb238d 100644 --- a/pytest_asyncio/plugin.py +++ b/pytest_asyncio/plugin.py @@ -657,9 +657,7 @@ def _patched_collect(): def _temporary_event_loop_policy(policy: AbstractEventLoopPolicy) -> Iterator[None]: old_loop_policy = asyncio.get_event_loop_policy() try: - with warnings.catch_warnings(): - warnings.simplefilter("ignore", DeprecationWarning) - old_loop = asyncio.get_event_loop() + old_loop = _get_event_loop_no_warn() except RuntimeError: old_loop = None asyncio.set_event_loop_policy(policy) @@ -673,7 +671,7 @@ def _temporary_event_loop_policy(policy: AbstractEventLoopPolicy) -> Iterator[No # subsequent tests from side-effects. We close this loop before restoring # the old loop to avoid ResourceWarnings. try: - asyncio.get_event_loop().close() + _get_event_loop_no_warn().close() except RuntimeError: pass asyncio.set_event_loop(old_loop) @@ -763,9 +761,7 @@ def pytest_fixture_setup( ) policy = asyncio.get_event_loop_policy() try: - with warnings.catch_warnings(): - warnings.simplefilter("ignore", DeprecationWarning) - old_loop = policy.get_event_loop() + old_loop = _get_event_loop_no_warn(policy) is_pytest_asyncio_loop = getattr(old_loop, "__pytest_asyncio", False) if old_loop is not loop and not is_pytest_asyncio_loop: old_loop.close() @@ -827,9 +823,7 @@ def _restore_policy(): # Close any event loop associated with the old loop policy # to avoid ResourceWarnings in the _provide_clean_event_loop finalizer try: - with warnings.catch_warnings(): - warnings.simplefilter("ignore", DeprecationWarning) - loop = previous_policy.get_event_loop() + loop = _get_event_loop_no_warn(previous_policy) except RuntimeError: loop = None if loop: @@ -851,6 +845,17 @@ def _provide_clean_event_loop() -> None: policy.set_event_loop(new_loop) +def _get_event_loop_no_warn( + policy: Optional[AbstractEventLoopPolicy] = None, +) -> asyncio.AbstractEventLoop: + with warnings.catch_warnings(): + warnings.simplefilter("ignore", DeprecationWarning) + if policy is not None: + return policy.get_event_loop() + else: + return asyncio.get_event_loop() + + @pytest.hookimpl(tryfirst=True, hookwrapper=True) def pytest_pyfunc_call(pyfuncitem: Function) -> Optional[object]: """ @@ -891,7 +896,7 @@ def wrap_in_sync( @functools.wraps(func) def inner(*args, **kwargs): coro = func(*args, **kwargs) - _loop = asyncio.get_event_loop() + _loop = _get_event_loop_no_warn() task = asyncio.ensure_future(coro, loop=_loop) try: _loop.run_until_complete(task) diff --git a/tests/async_fixtures/test_async_fixtures_with_finalizer.py b/tests/async_fixtures/test_async_fixtures_with_finalizer.py index 699ac49d..b4d2ac94 100644 --- a/tests/async_fixtures/test_async_fixtures_with_finalizer.py +++ b/tests/async_fixtures/test_async_fixtures_with_finalizer.py @@ -33,7 +33,7 @@ async def port_afinalizer(): # RuntimeError is raised if task is created on a different loop await finalizer - asyncio.get_event_loop().run_until_complete(port_afinalizer()) + asyncio.run(port_afinalizer()) worker = asyncio.ensure_future(asyncio.sleep(0.2)) request.addfinalizer(functools.partial(port_finalizer, worker))