Apply review comments

This commit is contained in:
Sadra Barikbin 2023-09-17 09:54:15 +03:30
parent 3f10d53b8c
commit fba008cf29
5 changed files with 106 additions and 16 deletions

View File

@ -818,8 +818,8 @@ case we just write some information out to a ``failures`` file:
mode = "a" if os.path.exists("failures") else "w" mode = "a" if os.path.exists("failures") else "w"
with open("failures", mode, encoding="utf-8") as f: with open("failures", mode, encoding="utf-8") as f:
# let's also access a fixture for the fun of it # let's also access a fixture for the fun of it
if "tmp_path" in item.fixturenames: if "tmp_path" in item.funcargs:
extra = " ({})".format(item._request.getfixturevalue("tmp_path")) extra = " ({})".format(item.funcargs["tmp_path"])
else: else:
extra = "" extra = ""

View File

@ -11,6 +11,7 @@ in case of warnings which need to format their messages.
from warnings import warn from warnings import warn
from _pytest.warning_types import PytestDeprecationWarning from _pytest.warning_types import PytestDeprecationWarning
from _pytest.warning_types import PytestRemovedIn8Warning
from _pytest.warning_types import PytestRemovedIn9Warning from _pytest.warning_types import PytestRemovedIn9Warning
from _pytest.warning_types import UnformattedWarning from _pytest.warning_types import UnformattedWarning
@ -48,6 +49,13 @@ MARKED_FIXTURE = PytestRemovedIn9Warning(
"See docs: https://docs.pytest.org/en/stable/deprecations.html#applying-a-mark-to-a-fixture-function" "See docs: https://docs.pytest.org/en/stable/deprecations.html#applying-a-mark-to-a-fixture-function"
) )
ITEM_FUNCARGS_MEMBERS = PytestRemovedIn9Warning(
"Access 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."
)
# You want to make some `__init__` or function "private". # You want to make some `__init__` or function "private".
# #
# def my_private_function(some, args): # def my_private_function(some, args):

View File

@ -15,6 +15,7 @@ from pathlib import Path
from typing import Any from typing import Any
from typing import Callable from typing import Callable
from typing import Dict from typing import Dict
from typing import Final
from typing import final from typing import final
from typing import Generator from typing import Generator
from typing import Iterable from typing import Iterable
@ -55,6 +56,7 @@ from _pytest.config import ExitCode
from _pytest.config import hookimpl from _pytest.config import hookimpl
from _pytest.config.argparsing import Parser from _pytest.config.argparsing import Parser
from _pytest.deprecated import check_ispytest from _pytest.deprecated import check_ispytest
from _pytest.deprecated import ITEM_FUNCARGS_MEMBERS
from _pytest.fixtures import FixtureDef from _pytest.fixtures import FixtureDef
from _pytest.fixtures import FixtureRequest from _pytest.fixtures import FixtureRequest
from _pytest.fixtures import FuncFixtureInfo from _pytest.fixtures import FuncFixtureInfo
@ -1660,19 +1662,13 @@ def write_docstring(tw: TerminalWriter, doc: str, indent: str = " ") -> None:
class DeprecatingFuncArgs(Dict[str, object]): class DeprecatingFuncArgs(Dict[str, object]):
def __init__(self, initialnames): def __init__(self, initialnames: Sequence[str]) -> None:
self.initialnames = initialnames
super().__init__() super().__init__()
self.initialnames: Final = initialnames
def __getitem__(self, key: str) -> object: def __getitem__(self, key: str) -> object:
if key not in self.initialnames: if key not in self.initialnames:
warnings.warn( warnings.warn(ITEM_FUNCARGS_MEMBERS)
"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) return super().__getitem__(key)

View File

@ -133,3 +133,93 @@ def test_fixture_disallowed_between_marks():
raise NotImplementedError() raise NotImplementedError()
assert len(record) == 2 # one for each mark decorator assert len(record) == 2 # one for each mark decorator
@pytest.mark.filterwarnings("default")
def test_nose_deprecated_with_setup(pytester: Pytester) -> None:
pytest.importorskip("nose")
pytester.makepyfile(
"""
from nose.tools import with_setup
def setup_fn_no_op():
...
def teardown_fn_no_op():
...
@with_setup(setup_fn_no_op, teardown_fn_no_op)
def test_omits_warnings():
...
"""
)
output = pytester.runpytest("-Wdefault::pytest.PytestRemovedIn8Warning")
message = [
"*PytestRemovedIn8Warning: Support for nose tests is deprecated and will be removed in a future release.",
"*test_nose_deprecated_with_setup.py::test_omits_warnings is using nose method: `setup_fn_no_op` (setup)",
"*PytestRemovedIn8Warning: Support for nose tests is deprecated and will be removed in a future release.",
"*test_nose_deprecated_with_setup.py::test_omits_warnings is using nose method: `teardown_fn_no_op` (teardown)",
]
output.stdout.fnmatch_lines(message)
output.assert_outcomes(passed=1)
@pytest.mark.filterwarnings("default")
def test_nose_deprecated_setup_teardown(pytester: Pytester) -> None:
pytest.importorskip("nose")
pytester.makepyfile(
"""
class Test:
def setup(self):
...
def teardown(self):
...
def test(self):
...
"""
)
output = pytester.runpytest("-Wdefault::pytest.PytestRemovedIn8Warning")
message = [
"*PytestRemovedIn8Warning: Support for nose tests is deprecated and will be removed in a future release.",
"*test_nose_deprecated_setup_teardown.py::Test::test is using nose-specific method: `setup(self)`",
"*To remove this warning, rename it to `setup_method(self)`",
"*PytestRemovedIn8Warning: Support for nose tests is deprecated and will be removed in a future release.",
"*test_nose_deprecated_setup_teardown.py::Test::test is using nose-specific method: `teardown(self)`",
"*To remove this warning, rename it to `teardown_method(self)`",
]
output.stdout.fnmatch_lines(message)
output.assert_outcomes(passed=1)
def test_deprecated_access_to_item_funcargs(pytester: Pytester) -> None:
module = pytester.makepyfile(
"""
import pytest
@pytest.fixture
def fixture1():
return None
@pytest.fixture
def fixture2(fixture1):
return None
def test(fixture2):
pass
"""
)
test = pytester.genitems((pytester.getmodulecol(module),))[0]
assert isinstance(test, pytest.Function)
test.session._setupstate.setup(test)
test.setup()
with pytest.warns(
pytest.PytestRemovedIn9Warning,
match=r"Access to names other than initialnames",
) as record:
test.funcargs["fixture1"]
assert len(record) == 1
test.funcargs["fixture2"]
assert len(record) == 1

View File

@ -122,20 +122,16 @@ class TestFillFixtures:
["*recursive dependency involving fixture 'fix1' detected*"] ["*recursive dependency involving fixture 'fix1' detected*"]
) )
def test_funcarg_basic(self, recwarn, pytester: Pytester) -> None: def test_funcarg_basic(self, pytester: Pytester) -> None:
pytester.copy_example() pytester.copy_example()
item = pytester.getitem(Path("test_funcarg_basic.py")) item = pytester.getitem(Path("test_funcarg_basic.py"))
assert isinstance(item, Function) assert isinstance(item, Function)
# Execute's item's setup, which fills fixtures. # Execute's item's setup, which fills fixtures.
item.session._setupstate.setup(item) item.session._setupstate.setup(item)
assert len(recwarn) == 0
item.funcargs["request"]
assert len(recwarn) == 1 and recwarn[0].category is DeprecationWarning
del item.funcargs["request"] del item.funcargs["request"]
assert len(get_public_names(item.funcargs)) == 2 assert len(get_public_names(item.funcargs)) == 2
assert item.funcargs["some"] == "test_func" assert item.funcargs["some"] == "test_func"
assert item.funcargs["other"] == 42 assert item.funcargs["other"] == 42
assert len(recwarn) == 1
def test_funcarg_lookup_modulelevel(self, pytester: Pytester) -> None: def test_funcarg_lookup_modulelevel(self, pytester: Pytester) -> None:
pytester.copy_example() pytester.copy_example()