@@ -213,7 +213,8 @@ def pytest_pycollect_makeitem(
213
213
and _hypothesis_test_wraps_coroutine (obj )
214
214
):
215
215
item = pytest .Function .from_parent (collector , name = name )
216
- if "asyncio" in item .keywords :
216
+ marker = item .get_closest_marker ("asyncio" )
217
+ if marker is not None :
217
218
return list (collector ._genfunctions (name , obj ))
218
219
else :
219
220
if _get_asyncio_mode (item .config ) == Mode .AUTO :
@@ -390,16 +391,19 @@ def pytest_pyfunc_call(pyfuncitem: pytest.Function) -> Optional[object]:
390
391
Wraps marked tests in a synchronous function
391
392
where the wrapped test coroutine is executed in an event loop.
392
393
"""
393
- if "asyncio" in pyfuncitem .keywords :
394
+ marker = pyfuncitem .get_closest_marker ("asyncio" )
395
+ if marker is not None :
394
396
funcargs : Dict [str , object ] = pyfuncitem .funcargs # type: ignore[name-defined]
395
397
loop = cast (asyncio .AbstractEventLoop , funcargs ["event_loop" ])
396
398
if _is_hypothesis_test (pyfuncitem .obj ):
397
399
pyfuncitem .obj .hypothesis .inner_test = wrap_in_sync (
400
+ pyfuncitem ,
398
401
pyfuncitem .obj .hypothesis .inner_test ,
399
402
_loop = loop ,
400
403
)
401
404
else :
402
405
pyfuncitem .obj = wrap_in_sync (
406
+ pyfuncitem ,
403
407
pyfuncitem .obj ,
404
408
_loop = loop ,
405
409
)
@@ -410,7 +414,11 @@ def _is_hypothesis_test(function: Any) -> bool:
410
414
return getattr (function , "is_hypothesis_test" , False )
411
415
412
416
413
- def wrap_in_sync (func : Callable [..., Awaitable [Any ]], _loop : asyncio .AbstractEventLoop ):
417
+ def wrap_in_sync (
418
+ pyfuncitem : pytest .Function ,
419
+ func : Callable [..., Awaitable [Any ]],
420
+ _loop : asyncio .AbstractEventLoop ,
421
+ ):
414
422
"""Return a sync wrapper around an async function executing it in the
415
423
current event loop."""
416
424
@@ -424,34 +432,44 @@ def wrap_in_sync(func: Callable[..., Awaitable[Any]], _loop: asyncio.AbstractEve
424
432
@functools .wraps (func )
425
433
def inner (** kwargs ):
426
434
coro = func (** kwargs )
427
- if coro is not None :
428
- task = asyncio .ensure_future (coro , loop = _loop )
429
- try :
430
- _loop .run_until_complete (task )
431
- except BaseException :
432
- # run_until_complete doesn't get the result from exceptions
433
- # that are not subclasses of `Exception`. Consume all
434
- # exceptions to prevent asyncio's warning from logging.
435
- if task .done () and not task .cancelled ():
436
- task .exception ()
437
- raise
435
+ if not inspect .isawaitable (coro ):
436
+ pyfuncitem .warn (
437
+ pytest .PytestWarning (
438
+ f"The test { pyfuncitem } is marked with '@pytest.mark.asyncio' "
439
+ "but it is not an async function. "
440
+ "Please remove asyncio marker. "
441
+ "If the test is not marked explicitly, "
442
+ "check for global markers applied via 'pytestmark'."
443
+ )
444
+ )
445
+ return
446
+ task = asyncio .ensure_future (coro , loop = _loop )
447
+ try :
448
+ _loop .run_until_complete (task )
449
+ except BaseException :
450
+ # run_until_complete doesn't get the result from exceptions
451
+ # that are not subclasses of `Exception`. Consume all
452
+ # exceptions to prevent asyncio's warning from logging.
453
+ if task .done () and not task .cancelled ():
454
+ task .exception ()
455
+ raise
438
456
439
457
inner ._raw_test_func = func # type: ignore[attr-defined]
440
458
return inner
441
459
442
460
443
461
def pytest_runtest_setup (item : pytest .Item ) -> None :
444
- if "asyncio" in item .keywords :
445
- fixturenames = item .fixturenames # type: ignore[attr-defined]
446
- # inject an event loop fixture for all async tests
447
- if "event_loop" in fixturenames :
448
- fixturenames .remove ("event_loop" )
449
- fixturenames .insert (0 , "event_loop" )
462
+ marker = item .get_closest_marker ("asyncio" )
463
+ if marker is None :
464
+ return
465
+ fixturenames = item .fixturenames # type: ignore[attr-defined]
466
+ # inject an event loop fixture for all async tests
467
+ if "event_loop" in fixturenames :
468
+ fixturenames .remove ("event_loop" )
469
+ fixturenames .insert (0 , "event_loop" )
450
470
obj = getattr (item , "obj" , None )
451
- if (
452
- item .get_closest_marker ("asyncio" ) is not None
453
- and not getattr (obj , "hypothesis" , False )
454
- and getattr (obj , "is_hypothesis_test" , False )
471
+ if not getattr (obj , "hypothesis" , False ) and getattr (
472
+ obj , "is_hypothesis_test" , False
455
473
):
456
474
pytest .fail (
457
475
"test function `%r` is using Hypothesis, but pytest-asyncio "
0 commit comments