@@ -148,15 +148,15 @@ async def test_a():
148148 )
149149
150150
151- def test_asyncio_marker_fallbacks_to_configured_default_loop_scope_if_not_set (
151+ def test_asyncio_marker_uses_marker_loop_scope_even_if_config_is_set (
152152 pytester : Pytester ,
153153):
154154 pytester .makeini (
155155 dedent (
156156 """\
157157 [pytest]
158158 asyncio_default_fixture_loop_scope = function
159- asyncio_default_test_loop_scope = session
159+ asyncio_default_test_loop_scope = module
160160 """
161161 )
162162 )
@@ -175,6 +175,7 @@ async def session_loop_fixture():
175175 global loop
176176 loop = asyncio.get_running_loop()
177177
178+ @pytest.mark.asyncio(loop_scope="session")
178179 async def test_a(session_loop_fixture):
179180 global loop
180181 assert asyncio.get_running_loop() is loop
@@ -186,56 +187,125 @@ async def test_a(session_loop_fixture):
186187 result .assert_outcomes (passed = 1 )
187188
188189
189- def test_asyncio_marker_uses_marker_loop_scope_even_if_config_is_set (
190- pytester : Pytester ,
191- ):
192- pytester .makeini (
190+ def test_uses_loop_factory_from_test (pytester : Pytester ):
191+ pytester .makeini ("[pytest]\n asyncio_default_fixture_loop_scope = function" )
192+ pytester .makepyfile (
193193 dedent (
194194 """\
195- [pytest]
196- asyncio_default_fixture_loop_scope = function
197- asyncio_default_test_loop_scope = module
195+ import asyncio
196+ import pytest_asyncio
197+ import pytest
198+
199+ class CustomEventLoop(asyncio.SelectorEventLoop):
200+ pass
201+
202+ @pytest_asyncio.fixture(loop_scope="module")
203+ async def any_fixture():
204+ assert type(asyncio.get_running_loop()) == CustomEventLoop
205+
206+ @pytest.mark.asyncio(loop_scope="module", loop_factory=CustomEventLoop)
207+ async def test_set_loop_factory(any_fixture):
208+ assert type(asyncio.get_running_loop()) == CustomEventLoop
198209 """
199210 )
200211 )
212+ result = pytester .runpytest ("--asyncio-mode=strict" )
213+ result .assert_outcomes (passed = 1 )
214+
201215
216+ def test_uses_loop_factory_from_fixture (pytester : Pytester ):
217+ pytester .makeini ("[pytest]\n asyncio_default_fixture_loop_scope = function" )
202218 pytester .makepyfile (
203219 dedent (
204220 """\
205221 import asyncio
206222 import pytest_asyncio
207223 import pytest
208224
209- loop: asyncio.AbstractEventLoop
225+ class CustomEventLoop(asyncio.SelectorEventLoop):
226+ pass
210227
211- @pytest_asyncio.fixture(loop_scope="session", scope="session")
212- async def session_loop_fixture():
213- global loop
214- loop = asyncio.get_running_loop()
228+ @pytest_asyncio.fixture(loop_scope="module", loop_factory=CustomEventLoop)
229+ async def any_fixture():
230+ assert type(asyncio.get_running_loop()) == CustomEventLoop
215231
216- @pytest.mark.asyncio(loop_scope="session")
217- async def test_a(session_loop_fixture):
218- global loop
219- assert asyncio.get_running_loop() is loop
232+ @pytest.mark.asyncio(loop_scope="module")
233+ async def test_set_loop_factory(any_fixture):
234+ assert type(asyncio.get_running_loop()) == CustomEventLoop
220235 """
221236 )
222237 )
238+ result = pytester .runpytest ("--asyncio-mode=strict" )
239+ result .assert_outcomes (passed = 1 )
223240
224- result = pytester .runpytest ("--asyncio-mode=auto" )
241+
242+ def test_uses_loop_factory_from_transitive_fixture (pytester : Pytester ):
243+ pytester .makeini ("[pytest]\n asyncio_default_fixture_loop_scope = function" )
244+ pytester .makepyfile (
245+ dedent (
246+ """\
247+ import asyncio
248+ import pytest_asyncio
249+ import pytest
250+
251+ class CustomEventLoop(asyncio.SelectorEventLoop):
252+ pass
253+
254+ @pytest_asyncio.fixture(loop_scope="module", loop_factory=CustomEventLoop)
255+ async def transitive_fixture():
256+ assert type(asyncio.get_running_loop()) == CustomEventLoop
257+
258+ @pytest_asyncio.fixture(loop_scope="module")
259+ async def any_fixture(transitive_fixture):
260+ assert type(asyncio.get_running_loop()) == CustomEventLoop
261+
262+ @pytest.mark.asyncio(loop_scope="module")
263+ async def test_set_loop_factory(any_fixture):
264+ assert type(asyncio.get_running_loop()) == CustomEventLoop
265+ """
266+ )
267+ )
268+ result = pytester .runpytest ("--asyncio-mode=strict" )
225269 result .assert_outcomes (passed = 1 )
226270
227271
228- def test_asyncio_marker_event_loop_factories (pytester : Pytester ):
229- pytester .makeini (
272+ def test_conflicting_loop_factories_in_tests_raise_error (pytester : Pytester ):
273+ pytester .makeini ("[pytest]\n asyncio_default_fixture_loop_scope = function" )
274+ pytester .makepyfile (
230275 dedent (
231276 """\
232- [pytest]
233- asyncio_default_fixture_loop_scope = function
234- asyncio_default_test_loop_scope = module
277+ import asyncio
278+ import pytest_asyncio
279+ import pytest
280+
281+ class CustomEventLoop(asyncio.SelectorEventLoop):
282+ pass
283+
284+ class AnotherCustomEventLoop(asyncio.SelectorEventLoop):
285+ pass
286+
287+ @pytest.mark.asyncio(loop_scope="module", loop_factory=CustomEventLoop)
288+ async def test_with_custom_loop_factory():
289+ ...
290+
291+ @pytest.mark.asyncio(
292+ loop_scope="module",
293+ loop_factory=AnotherCustomEventLoop
294+ )
295+ async def test_with_a_different_custom_loop_factory():
296+ ...
235297 """
236298 )
237299 )
238300
301+ result = pytester .runpytest ("--asyncio-mode=strict" , "-s" , "--setup-show" )
302+ result .assert_outcomes (errors = 2 )
303+
304+
305+ def test_conflicting_loop_factories_in_tests_and_fixtures_raise_error (
306+ pytester : Pytester ,
307+ ):
308+ pytester .makeini ("[pytest]\n asyncio_default_fixture_loop_scope = function" )
239309 pytester .makepyfile (
240310 dedent (
241311 """\
@@ -246,22 +316,109 @@ def test_asyncio_marker_event_loop_factories(pytester: Pytester):
246316 class CustomEventLoop(asyncio.SelectorEventLoop):
247317 pass
248318
249- @pytest.mark.asyncio(loop_factory=CustomEventLoop)
250- async def test_has_different_event_loop():
251- assert type(asyncio.get_running_loop()).__name__ == "CustomEventLoop"
319+ class AnotherCustomEventLoop(asyncio.SelectorEventLoop):
320+ pass
321+
322+ @pytest_asyncio.fixture(loop_scope="module", loop_factory=CustomEventLoop)
323+ async def fixture_with_custom_loop_factory():
324+ ...
325+
326+ @pytest.mark.asyncio(
327+ loop_scope="module",
328+ loop_factory=AnotherCustomEventLoop
329+ )
330+ async def test_trying_to_override_fixtures_loop_factory(
331+ fixture_with_custom_loop_factory
332+ ):
333+ # Fails, because it tries to use a different loop factory on the
334+ # same runner as the first test
335+ ...
336+ """
337+ )
338+ )
339+
340+ result = pytester .runpytest ("--asyncio-mode=strict" )
341+ result .assert_outcomes (passed = 1 , errors = 1 )
252342
253- @pytest_asyncio.fixture(loop_factory=CustomEventLoop)
254- async def custom_fixture():
255- yield asyncio.get_running_loop()
256343
257- async def test_with_fixture(custom_fixture):
258- # Both of these should be the same...
259- type(asyncio.get_running_loop()).__name__ == "CustomEventLoop"
260- type(custom_fixture).__name__ == "CustomEventLoop"
344+ def test_conflicting_loop_factories_in_fixtures_raise_error (pytester : Pytester ):
345+ pytester .makeini ("[pytest]\n asyncio_default_fixture_loop_scope = function" )
346+ pytester .makepyfile (
347+ dedent (
348+ """\
349+ import asyncio
350+ import pytest_asyncio
351+ import pytest
261352
353+ class CustomEventLoop(asyncio.SelectorEventLoop):
354+ pass
355+
356+ class AnotherCustomEventLoop(asyncio.SelectorEventLoop):
357+ pass
358+
359+ @pytest_asyncio.fixture(loop_scope="module", loop_factory=CustomEventLoop)
360+ async def fixture_with_custom_loop_factory():
361+ ...
362+
363+ @pytest_asyncio.fixture(
364+ loop_scope="module",
365+ loop_factory=AnotherCustomEventLoop
366+ )
367+ async def another_fixture_with_custom_loop_factory():
368+ ...
369+
370+ @pytest.mark.asyncio(loop_scope="module")
371+ async def test_requesting_two_fixtures_with_different_loop_facoties(
372+ fixture_with_custom_loop_factory,
373+ another_fixture_with_custom_loop_factory,
374+ ):
375+ ...
262376 """
263377 )
264378 )
265379
266- result = pytester .runpytest ("--asyncio-mode=auto" )
267- result .assert_outcomes (passed = 2 )
380+ result = pytester .runpytest ("--asyncio-mode=strict" , "-s" , "--setup-show" )
381+ result .assert_outcomes (errors = 1 )
382+
383+
384+ def test_conflicting_loop_factories_in_transitive_fixtures_raise_error (
385+ pytester : Pytester ,
386+ ):
387+ pytester .makeini ("[pytest]\n asyncio_default_fixture_loop_scope = function" )
388+ pytester .makepyfile (
389+ dedent (
390+ """\
391+ import asyncio
392+ import pytest_asyncio
393+ import pytest
394+
395+ class CustomEventLoop(asyncio.SelectorEventLoop):
396+ pass
397+
398+ class AnotherCustomEventLoop(asyncio.SelectorEventLoop):
399+ pass
400+
401+ @pytest_asyncio.fixture(loop_scope="module", loop_factory=CustomEventLoop)
402+ async def fixture_with_custom_loop_factory():
403+ ...
404+
405+ @pytest_asyncio.fixture(
406+ loop_scope="module",
407+ loop_factory=AnotherCustomEventLoop
408+ )
409+ async def another_fixture_with_custom_loop_factory(
410+ fixture_with_custom_loop_factory
411+ ):
412+ ...
413+
414+ @pytest.mark.asyncio(loop_scope="module")
415+ async def test_requesting_two_fixtures_with_different_loop_facories(
416+ another_fixture_with_custom_loop_factory,
417+ ):
418+ ...
419+ """
420+ )
421+ )
422+
423+ result = pytester .runpytest ("--asyncio-mode=strict" )
424+ result .assert_outcomes (errors = 1 )
0 commit comments