Skip to content

Commit e075f15

Browse files
committed
[feat] Added optional "loop_scope" argument to pytest_asyncio.fixture.
Signed-off-by: Michael Seifert <[email protected]>
1 parent a56bb3f commit e075f15

File tree

2 files changed

+32
-6
lines changed

2 files changed

+32
-6
lines changed

pytest_asyncio/plugin.py

+13-6
Original file line numberDiff line numberDiff line change
@@ -110,6 +110,7 @@ def fixture(
110110
fixture_function: FixtureFunction,
111111
*,
112112
scope: "Union[_ScopeName, Callable[[str, Config], _ScopeName]]" = ...,
113+
loop_scope: Union[_ScopeName] = ...,
113114
params: Optional[Iterable[object]] = ...,
114115
autouse: bool = ...,
115116
ids: Union[
@@ -126,6 +127,7 @@ def fixture(
126127
fixture_function: None = ...,
127128
*,
128129
scope: "Union[_ScopeName, Callable[[str, Config], _ScopeName]]" = ...,
130+
loop_scope: Union[_ScopeName, None] = ...,
129131
params: Optional[Iterable[object]] = ...,
130132
autouse: bool = ...,
131133
ids: Union[
@@ -138,17 +140,19 @@ def fixture(
138140

139141

140142
def fixture(
141-
fixture_function: Optional[FixtureFunction] = None, **kwargs: Any
143+
fixture_function: Optional[FixtureFunction] = None,
144+
loop_scope: Union[_ScopeName, None] = None,
145+
**kwargs: Any,
142146
) -> Union[FixtureFunction, FixtureFunctionMarker]:
143147
if fixture_function is not None:
144-
_make_asyncio_fixture_function(fixture_function)
148+
_make_asyncio_fixture_function(fixture_function, loop_scope)
145149
return pytest.fixture(fixture_function, **kwargs)
146150

147151
else:
148152

149153
@functools.wraps(fixture)
150154
def inner(fixture_function: FixtureFunction) -> FixtureFunction:
151-
return fixture(fixture_function, **kwargs)
155+
return fixture(fixture_function, loop_scope=loop_scope, **kwargs)
152156

153157
return inner
154158

@@ -158,11 +162,14 @@ def _is_asyncio_fixture_function(obj: Any) -> bool:
158162
return getattr(obj, "_force_asyncio_fixture", False)
159163

160164

161-
def _make_asyncio_fixture_function(obj: Any) -> None:
165+
def _make_asyncio_fixture_function(
166+
obj: Any, loop_scope: Union[_ScopeName, None]
167+
) -> None:
162168
if hasattr(obj, "__func__"):
163169
# instance method, check the function object
164170
obj = obj.__func__
165171
obj._force_asyncio_fixture = True
172+
obj._loop_scope = loop_scope
166173

167174

168175
def _is_coroutine_or_asyncgen(obj: Any) -> bool:
@@ -218,7 +225,7 @@ def _preprocess_async_fixtures(
218225
# Ignore async fixtures without explicit asyncio mark in strict mode
219226
# This applies to pytest_trio fixtures, for example
220227
continue
221-
scope = fixturedef.scope
228+
scope = getattr(func, "_loop_scope", None) or fixturedef.scope
222229
if scope == "function":
223230
event_loop_fixture_id: Optional[str] = "event_loop"
224231
else:
@@ -228,7 +235,7 @@ def _preprocess_async_fixtures(
228235
_event_loop_fixture_id, # type: ignore[arg-type]
229236
None,
230237
)
231-
_make_asyncio_fixture_function(func)
238+
_make_asyncio_fixture_function(func, scope)
232239
function_signature = inspect.signature(func)
233240
if "event_loop" in function_signature.parameters:
234241
warnings.warn(

tests/test_fixture_loop_scopes.py

+19
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
import asyncio
2+
3+
import pytest
4+
5+
import pytest_asyncio
6+
7+
loop: asyncio.AbstractEventLoop
8+
9+
10+
@pytest_asyncio.fixture(loop_scope="session")
11+
async def fixture():
12+
global loop
13+
loop = asyncio.get_running_loop()
14+
15+
16+
@pytest.mark.asyncio(scope="session")
17+
async def test_fixture_loop_scopes(fixture):
18+
global loop
19+
assert loop == asyncio.get_running_loop()

0 commit comments

Comments
 (0)