18
18
import os
19
19
import re
20
20
from collections .abc import Iterable , Iterator
21
+ from inspect import signature
21
22
from typing import TYPE_CHECKING , Any , Callable , TypeVar , cast
22
23
23
24
import pytest
28
29
from .compat import getfixturedefs , inject_fixture
29
30
from .feature import get_feature , get_features
30
31
from .steps import StepFunctionContext , get_step_fixture_name
31
- from .utils import CONFIG_STACK , get_args , get_caller_module_locals , get_caller_module_path , identity
32
+ from .utils import CONFIG_STACK , get_caller_module_locals , get_caller_module_path , get_required_args , identity
32
33
33
34
if TYPE_CHECKING :
34
35
from _pytest .mark .structures import ParameterSet
@@ -201,6 +202,9 @@ def _execute_step_function(
201
202
) -> None :
202
203
"""Execute step function."""
203
204
__tracebackhide__ = True
205
+
206
+ func_sig = signature (context .step_func )
207
+
204
208
kw = {
205
209
"request" : request ,
206
210
"feature" : scenario .feature ,
@@ -210,24 +214,31 @@ def _execute_step_function(
210
214
"step_func_args" : {},
211
215
}
212
216
request .config .hook .pytest_bdd_before_step (** kw )
213
- args = get_args (context .step_func )
214
217
215
218
try :
216
- kwargs = parse_step_arguments (step = step , context = context )
219
+ parsed_args = parse_step_arguments (step = step , context = context )
217
220
218
- if step . datatable is not None :
219
- kwargs [ STEP_ARGUMENT_DATATABLE ] = step . datatable . raw ()
221
+ # Filter out the arguments that are not in the function signature
222
+ kwargs = { k : v for k , v in parsed_args . items () if k in func_sig . parameters }
220
223
221
- if step .docstring is not None :
224
+ if STEP_ARGUMENT_DATATABLE in func_sig .parameters and step .datatable is not None :
225
+ kwargs [STEP_ARGUMENT_DATATABLE ] = step .datatable .raw ()
226
+ if STEP_ARGUMENT_DOCSTRING in func_sig .parameters and step .docstring is not None :
222
227
kwargs [STEP_ARGUMENT_DOCSTRING ] = step .docstring
223
228
224
- kwargs = {arg : kwargs [arg ] if arg in kwargs else request .getfixturevalue (arg ) for arg in args }
229
+ # Fill the missing arguments requesting the fixture values
230
+ kwargs |= {
231
+ arg : request .getfixturevalue (arg ) for arg in get_required_args (context .step_func ) if arg not in kwargs
232
+ }
225
233
226
234
kw ["step_func_args" ] = kwargs
227
235
228
236
request .config .hook .pytest_bdd_before_step_call (** kw )
229
- # Execute the step as if it was a pytest fixture, so that we can allow "yield" statements in it
237
+
238
+ # Execute the step as if it was a pytest fixture using `call_fixture_func`,
239
+ # so that we can allow "yield" statements in it
230
240
return_value = call_fixture_func (fixturefunc = context .step_func , request = request , kwargs = kwargs )
241
+
231
242
except Exception as exception :
232
243
request .config .hook .pytest_bdd_step_error (exception = exception , ** kw )
233
244
raise
@@ -280,7 +291,7 @@ def decorator(*args: Callable[P, T]) -> Callable[P, T]:
280
291
"scenario function can only be used as a decorator. Refer to the documentation."
281
292
)
282
293
[fn ] = args
283
- func_args = get_args (fn )
294
+ func_args = get_required_args (fn )
284
295
285
296
def scenario_wrapper (request : FixtureRequest , _pytest_bdd_example : dict [str , str ]) -> Any :
286
297
__tracebackhide__ = True
0 commit comments