Skip to content

Commit 53ff025

Browse files
committed
[feat] The "policy" keyword argument to asyncio_event_loop allows passing an iterable of policies.
This causes tests under the _asyncio_event_loop_ mark to be parametrized with the different loop policies. Signed-off-by: Michael Seifert <m.seifert@digitalernachschub.de>
1 parent c24848d commit 53ff025

File tree

4 files changed

+85
-2
lines changed

4 files changed

+85
-2
lines changed

docs/source/reference/markers.rst

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -126,6 +126,30 @@ The `asyncio_event_loop` mark supports an optional `policy` keyword argument to
126126
async def test_uses_custom_event_loop_policy(self):
127127
assert isinstance(asyncio.get_event_loop_policy(), CustomEventLoopPolicy)
128128
129+
130+
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:
131+
132+
.. code-block:: python
133+
134+
import asyncio
135+
136+
import pytest
137+
138+
import pytest_asyncio
139+
140+
141+
@pytest.mark.asyncio_event_loop(
142+
policy=[
143+
asyncio.DefaultEventLoopPolicy(),
144+
uvloop.EventLoopPolicy(),
145+
]
146+
)
147+
class TestWithDifferentLoopPolicies:
148+
@pytest.mark.asyncio
149+
async def test_parametrized_loop(self):
150+
pass
151+
152+
129153
If no explicit policy is provided, the mark will use the loop policy returned by ``asyncio.get_event_loop_policy()``.
130154

131155
.. |pytestmark| replace:: ``pytestmark``

pytest_asyncio/plugin.py

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -369,6 +369,11 @@ def pytest_collectstart(collector: pytest.Collector):
369369
if not mark.name == "asyncio_event_loop":
370370
continue
371371
event_loop_policy = mark.kwargs.get("policy", asyncio.get_event_loop_policy())
372+
policy_params = (
373+
event_loop_policy
374+
if isinstance(event_loop_policy, Iterable)
375+
else (event_loop_policy,)
376+
)
372377

373378
# There seem to be issues when a fixture is shadowed by another fixture
374379
# and both differ in their params.
@@ -383,8 +388,8 @@ def pytest_collectstart(collector: pytest.Collector):
383388
@pytest.fixture(
384389
scope="class" if isinstance(collector, pytest.Class) else "module",
385390
name=event_loop_fixture_id,
386-
params=(event_loop_policy,),
387-
ids=(type(event_loop_policy).__name__,),
391+
params=policy_params,
392+
ids=tuple(type(policy).__name__ for policy in policy_params),
388393
)
389394
def scoped_event_loop(
390395
*args, # Function needs to accept "cls" when collected by pytest.Class

tests/markers/test_class_marker.py

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -161,3 +161,30 @@ async def test_does_not_use_custom_event_loop_policy():
161161
)
162162
result = pytester.runpytest("--asyncio-mode=strict")
163163
result.assert_outcomes(passed=2)
164+
165+
166+
def test_asyncio_event_loop_mark_allows_specifying_multiple_loop_policies(
167+
pytester: pytest.Pytester,
168+
):
169+
pytester.makepyfile(
170+
dedent(
171+
"""\
172+
import asyncio
173+
174+
import pytest
175+
176+
@pytest.mark.asyncio_event_loop(
177+
policy=[
178+
asyncio.DefaultEventLoopPolicy(),
179+
asyncio.DefaultEventLoopPolicy(),
180+
]
181+
)
182+
class TestWithDifferentLoopPolicies:
183+
@pytest.mark.asyncio
184+
async def test_parametrized_loop(self):
185+
pass
186+
"""
187+
)
188+
)
189+
result = pytester.runpytest_subprocess("--asyncio-mode=strict")
190+
result.assert_outcomes(passed=2)

tests/markers/test_module_marker.py

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -185,3 +185,30 @@ async def test_does_not_use_custom_event_loop_policy():
185185
)
186186
result = pytester.runpytest("--asyncio-mode=strict")
187187
result.assert_outcomes(passed=2)
188+
189+
190+
def test_asyncio_event_loop_mark_allows_specifying_multiple_loop_policies(
191+
pytester: Pytester,
192+
):
193+
pytester.makepyfile(
194+
dedent(
195+
"""\
196+
import asyncio
197+
198+
import pytest
199+
200+
pytestmark = pytest.mark.asyncio_event_loop(
201+
policy=[
202+
asyncio.DefaultEventLoopPolicy(),
203+
asyncio.DefaultEventLoopPolicy(),
204+
]
205+
)
206+
207+
@pytest.mark.asyncio
208+
async def test_parametrized_loop():
209+
pass
210+
"""
211+
)
212+
)
213+
result = pytester.runpytest_subprocess("--asyncio-mode=strict")
214+
result.assert_outcomes(passed=2)

0 commit comments

Comments
 (0)