1616 Awaitable ,
1717 Callable ,
1818 Dict ,
19+ Generator ,
1920 Iterable ,
2021 Iterator ,
2122 List ,
2223 Literal ,
24+ Mapping ,
2325 Optional ,
26+ Sequence ,
2427 Set ,
2528 Type ,
2629 TypeVar ,
4750 StashKey ,
4851)
4952
50- _R = TypeVar ("_R" )
51-
5253_ScopeName = Literal ["session" , "package" , "module" , "class" , "function" ]
5354_T = TypeVar ("_T" )
5455
5556SimpleFixtureFunction = TypeVar (
56- "SimpleFixtureFunction" , bound = Callable [..., Awaitable [_R ]]
57+ "SimpleFixtureFunction" , bound = Callable [..., Awaitable [object ]]
5758)
5859FactoryFixtureFunction = TypeVar (
59- "FactoryFixtureFunction" , bound = Callable [..., AsyncIterator [_R ]]
60+ "FactoryFixtureFunction" , bound = Callable [..., AsyncIterator [object ]]
6061)
6162FixtureFunction = Union [SimpleFixtureFunction , FactoryFixtureFunction ]
6263FixtureFunctionMarker = Callable [[FixtureFunction ], FixtureFunction ]
@@ -204,6 +205,7 @@ def _preprocess_async_fixtures(
204205 config = collector .config
205206 asyncio_mode = _get_asyncio_mode (config )
206207 fixturemanager = config .pluginmanager .get_plugin ("funcmanage" )
208+ assert fixturemanager is not None
207209 for fixtures in fixturemanager ._arg2fixturedefs .values ():
208210 for fixturedef in fixtures :
209211 func = fixturedef .func
@@ -217,11 +219,13 @@ def _preprocess_async_fixtures(
217219 continue
218220 scope = fixturedef .scope
219221 if scope == "function" :
220- event_loop_fixture_id = "event_loop"
222+ event_loop_fixture_id : Optional [ str ] = "event_loop"
221223 else :
222224 event_loop_node = _retrieve_scope_root (collector , scope )
223225 event_loop_fixture_id = event_loop_node .stash .get (
224- _event_loop_fixture_id , None
226+ # Type ignored because of non-optimal mypy inference.
227+ _event_loop_fixture_id , # type: ignore[arg-type]
228+ None ,
225229 )
226230 _make_asyncio_fixture_function (func )
227231 function_signature = inspect .signature (func )
@@ -234,8 +238,15 @@ def _preprocess_async_fixtures(
234238 f"instead."
235239 )
236240 )
237- _inject_fixture_argnames (fixturedef , event_loop_fixture_id )
238- _synchronize_async_fixture (fixturedef , event_loop_fixture_id )
241+ assert event_loop_fixture_id
242+ _inject_fixture_argnames (
243+ fixturedef ,
244+ event_loop_fixture_id ,
245+ )
246+ _synchronize_async_fixture (
247+ fixturedef ,
248+ event_loop_fixture_id ,
249+ )
239250 assert _is_asyncio_fixture_function (fixturedef .func )
240251 processed_fixturedefs .add (fixturedef )
241252
@@ -512,25 +523,26 @@ def pytest_pycollect_makeitem_preprocess_async_fixtures(
512523 return None
513524
514525
526+ # TODO: #778 Narrow down return type of function when dropping support for pytest 7
515527# The function name needs to start with "pytest_"
516528# see https://github.com/pytest-dev/pytest/issues/11307
517529@pytest .hookimpl (specname = "pytest_pycollect_makeitem" , hookwrapper = True )
518530def pytest_pycollect_makeitem_convert_async_functions_to_subclass (
519531 collector : Union [pytest .Module , pytest .Class ], name : str , obj : object
520- ) -> Union [
521- pytest .Item , pytest .Collector , List [Union [pytest .Item , pytest .Collector ]], None
522- ]:
532+ ) -> Generator [None , Any , None ]:
523533 """
524534 Converts coroutines and async generators collected as pytest.Functions
525535 to AsyncFunction items.
526536 """
527537 hook_result = yield
528- node_or_list_of_nodes = hook_result .get_result ()
538+ node_or_list_of_nodes : Union [
539+ pytest .Item , pytest .Collector , List [Union [pytest .Item , pytest .Collector ]], None
540+ ] = hook_result .get_result ()
529541 if not node_or_list_of_nodes :
530542 return
531- try :
543+ if isinstance ( node_or_list_of_nodes , Sequence ) :
532544 node_iterator = iter (node_or_list_of_nodes )
533- except TypeError :
545+ else :
534546 # Treat single node as a single-element iterable
535547 node_iterator = iter ((node_or_list_of_nodes ,))
536548 updated_node_collection = []
@@ -549,8 +561,8 @@ def pytest_pycollect_makeitem_convert_async_functions_to_subclass(
549561 hook_result .force_result (updated_node_collection )
550562
551563
552- _event_loop_fixture_id = StashKey [str ]
553- _fixture_scope_by_collector_type = {
564+ _event_loop_fixture_id = StashKey [str ]()
565+ _fixture_scope_by_collector_type : Mapping [ Type [ pytest . Collector ], _ScopeName ] = {
554566 Class : "class" ,
555567 # Package is a subclass of module and the dict is used in isinstance checks
556568 # Therefore, the order matters and Package needs to appear before Module
@@ -565,7 +577,7 @@ def pytest_pycollect_makeitem_convert_async_functions_to_subclass(
565577
566578
567579@pytest .hookimpl
568- def pytest_collectstart (collector : pytest .Collector ):
580+ def pytest_collectstart (collector : pytest .Collector ) -> None :
569581 try :
570582 collector_scope = next (
571583 scope
@@ -639,8 +651,8 @@ def _patched_collect():
639651 pass
640652 return collector .__original_collect ()
641653
642- collector .__original_collect = collector .collect
643- collector .collect = _patched_collect
654+ collector .__original_collect = collector .collect # type: ignore[attr-defined]
655+ collector .collect = _patched_collect # type: ignore[method-assign]
644656 elif isinstance (collector , Class ):
645657 collector .obj .__pytest_asyncio_scoped_event_loop = scoped_event_loop
646658
@@ -708,6 +720,7 @@ def pytest_generate_tests(metafunc: Metafunc) -> None:
708720 if event_loop_fixture_id in metafunc .fixturenames :
709721 return
710722 fixturemanager = metafunc .config .pluginmanager .get_plugin ("funcmanage" )
723+ assert fixturemanager is not None
711724 if "event_loop" in metafunc .fixturenames :
712725 raise MultipleEventLoopsRequestedError (
713726 _MULTIPLE_LOOPS_REQUESTED_ERROR .format (
@@ -726,10 +739,11 @@ def pytest_generate_tests(metafunc: Metafunc) -> None:
726739 )
727740
728741
742+ # TODO: #778 Narrow down return type of function when dropping support for pytest 7
729743@pytest .hookimpl (hookwrapper = True )
730744def pytest_fixture_setup (
731- fixturedef : FixtureDef , request : SubRequest
732- ) -> Optional [ object ]:
745+ fixturedef : FixtureDef ,
746+ ) -> Generator [ None , Any , None ]:
733747 """Adjust the event loop policy when an event loop is produced."""
734748 if fixturedef .argname == "event_loop" :
735749 # The use of a fixture finalizer is preferred over the
@@ -744,7 +758,7 @@ def pytest_fixture_setup(
744758 _provide_clean_event_loop ,
745759 )
746760 outcome = yield
747- loop = outcome .get_result ()
761+ loop : asyncio . AbstractEventLoop = outcome .get_result ()
748762 # Weird behavior was observed when checking for an attribute of FixtureDef.func
749763 # Instead, we now check for a special attribute of the returned event loop
750764 fixture_filename = inspect .getsourcefile (fixturedef .func )
@@ -946,6 +960,7 @@ def _retrieve_scope_root(item: Union[Collector, Item], scope: str) -> Collector:
946960 scope_root_type = node_type_by_scope [scope ]
947961 for node in reversed (item .listchain ()):
948962 if isinstance (node , scope_root_type ):
963+ assert isinstance (node , pytest .Collector )
949964 return node
950965 error_message = (
951966 f"{ item .name } is marked to be run in an event loop with scope { scope } , "
0 commit comments