Skip to content

Commit a84fcbf

Browse files
committed
Revert "[parametrize] enforce explicit argnames declaration (#6330)"
This reverts commit 9e26203. Fix #6909
1 parent c9fd1bd commit a84fcbf

File tree

6 files changed

+9
-101
lines changed

6 files changed

+9
-101
lines changed

changelog/6909.bugfix.rst

+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
Revert the change introduced by `#6330 <https://github.com/pytest-dev/pytest/pull/6330>`_, which required all arguments to ``@pytest.mark.parametrize`` to be explicitly defined in the function signature.
2+
3+
The intention of the original change was to remove what was expected to be an unintended/surprising behavior, but it turns out many people relied on it, so the restriction has been reverted.

doc/en/example/parametrize.rst

-3
Original file line numberDiff line numberDiff line change
@@ -402,9 +402,6 @@ The result of this test will be successful:
402402
403403
.. regendoc:wipe
404404
405-
Note, that each argument in `parametrize` list should be explicitly declared in corresponding
406-
python test function or via `indirect`.
407-
408405
Parametrizing test methods through per-class configuration
409406
--------------------------------------------------------------
410407

src/_pytest/fixtures.py

+5-11
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import functools
22
import inspect
3+
import itertools
34
import sys
45
import warnings
56
from collections import defaultdict
@@ -1277,8 +1278,10 @@ def getfixtureinfo(self, node, func, cls, funcargs=True):
12771278
else:
12781279
argnames = ()
12791280

1280-
usefixtures = get_use_fixtures_for_node(node)
1281-
initialnames = usefixtures + argnames
1281+
usefixtures = itertools.chain.from_iterable(
1282+
mark.args for mark in node.iter_markers(name="usefixtures")
1283+
)
1284+
initialnames = tuple(usefixtures) + argnames
12821285
fm = node.session._fixturemanager
12831286
initialnames, names_closure, arg2fixturedefs = fm.getfixtureclosure(
12841287
initialnames, node, ignore_args=self._get_direct_parametrize_args(node)
@@ -1475,12 +1478,3 @@ def _matchfactories(self, fixturedefs, nodeid):
14751478
for fixturedef in fixturedefs:
14761479
if nodes.ischildnode(fixturedef.baseid, nodeid):
14771480
yield fixturedef
1478-
1479-
1480-
def get_use_fixtures_for_node(node) -> Tuple[str, ...]:
1481-
"""Returns the names of all the usefixtures() marks on the given node"""
1482-
return tuple(
1483-
str(name)
1484-
for mark in node.iter_markers(name="usefixtures")
1485-
for name in mark.args
1486-
)

src/_pytest/python.py

-35
Original file line numberDiff line numberDiff line change
@@ -936,8 +936,6 @@ def parametrize(
936936

937937
arg_values_types = self._resolve_arg_value_types(argnames, indirect)
938938

939-
self._validate_explicit_parameters(argnames, indirect)
940-
941939
# Use any already (possibly) generated ids with parametrize Marks.
942940
if _param_mark and _param_mark._param_ids_from:
943941
generated_ids = _param_mark._param_ids_from._param_ids_generated
@@ -1110,39 +1108,6 @@ def _validate_if_using_arg_names(
11101108
pytrace=False,
11111109
)
11121110

1113-
def _validate_explicit_parameters(
1114-
self,
1115-
argnames: typing.Sequence[str],
1116-
indirect: Union[bool, typing.Sequence[str]],
1117-
) -> None:
1118-
"""
1119-
The argnames in *parametrize* should either be declared explicitly via
1120-
indirect list or in the function signature
1121-
1122-
:param List[str] argnames: list of argument names passed to ``parametrize()``.
1123-
:param indirect: same ``indirect`` parameter of ``parametrize()``.
1124-
:raise ValueError: if validation fails
1125-
"""
1126-
if isinstance(indirect, bool):
1127-
parametrized_argnames = [] if indirect else argnames
1128-
else:
1129-
parametrized_argnames = [arg for arg in argnames if arg not in indirect]
1130-
1131-
if not parametrized_argnames:
1132-
return
1133-
1134-
funcargnames = _pytest.compat.getfuncargnames(self.function)
1135-
usefixtures = fixtures.get_use_fixtures_for_node(self.definition)
1136-
1137-
for arg in parametrized_argnames:
1138-
if arg not in funcargnames and arg not in usefixtures:
1139-
func_name = self.function.__name__
1140-
msg = (
1141-
'In function "{func_name}":\n'
1142-
'Parameter "{arg}" should be declared explicitly via indirect or in function itself'
1143-
).format(func_name=func_name, arg=arg)
1144-
fail(msg, pytrace=False)
1145-
11461111

11471112
def _find_parametrized_scope(argnames, arg2fixturedefs, indirect):
11481113
"""Find the most appropriate scope for a parametrized call based on its arguments.

testing/python/collect.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -463,7 +463,7 @@ def fix3():
463463
return '3'
464464
465465
@pytest.mark.parametrize('fix2', ['2'])
466-
def test_it(fix1, fix2):
466+
def test_it(fix1):
467467
assert fix1 == '21'
468468
assert not fix3_instantiated
469469
"""

testing/python/metafunc.py

-51
Original file line numberDiff line numberDiff line change
@@ -36,9 +36,6 @@ def __init__(self, names):
3636
class DefinitionMock(python.FunctionDefinition):
3737
obj = attr.ib()
3838

39-
def listchain(self):
40-
return []
41-
4239
names = fixtures.getfuncargnames(func)
4340
fixtureinfo = FuncFixtureInfoMock(names) # type: Any
4441
definition = DefinitionMock._create(func) # type: Any
@@ -1902,51 +1899,3 @@ def test_converted_to_str(a, b):
19021899
"*= 6 passed in *",
19031900
]
19041901
)
1905-
1906-
def test_parametrize_explicit_parameters_func(self, testdir: Testdir) -> None:
1907-
testdir.makepyfile(
1908-
"""
1909-
import pytest
1910-
1911-
1912-
@pytest.fixture
1913-
def fixture(arg):
1914-
return arg
1915-
1916-
@pytest.mark.parametrize("arg", ["baz"])
1917-
def test_without_arg(fixture):
1918-
assert "baz" == fixture
1919-
"""
1920-
)
1921-
result = testdir.runpytest()
1922-
result.assert_outcomes(error=1)
1923-
result.stdout.fnmatch_lines(
1924-
[
1925-
'*In function "test_without_arg"*',
1926-
'*Parameter "arg" should be declared explicitly via indirect or in function itself*',
1927-
]
1928-
)
1929-
1930-
def test_parametrize_explicit_parameters_method(self, testdir: Testdir) -> None:
1931-
testdir.makepyfile(
1932-
"""
1933-
import pytest
1934-
1935-
class Test:
1936-
@pytest.fixture
1937-
def test_fixture(self, argument):
1938-
return argument
1939-
1940-
@pytest.mark.parametrize("argument", ["foobar"])
1941-
def test_without_argument(self, test_fixture):
1942-
assert "foobar" == test_fixture
1943-
"""
1944-
)
1945-
result = testdir.runpytest()
1946-
result.assert_outcomes(error=1)
1947-
result.stdout.fnmatch_lines(
1948-
[
1949-
'*In function "test_without_argument"*',
1950-
'*Parameter "argument" should be declared explicitly via indirect or in function itself*',
1951-
]
1952-
)

0 commit comments

Comments
 (0)