Skip to content

Commit 89086a1

Browse files
committed
First approach to enforcing setting 'indirect' on dependent fixtures
This is a try to solve pytest-dev#5712 using following logic: (1) If there exists a fixture F which uses say parameter A (2) And there exist a test T in which parameter named A is present in pytest.mark.parametrize() arglist (3) Then A should be marked explicitly as indirect (via indirect=True or indirect=['A',...]) And if it isn't, we raise ValueError TODO: as of now, ValueError occurs during collection phase. Maybe we want it to appear during test phase?
1 parent 9d90093 commit 89086a1

File tree

2 files changed

+28
-0
lines changed

2 files changed

+28
-0
lines changed

AUTHORS

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -265,6 +265,7 @@ Vidar T. Fauske
265265
Virgil Dupras
266266
Vitaly Lashmanov
267267
Vlad Dragos
268+
Vladyslav Rachek
268269
Volodymyr Piskun
269270
Wei Lin
270271
Wil Cooley

src/_pytest/python.py

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -974,6 +974,7 @@ def parametrize(self, argnames, argvalues, indirect=False, ids=None, scope=None)
974974
scope = _find_parametrized_scope(argnames, self._arg2fixturedefs, indirect)
975975

976976
self._validate_if_using_arg_names(argnames, indirect)
977+
self._validate_dependent_fixtures(argnames, indirect)
977978

978979
arg_values_types = self._resolve_arg_value_types(argnames, indirect)
979980

@@ -1096,6 +1097,32 @@ def _validate_if_using_arg_names(self, argnames, indirect):
10961097
pytrace=False,
10971098
)
10981099

1100+
def _validate_dependent_fixtures(self, argnames, indirect):
1101+
"""
1102+
If there exists a fixture F1 which uses fixture F2
1103+
and in some test T fixture F2 is overriden via pytest.mark.parametrize
1104+
then F2 should be marked as indirect, or we raise an explicit error
1105+
1106+
:param List[str] argnames: list of argument names passed to ``parametrize()``.
1107+
:param indirect: same ``indirect`` parameter of ``parametrize()``.
1108+
:raise ValueError: if validation fails
1109+
"""
1110+
func_name = self.function.__name__
1111+
for arg in argnames:
1112+
if (type(indirect) is bool and indirect is False) or (
1113+
type(indirect) is not bool and arg not in indirect
1114+
):
1115+
for f, f_def_list in self._arg2fixturedefs.items():
1116+
for f_def in f_def_list:
1117+
if (
1118+
arg in f_def.argnames
1119+
): # if f uses a as an argument, then a should be marked as indirect
1120+
raise ValueError(
1121+
f'In function "{func_name}":\n'
1122+
f'Parameter "{arg}" should be explicitly marked as indirect\n'
1123+
f'Because it\'s used by fixture: "{f}"'
1124+
)
1125+
10991126

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

0 commit comments

Comments
 (0)