7272from _pytest .pathlib import ImportPathMismatchError
7373from _pytest .pathlib import parts
7474from _pytest .pathlib import visit
75+ from _pytest .scope import Scope
7576from _pytest .warning_types import PytestCollectionWarning
7677from _pytest .warning_types import PytestUnhandledCoroutineWarning
7778
7879if TYPE_CHECKING :
7980 from typing_extensions import Literal
80- from _pytest .fixtures import _Scope
81+ from _pytest .scope import _ScopeName
8182
8283
8384def pytest_addoption (parser : Parser ) -> None :
@@ -896,7 +897,7 @@ def __init__(self, metafunc: "Metafunc") -> None:
896897 self ._idlist : List [str ] = []
897898 self .params : Dict [str , object ] = {}
898899 # Used for sorting parametrized resources.
899- self ._arg2scopenum : Dict [str , int ] = {}
900+ self ._arg2scope : Dict [str , Scope ] = {}
900901 self .marks : List [Mark ] = []
901902 self .indices : Dict [str , int ] = {}
902903
@@ -906,7 +907,7 @@ def copy(self) -> "CallSpec2":
906907 cs .params .update (self .params )
907908 cs .marks .extend (self .marks )
908909 cs .indices .update (self .indices )
909- cs ._arg2scopenum .update (self ._arg2scopenum )
910+ cs ._arg2scope .update (self ._arg2scope )
910911 cs ._idlist = list (self ._idlist )
911912 return cs
912913
@@ -927,7 +928,7 @@ def setmulti2(
927928 valset : Iterable [object ],
928929 id : str ,
929930 marks : Iterable [Union [Mark , MarkDecorator ]],
930- scopenum : int ,
931+ scope : Scope ,
931932 param_index : int ,
932933 ) -> None :
933934 for arg , val in zip (argnames , valset ):
@@ -941,7 +942,7 @@ def setmulti2(
941942 else : # pragma: no cover
942943 assert False , f"Unhandled valtype for arg: { valtype_for_arg } "
943944 self .indices [arg ] = param_index
944- self ._arg2scopenum [arg ] = scopenum
945+ self ._arg2scope [arg ] = scope
945946 self ._idlist .append (id )
946947 self .marks .extend (normalize_mark_list (marks ))
947948
@@ -999,7 +1000,7 @@ def parametrize(
9991000 Callable [[Any ], Optional [object ]],
10001001 ]
10011002 ] = None ,
1002- scope : "Optional[_Scope ]" = None ,
1003+ scope : "Optional[_ScopeName ]" = None ,
10031004 * ,
10041005 _param_mark : Optional [Mark ] = None ,
10051006 ) -> None :
@@ -1055,8 +1056,6 @@ def parametrize(
10551056 It will also override any fixture-function defined scope, allowing
10561057 to set a dynamic scope using test context or configuration.
10571058 """
1058- from _pytest .fixtures import scope2index
1059-
10601059 argnames , parameters = ParameterSet ._for_parametrize (
10611060 argnames ,
10621061 argvalues ,
@@ -1072,8 +1071,12 @@ def parametrize(
10721071 pytrace = False ,
10731072 )
10741073
1075- if scope is None :
1076- scope = _find_parametrized_scope (argnames , self ._arg2fixturedefs , indirect )
1074+ if scope is not None :
1075+ scope_ = Scope .from_user (
1076+ scope , descr = f"parametrize() call in { self .function .__name__ } "
1077+ )
1078+ else :
1079+ scope_ = _find_parametrized_scope (argnames , self ._arg2fixturedefs , indirect )
10771080
10781081 self ._validate_if_using_arg_names (argnames , indirect )
10791082
@@ -1093,10 +1096,6 @@ def parametrize(
10931096 if _param_mark and _param_mark ._param_ids_from and generated_ids is None :
10941097 object .__setattr__ (_param_mark ._param_ids_from , "_param_ids_generated" , ids )
10951098
1096- scopenum = scope2index (
1097- scope , descr = f"parametrize() call in { self .function .__name__ } "
1098- )
1099-
11001099 # Create the new calls: if we are parametrize() multiple times (by applying the decorator
11011100 # more than once) then we accumulate those calls generating the cartesian product
11021101 # of all calls.
@@ -1110,7 +1109,7 @@ def parametrize(
11101109 param_set .values ,
11111110 param_id ,
11121111 param_set .marks ,
1113- scopenum ,
1112+ scope_ ,
11141113 param_index ,
11151114 )
11161115 newcalls .append (newcallspec )
@@ -1263,7 +1262,7 @@ def _find_parametrized_scope(
12631262 argnames : Sequence [str ],
12641263 arg2fixturedefs : Mapping [str , Sequence [fixtures .FixtureDef [object ]]],
12651264 indirect : Union [bool , Sequence [str ]],
1266- ) -> "fixtures._Scope" :
1265+ ) -> Scope :
12671266 """Find the most appropriate scope for a parametrized call based on its arguments.
12681267
12691268 When there's at least one direct argument, always use "function" scope.
@@ -1281,17 +1280,14 @@ def _find_parametrized_scope(
12811280 if all_arguments_are_fixtures :
12821281 fixturedefs = arg2fixturedefs or {}
12831282 used_scopes = [
1284- fixturedef [0 ].scope
1283+ fixturedef [0 ]._scope
12851284 for name , fixturedef in fixturedefs .items ()
12861285 if name in argnames
12871286 ]
1288- if used_scopes :
1289- # Takes the most narrow scope from used fixtures.
1290- for scope in reversed (fixtures .scopes ):
1291- if scope in used_scopes :
1292- return scope
1287+ # Takes the most narrow scope from used fixtures.
1288+ return min (used_scopes , default = Scope .Function )
12931289
1294- return "function"
1290+ return Scope . Function
12951291
12961292
12971293def _ascii_escaped_by_config (val : Union [str , bytes ], config : Optional [Config ]) -> str :
0 commit comments