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
@@ -177,6 +178,38 @@ def _execute_step_function(
177
178
) -> None :
178
179
"""Execute step function."""
179
180
__tracebackhide__ = True
181
+
182
+ func_sig = signature (context .step_func )
183
+ converters = context .converters
184
+
185
+ def _get_parsed_arguments ():
186
+ """Parse and convert step arguments."""
187
+ parsed_args = context .parser .parse_arguments (step .name )
188
+ if parsed_args is None :
189
+ raise ValueError (
190
+ f"Unexpected `NoneType` returned from parse_arguments(...) in parser: { context .parser !r} "
191
+ )
192
+ kwargs = {}
193
+ for arg , value in parsed_args .items ():
194
+ param = func_sig .parameters .get (arg )
195
+ if param :
196
+ if arg in converters :
197
+ value = converters [arg ](value )
198
+ kwargs [arg ] = value
199
+ return kwargs
200
+
201
+ def _get_argument_values (kwargs ):
202
+ """Get default values or request fixture values for missing arguments."""
203
+ for arg in get_args (context .step_func ):
204
+ if arg not in kwargs :
205
+ param = func_sig .parameters .get (arg )
206
+ if param :
207
+ if param .default != param .empty :
208
+ kwargs [arg ] = param .default
209
+ else :
210
+ kwargs [arg ] = request .getfixturevalue (arg )
211
+ return kwargs
212
+
180
213
kw = {
181
214
"request" : request ,
182
215
"feature" : scenario .feature ,
@@ -188,37 +221,23 @@ def _execute_step_function(
188
221
189
222
request .config .hook .pytest_bdd_before_step (** kw )
190
223
191
- # Get the step argument values.
192
- converters = context .converters
193
- kwargs = {}
194
- args = get_args (context .step_func )
195
-
196
224
try :
197
- parsed_args = context .parser .parse_arguments (step .name )
198
- assert parsed_args is not None , (
199
- f"Unexpected `NoneType` returned from " f"parse_arguments(...) in parser: { context .parser !r} "
200
- )
201
-
202
- for arg , value in parsed_args .items ():
203
- if arg in converters :
204
- value = converters [arg ](value )
205
- kwargs [arg ] = value
225
+ # Use internal methods without passing redundant arguments
226
+ kwargs = _get_parsed_arguments ()
206
227
207
- if step .datatable is not None :
228
+ if "datatable" in func_sig . parameters and step .datatable is not None :
208
229
kwargs ["datatable" ] = step .datatable .raw ()
209
-
210
- if step .docstring is not None :
230
+ if "docstring" in func_sig .parameters and step .docstring is not None :
211
231
kwargs ["docstring" ] = step .docstring
212
232
213
- for arg in args :
214
- if arg not in kwargs :
215
- kwargs [arg ] = request .getfixturevalue (arg )
233
+ kwargs = _get_argument_values (kwargs )
216
234
217
235
kw ["step_func_args" ] = kwargs
218
236
219
237
request .config .hook .pytest_bdd_before_step_call (** kw )
220
- # Execute the step as if it was a pytest fixture, so that we can allow "yield" statements in it
238
+
221
239
return_value = call_fixture_func (fixturefunc = context .step_func , request = request , kwargs = kwargs )
240
+
222
241
except Exception as exception :
223
242
request .config .hook .pytest_bdd_step_error (exception = exception , ** kw )
224
243
raise
0 commit comments