Skip to content

Commit a7b1c39

Browse files
committed
[feat!] Replaced the asyncio_event_loop marker with an optional "scope" kwarg to the asyncio mark.
Signed-off-by: Michael Seifert <[email protected]>
1 parent 4c5e660 commit a7b1c39

15 files changed

+209
-276
lines changed

docs/source/reference/changelog.rst

+8-1
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,18 @@ Changelog
44

55
0.23.0 (UNRELEASED)
66
===================
7-
- Removes pytest-trio from the test dependencies `#620 <https://github.com/pytest-dev/pytest-asyncio/pull/620>`_
7+
This release is backwards-compatible with v0.21.
8+
Changes are non-breaking, unless you upgrade from v0.22.
9+
10+
- BREAKING: The *asyncio_event_loop* mark has been removed. Class-scoped and module-scoped event loops can be requested
11+
via the *scope* keyword argument to the _asyncio_ mark.
812
- Introduces the *event_loop_policy* fixture which allows testing with non-default or multiple event loops `#662 <https://github.com/pytest-dev/pytest-asyncio/pull/662>`_
13+
- Removes pytest-trio from the test dependencies `#620 <https://github.com/pytest-dev/pytest-asyncio/pull/620>`_
914

1015
0.22.0 (2023-10-31)
1116
===================
17+
This release has been yanked from PyPI due to fundamental issues with the _asyncio_event_loop_ mark.
18+
1219
- Class-scoped and module-scoped event loops can be requested
1320
via the _asyncio_event_loop_ mark. `#620 <https://github.com/pytest-dev/pytest-asyncio/pull/620>`_
1421
- Deprecate redefinition of the `event_loop` fixture. `#587 <https://github.com/pytest-dev/pytest-asyncio/issues/531>`_

docs/source/reference/fixtures/index.rst

+2-4
Original file line numberDiff line numberDiff line change
@@ -6,17 +6,15 @@ event_loop
66
==========
77
Creates a new asyncio event loop based on the current event loop policy. The new loop
88
is available as the return value of this fixture for synchronous functions, or via `asyncio.get_running_loop <https://docs.python.org/3/library/asyncio-eventloop.html#asyncio.get_running_loop>`__ for asynchronous functions.
9-
The event loop is closed when the fixture scope ends. The fixture scope defaults
10-
to ``function`` scope.
9+
The event loop is closed when the fixture scope ends.
10+
The fixture scope defaults to ``function`` scope.
1111

1212
.. include:: event_loop_example.py
1313
:code: python
1414

1515
Note that, when using the ``event_loop`` fixture, you need to interact with the event loop using methods like ``event_loop.run_until_complete``. If you want to *await* code inside your test function, you need to write a coroutine and use it as a test function. The `asyncio <#pytest-mark-asyncio>`__ marker
1616
is used to mark coroutines that should be treated as test functions.
1717

18-
If your tests require an asyncio event loop with class or module scope, apply the `asyncio_event_loop mark <./markers.html/#pytest-mark-asyncio-event-loop>`__ to the respective class or module.
19-
2018
If you need to change the type of the event loop, prefer setting a custom event loop policy over redefining the ``event_loop`` fixture.
2119

2220
If the ``pytest.mark.asyncio`` decorator is applied to a test function, the ``event_loop``

docs/source/reference/markers/class_scoped_loop_auto_mode_example.py

-14
This file was deleted.

docs/source/reference/markers/class_scoped_loop_custom_policy_strict_mode_example.py

-19
This file was deleted.

docs/source/reference/markers/class_scoped_loop_strict_mode_example.py

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

55

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

10-
@pytest.mark.asyncio
1110
async def test_remember_loop(self):
1211
TestClassScopedLoop.loop = asyncio.get_running_loop()
1312

14-
@pytest.mark.asyncio
1513
async def test_this_runs_in_same_loop(self):
1614
assert asyncio.get_running_loop() is TestClassScopedLoop.loop

docs/source/reference/markers/class_scoped_loop_with_fixture_strict_mode_example.py

+1-2
Original file line numberDiff line numberDiff line change
@@ -5,14 +5,13 @@
55
import pytest_asyncio
66

77

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

1212
@pytest_asyncio.fixture
1313
async def my_fixture(self):
1414
TestClassScopedLoop.loop = asyncio.get_running_loop()
1515

16-
@pytest.mark.asyncio
1716
async def test_runs_is_same_loop_as_fixture(self, my_fixture):
1817
assert asyncio.get_running_loop() is TestClassScopedLoop.loop
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
import asyncio
2+
3+
import pytest
4+
5+
# Marks all test coroutines in this module
6+
pytestmark = pytest.mark.asyncio
7+
8+
9+
async def test_runs_in_asyncio_event_loop():
10+
assert asyncio.get_running_loop()
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
import asyncio
2+
3+
import pytest
4+
5+
6+
@pytest.mark.asyncio
7+
async def test_runs_in_asyncio_event_loop():
8+
assert asyncio.get_running_loop()

docs/source/reference/markers/index.rst

+15-43
Original file line numberDiff line numberDiff line change
@@ -4,62 +4,34 @@ Markers
44

55
``pytest.mark.asyncio``
66
=======================
7-
A coroutine or async generator with this marker will be treated as a test function by pytest. The marked function will be executed as an
8-
asyncio task in the event loop provided by the ``event_loop`` fixture.
7+
A coroutine or async generator with this marker is treated as a test function by pytest.
8+
The marked function is executed as an asyncio task in the event loop provided by pytest-asyncio.
99

10-
In order to make your test code a little more concise, the pytest |pytestmark|_
11-
feature can be used to mark entire modules or classes with this marker.
12-
Only test coroutines will be affected (by default, coroutines prefixed by
13-
``test_``), so, for example, fixtures are safe to define.
14-
15-
.. include:: pytestmark_asyncio_strict_mode_example.py
16-
:code: python
17-
18-
In *auto* mode, the ``pytest.mark.asyncio`` marker can be omitted, the marker is added
19-
automatically to *async* test functions.
20-
21-
22-
``pytest.mark.asyncio_event_loop``
23-
==================================
24-
Test classes or modules with this mark provide a class-scoped or module-scoped asyncio event loop.
25-
26-
This functionality is orthogonal to the `asyncio` mark.
27-
That means the presence of this mark does not imply that async test functions inside the class or module are collected by pytest-asyncio.
28-
The collection happens automatically in `auto` mode.
29-
However, if you're using strict mode, you still have to apply the `asyncio` mark to your async test functions.
30-
31-
The following code example uses the `asyncio_event_loop` mark to provide a shared event loop for all tests in `TestClassScopedLoop`:
32-
33-
.. include:: class_scoped_loop_strict_mode_example.py
10+
.. include:: function_scoped_loop_strict_mode_example.py
3411
:code: python
3512

36-
In *auto* mode, the ``pytest.mark.asyncio`` marker can be omitted:
13+
Multiple async tests in a single class or module can be marked using |pytestmark|_.
3714

38-
.. include:: class_scoped_loop_auto_mode_example.py
15+
.. include:: function_scoped_loop_pytestmark_strict_mode_example.py
3916
:code: python
4017

41-
Similarly, a module-scoped loop is provided when adding the `asyncio_event_loop` mark to the module:
42-
43-
.. include:: module_scoped_loop_auto_mode_example.py
44-
:code: python
18+
The ``pytest.mark.asyncio`` marker can be omitted entirely in *auto* mode, where the *asyncio* marker is added automatically to *async* test functions.
4519

46-
The `asyncio_event_loop` mark supports an optional `policy` keyword argument to set the asyncio event loop policy.
20+
By default, each test runs in it's own asyncio event loop.
21+
Multiple tests can share the same event loop by providing a *scope* keyword argument to the *asyncio* mark.
22+
The following code example provides a shared event loop for all tests in `TestClassScopedLoop`:
4723

48-
.. include:: class_scoped_loop_custom_policy_strict_mode_example.py
24+
.. include:: class_scoped_loop_strict_mode_example.py
4925
:code: python
5026

27+
Requesting class scope for tests that are not part of a class will give a *UsageError.*
28+
Similar to class-scoped event loops, a module-scoped loop is provided when setting the asyncio mark's scope to *module:*
5129

52-
The ``policy`` keyword argument may also take an iterable of event loop policies. This causes tests under by the `asyncio_event_loop` mark to be parametrized with different policies:
53-
54-
.. include:: class_scoped_loop_custom_policies_strict_mode_example.py
30+
.. include:: module_scoped_loop_strict_mode_example.py
5531
:code: python
5632

57-
If no explicit policy is provided, the mark will use the loop policy returned by ``asyncio.get_event_loop_policy()``.
58-
59-
Fixtures and tests sharing the same `asyncio_event_loop` mark are executed in the same event loop:
60-
61-
.. include:: class_scoped_loop_with_fixture_strict_mode_example.py
62-
:code: python
33+
Requesting class scope with the test being part of a class will give a *UsageError*.
34+
The supported scopes are *class*, and *module.*
6335

6436
.. |pytestmark| replace:: ``pytestmark``
6537
.. _pytestmark: http://doc.pytest.org/en/latest/example/markers.html#marking-whole-classes-or-modules

docs/source/reference/markers/module_scoped_loop_auto_mode_example.py renamed to 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_event_loop
5+
pytestmark = pytest.mark.asyncio(scope="module")
66

77
loop: asyncio.AbstractEventLoop
88

docs/source/reference/markers/pytestmark_asyncio_strict_mode_example.py

-11
This file was deleted.

0 commit comments

Comments
 (0)