Files
pytest2/testing/deprecated_test.py
Ran Benita 128f29ee35 Categorize deprecation warnings to PytestRemovedInXWarning
Closes #7480.

This allows us to more easily follow our deprecation policy of turning
warnings into errors for the X.0 releases before complete removal in
X.1.

It also makes the deprecation timeline clear to both the users and
pytest developers -- it can be hard to keep track.

Note that the designation is not meant to be a binding contract - if the
time comes for removal of a specific deprecation but we decide it's too
soon, can just bump it to the next major.

Inspired by Django:
https://docs.djangoproject.com/en/dev/internals/contributing/writing-code/submitting-patches/#deprecating-a-feature
2021-11-14 23:57:10 +02:00

307 lines
9.3 KiB
Python

import re
import sys
import warnings
from pathlib import Path
from unittest import mock
import pytest
from _pytest import deprecated
from _pytest.compat import legacy_path
from _pytest.pytester import Pytester
from pytest import PytestDeprecationWarning
@pytest.mark.parametrize("attribute", pytest.collect.__all__) # type: ignore
# false positive due to dynamic attribute
def test_pytest_collect_module_deprecated(attribute) -> None:
with pytest.warns(DeprecationWarning, match=attribute):
getattr(pytest.collect, attribute)
@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_fillfuncargs_is_deprecated() -> None:
with pytest.warns(
pytest.PytestDeprecationWarning,
match=re.escape(
"pytest._fillfuncargs() is deprecated, use "
"function._request._fillfixtures() instead if you cannot avoid reaching into internals."
),
):
pytest._fillfuncargs(mock.Mock())
def test_fillfixtures_is_deprecated() -> None:
import _pytest.fixtures
with pytest.warns(
pytest.PytestDeprecationWarning,
match=re.escape(
"_pytest.fixtures.fillfixtures() is deprecated, use "
"function._request._fillfixtures() instead if you cannot avoid reaching into internals."
),
):
_pytest.fixtures.fillfixtures(mock.Mock())
def test_minus_k_dash_is_deprecated(pytester: Pytester) -> None:
threepass = pytester.makepyfile(
test_threepass="""
def test_one(): assert 1
def test_two(): assert 1
def test_three(): assert 1
"""
)
result = pytester.runpytest("-k=-test_two", threepass)
result.stdout.fnmatch_lines(["*The `-k '-expr'` syntax*deprecated*"])
def test_minus_k_colon_is_deprecated(pytester: Pytester) -> None:
threepass = pytester.makepyfile(
test_threepass="""
def test_one(): assert 1
def test_two(): assert 1
def test_three(): assert 1
"""
)
result = pytester.runpytest("-k", "test_two:", threepass)
result.stdout.fnmatch_lines(["*The `-k 'expr:'` syntax*deprecated*"])
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")
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)
def test_raising_unittest_skiptest_during_collection_is_deprecated(
pytester: Pytester,
) -> None:
pytester.makepyfile(
"""
import unittest
raise unittest.SkipTest()
"""
)
result = pytester.runpytest()
result.stdout.fnmatch_lines(
[
"*PytestRemovedIn8Warning: Raising unittest.SkipTest*",
]
)
@pytest.mark.parametrize("hooktype", ["hook", "ihook"])
def test_hookproxy_warnings_for_fspath(tmp_path, hooktype, request):
path = legacy_path(tmp_path)
PATH_WARN_MATCH = r".*path: py\.path\.local\) argument is deprecated, please use \(fspath: 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, fspath=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, fspath=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, fspath=Path("/bla/bla")
)
def test_warns_none_is_deprecated():
with pytest.warns(
PytestDeprecationWarning,
match=re.escape(
"Passing None to catch any warning has been deprecated, pass no arguments instead:\n "
"Replace pytest.warns(None) by simply pytest.warns()."
),
):
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)
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)
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)
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()
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("")
with pytest.warns(
pytest.PytestDeprecationWarning,
match=re.escape("The (fspath: py.path.local) argument to File is deprecated."),
):
pytest.File.from_parent(
parent=mod.parent,
fspath=legacy_path("bla"),
)
@pytest.mark.skipif(
sys.version_info < (3, 7),
reason="This deprecation can only be emitted on python>=3.7",
)
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
with pytest.warns(
pytest.PytestDeprecationWarning,
match=re.escape("The pytest.Instance collector type is deprecated"),
):
from _pytest.python import Instance # noqa: F401