Skip to content

Commit 947e31a

Browse files
authored
Deprecate closing of existing loops (#510)
* [docs] Corrected comment on when a RuntimeError occurs upon calling get_event_loop. Signed-off-by: Michael Seifert <[email protected]> * [refactor] Turn ResourceWarning for unclosed event loops into a DeprecationWarning. Changing the warning type emphasizes that the functionality will no longer be available in the future. The commit also extends the tests for the deprecation warning and adjusts the changlog entry and deprecation message. Signed-off-by: Michael Seifert <[email protected]> --------- Signed-off-by: Michael Seifert <[email protected]>
1 parent e1cc62d commit 947e31a

File tree

3 files changed

+38
-14
lines changed

3 files changed

+38
-14
lines changed

Diff for: docs/source/reference/changelog.rst

+4-1
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,10 @@ Changelog
55
UNRELEASED
66
=================
77
- Drop compatibility with pytest 6.1. Pytest-asyncio now depends on pytest 7.0 or newer.
8-
- event_loop fixture teardown emits a ResourceWarning when the current event loop has not been closed.
8+
- pytest-asyncio cleans up any stale event loops when setting up and tearing down the
9+
event_loop fixture. This behavior has been deprecated and pytest-asyncio emits a
10+
DeprecationWarning when tearing down the event_loop fixture and current event loop
11+
has not been closed.
912

1013
0.20.3 (22-12-08)
1114
=================

Diff for: pytest_asyncio/plugin.py

+11-11
Original file line numberDiff line numberDiff line change
@@ -397,7 +397,9 @@ def pytest_fixture_setup(
397397
if old_loop is not loop:
398398
old_loop.close()
399399
except RuntimeError:
400-
# Swallow this, since it's probably bad event loop hygiene.
400+
# Either the current event loop has been set to None
401+
# or the loop policy doesn't specify to create new loops
402+
# or we're not in the main thread
401403
pass
402404
policy.set_event_loop(loop)
403405
return
@@ -420,11 +422,13 @@ def _add_finalizers(fixturedef: FixtureDef, *finalizers: Callable[[], object]) -
420422

421423
_UNCLOSED_EVENT_LOOP_WARNING = dedent(
422424
"""\
423-
unclosed event loop %r.
424-
Possible causes are:
425-
1. A custom "event_loop" fixture is used which doesn't close the loop
426-
2. Your code or one of your dependencies created a new event loop during
427-
the test run
425+
pytest-asyncio detected an unclosed event loop when tearing down the event_loop
426+
fixture: %r
427+
pytest-asyncio will close the event loop for you, but future versions of the
428+
library will no longer do so. In order to ensure compatibility with future
429+
versions, please make sure that:
430+
1. Any custom "event_loop" fixture properly closes the loop after yielding it
431+
2. Your code does not modify the event loop in async fixtures or tests
428432
"""
429433
)
430434

@@ -436,14 +440,10 @@ def _close_event_loop() -> None:
436440
except RuntimeError:
437441
loop = None
438442
if loop is not None:
439-
# Emit ResourceWarnings in the context of the fixture/test case
440-
# rather than waiting for the interpreter to trigger the warning when
441-
# garbage collecting the event loop.
442443
if not loop.is_closed():
443444
warnings.warn(
444445
_UNCLOSED_EVENT_LOOP_WARNING % loop,
445-
ResourceWarning,
446-
source=loop,
446+
DeprecationWarning,
447447
)
448448
loop.close()
449449

Diff for: tests/test_event_loop_fixture_finalizer.py

+23-2
Original file line numberDiff line numberDiff line change
@@ -88,15 +88,14 @@ async def test_async_with_explicit_fixture_request(event_loop):
8888
result.assert_outcomes(passed=1)
8989

9090

91-
def test_event_loop_fixture_finalizer_raises_warning_when_loop_is_unclosed(
91+
def test_event_loop_fixture_finalizer_raises_warning_when_fixture_leaves_loop_unclosed(
9292
pytester: Pytester,
9393
):
9494
pytester.makepyfile(
9595
dedent(
9696
"""\
9797
import asyncio
9898
import pytest
99-
import pytest_asyncio
10099
101100
pytest_plugins = 'pytest_asyncio'
102101
@@ -114,3 +113,25 @@ async def test_ends_with_unclosed_loop():
114113
result = pytester.runpytest("--asyncio-mode=strict", "-W", "default")
115114
result.assert_outcomes(passed=1, warnings=1)
116115
result.stdout.fnmatch_lines("*unclosed event loop*")
116+
117+
118+
def test_event_loop_fixture_finalizer_raises_warning_when_test_leaves_loop_unclosed(
119+
pytester: Pytester,
120+
):
121+
pytester.makepyfile(
122+
dedent(
123+
"""\
124+
import asyncio
125+
import pytest
126+
127+
pytest_plugins = 'pytest_asyncio'
128+
129+
@pytest.mark.asyncio
130+
async def test_ends_with_unclosed_loop():
131+
asyncio.set_event_loop(asyncio.new_event_loop())
132+
"""
133+
)
134+
)
135+
result = pytester.runpytest("--asyncio-mode=strict", "-W", "default")
136+
result.assert_outcomes(passed=1, warnings=1)
137+
result.stdout.fnmatch_lines("*unclosed event loop*")

0 commit comments

Comments
 (0)