The deprecation has only been added in 8.0, so can't be removed in 8. That will have to wait for 9.
398 lines
13 KiB
Python
398 lines
13 KiB
Python
import re
|
|
import sys
|
|
import warnings
|
|
from pathlib import Path
|
|
|
|
import pytest
|
|
from _pytest import deprecated
|
|
from _pytest.compat import legacy_path
|
|
from _pytest.pytester import Pytester
|
|
from pytest import PytestDeprecationWarning
|
|
|
|
|
|
@pytest.mark.parametrize("plugin", sorted(deprecated.DEPRECATED_EXTERNAL_PLUGINS))
|
|
@pytest.mark.filterwarnings("default")
|
|
def test_external_plugins_integrated(pytester: Pytester, plugin) -> None:
|
|
pytester.syspathinsert()
|
|
pytester.makepyfile(**{plugin: ""})
|
|
|
|
with pytest.warns(pytest.PytestConfigWarning):
|
|
pytester.parseconfig("-p", plugin)
|
|
|
|
|
|
def test_hookspec_via_function_attributes_are_deprecated():
|
|
from _pytest.config import PytestPluginManager
|
|
|
|
pm = PytestPluginManager()
|
|
|
|
class DeprecatedHookMarkerSpec:
|
|
def pytest_bad_hook(self):
|
|
pass
|
|
|
|
pytest_bad_hook.historic = False # type: ignore[attr-defined]
|
|
|
|
with pytest.warns(
|
|
PytestDeprecationWarning,
|
|
match=r"Please use the pytest\.hookspec\(historic=False\) decorator",
|
|
) as recorder:
|
|
pm.add_hookspecs(DeprecatedHookMarkerSpec)
|
|
(record,) = recorder
|
|
assert (
|
|
record.lineno
|
|
== DeprecatedHookMarkerSpec.pytest_bad_hook.__code__.co_firstlineno
|
|
)
|
|
assert record.filename == __file__
|
|
|
|
|
|
def test_hookimpl_via_function_attributes_are_deprecated():
|
|
from _pytest.config import PytestPluginManager
|
|
|
|
pm = PytestPluginManager()
|
|
|
|
class DeprecatedMarkImplPlugin:
|
|
def pytest_runtest_call(self):
|
|
pass
|
|
|
|
pytest_runtest_call.tryfirst = True # type: ignore[attr-defined]
|
|
|
|
with pytest.warns(
|
|
PytestDeprecationWarning,
|
|
match=r"Please use the pytest.hookimpl\(tryfirst=True\)",
|
|
) as recorder:
|
|
pm.register(DeprecatedMarkImplPlugin())
|
|
(record,) = recorder
|
|
assert (
|
|
record.lineno
|
|
== DeprecatedMarkImplPlugin.pytest_runtest_call.__code__.co_firstlineno
|
|
)
|
|
assert record.filename == __file__
|
|
|
|
|
|
def test_fscollector_gethookproxy_isinitpath(pytester: Pytester) -> None:
|
|
module = pytester.getmodulecol(
|
|
"""
|
|
def test_foo(): pass
|
|
""",
|
|
withinit=True,
|
|
)
|
|
assert isinstance(module, pytest.Module)
|
|
package = module.parent
|
|
assert isinstance(package, pytest.Package)
|
|
|
|
with pytest.warns(pytest.PytestDeprecationWarning, match="gethookproxy"):
|
|
package.gethookproxy(pytester.path)
|
|
|
|
with pytest.warns(pytest.PytestDeprecationWarning, match="isinitpath"):
|
|
package.isinitpath(pytester.path)
|
|
|
|
# The methods on Session are *not* deprecated.
|
|
session = module.session
|
|
with warnings.catch_warnings(record=True) as rec:
|
|
session.gethookproxy(pytester.path)
|
|
session.isinitpath(pytester.path)
|
|
assert len(rec) == 0
|
|
|
|
|
|
def test_strict_option_is_deprecated(pytester: Pytester) -> None:
|
|
"""--strict is a deprecated alias to --strict-markers (#7530)."""
|
|
pytester.makepyfile(
|
|
"""
|
|
import pytest
|
|
|
|
@pytest.mark.unknown
|
|
def test_foo(): pass
|
|
"""
|
|
)
|
|
result = pytester.runpytest("--strict", "-Wdefault::pytest.PytestRemovedIn8Warning")
|
|
result.stdout.fnmatch_lines(
|
|
[
|
|
"'unknown' not found in `markers` configuration option",
|
|
"*PytestRemovedIn8Warning: The --strict option is deprecated, use --strict-markers instead.",
|
|
]
|
|
)
|
|
|
|
|
|
def test_yield_fixture_is_deprecated() -> None:
|
|
with pytest.warns(DeprecationWarning, match=r"yield_fixture is deprecated"):
|
|
|
|
@pytest.yield_fixture
|
|
def fix():
|
|
assert False
|
|
|
|
|
|
def test_private_is_deprecated() -> None:
|
|
class PrivateInit:
|
|
def __init__(self, foo: int, *, _ispytest: bool = False) -> None:
|
|
deprecated.check_ispytest(_ispytest)
|
|
|
|
with pytest.warns(
|
|
pytest.PytestDeprecationWarning, match="private pytest class or function"
|
|
):
|
|
PrivateInit(10)
|
|
|
|
# Doesn't warn.
|
|
PrivateInit(10, _ispytest=True)
|
|
|
|
|
|
@pytest.mark.parametrize("hooktype", ["hook", "ihook"])
|
|
def test_hookproxy_warnings_for_pathlib(tmp_path, hooktype, request):
|
|
path = legacy_path(tmp_path)
|
|
|
|
PATH_WARN_MATCH = r".*path: py\.path\.local\) argument is deprecated, please use \(collection_path: pathlib\.Path.*"
|
|
if hooktype == "ihook":
|
|
hooks = request.node.ihook
|
|
else:
|
|
hooks = request.config.hook
|
|
|
|
with pytest.warns(PytestDeprecationWarning, match=PATH_WARN_MATCH) as r:
|
|
l1 = sys._getframe().f_lineno
|
|
hooks.pytest_ignore_collect(
|
|
config=request.config, path=path, collection_path=tmp_path
|
|
)
|
|
l2 = sys._getframe().f_lineno
|
|
|
|
(record,) = r
|
|
assert record.filename == __file__
|
|
assert l1 < record.lineno < l2
|
|
|
|
hooks.pytest_ignore_collect(config=request.config, collection_path=tmp_path)
|
|
|
|
# Passing entirely *different* paths is an outright error.
|
|
with pytest.raises(ValueError, match=r"path.*fspath.*need to be equal"):
|
|
with pytest.warns(PytestDeprecationWarning, match=PATH_WARN_MATCH) as r:
|
|
hooks.pytest_ignore_collect(
|
|
config=request.config, path=path, collection_path=Path("/bla/bla")
|
|
)
|
|
|
|
|
|
def test_warns_none_is_deprecated():
|
|
with pytest.warns(
|
|
PytestDeprecationWarning,
|
|
match=re.escape(
|
|
"Passing None has been deprecated.\n"
|
|
"See https://docs.pytest.org/en/latest/how-to/capture-warnings.html"
|
|
"#additional-use-cases-of-warnings-in-tests"
|
|
" for alternatives in common use cases."
|
|
),
|
|
):
|
|
with pytest.warns(None): # type: ignore[call-overload]
|
|
pass
|
|
|
|
|
|
class TestSkipMsgArgumentDeprecated:
|
|
def test_skip_with_msg_is_deprecated(self, pytester: Pytester) -> None:
|
|
p = pytester.makepyfile(
|
|
"""
|
|
import pytest
|
|
|
|
def test_skipping_msg():
|
|
pytest.skip(msg="skippedmsg")
|
|
"""
|
|
)
|
|
result = pytester.runpytest(p, "-Wdefault::pytest.PytestRemovedIn8Warning")
|
|
result.stdout.fnmatch_lines(
|
|
[
|
|
"*PytestRemovedIn8Warning: pytest.skip(msg=...) is now deprecated, "
|
|
"use pytest.skip(reason=...) instead",
|
|
'*pytest.skip(msg="skippedmsg")*',
|
|
]
|
|
)
|
|
result.assert_outcomes(skipped=1, warnings=1)
|
|
|
|
def test_fail_with_msg_is_deprecated(self, pytester: Pytester) -> None:
|
|
p = pytester.makepyfile(
|
|
"""
|
|
import pytest
|
|
|
|
def test_failing_msg():
|
|
pytest.fail(msg="failedmsg")
|
|
"""
|
|
)
|
|
result = pytester.runpytest(p, "-Wdefault::pytest.PytestRemovedIn8Warning")
|
|
result.stdout.fnmatch_lines(
|
|
[
|
|
"*PytestRemovedIn8Warning: pytest.fail(msg=...) is now deprecated, "
|
|
"use pytest.fail(reason=...) instead",
|
|
'*pytest.fail(msg="failedmsg")',
|
|
]
|
|
)
|
|
result.assert_outcomes(failed=1, warnings=1)
|
|
|
|
def test_exit_with_msg_is_deprecated(self, pytester: Pytester) -> None:
|
|
p = pytester.makepyfile(
|
|
"""
|
|
import pytest
|
|
|
|
def test_exit_msg():
|
|
pytest.exit(msg="exitmsg")
|
|
"""
|
|
)
|
|
result = pytester.runpytest(p, "-Wdefault::pytest.PytestRemovedIn8Warning")
|
|
result.stdout.fnmatch_lines(
|
|
[
|
|
"*PytestRemovedIn8Warning: pytest.exit(msg=...) is now deprecated, "
|
|
"use pytest.exit(reason=...) instead",
|
|
]
|
|
)
|
|
result.assert_outcomes(warnings=1)
|
|
|
|
|
|
def test_deprecation_of_cmdline_preparse(pytester: Pytester) -> None:
|
|
pytester.makeconftest(
|
|
"""
|
|
def pytest_cmdline_preparse(config, args):
|
|
...
|
|
|
|
"""
|
|
)
|
|
result = pytester.runpytest("-Wdefault::pytest.PytestRemovedIn8Warning")
|
|
result.stdout.fnmatch_lines(
|
|
[
|
|
"*PytestRemovedIn8Warning: The pytest_cmdline_preparse hook is deprecated*",
|
|
"*Please use pytest_load_initial_conftests hook instead.*",
|
|
]
|
|
)
|
|
|
|
|
|
def test_node_ctor_fspath_argument_is_deprecated(pytester: Pytester) -> None:
|
|
mod = pytester.getmodulecol("")
|
|
|
|
class MyFile(pytest.File):
|
|
def collect(self):
|
|
raise NotImplementedError()
|
|
|
|
with pytest.warns(
|
|
pytest.PytestDeprecationWarning,
|
|
match=re.escape(
|
|
"The (fspath: py.path.local) argument to MyFile is deprecated."
|
|
),
|
|
):
|
|
MyFile.from_parent(
|
|
parent=mod.parent,
|
|
fspath=legacy_path("bla"),
|
|
)
|
|
|
|
|
|
def test_importing_instance_is_deprecated(pytester: Pytester) -> None:
|
|
with pytest.warns(
|
|
pytest.PytestDeprecationWarning,
|
|
match=re.escape("The pytest.Instance collector type is deprecated"),
|
|
):
|
|
pytest.Instance # type:ignore[attr-defined]
|
|
|
|
with pytest.warns(
|
|
pytest.PytestDeprecationWarning,
|
|
match=re.escape("The pytest.Instance collector type is deprecated"),
|
|
):
|
|
from _pytest.python import Instance # noqa: F401
|
|
|
|
|
|
def test_fixture_disallow_on_marked_functions():
|
|
"""Test that applying @pytest.fixture to a marked function warns (#3364)."""
|
|
with pytest.warns(
|
|
pytest.PytestRemovedIn9Warning,
|
|
match=r"Marks applied to fixtures have no effect",
|
|
) as record:
|
|
|
|
@pytest.fixture
|
|
@pytest.mark.parametrize("example", ["hello"])
|
|
@pytest.mark.usefixtures("tmp_path")
|
|
def foo():
|
|
raise NotImplementedError()
|
|
|
|
# it's only possible to get one warning here because you're already prevented
|
|
# from applying @fixture twice
|
|
# ValueError("fixture is being applied more than once to the same function")
|
|
assert len(record) == 1
|
|
|
|
|
|
def test_fixture_disallow_marks_on_fixtures():
|
|
"""Test that applying a mark to a fixture warns (#3364)."""
|
|
with pytest.warns(
|
|
pytest.PytestRemovedIn9Warning,
|
|
match=r"Marks applied to fixtures have no effect",
|
|
) as record:
|
|
|
|
@pytest.mark.parametrize("example", ["hello"])
|
|
@pytest.mark.usefixtures("tmp_path")
|
|
@pytest.fixture
|
|
def foo():
|
|
raise NotImplementedError()
|
|
|
|
assert len(record) == 2 # one for each mark decorator
|
|
|
|
|
|
def test_fixture_disallowed_between_marks():
|
|
"""Test that applying a mark to a fixture warns (#3364)."""
|
|
with pytest.warns(
|
|
pytest.PytestRemovedIn9Warning,
|
|
match=r"Marks applied to fixtures have no effect",
|
|
) as record:
|
|
|
|
@pytest.mark.parametrize("example", ["hello"])
|
|
@pytest.fixture
|
|
@pytest.mark.usefixtures("tmp_path")
|
|
def foo():
|
|
raise NotImplementedError()
|
|
|
|
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)
|