Apply all but one review comments

This commit is contained in:
Sadra Barikbin 2024-01-14 23:53:10 +03:30
parent 1de56fc344
commit 56e9533354
6 changed files with 64 additions and 28 deletions

View File

@ -280,18 +280,15 @@ The accompanying ``py.path.local`` based paths have been deprecated: plugins whi
.. _item-funcargs-deprecation: .. _item-funcargs-deprecation:
Accessing ``item.funcargs`` with not directly requested fixture names Accessing ``item.funcargs`` with non-directly requested fixture names
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
.. deprecated:: 8.0 .. versionremoved:: 8.1
.. versionremoved:: 9.0
Accessing ``item.funcargs`` with not directly requested fixture names issues warning and Accessing ``item.funcargs`` with non-directly requested fixture names issues a warning and will be erroneous starting from pytest 9.
will be erroneous starting from pytest 9. Directly requested fixtures are the direct args Directly requested fixtures are the direct arguments to the test, ``usefixtures`` fixtures and ``autouse`` fixtures.
to the test, the ``usefixtures`` fixtures and the ``autouse`` ones.
To request fixtures other than the directly requested ones, user could use To request a fixture other than the directly requested ones, use :func:`request.getfixturevalue <pytest.FixtureRequest.getfixturevalue>` instead.
``request.getfixturevalue`` instead.
.. _nose-deprecation: .. _nose-deprecation:

View File

@ -17,6 +17,7 @@ from collections import defaultdict
from pathlib import Path from pathlib import Path
from pathlib import PurePath from pathlib import PurePath
from typing import Callable from typing import Callable
from typing import DefaultDict
from typing import Dict from typing import Dict
from typing import IO from typing import IO
from typing import Iterable from typing import Iterable
@ -668,9 +669,9 @@ class AssertionRewriter(ast.NodeVisitor):
else: else:
self.enable_assertion_pass_hook = False self.enable_assertion_pass_hook = False
self.source = source self.source = source
self.scope: tuple[ast.AST, ...] = () self.scope: Tuple[ast.AST, ...] = ()
self.variables_overwrite: defaultdict[ self.variables_overwrite: DefaultDict[
tuple[ast.AST, ...], Dict[str, str] Tuple[ast.AST, ...], Dict[str, str]
] = defaultdict(dict) ] = defaultdict(dict)
def run(self, mod: ast.Module) -> None: def run(self, mod: ast.Module) -> None:

View File

@ -40,6 +40,7 @@ from _pytest.outcomes import OutcomeException
from _pytest.outcomes import skip from _pytest.outcomes import skip
from _pytest.pathlib import fnmatch_ex from _pytest.pathlib import fnmatch_ex
from _pytest.pathlib import import_path from _pytest.pathlib import import_path
from _pytest.python import DeprecatingFuncArgs
from _pytest.python import Module from _pytest.python import Module
from _pytest.python_api import approx from _pytest.python_api import approx
from _pytest.warning_types import PytestWarning from _pytest.warning_types import PytestWarning
@ -284,7 +285,9 @@ class DoctestItem(Item):
return super().from_parent(name=name, parent=parent, runner=runner, dtest=dtest) return super().from_parent(name=name, parent=parent, runner=runner, dtest=dtest)
def _initrequest(self) -> None: def _initrequest(self) -> None:
self.funcargs: Dict[str, object] = {} self.funcargs: Dict[str, object] = DeprecatingFuncArgs(
self._fixtureinfo.initialnames
)
self._request = TopRequest(self, _ispytest=True) # type: ignore[arg-type] self._request = TopRequest(self, _ispytest=True) # type: ignore[arg-type]
def setup(self) -> None: def setup(self) -> None:

View File

@ -1664,10 +1664,12 @@ def write_docstring(tw: TerminalWriter, doc: str, indent: str = " ") -> None:
class DeprecatingFuncArgs(Dict[str, object]): class DeprecatingFuncArgs(Dict[str, object]):
def __init__(self, initialnames: Sequence[str]) -> None: def __init__(self, initialnames: Sequence[str]) -> None:
super().__init__() super().__init__()
self.warned: bool = False
self.initialnames: Final = initialnames self.initialnames: Final = initialnames
def __getitem__(self, key: str) -> object: def __getitem__(self, key: str) -> object:
if key not in self.initialnames: if not self.warned and key not in self.initialnames:
self.warned = True
warnings.warn(ITEM_FUNCARGS_MEMBERS, stacklevel=2) warnings.warn(ITEM_FUNCARGS_MEMBERS, stacklevel=2)
return super().__getitem__(key) return super().__getitem__(key)

View File

@ -195,7 +195,7 @@ def test_nose_deprecated_setup_teardown(pytester: Pytester) -> None:
def test_deprecated_access_to_item_funcargs(pytester: Pytester) -> None: def test_deprecated_access_to_item_funcargs(pytester: Pytester) -> None:
module = pytester.makepyfile( pytester.makepyfile(
""" """
import pytest import pytest
@ -207,19 +207,17 @@ def test_deprecated_access_to_item_funcargs(pytester: Pytester) -> None:
def fixture2(fixture1): def fixture2(fixture1):
return None return None
def test(fixture2): def test(request, fixture2):
pass with pytest.warns(
pytest.PytestRemovedIn9Warning,
match=r"Accessing `item.funcargs` with a fixture",
) as record:
request.node.funcargs["fixture1"]
assert request.node.funcargs.warned
request.node.funcargs.warned = False
request.node.funcargs["fixture2"]
assert len(record) == 1
""" """
) )
test = pytester.genitems((pytester.getmodulecol(module),))[0] output = pytester.runpytest()
assert isinstance(test, pytest.Function) output.assert_outcomes(passed=1)
test.session._setupstate.setup(test)
test.setup()
with pytest.warns(
pytest.PytestRemovedIn9Warning,
match=r"Accessing `item.funcargs` with a fixture",
) as record:
test.funcargs["fixture1"]
assert len(record) == 1
test.funcargs["fixture2"]
assert len(record) == 1

View File

@ -881,6 +881,41 @@ class TestDoctests:
result = pytester.runpytest(p, "--doctest-modules") result = pytester.runpytest(p, "--doctest-modules")
result.stdout.fnmatch_lines(["*collected 1 item*"]) result.stdout.fnmatch_lines(["*collected 1 item*"])
def test_deprecated_access_to_item_funcargs(self, pytester: Pytester):
pytester.makeconftest(
"""
import pytest
@pytest.fixture
def fixture1():
return None
@pytest.fixture(autouse=True)
def fixture2(fixture1):
return None
"""
)
pytester.makepyfile(
"""
'''
>>> import pytest
>>> request = getfixture('request')
>>> with pytest.warns(
... pytest.PytestRemovedIn9Warning,
... match=r"Accessing `item.funcargs` with a fixture",
... ) as record:
... request.node.funcargs["fixture1"]
... assert request.node.funcargs.warned
... request.node.funcargs.warned = False
... request.node.funcargs["fixture2"]
>>> len(record)
1
'''
"""
)
result = pytester.runpytest("--doctest-modules")
result.assert_outcomes(passed=1)
class TestLiterals: class TestLiterals:
@pytest.mark.parametrize("config_mode", ["ini", "comment"]) @pytest.mark.parametrize("config_mode", ["ini", "comment"])