From 3f10d53b8c8694986feb4692b45fe3aa1ee58ab4 Mon Sep 17 00:00:00 2001 From: Sadra Barikbin Date: Wed, 6 Sep 2023 17:53:49 +0330 Subject: [PATCH] Just raise deprecation warning --- doc/en/example/simple.rst | 2 +- src/_pytest/fixtures.py | 6 ++---- src/_pytest/python.py | 21 ++++++++++++++++++++- testing/python/fixtures.py | 13 ++++++++++--- 4 files changed, 33 insertions(+), 9 deletions(-) diff --git a/doc/en/example/simple.rst b/doc/en/example/simple.rst index 21e5f4a09..64420874e 100644 --- a/doc/en/example/simple.rst +++ b/doc/en/example/simple.rst @@ -819,7 +819,7 @@ case we just write some information out to a ``failures`` file: with open("failures", mode, encoding="utf-8") as f: # let's also access a fixture for the fun of it if "tmp_path" in item.fixturenames: - extra = " ({})".format(item.funcargs["tmp_path"]) + extra = " ({})".format(item._request.getfixturevalue("tmp_path")) else: extra = "" diff --git a/src/_pytest/fixtures.py b/src/_pytest/fixtures.py index 923254053..440116dfa 100644 --- a/src/_pytest/fixtures.py +++ b/src/_pytest/fixtures.py @@ -683,11 +683,9 @@ class TopRequest(FixtureRequest): def _fillfixtures(self) -> None: item = self._pyfuncitem fixturenames = getattr(item, "fixturenames", self.fixturenames) - initialnames = item._fixtureinfo.initialnames for argname in fixturenames: - value = self.getfixturevalue(argname) - if argname not in item.funcargs and argname in initialnames: - item.funcargs[argname] = value + if argname not in item.funcargs: + item.funcargs[argname] = self.getfixturevalue(argname) def addfinalizer(self, finalizer: Callable[[], object]) -> None: self.node.addfinalizer(finalizer) diff --git a/src/_pytest/python.py b/src/_pytest/python.py index 4ca77fbfa..2a7cd4979 100644 --- a/src/_pytest/python.py +++ b/src/_pytest/python.py @@ -1659,6 +1659,23 @@ def write_docstring(tw: TerminalWriter, doc: str, indent: str = " ") -> None: tw.line(indent + line) +class DeprecatingFuncArgs(Dict[str, object]): + def __init__(self, initialnames): + self.initialnames = initialnames + super().__init__() + + def __getitem__(self, key: str) -> object: + if key not in self.initialnames: + warnings.warn( + "Accessing to names other than initialnames i.e., direct args," + " the ones with `usefixture` or the ones with `autouse` through " + "`item.funcargs` is deprecated and will raise `KeyError` from " + "pytest 9. Please use `request.getfixturevalue` instead.", + DeprecationWarning, + ) + return super().__getitem__(key) + + class Function(PyobjMixin, nodes.Item): """Item responsible for setting up and executing a Python test function. @@ -1747,7 +1764,9 @@ class Function(PyobjMixin, nodes.Item): return super().from_parent(parent=parent, **kw) def _initrequest(self) -> None: - self.funcargs: Dict[str, object] = {} + self.funcargs: Dict[str, object] = DeprecatingFuncArgs( + self._fixtureinfo.initialnames + ) self._request = fixtures.TopRequest(self, _ispytest=True) @property diff --git a/testing/python/fixtures.py b/testing/python/fixtures.py index c976b656d..199636ef7 100644 --- a/testing/python/fixtures.py +++ b/testing/python/fixtures.py @@ -9,6 +9,7 @@ from _pytest.config import ExitCode from _pytest.fixtures import deduplicate_names from _pytest.fixtures import TopRequest from _pytest.monkeypatch import MonkeyPatch +from _pytest.pytester import get_public_names from _pytest.pytester import Pytester from _pytest.python import Function @@ -121,15 +122,20 @@ class TestFillFixtures: ["*recursive dependency involving fixture 'fix1' detected*"] ) - def test_funcarg_basic(self, pytester: Pytester) -> None: + def test_funcarg_basic(self, recwarn, pytester: Pytester) -> None: pytester.copy_example() item = pytester.getitem(Path("test_funcarg_basic.py")) assert isinstance(item, Function) # Execute's item's setup, which fills fixtures. item.session._setupstate.setup(item) - assert len(item.funcargs) == 2 + assert len(recwarn) == 0 + item.funcargs["request"] + assert len(recwarn) == 1 and recwarn[0].category is DeprecationWarning + del item.funcargs["request"] + assert len(get_public_names(item.funcargs)) == 2 assert item.funcargs["some"] == "test_func" assert item.funcargs["other"] == 42 + assert len(recwarn) == 1 def test_funcarg_lookup_modulelevel(self, pytester: Pytester) -> None: pytester.copy_example() @@ -839,7 +845,8 @@ class TestRequestBasic: val2 = req.getfixturevalue("other") # see about caching assert val2 == 2 assert item.funcargs["something"] == 1 - assert len(item.funcargs) == 1 + assert len(get_public_names(item.funcargs)) == 2 + assert "request" in item.funcargs def test_request_addfinalizer(self, pytester: Pytester) -> None: item = pytester.getitem(