1010from functools import partial
1111from textwrap import dedent
1212from typing import List
13+ from typing import Optional
1314from typing import Tuple
1415
1516import py
3637from _pytest .main import FSHookProxy
3738from _pytest .mark import MARK_GEN
3839from _pytest .mark .structures import get_unpacked_marks
40+ from _pytest .mark .structures import Mark
3941from _pytest .mark .structures import normalize_mark_list
4042from _pytest .outcomes import fail
4143from _pytest .outcomes import skip
@@ -132,25 +134,7 @@ def pytest_generate_tests(metafunc):
132134 _validate_parametrize_spelling (metafunc )
133135
134136 for marker in metafunc .definition .iter_markers (name = "parametrize" ):
135- args , kwargs = marker .args , marker .kwargs
136- if marker ._param_ids_from :
137- ids = marker ._param_ids_from ._param_ids_generated
138- if ids is None :
139- save_ids = True
140- else :
141- save_ids = False
142- if len (args ) > 3 :
143- args = args .copy ()
144- args [3 ] = ids
145- else :
146- assert "ids" in kwargs
147- kwargs = kwargs .copy ()
148- kwargs ["ids" ] = ids
149-
150- new_ids = metafunc .parametrize (* args , ** kwargs )
151-
152- if marker ._param_ids_from and save_ids :
153- object .__setattr__ (marker ._param_ids_from , "_param_ids_generated" , new_ids )
137+ metafunc .parametrize (* marker .args , ** marker .kwargs , _param_mark = marker )
154138
155139
156140def pytest_configure (config ):
@@ -947,7 +931,15 @@ def funcargnames(self):
947931 warnings .warn (FUNCARGNAMES , stacklevel = 2 )
948932 return self .fixturenames
949933
950- def parametrize (self , argnames , argvalues , indirect = False , ids = None , scope = None ):
934+ def parametrize (
935+ self ,
936+ argnames ,
937+ argvalues ,
938+ indirect = False ,
939+ ids = None ,
940+ scope = None ,
941+ _param_mark : Optional [Mark ] = None ,
942+ ):
951943 """ Add new invocations to the underlying test function using the list
952944 of argvalues for the given argnames. Parametrization is performed
953945 during the collection phase. If you need to setup expensive resources
@@ -1018,8 +1010,16 @@ def parametrize(self, argnames, argvalues, indirect=False, ids=None, scope=None)
10181010
10191011 arg_values_types = self ._resolve_arg_value_types (argnames , indirect )
10201012
1013+ if _param_mark and _param_mark ._param_ids_from :
1014+ generated_ids = _param_mark ._param_ids_from ._param_ids_generated
1015+ if generated_ids is not None :
1016+ ids = generated_ids
1017+
10211018 ids = self ._resolve_arg_ids (argnames , ids , parameters , item = self .definition )
10221019
1020+ if _param_mark and _param_mark ._param_ids_from and generated_ids is None :
1021+ object .__setattr__ (_param_mark ._param_ids_from , "_param_ids_generated" , ids )
1022+
10231023 scopenum = scope2index (
10241024 scope , descr = "parametrize() call in {}" .format (self .function .__name__ )
10251025 )
@@ -1042,7 +1042,6 @@ def parametrize(self, argnames, argvalues, indirect=False, ids=None, scope=None)
10421042 )
10431043 newcalls .append (newcallspec )
10441044 self ._calls = newcalls
1045- return ids
10461045
10471046 def _resolve_arg_ids (self , argnames , ids , parameters , item ):
10481047 """Resolves the actual ids for the given argnames, based on the ``ids`` parameter given
0 commit comments