Skip to content

Commit

Permalink
Injecting fixtures is much easier in pytest 8.1!
Browse files Browse the repository at this point in the history
Move logic for older pythons in the `compat.py` module.
  • Loading branch information
youtux committed Mar 13, 2024
1 parent 0bf17f1 commit f8a9ce0
Show file tree
Hide file tree
Showing 3 changed files with 57 additions and 52 deletions.
63 changes: 55 additions & 8 deletions src/pytest_bdd/compat.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,28 +2,75 @@

from collections.abc import Sequence
from importlib.metadata import version
from typing import Any

from _pytest.fixtures import FixtureDef as _FixtureDef
from _pytest.fixtures import FixtureManager
from _pytest.fixtures import FixtureDef, FixtureManager, FixtureRequest
from _pytest.nodes import Node
from packaging.version import parse as parse_version

pytest_version = parse_version(version("pytest"))

__all__ = ["getfixturedefs", "FixtureDef"]
__all__ = ["getfixturedefs", "inject_fixture"]

if pytest_version.release >= (8, 1):

def getfixturedefs(fixturemanager: FixtureManager, fixturename: str, node: Node) -> Sequence[_FixtureDef] | None:
def getfixturedefs(fixturemanager: FixtureManager, fixturename: str, node: Node) -> Sequence[FixtureDef] | None:
return fixturemanager.getfixturedefs(fixturename, node)

def FixtureDef(fixturemanager, **kwargs):
kwargs.setdefault("config", fixturemanager.config)
return _FixtureDef(**kwargs)
def inject_fixture(request: FixtureRequest, arg: str, value: Any) -> None:
"""Inject fixture into pytest fixture request.
:param request: pytest fixture request
:param arg: argument name
:param value: argument value
"""

request._fixturemanager._register_fixture(
name=arg,
func=lambda: value,
nodeid=request.node.nodeid,
)

else:

def getfixturedefs(fixturemanager: FixtureManager, fixturename: str, node: Node) -> Sequence[FixtureDef] | None:
return fixturemanager.getfixturedefs(fixturename, node.nodeid)

FixtureDef = _FixtureDef
def inject_fixture(request: FixtureRequest, arg: str, value: Any) -> None:
"""Inject fixture into pytest fixture request.
:param request: pytest fixture request
:param arg: argument name
:param value: argument value
"""
fd = FixtureDef(
fixturemanager=request._fixturemanager,
baseid=None,
argname=arg,
func=lambda: value,
scope="function",
params=None,
)
fd.cached_result = (value, 0, None)

old_fd = request._fixture_defs.get(arg)
add_fixturename = arg not in request.fixturenames

def fin() -> None:
request._fixturemanager._arg2fixturedefs[arg].remove(fd)

if old_fd is not None:
request._fixture_defs[arg] = old_fd

if add_fixturename:
request._pyfuncitem._fixtureinfo.names_closure.remove(arg)

request.addfinalizer(fin)

# inject fixture definition
request._fixturemanager._arg2fixturedefs.setdefault(arg, []).append(fd)

# inject fixture value in request cache
request._fixture_defs[arg] = fd
if add_fixturename:
request._pyfuncitem._fixtureinfo.names_closure.append(arg)
4 changes: 2 additions & 2 deletions src/pytest_bdd/scenario.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,9 +23,9 @@
from typing_extensions import ParamSpec

from . import exceptions
from .compat import getfixturedefs
from .compat import getfixturedefs, inject_fixture
from .feature import get_feature, get_features
from .steps import StepFunctionContext, get_step_fixture_name, inject_fixture
from .steps import StepFunctionContext, get_step_fixture_name
from .utils import CONFIG_STACK, get_args, get_caller_module_locals, get_caller_module_path

if TYPE_CHECKING:
Expand Down
42 changes: 0 additions & 42 deletions src/pytest_bdd/steps.py
Original file line number Diff line number Diff line change
Expand Up @@ -201,45 +201,3 @@ def find_unique_name(name: str, seen: Iterable[str]) -> str:
new_name = f"{name}_{i}"
if new_name not in seen:
return new_name


def inject_fixture(request: FixtureRequest, arg: str, value: Any) -> None:
"""Inject fixture into pytest fixture request.
:param request: pytest fixture request
:param arg: argument name
:param value: argument value
"""

fd = compat.FixtureDef(
fixturemanager=request._fixturemanager,
baseid=None,
argname=arg,
func=lambda: value,
scope="function",
params=None,
)
fd.cached_result = (value, 0, None)

old_fd = request._fixture_defs.get(arg)
add_fixturename = arg not in request.fixturenames

def fin() -> None:
# TODO: Still required?
request._fixturemanager._arg2fixturedefs[arg].remove(fd)

if old_fd is not None:
request._fixture_defs[arg] = old_fd

if add_fixturename:
request._pyfuncitem._fixtureinfo.names_closure.remove(arg)

request.addfinalizer(fin)

# inject fixture definition
request._fixturemanager._arg2fixturedefs.setdefault(arg, []).append(fd)

# inject fixture value in request cache
request._fixture_defs[arg] = fd
if add_fixturename:
request._pyfuncitem._fixtureinfo.names_closure.append(arg)

0 comments on commit f8a9ce0

Please sign in to comment.