File tree 2 files changed +78
-0
lines changed
2 files changed +78
-0
lines changed Original file line number Diff line number Diff line change 26
26
)
27
27
28
28
import pytest
29
+ from _pytest .mark .structures import get_unpacked_marks
29
30
from pytest import (
30
31
Config ,
31
32
FixtureRequest ,
@@ -339,6 +340,33 @@ def pytest_pycollect_makeitem(
339
340
return None
340
341
341
342
343
+ @pytest .hookimpl
344
+ def pytest_collectstart (collector : pytest .Collector ):
345
+ if not isinstance (collector , pytest .Class ):
346
+ return
347
+ # pytest.Collector.own_markers is empty at this point,
348
+ # so we rely on _pytest.mark.structures.get_unpacked_marks
349
+ marks = get_unpacked_marks (collector .obj , consider_mro = True )
350
+ for mark in marks :
351
+ if not mark .name == "asyncio" :
352
+ continue
353
+
354
+ @pytest .fixture (
355
+ scope = "class" ,
356
+ name = "event_loop" ,
357
+ )
358
+ def scoped_event_loop (cls ) -> Iterator [asyncio .AbstractEventLoop ]:
359
+ loop = asyncio .get_event_loop_policy ().new_event_loop ()
360
+ yield loop
361
+ loop .close ()
362
+
363
+ # @pytest.fixture does not register the fixture anywhere, so pytest doesn't
364
+ # know it exists. We work around this by attaching the fixture function to the
365
+ # collected Python class, where it will be picked up by pytest.Class.collect()
366
+ collector .obj .__pytest_asyncio_scoped_event_loop = scoped_event_loop
367
+ break
368
+
369
+
342
370
def pytest_collection_modifyitems (
343
371
session : Session , config : Config , items : List [Item ]
344
372
) -> None :
Original file line number Diff line number Diff line change 1
1
"""Test if pytestmark works when defined on a class."""
2
2
import asyncio
3
+ from textwrap import dedent
3
4
4
5
import pytest
5
6
@@ -23,3 +24,52 @@ async def inc():
23
24
@pytest .fixture
24
25
def sample_fixture ():
25
26
return None
27
+
28
+
29
+ def test_asyncio_mark_provides_class_scoped_loop (pytester : pytest .Pytester ):
30
+ pytester .makepyfile (
31
+ dedent (
32
+ """\
33
+ import asyncio
34
+ import pytest
35
+
36
+ @pytest.mark.asyncio
37
+ class TestClassScopedLoop:
38
+ loop: asyncio.AbstractEventLoop
39
+
40
+ async def test_remember_loop(self):
41
+ TestClassScopedLoop.loop = asyncio.get_running_loop()
42
+
43
+ async def test_this_runs_in_same_loop(self):
44
+ assert asyncio.get_running_loop() is TestClassScopedLoop.loop
45
+ """
46
+ )
47
+ )
48
+ result = pytester .runpytest ("--asyncio-mode=strict" )
49
+ result .assert_outcomes (passed = 2 )
50
+
51
+
52
+ def test_asyncio_mark_is_inherited_to_subclasses (pytester : pytest .Pytester ):
53
+ pytester .makepyfile (
54
+ dedent (
55
+ """\
56
+ import asyncio
57
+ import pytest
58
+
59
+ @pytest.mark.asyncio
60
+ class TestSuperClassWithMark:
61
+ pass
62
+
63
+ class TestWithoutMark(TestSuperClassWithMark):
64
+ loop: asyncio.AbstractEventLoop
65
+
66
+ async def test_remember_loop(self):
67
+ TestWithoutMark.loop = asyncio.get_running_loop()
68
+
69
+ async def test_this_runs_in_same_loop(self):
70
+ assert asyncio.get_running_loop() is TestWithoutMark.loop
71
+ """
72
+ )
73
+ )
74
+ result = pytester .runpytest ("--asyncio-mode=strict" )
75
+ result .assert_outcomes (passed = 2 )
You can’t perform that action at this time.
0 commit comments