Skip to content

Commit a9ce43f

Browse files
authored
Update scenario.py
Add regression tested code to not break when Args not in the method signature are present
1 parent 7124f1a commit a9ce43f

File tree

1 file changed

+40
-21
lines changed

1 file changed

+40
-21
lines changed

src/pytest_bdd/scenario.py

Lines changed: 40 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
import os
1919
import re
2020
from collections.abc import Iterable, Iterator
21+
from inspect import signature
2122
from typing import TYPE_CHECKING, Any, Callable, TypeVar, cast
2223

2324
import pytest
@@ -177,6 +178,38 @@ def _execute_step_function(
177178
) -> None:
178179
"""Execute step function."""
179180
__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+
180213
kw = {
181214
"request": request,
182215
"feature": scenario.feature,
@@ -188,37 +221,23 @@ def _execute_step_function(
188221

189222
request.config.hook.pytest_bdd_before_step(**kw)
190223

191-
# Get the step argument values.
192-
converters = context.converters
193-
kwargs = {}
194-
args = get_args(context.step_func)
195-
196224
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()
206227

207-
if step.datatable is not None:
228+
if "datatable" in func_sig.parameters and step.datatable is not None:
208229
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:
211231
kwargs["docstring"] = step.docstring
212232

213-
for arg in args:
214-
if arg not in kwargs:
215-
kwargs[arg] = request.getfixturevalue(arg)
233+
kwargs = _get_argument_values(kwargs)
216234

217235
kw["step_func_args"] = kwargs
218236

219237
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+
221239
return_value = call_fixture_func(fixturefunc=context.step_func, request=request, kwargs=kwargs)
240+
222241
except Exception as exception:
223242
request.config.hook.pytest_bdd_step_error(exception=exception, **kw)
224243
raise

0 commit comments

Comments
 (0)