@@ -238,8 +238,8 @@ def _preprocess_async_fixtures(
238
238
for fixtures in fixturemanager ._arg2fixturedefs .values ():
239
239
for fixturedef in fixtures :
240
240
func = fixturedef .func
241
- if fixturedef in processed_fixturedefs or not _is_coroutine_or_asyncgen (
242
- func
241
+ if not _is_coroutine_or_asyncgen ( func ) and not getattr (
242
+ func , "_async_fixture" , False
243
243
):
244
244
continue
245
245
if not _is_asyncio_fixture_function (func ) and asyncio_mode == Mode .STRICT :
@@ -252,14 +252,21 @@ def _preprocess_async_fixtures(
252
252
or fixturedef .scope
253
253
)
254
254
if scope == "function" :
255
+ event_loop_fixture_name = "function"
255
256
event_loop_fixture_id : Optional [str ] = "event_loop"
256
257
else :
257
- event_loop_node = _retrieve_scope_root (collector , scope )
258
+ try :
259
+ event_loop_node = _retrieve_scope_root (collector , scope )
260
+ except Exception :
261
+ continue
262
+ event_loop_fixture_name = event_loop_node .name
258
263
event_loop_fixture_id = event_loop_node .stash .get (
259
264
# Type ignored because of non-optimal mypy inference.
260
265
_event_loop_fixture_id , # type: ignore[arg-type]
261
266
None ,
262
267
)
268
+ if (fixturedef , event_loop_fixture_id ) in processed_fixturedefs :
269
+ continue
263
270
_make_asyncio_fixture_function (func , scope )
264
271
function_signature = inspect .signature (func )
265
272
if "event_loop" in function_signature .parameters :
@@ -272,42 +279,33 @@ def _preprocess_async_fixtures(
272
279
)
273
280
)
274
281
assert event_loop_fixture_id
275
- _inject_fixture_argnames (
276
- fixturedef ,
277
- event_loop_fixture_id ,
278
- )
282
+ if "request" not in fixturedef .argnames :
283
+ fixturedef .argnames += ("request" ,)
279
284
_synchronize_async_fixture (
280
285
fixturedef ,
286
+ event_loop_fixture_name ,
281
287
event_loop_fixture_id ,
282
288
)
283
289
assert _is_asyncio_fixture_function (fixturedef .func )
284
- processed_fixturedefs .add (fixturedef )
285
-
286
-
287
- def _inject_fixture_argnames (
288
- fixturedef : FixtureDef , event_loop_fixture_id : str
289
- ) -> None :
290
- """
291
- Ensures that `request` and `event_loop` are arguments of the specified fixture.
292
- """
293
- to_add = []
294
- for name in ("request" , event_loop_fixture_id ):
295
- if name not in fixturedef .argnames :
296
- to_add .append (name )
297
- if to_add :
298
- fixturedef .argnames += tuple (to_add )
290
+ processed_fixturedefs .add ((fixturedef , event_loop_fixture_id ))
299
291
300
292
301
293
def _synchronize_async_fixture (
302
- fixturedef : FixtureDef , event_loop_fixture_id : str
294
+ fixturedef : FixtureDef , event_loop_fixture_name : str , event_loop_fixture_id : str
303
295
) -> None :
304
296
"""
305
297
Wraps the fixture function of an async fixture in a synchronous function.
306
298
"""
307
- if inspect .isasyncgenfunction (fixturedef .func ):
308
- _wrap_asyncgen_fixture (fixturedef , event_loop_fixture_id )
309
- elif inspect .iscoroutinefunction (fixturedef .func ):
310
- _wrap_async_fixture (fixturedef , event_loop_fixture_id )
299
+ if inspect .isasyncgenfunction (fixturedef .func ) or getattr (
300
+ fixturedef .func , "_async_fixture" , False
301
+ ):
302
+ _wrap_asyncgen_fixture (
303
+ fixturedef , event_loop_fixture_name , event_loop_fixture_id
304
+ )
305
+ elif inspect .iscoroutinefunction (fixturedef .func ) or getattr (
306
+ fixturedef .func , "_async_fixture" , False
307
+ ):
308
+ _wrap_async_fixture (fixturedef , event_loop_fixture_name , event_loop_fixture_id )
311
309
312
310
313
311
def _add_kwargs (
@@ -345,14 +343,27 @@ def _perhaps_rebind_fixture_func(
345
343
return func
346
344
347
345
348
- def _wrap_asyncgen_fixture (fixturedef : FixtureDef , event_loop_fixture_id : str ) -> None :
346
+ def _wrap_asyncgen_fixture (
347
+ fixturedef : FixtureDef , event_loop_fixture_name : str , event_loop_fixture_id : str
348
+ ) -> None :
349
349
fixture = fixturedef .func
350
350
351
+ event_loop_id_mapping = getattr (fixture , "_event_loop_id_mapping" , {})
352
+ event_loop_id_mapping [event_loop_fixture_name ] = event_loop_fixture_id
353
+ event_loop_id_mapping ["function" ] = event_loop_fixture_id
354
+
355
+ if getattr (fixture , "_async_fixture" , False ):
356
+ return fixture
357
+
351
358
@functools .wraps (fixture )
352
359
def _asyncgen_fixture_wrapper (request : FixtureRequest , ** kwargs : Any ):
353
360
unittest = fixturedef .unittest if hasattr (fixturedef , "unittest" ) else False
354
361
func = _perhaps_rebind_fixture_func (fixture , request .instance , unittest )
355
- event_loop = kwargs .pop (event_loop_fixture_id )
362
+ event_loop_fixture_id = event_loop_id_mapping .get (
363
+ request .node .name , event_loop_id_mapping ["function" ]
364
+ )
365
+ event_loop = request .getfixturevalue (event_loop_fixture_id )
366
+ kwargs .pop (event_loop_fixture_id , None )
356
367
gen_obj = func (
357
368
** _add_kwargs (func , kwargs , event_loop_fixture_id , event_loop , request )
358
369
)
@@ -380,17 +391,33 @@ async def async_finalizer() -> None:
380
391
request .addfinalizer (finalizer )
381
392
return result
382
393
394
+ setattr (_asyncgen_fixture_wrapper , "_event_loop_id_mapping" , event_loop_id_mapping )
395
+ setattr (_asyncgen_fixture_wrapper , "_async_fixture" , True )
396
+
383
397
fixturedef .func = _asyncgen_fixture_wrapper
384
398
385
399
386
- def _wrap_async_fixture (fixturedef : FixtureDef , event_loop_fixture_id : str ) -> None :
400
+ def _wrap_async_fixture (
401
+ fixturedef : FixtureDef , event_loop_fixture_name : str , event_loop_fixture_id : str
402
+ ) -> None :
387
403
fixture = fixturedef .func
388
404
405
+ event_loop_id_mapping = getattr (fixture , "_event_loop_id_mapping" , {})
406
+ event_loop_id_mapping [event_loop_fixture_name ] = event_loop_fixture_id
407
+ event_loop_id_mapping ["function" ] = event_loop_fixture_id
408
+
409
+ if getattr (fixture , "_async_fixture" , False ):
410
+ return fixture
411
+
389
412
@functools .wraps (fixture )
390
413
def _async_fixture_wrapper (request : FixtureRequest , ** kwargs : Any ):
391
414
unittest = False if pytest .version_tuple >= (8 , 2 ) else fixturedef .unittest
392
415
func = _perhaps_rebind_fixture_func (fixture , request .instance , unittest )
393
- event_loop = kwargs .pop (event_loop_fixture_id )
416
+ event_loop_fixture_id = event_loop_id_mapping .get (
417
+ request .node .name , event_loop_id_mapping ["function" ]
418
+ )
419
+ event_loop = request .getfixturevalue (event_loop_fixture_id )
420
+ kwargs .pop (event_loop_fixture_id , None )
394
421
395
422
async def setup ():
396
423
res = await func (
@@ -400,6 +427,9 @@ async def setup():
400
427
401
428
return event_loop .run_until_complete (setup ())
402
429
430
+ setattr (_async_fixture_wrapper , "_event_loop_id_mapping" , event_loop_id_mapping )
431
+ setattr (_async_fixture_wrapper , "_async_fixture" , True )
432
+
403
433
fixturedef .func = _async_fixture_wrapper
404
434
405
435
0 commit comments