Skip to content

Commit 7f802bb

Browse files
committed
[feat] Deprecates the optional scope keyword argument of asyncio markers. Users are encouraged to use the loop_scope keyword argument. The loop_scope kwarg does exactly the same, though its naming is consistent with the loop_scope kwarg of pytest_asyncio.fixture.
Signed-off-by: Michael Seifert <[email protected]>
1 parent 1bb4299 commit 7f802bb

22 files changed

+96
-68
lines changed

docs/source/concepts_module_scope_example.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -5,13 +5,13 @@
55
loop: asyncio.AbstractEventLoop
66

77

8-
@pytest.mark.asyncio(scope="module")
8+
@pytest.mark.asyncio(loop_scope="module")
99
async def test_remember_loop():
1010
global loop
1111
loop = asyncio.get_running_loop()
1212

1313

14-
@pytest.mark.asyncio(scope="module")
14+
@pytest.mark.asyncio(loop_scope="module")
1515
async def test_runs_in_a_loop():
1616
global loop
1717
assert asyncio.get_running_loop() is loop

docs/source/how-to-guides/class_scoped_loop_example.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
import pytest
44

55

6-
@pytest.mark.asyncio(scope="class")
6+
@pytest.mark.asyncio(loop_scope="class")
77
class TestInOneEventLoopPerClass:
88
loop: asyncio.AbstractEventLoop
99

docs/source/how-to-guides/module_scoped_loop_example.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
import pytest
44

5-
pytestmark = pytest.mark.asyncio(scope="module")
5+
pytestmark = pytest.mark.asyncio(loop_scope="module")
66

77
loop: asyncio.AbstractEventLoop
88

Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
11
import pytest
22

3-
pytestmark = pytest.mark.asyncio(scope="package")
3+
pytestmark = pytest.mark.asyncio(loop_scope="package")

docs/source/how-to-guides/run_class_tests_in_same_loop.rst

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
======================================================
22
How to run all tests in a class in the same event loop
33
======================================================
4-
All tests can be run inside the same event loop by marking them with ``pytest.mark.asyncio(scope="class")``.
4+
All tests can be run inside the same event loop by marking them with ``pytest.mark.asyncio(loop_scope="class")``.
55
This is easily achieved by using the *asyncio* marker as a class decorator.
66

77
.. include:: class_scoped_loop_example.py

docs/source/how-to-guides/run_module_tests_in_same_loop.rst

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
=======================================================
22
How to run all tests in a module in the same event loop
33
=======================================================
4-
All tests can be run inside the same event loop by marking them with ``pytest.mark.asyncio(scope="module")``.
4+
All tests can be run inside the same event loop by marking them with ``pytest.mark.asyncio(loop_scope="module")``.
55
This is easily achieved by adding a `pytestmark` statement to your module.
66

77
.. include:: module_scoped_loop_example.py

docs/source/how-to-guides/run_package_tests_in_same_loop.rst

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
========================================================
22
How to run all tests in a package in the same event loop
33
========================================================
4-
All tests can be run inside the same event loop by marking them with ``pytest.mark.asyncio(scope="package")``.
4+
All tests can be run inside the same event loop by marking them with ``pytest.mark.asyncio(loop_scope="package")``.
55
Add the following code to the ``__init__.py`` of the test package:
66

77
.. include:: package_scoped_loop_example.py

docs/source/how-to-guides/run_session_tests_in_same_loop.rst

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
==========================================================
22
How to run all tests in the session in the same event loop
33
==========================================================
4-
All tests can be run inside the same event loop by marking them with ``pytest.mark.asyncio(scope="session")``.
4+
All tests can be run inside the same event loop by marking them with ``pytest.mark.asyncio(loop_scope="session")``.
55
The easiest way to mark all tests is via a ``pytest_collection_modifyitems`` hook in the ``conftest.py`` at the root folder of your test suite.
66

77
.. include:: session_scoped_loop_example.py

docs/source/how-to-guides/session_scoped_loop_example.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,6 @@
55

66
def pytest_collection_modifyitems(items):
77
pytest_asyncio_tests = (item for item in items if is_async_test(item))
8-
session_scope_marker = pytest.mark.asyncio(scope="session")
8+
session_scope_marker = pytest.mark.asyncio(loop_scope="session")
99
for async_test in pytest_asyncio_tests:
1010
async_test.add_marker(session_scope_marker, append=False)

docs/source/reference/changelog.rst

+4
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,10 @@
22
Changelog
33
=========
44

5+
0.24.0 (UNRELEASED)
6+
===================
7+
- Deprecates the optional `scope` keyword argument of asyncio markers. Users are encouraged to use the `loop_scope` keyword argument. The `loop_scope` kwarg does exactly the same, though its naming is consistent with the `loop_scope` kwarg of ``pytest_asyncio.fixture``.
8+
59
0.23.8 (UNRELEASED)
610
===================
711
- Fixes a bug that caused duplicate markers in async tests `#813 <https://github.com/pytest-dev/pytest-asyncio/issues/813>`_

docs/source/reference/fixtures/event_loop_policy_example.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,6 @@ def event_loop_policy(request):
1212
return CustomEventLoopPolicy()
1313

1414

15-
@pytest.mark.asyncio(scope="module")
15+
@pytest.mark.asyncio(loop_scope="module")
1616
async def test_uses_custom_event_loop_policy():
1717
assert isinstance(asyncio.get_event_loop_policy(), CustomEventLoopPolicy)

docs/source/reference/markers/class_scoped_loop_strict_mode_example.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
import pytest
44

55

6-
@pytest.mark.asyncio(scope="class")
6+
@pytest.mark.asyncio(loop_scope="class")
77
class TestClassScopedLoop:
88
loop: asyncio.AbstractEventLoop
99

docs/source/reference/markers/class_scoped_loop_with_fixture_strict_mode_example.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
import pytest_asyncio
66

77

8-
@pytest.mark.asyncio(scope="class")
8+
@pytest.mark.asyncio(loop_scope="class")
99
class TestClassScopedLoop:
1010
loop: asyncio.AbstractEventLoop
1111

docs/source/reference/markers/module_scoped_loop_strict_mode_example.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
import pytest
44

5-
pytestmark = pytest.mark.asyncio(scope="module")
5+
pytestmark = pytest.mark.asyncio(loop_scope="module")
66

77
loop: asyncio.AbstractEventLoop
88

pytest_asyncio/plugin.py

+9-2
Original file line numberDiff line numberDiff line change
@@ -995,11 +995,18 @@ def pytest_runtest_setup(item: pytest.Item) -> None:
995995
but it should only use "loop_scope".
996996
"""
997997

998+
_MARKER_SCOPE_KWARG_DEPRECATION_WARNING = """\
999+
The "scope" keyword argument to the asyncio marker has been deprecated. \
1000+
Please use the "loop_scope" argument instead.
1001+
"""
1002+
9981003

9991004
def _get_marked_loop_scope(asyncio_marker: Mark) -> _ScopeName:
10001005
assert asyncio_marker.name == "asyncio"
1001-
if "scope" in asyncio_marker.kwargs and "loop_scope" in asyncio_marker.kwargs:
1002-
raise pytest.UsageError(_DUPLICATE_LOOP_SCOPE_DEFINITION_ERROR)
1006+
if "scope" in asyncio_marker.kwargs:
1007+
if "loop_scope" in asyncio_marker.kwargs:
1008+
raise pytest.UsageError(_DUPLICATE_LOOP_SCOPE_DEFINITION_ERROR)
1009+
warnings.warn(PytestDeprecationWarning(_MARKER_SCOPE_KWARG_DEPRECATION_WARNING))
10031010
scope = asyncio_marker.kwargs.get("loop_scope") or asyncio_marker.kwargs.get(
10041011
"scope", "function"
10051012
)

tests/async_fixtures/test_async_fixtures_with_finalizer.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,13 @@
44
import pytest
55

66

7-
@pytest.mark.asyncio(scope="module")
7+
@pytest.mark.asyncio(loop_scope="module")
88
async def test_module_with_event_loop_finalizer(port_with_event_loop_finalizer):
99
await asyncio.sleep(0.01)
1010
assert port_with_event_loop_finalizer
1111

1212

13-
@pytest.mark.asyncio(scope="module")
13+
@pytest.mark.asyncio(loop_scope="module")
1414
async def test_module_with_get_event_loop_finalizer(port_with_get_event_loop_finalizer):
1515
await asyncio.sleep(0.01)
1616
assert port_with_get_event_loop_finalizer

tests/markers/test_class_scope.py

+10-10
Original file line numberDiff line numberDiff line change
@@ -39,11 +39,11 @@ def test_asyncio_mark_provides_class_scoped_loop_when_applied_to_functions(
3939
class TestClassScopedLoop:
4040
loop: asyncio.AbstractEventLoop
4141
42-
@pytest.mark.asyncio(scope="class")
42+
@pytest.mark.asyncio(loop_scope="class")
4343
async def test_remember_loop(self):
4444
TestClassScopedLoop.loop = asyncio.get_running_loop()
4545
46-
@pytest.mark.asyncio(scope="class")
46+
@pytest.mark.asyncio(loop_scope="class")
4747
async def test_this_runs_in_same_loop(self):
4848
assert asyncio.get_running_loop() is TestClassScopedLoop.loop
4949
"""
@@ -62,7 +62,7 @@ def test_asyncio_mark_provides_class_scoped_loop_when_applied_to_class(
6262
import asyncio
6363
import pytest
6464
65-
@pytest.mark.asyncio(scope="class")
65+
@pytest.mark.asyncio(loop_scope="class")
6666
class TestClassScopedLoop:
6767
loop: asyncio.AbstractEventLoop
6868
@@ -87,7 +87,7 @@ def test_asyncio_mark_raises_when_class_scoped_is_request_without_class(
8787
import asyncio
8888
import pytest
8989
90-
@pytest.mark.asyncio(scope="class")
90+
@pytest.mark.asyncio(loop_scope="class")
9191
async def test_has_no_surrounding_class():
9292
pass
9393
"""
@@ -107,7 +107,7 @@ def test_asyncio_mark_is_inherited_to_subclasses(pytester: pytest.Pytester):
107107
import asyncio
108108
import pytest
109109
110-
@pytest.mark.asyncio(scope="class")
110+
@pytest.mark.asyncio(loop_scope="class")
111111
class TestSuperClassWithMark:
112112
pass
113113
@@ -183,7 +183,7 @@ def test_asyncio_mark_respects_parametrized_loop_policies(
183183
def event_loop_policy(request):
184184
return request.param
185185
186-
@pytest.mark.asyncio(scope="class")
186+
@pytest.mark.asyncio(loop_scope="class")
187187
class TestWithDifferentLoopPolicies:
188188
async def test_parametrized_loop(self, request):
189189
pass
@@ -205,7 +205,7 @@ def test_asyncio_mark_provides_class_scoped_loop_to_fixtures(
205205
import pytest
206206
import pytest_asyncio
207207
208-
@pytest.mark.asyncio(scope="class")
208+
@pytest.mark.asyncio(loop_scope="class")
209209
class TestClassScopedLoop:
210210
loop: asyncio.AbstractEventLoop
211211
@@ -242,7 +242,7 @@ async def async_fixture(self):
242242
global loop
243243
loop = asyncio.get_running_loop()
244244
245-
@pytest.mark.asyncio(scope="function")
245+
@pytest.mark.asyncio(loop_scope="function")
246246
async def test_runs_in_different_loop_as_fixture(self, async_fixture):
247247
global loop
248248
assert asyncio.get_running_loop() is not loop
@@ -277,7 +277,7 @@ def sets_event_loop_to_none(self):
277277
return asyncio.run(asyncio.sleep(0))
278278
# asyncio.run() sets the current event loop to None when finished
279279
280-
@pytest.mark.asyncio(scope="class")
280+
@pytest.mark.asyncio(loop_scope="class")
281281
# parametrization may impact fixture ordering
282282
@pytest.mark.parametrize("n", (0, 1))
283283
async def test_does_not_fail(self, sets_event_loop_to_none, n):
@@ -297,7 +297,7 @@ def test_standalone_test_does_not_trigger_warning_about_no_current_event_loop_be
297297
"""\
298298
import pytest
299299
300-
@pytest.mark.asyncio(scope="class")
300+
@pytest.mark.asyncio(loop_scope="class")
301301
class TestClass:
302302
async def test_anything(self):
303303
pass

tests/markers/test_function_scope.py

+17
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,23 @@ async def test_raises():
6969
result.assert_outcomes(errors=1)
7070

7171

72+
def test_warns_when_scope_argument_is_present(pytester: Pytester):
73+
pytester.makepyfile(
74+
dedent(
75+
"""\
76+
import pytest
77+
78+
@pytest.mark.asyncio(scope="function")
79+
async def test_warns():
80+
...
81+
"""
82+
)
83+
)
84+
result = pytester.runpytest_subprocess("--asyncio-mode=strict")
85+
result.assert_outcomes(passed=1, warnings=2)
86+
result.stdout.fnmatch_lines("*DeprecationWarning*")
87+
88+
7289
def test_function_scope_supports_explicit_event_loop_fixture_request(
7390
pytester: Pytester,
7491
):

tests/markers/test_module_scope.py

+11-11
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@ def test_asyncio_mark_provides_module_scoped_loop_strict_mode(pytester: Pytester
6262
import asyncio
6363
import pytest
6464
65-
pytestmark = pytest.mark.asyncio(scope="module")
65+
pytestmark = pytest.mark.asyncio(loop_scope="module")
6666
6767
loop: asyncio.AbstractEventLoop
6868
@@ -94,7 +94,7 @@ def test_raise_when_event_loop_fixture_is_requested_in_addition_to_scoped_loop(
9494
import asyncio
9595
import pytest
9696
97-
pytestmark = pytest.mark.asyncio(scope="module")
97+
pytestmark = pytest.mark.asyncio(loop_scope="module")
9898
9999
async def test_remember_loop(event_loop):
100100
pass
@@ -126,7 +126,7 @@ class CustomEventLoopPolicy(asyncio.DefaultEventLoopPolicy):
126126
127127
from .custom_policy import CustomEventLoopPolicy
128128
129-
pytestmark = pytest.mark.asyncio(scope="module")
129+
pytestmark = pytest.mark.asyncio(loop_scope="module")
130130
131131
@pytest.fixture(scope="module")
132132
def event_loop_policy():
@@ -146,7 +146,7 @@ async def test_uses_custom_event_loop_policy():
146146
147147
from .custom_policy import CustomEventLoopPolicy
148148
149-
pytestmark = pytest.mark.asyncio(scope="module")
149+
pytestmark = pytest.mark.asyncio(loop_scope="module")
150150
151151
async def test_does_not_use_custom_event_loop_policy():
152152
assert not isinstance(
@@ -170,7 +170,7 @@ def test_asyncio_mark_respects_parametrized_loop_policies(
170170
171171
import pytest
172172
173-
pytestmark = pytest.mark.asyncio(scope="module")
173+
pytestmark = pytest.mark.asyncio(loop_scope="module")
174174
175175
@pytest.fixture(
176176
scope="module",
@@ -202,7 +202,7 @@ def test_asyncio_mark_provides_module_scoped_loop_to_fixtures(
202202
import pytest
203203
import pytest_asyncio
204204
205-
pytestmark = pytest.mark.asyncio(scope="module")
205+
pytestmark = pytest.mark.asyncio(loop_scope="module")
206206
207207
loop: asyncio.AbstractEventLoop
208208
@@ -239,7 +239,7 @@ async def async_fixture():
239239
global loop
240240
loop = asyncio.get_running_loop()
241241
242-
@pytest.mark.asyncio(scope="class")
242+
@pytest.mark.asyncio(loop_scope="class")
243243
class TestMixedScopes:
244244
async def test_runs_in_different_loop_as_fixture(self, async_fixture):
245245
global loop
@@ -271,7 +271,7 @@ async def async_fixture():
271271
global loop
272272
loop = asyncio.get_running_loop()
273273
274-
@pytest.mark.asyncio(scope="function")
274+
@pytest.mark.asyncio(loop_scope="function")
275275
async def test_runs_in_different_loop_as_fixture(async_fixture):
276276
global loop
277277
assert asyncio.get_running_loop() is not loop
@@ -301,7 +301,7 @@ async def async_fixture():
301301
loop = asyncio.get_running_loop()
302302
yield
303303
304-
@pytest.mark.asyncio(scope="function")
304+
@pytest.mark.asyncio(loop_scope="function")
305305
async def test_runs_in_different_loop_as_fixture(async_fixture):
306306
global loop
307307
assert asyncio.get_running_loop() is not loop
@@ -334,7 +334,7 @@ def sets_event_loop_to_none():
334334
return asyncio.run(asyncio.sleep(0))
335335
# asyncio.run() sets the current event loop to None when finished
336336
337-
@pytest.mark.asyncio(scope="module")
337+
@pytest.mark.asyncio(loop_scope="module")
338338
# parametrization may impact fixture ordering
339339
@pytest.mark.parametrize("n", (0, 1))
340340
async def test_does_not_fail(sets_event_loop_to_none, n):
@@ -354,7 +354,7 @@ def test_standalone_test_does_not_trigger_warning_about_no_current_event_loop_be
354354
"""\
355355
import pytest
356356
357-
@pytest.mark.asyncio(scope="module")
357+
@pytest.mark.asyncio(loop_scope="module")
358358
async def test_anything():
359359
pass
360360
"""

0 commit comments

Comments
 (0)