Skip to content

Commit 6d03e6f

Browse files
committed
python: add a DirectParamFixtureDef subclass to mark direct-parametrization helper fixtures
No functional changes. This is intended for next commit (wants to skip showing these fixtures in `--fixtures-per-test`). These fixtures were previously called "pseudo fixtures". I took the opportunity to rename them "direct param fixture def", which, while less catchy, is more self-descriptive and less judgmental.
1 parent c26c145 commit 6d03e6f

2 files changed

Lines changed: 42 additions & 22 deletions

File tree

src/_pytest/python.py

Lines changed: 41 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,7 @@
5555
from _pytest.fixtures import _resolve_args_directness
5656
from _pytest.fixtures import FixtureDef
5757
from _pytest.fixtures import FixtureRequest
58+
from _pytest.fixtures import FixtureValue
5859
from _pytest.fixtures import FuncFixtureInfo
5960
from _pytest.fixtures import get_scope_node
6061
from _pytest.main import Session
@@ -1095,8 +1096,7 @@ class CallSpec2:
10951096
and stored in item.callspec.
10961097
"""
10971098

1098-
# arg name -> arg value which will be passed to a fixture or pseudo-fixture
1099-
# of the same name. (indirect or direct parametrization respectively)
1099+
# arg name -> arg value which will be passed to a fixture of the same name.
11001100
params: dict[str, object] = dataclasses.field(default_factory=dict)
11011101
# arg name -> arg index.
11021102
indices: dict[str, int] = dataclasses.field(default_factory=dict)
@@ -1153,8 +1153,30 @@ def get_direct_param_fixture_func(request: FixtureRequest) -> Any:
11531153
return request.param
11541154

11551155

1156-
# Used for storing pseudo fixturedefs for direct parametrization.
1157-
name2pseudofixturedef_key = StashKey[dict[str, FixtureDef[Any]]]()
1156+
class DirectParamFixtureDef(FixtureDef[FixtureValue]):
1157+
"""A custom FixtureDef for direct parametrization fixtures.
1158+
1159+
Each parameter in direct parametrization is desugared to a parametrized
1160+
fixture which returns the direct parameterization value as its param.
1161+
We use this custom type as a "marker" for this type of FixtureDef, but
1162+
usually behaves like any other FixtureDef.
1163+
"""
1164+
1165+
def __init__(self, *, config: Config, argname: str, scope: Scope) -> None:
1166+
super().__init__(
1167+
config=config,
1168+
baseid="",
1169+
argname=argname,
1170+
func=get_direct_param_fixture_func,
1171+
scope=scope,
1172+
params=None,
1173+
ids=None,
1174+
_ispytest=True,
1175+
)
1176+
1177+
1178+
# Used for storing fixturedefs for direct parametrization.
1179+
name2directparamfixturedef_key = StashKey[dict[str, DirectParamFixtureDef[object]]]()
11581180

11591181

11601182
@final
@@ -1333,14 +1355,14 @@ def parametrize(
13331355
self._params_directness.update(arg_directness)
13341356

13351357
# Add direct parametrizations as fixturedefs to arg2fixturedefs by
1336-
# registering artificial "pseudo" FixtureDef's such that later at test
1358+
# registering artificial DirectParamFixtureDef's such that later at test
13371359
# setup time we can rely on FixtureDefs to exist for all argnames.
13381360
node = None
1339-
# For scopes higher than function, a "pseudo" FixtureDef might have
1361+
# For scopes higher than function, a DirectParamFixtureDef might have
13401362
# already been created for the scope. We thus store and cache the
1341-
# FixtureDef on the node related to the scope.
1363+
# DirectParamFixtureDef on the node related to the scope.
13421364
if scope_ is Scope.Function:
1343-
name2pseudofixturedef = None
1365+
name2directparamfixturedef = None
13441366
else:
13451367
collector = self.definition.parent
13461368
assert collector is not None
@@ -1357,28 +1379,26 @@ def parametrize(
13571379
node = collector.session
13581380
else:
13591381
assert False, f"Unhandled missing scope: {scope}"
1360-
default: dict[str, FixtureDef[Any]] = {}
1361-
name2pseudofixturedef = node.stash.setdefault(
1362-
name2pseudofixturedef_key, default
1382+
default: dict[str, DirectParamFixtureDef[object]] = {}
1383+
name2directparamfixturedef = node.stash.setdefault(
1384+
name2directparamfixturedef_key, default
13631385
)
13641386
for argname in argnames:
13651387
if arg_directness[argname] == "indirect":
13661388
continue
1367-
if name2pseudofixturedef is not None and argname in name2pseudofixturedef:
1368-
fixturedef = name2pseudofixturedef[argname]
1389+
if (
1390+
name2directparamfixturedef is not None
1391+
and argname in name2directparamfixturedef
1392+
):
1393+
fixturedef = name2directparamfixturedef[argname]
13691394
else:
1370-
fixturedef = FixtureDef(
1395+
fixturedef = DirectParamFixtureDef(
13711396
config=self.config,
1372-
baseid="",
13731397
argname=argname,
1374-
func=get_direct_param_fixture_func,
13751398
scope=scope_,
1376-
params=None,
1377-
ids=None,
1378-
_ispytest=True,
13791399
)
1380-
if name2pseudofixturedef is not None:
1381-
name2pseudofixturedef[argname] = fixturedef
1400+
if name2directparamfixturedef is not None:
1401+
name2directparamfixturedef[argname] = fixturedef
13821402
self._arg2fixturedefs[argname] = [fixturedef]
13831403

13841404
# Create the new calls: if we are parametrize() multiple times (by applying the decorator

testing/python/metafunc.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -801,7 +801,7 @@ def func(x, y):
801801
metafunc = self.Metafunc(func)
802802
metafunc.parametrize("x, y", [("a", "b")], indirect=["x"])
803803
assert metafunc._calls[0].params == dict(x="a", y="b")
804-
# Since `y` is a direct parameter, its pseudo-fixture would
804+
# Since `y` is a direct parameter, its DirectParamFixtureDef would
805805
# be registered.
806806
assert list(metafunc._arg2fixturedefs.keys()) == ["y"]
807807

0 commit comments

Comments
 (0)