Skip to content

Commit

Permalink
Revert FixtureDef to a single argument
Browse files Browse the repository at this point in the history
  • Loading branch information
nicoddemus committed Dec 7, 2024
1 parent af0d67a commit 9f78c6c
Show file tree
Hide file tree
Showing 6 changed files with 36 additions and 43 deletions.
54 changes: 25 additions & 29 deletions src/_pytest/fixtures.py
Original file line number Diff line number Diff line change
Expand Up @@ -131,7 +131,7 @@ def pytest_sessionstart(session: Session) -> None:

def get_scope_package(
node: nodes.Item,
fixturedef: FixtureDef[Any, object],
fixturedef: FixtureDef[object],
) -> nodes.Node | None:
from _pytest.python import Package

Expand Down Expand Up @@ -328,7 +328,7 @@ class FuncFixtureInfo:
# matching the name which are applicable to this function.
# There may be multiple overriding fixtures with the same name. The
# sequence is ordered from furthest to closes to the function.
name2fixturedefs: dict[str, Sequence[FixtureDef[Any, Any]]]
name2fixturedefs: dict[str, Sequence[FixtureDef[Any]]]

def prune_dependency_tree(self) -> None:
"""Recompute names_closure from initialnames and name2fixturedefs.
Expand Down Expand Up @@ -369,8 +369,8 @@ def __init__(
self,
pyfuncitem: Function,
fixturename: str | None,
arg2fixturedefs: dict[str, Sequence[FixtureDef[Any, Any]]],
fixture_defs: dict[str, FixtureDef[Any, Any]],
arg2fixturedefs: dict[str, Sequence[FixtureDef[Any]]],
fixture_defs: dict[str, FixtureDef[Any]],
*,
_ispytest: bool = False,
) -> None:
Expand Down Expand Up @@ -413,7 +413,7 @@ def scope(self) -> _ScopeName:
@abc.abstractmethod
def _check_scope(
self,
requested_fixturedef: FixtureDef[Any, object] | PseudoFixtureDef[object],
requested_fixturedef: FixtureDef[object] | PseudoFixtureDef[object],
requested_scope: Scope,
) -> None:
raise NotImplementedError()
Expand Down Expand Up @@ -554,7 +554,7 @@ def _iter_chain(self) -> Iterator[SubRequest]:

def _get_active_fixturedef(
self, argname: str
) -> FixtureDef[Any, object] | PseudoFixtureDef[object]:
) -> FixtureDef[object] | PseudoFixtureDef[object]:
if argname == "request":
cached_result = (self, [0], None)
return PseudoFixtureDef(cached_result, Scope.Function)
Expand Down Expand Up @@ -626,9 +626,7 @@ def _get_active_fixturedef(
self._fixture_defs[argname] = fixturedef
return fixturedef

def _check_fixturedef_without_param(
self, fixturedef: FixtureDef[Any, object]
) -> None:
def _check_fixturedef_without_param(self, fixturedef: FixtureDef[object]) -> None:
"""Check that this request is allowed to execute this fixturedef without
a param."""
funcitem = self._pyfuncitem
Expand Down Expand Up @@ -661,7 +659,7 @@ def _check_fixturedef_without_param(
)
fail(msg, pytrace=False)

def _get_fixturestack(self) -> list[FixtureDef[Any, Any]]:
def _get_fixturestack(self) -> list[FixtureDef[Any]]:
values = [request._fixturedef for request in self._iter_chain()]
values.reverse()
return values
Expand All @@ -686,7 +684,7 @@ def _scope(self) -> Scope:

def _check_scope(
self,
requested_fixturedef: FixtureDef[Any, object] | PseudoFixtureDef[object],
requested_fixturedef: FixtureDef[object] | PseudoFixtureDef[object],
requested_scope: Scope,
) -> None:
# TopRequest always has function scope so always valid.
Expand Down Expand Up @@ -720,7 +718,7 @@ def __init__(
scope: Scope,
param: Any,
param_index: int,
fixturedef: FixtureDef[Any, object],
fixturedef: FixtureDef[object],
*,
_ispytest: bool = False,
) -> None:
Expand All @@ -733,7 +731,7 @@ def __init__(
)
self._parent_request: Final[FixtureRequest] = request
self._scope_field: Final = scope
self._fixturedef: Final[FixtureDef[Any, object]] = fixturedef
self._fixturedef: Final[FixtureDef[object]] = fixturedef
if param is not NOTSET:
self.param = param
self.param_index: Final = param_index
Expand Down Expand Up @@ -763,7 +761,7 @@ def node(self):

def _check_scope(
self,
requested_fixturedef: FixtureDef[Any, object] | PseudoFixtureDef[object],
requested_fixturedef: FixtureDef[object] | PseudoFixtureDef[object],
requested_scope: Scope,
) -> None:
if isinstance(requested_fixturedef, PseudoFixtureDef):
Expand All @@ -784,7 +782,7 @@ def _check_scope(
pytrace=False,
)

def _format_fixturedef_line(self, fixturedef: FixtureDef[Any, object]) -> str:
def _format_fixturedef_line(self, fixturedef: FixtureDef[object]) -> str:
factory = fixturedef.func
path, lineno = getfslineno(factory)
if isinstance(path, Path):
Expand Down Expand Up @@ -959,11 +957,9 @@ def _eval_scope_callable(


@final
class FixtureDef(Generic[FixtureParams, FixtureValue]):
class FixtureDef(Generic[FixtureValue]):
"""A container for a fixture definition.
This is a generic class parametrized on the parameters that a fixture function receives and its return value.
Note: At this time, only explicitly documented fields and methods are
considered public stable API.
"""
Expand All @@ -973,7 +969,7 @@ def __init__(
config: Config,
baseid: str | None,
argname: str,
func: _FixtureFunc[FixtureParams, FixtureValue],
func: _FixtureFunc[Any, FixtureValue],
scope: Scope | _ScopeName | Callable[[str, Config], _ScopeName] | None,
params: Sequence[object] | None,
ids: tuple[object | None, ...] | Callable[[Any], object | None] | None = None,
Expand Down Expand Up @@ -1128,8 +1124,8 @@ def __repr__(self) -> str:


def resolve_fixture_function(
fixturedef: FixtureDef[FixtureParams, FixtureValue], request: FixtureRequest
) -> _FixtureFunc[FixtureParams, FixtureValue]:
fixturedef: FixtureDef[FixtureValue], request: FixtureRequest
) -> _FixtureFunc[Any, FixtureValue]:
"""Get the actual callable that can be called to obtain the fixture
value."""
fixturefunc = fixturedef.func
Expand All @@ -1152,7 +1148,7 @@ def resolve_fixture_function(


def pytest_fixture_setup(
fixturedef: FixtureDef[FixtureParams, FixtureValue], request: SubRequest
fixturedef: FixtureDef[FixtureValue], request: SubRequest
) -> FixtureValue:
"""Execution of fixture setup."""
kwargs = {}
Expand Down Expand Up @@ -1525,7 +1521,7 @@ def __init__(self, session: Session) -> None:
# suite/plugins defined with this name. Populated by parsefactories().
# TODO: The order of the FixtureDefs list of each arg is significant,
# explain.
self._arg2fixturedefs: Final[dict[str, list[FixtureDef[Any, Any]]]] = {}
self._arg2fixturedefs: Final[dict[str, list[FixtureDef[Any]]]] = {}
self._holderobjseen: Final[set[object]] = set()
# A mapping from a nodeid to a list of autouse fixtures it defines.
self._nodeid_autousenames: Final[dict[str, list[str]]] = {
Expand Down Expand Up @@ -1616,7 +1612,7 @@ def getfixtureclosure(
parentnode: nodes.Node,
initialnames: tuple[str, ...],
ignore_args: AbstractSet[str],
) -> tuple[list[str], dict[str, Sequence[FixtureDef[Any, Any]]]]:
) -> tuple[list[str], dict[str, Sequence[FixtureDef[Any]]]]:
# Collect the closure of all fixtures, starting with the given
# fixturenames as the initial set. As we have to visit all
# factory definitions anyway, we also return an arg2fixturedefs
Expand All @@ -1626,7 +1622,7 @@ def getfixtureclosure(

fixturenames_closure = list(initialnames)

arg2fixturedefs: dict[str, Sequence[FixtureDef[Any, Any]]] = {}
arg2fixturedefs: dict[str, Sequence[FixtureDef[Any]]] = {}
lastlen = -1
while lastlen != len(fixturenames_closure):
lastlen = len(fixturenames_closure)
Expand Down Expand Up @@ -1841,7 +1837,7 @@ def parsefactories(

def getfixturedefs(
self, argname: str, node: nodes.Node
) -> Sequence[FixtureDef[Any, Any]] | None:
) -> Sequence[FixtureDef[Any]] | None:
"""Get FixtureDefs for a fixture name which are applicable
to a given node.
Expand All @@ -1860,8 +1856,8 @@ def getfixturedefs(
return tuple(self._matchfactories(fixturedefs, node))

def _matchfactories(
self, fixturedefs: Iterable[FixtureDef[Any, Any]], node: nodes.Node
) -> Iterator[FixtureDef[Any, Any]]:
self, fixturedefs: Iterable[FixtureDef[Any]], node: nodes.Node
) -> Iterator[FixtureDef[Any]]:
parentnodeids = {n.nodeid for n in node.iter_parents()}
for fixturedef in fixturedefs:
if fixturedef.baseid in parentnodeids:
Expand Down Expand Up @@ -1898,7 +1894,7 @@ def get_best_relpath(func) -> str:
loc = getlocation(func, invocation_dir)
return bestrelpath(invocation_dir, Path(loc))

def write_fixture(fixture_def: FixtureDef[Any, object]) -> None:
def write_fixture(fixture_def: FixtureDef[object]) -> None:
argname = fixture_def.argname
if verbose <= 0 and argname.startswith("_"):
return
Expand Down
4 changes: 2 additions & 2 deletions src/_pytest/hookspec.py
Original file line number Diff line number Diff line change
Expand Up @@ -866,7 +866,7 @@ def pytest_report_from_serializable(

@hookspec(firstresult=True)
def pytest_fixture_setup(
fixturedef: FixtureDef[Any, Any], request: SubRequest
fixturedef: FixtureDef[Any], request: SubRequest
) -> object | None:
"""Perform fixture setup execution.
Expand Down Expand Up @@ -894,7 +894,7 @@ def pytest_fixture_setup(


def pytest_fixture_post_finalizer(
fixturedef: FixtureDef[Any, Any], request: SubRequest
fixturedef: FixtureDef[Any], request: SubRequest
) -> None:
"""Called after fixture teardown, but before the cache is cleared, so
the fixture result ``fixturedef.cached_result`` is still available (not
Expand Down
6 changes: 3 additions & 3 deletions src/_pytest/python.py
Original file line number Diff line number Diff line change
Expand Up @@ -1085,7 +1085,7 @@ def get_direct_param_fixture_func(request: FixtureRequest) -> Any:


# Used for storing pseudo fixturedefs for direct parametrization.
name2pseudofixturedef_key = StashKey[dict[str, FixtureDef[Any, Any]]]()
name2pseudofixturedef_key = StashKey[dict[str, FixtureDef[Any]]]()


@final
Expand Down Expand Up @@ -1271,7 +1271,7 @@ def parametrize(
if node is None:
name2pseudofixturedef = None
else:
default: dict[str, FixtureDef[Any, Any]] = {}
default: dict[str, FixtureDef[Any]] = {}
name2pseudofixturedef = node.stash.setdefault(
name2pseudofixturedef_key, default
)
Expand Down Expand Up @@ -1458,7 +1458,7 @@ def _recompute_direct_params_indices(self) -> None:

def _find_parametrized_scope(
argnames: Sequence[str],
arg2fixturedefs: Mapping[str, Sequence[fixtures.FixtureDef[Any, object]]],
arg2fixturedefs: Mapping[str, Sequence[fixtures.FixtureDef[object]]],
indirect: bool | Sequence[str],
) -> Scope:
"""Find the most appropriate scope for a parametrized call based on its arguments.
Expand Down
7 changes: 3 additions & 4 deletions src/_pytest/setuponly.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
from __future__ import annotations

from collections.abc import Generator
from typing import Any

from _pytest._io.saferepr import saferepr
from _pytest.config import Config
Expand Down Expand Up @@ -31,7 +30,7 @@ def pytest_addoption(parser: Parser) -> None:

@pytest.hookimpl(wrapper=True)
def pytest_fixture_setup(
fixturedef: FixtureDef[Any, object], request: SubRequest
fixturedef: FixtureDef[object], request: SubRequest
) -> Generator[None, object, object]:
try:
return (yield)
Expand All @@ -52,7 +51,7 @@ def pytest_fixture_setup(


def pytest_fixture_post_finalizer(
fixturedef: FixtureDef[Any, object], request: SubRequest
fixturedef: FixtureDef[object], request: SubRequest
) -> None:
if fixturedef.cached_result is not None:
config = request.config
Expand All @@ -63,7 +62,7 @@ def pytest_fixture_post_finalizer(


def _show_fixture_action(
fixturedef: FixtureDef[Any, object], config: Config, msg: str
fixturedef: FixtureDef[object], config: Config, msg: str
) -> None:
capman = config.pluginmanager.getplugin("capturemanager")
if capman:
Expand Down
4 changes: 1 addition & 3 deletions src/_pytest/setupplan.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
from __future__ import annotations

from typing import Any

from _pytest.config import Config
from _pytest.config import ExitCode
from _pytest.config.argparsing import Parser
Expand All @@ -23,7 +21,7 @@ def pytest_addoption(parser: Parser) -> None:

@pytest.hookimpl(tryfirst=True)
def pytest_fixture_setup(
fixturedef: FixtureDef[Any, object], request: SubRequest
fixturedef: FixtureDef[object], request: SubRequest
) -> object | None:
# Will return a dummy fixture if the setuponly option is provided.
if request.config.option.setupplan:
Expand Down
4 changes: 2 additions & 2 deletions testing/python/metafunc.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ def Metafunc(self, func, config=None) -> python.Metafunc:
# on the funcarg level, so we don't need a full blown
# initialization.
class FuncFixtureInfoMock:
name2fixturedefs: dict[str, list[fixtures.FixtureDef[Any, object]]] = {}
name2fixturedefs: dict[str, list[fixtures.FixtureDef[object]]] = {}

def __init__(self, names):
self.names_closure = names
Expand Down Expand Up @@ -153,7 +153,7 @@ class DummyFixtureDef:
_scope: Scope

fixtures_defs = cast(
dict[str, Sequence[fixtures.FixtureDef[Any, object]]],
dict[str, Sequence[fixtures.FixtureDef[object]]],
dict(
session_fix=[DummyFixtureDef(Scope.Session)],
package_fix=[DummyFixtureDef(Scope.Package)],
Expand Down

0 comments on commit 9f78c6c

Please sign in to comment.