Emit nose deprecation warnings for plain setup/teardown methods
This commit is contained in:
parent
02e28106e0
commit
370df81332
|
@ -25,7 +25,7 @@ Support for tests written for nose
|
||||||
|
|
||||||
Support for running tests written for `nose <https://nose.readthedocs.io/en/latest/>`__ is now deprecated.
|
Support for running tests written for `nose <https://nose.readthedocs.io/en/latest/>`__ is now deprecated.
|
||||||
|
|
||||||
`nose` has been in maintenance mode-only for years, and maintaining the plugin is not trivial as it spills
|
``nose`` has been in maintenance mode-only for years, and maintaining the plugin is not trivial as it spills
|
||||||
over the code base (see :issue:`9886` for more details).
|
over the code base (see :issue:`9886` for more details).
|
||||||
|
|
||||||
setup/teardown
|
setup/teardown
|
||||||
|
@ -70,11 +70,12 @@ Native pytest support uses ``setup_method`` and ``teardown_method`` (see :ref:`x
|
||||||
...
|
...
|
||||||
|
|
||||||
|
|
||||||
|
This is easy to do in an entire code base by doing a simple find/replace.
|
||||||
|
|
||||||
@with_setup
|
@with_setup
|
||||||
^^^^^^^^^^^
|
^^^^^^^^^^^
|
||||||
|
|
||||||
Code using `@with_setup <with-setup-nose>`_ will also need to be ported to a supported
|
Code using `@with_setup <with-setup-nose>`_ such as this:
|
||||||
pytest style:
|
|
||||||
|
|
||||||
.. code-block:: python
|
.. code-block:: python
|
||||||
|
|
||||||
|
@ -93,7 +94,7 @@ pytest style:
|
||||||
def test_foo():
|
def test_foo():
|
||||||
...
|
...
|
||||||
|
|
||||||
One way to do it is using a fixture:
|
Will also need to be ported to a supported pytest style. One way to do it is using a fixture:
|
||||||
|
|
||||||
.. code-block:: python
|
.. code-block:: python
|
||||||
|
|
||||||
|
|
|
@ -25,7 +25,16 @@ DEPRECATED_EXTERNAL_PLUGINS = {
|
||||||
NOSE_SUPPORT = UnformattedWarning(
|
NOSE_SUPPORT = UnformattedWarning(
|
||||||
PytestRemovedIn8Warning,
|
PytestRemovedIn8Warning,
|
||||||
"Support for nose tests is deprecated and will be removed in a future release.\n"
|
"Support for nose tests is deprecated and will be removed in a future release.\n"
|
||||||
"{nodeid} is using nose method: `{method}` ({stage})",
|
"{nodeid} is using nose method: `{method}` ({stage})\n"
|
||||||
|
"See docs: https://docs.pytest.org/en/stable/deprecations.html#support-for-tests-written-for-nose",
|
||||||
|
)
|
||||||
|
|
||||||
|
NOSE_SUPPORT_METHOD = UnformattedWarning(
|
||||||
|
PytestRemovedIn8Warning,
|
||||||
|
"Support for nose tests is deprecated and will be removed in a future release.\n"
|
||||||
|
"{nodeid} is using nose-specific method: `{method}(self)`\n"
|
||||||
|
"To remove this warning, rename it to `{method}_method(self)`\n"
|
||||||
|
"See docs: https://docs.pytest.org/en/stable/deprecations.html#support-for-tests-written-for-nose",
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -59,6 +59,7 @@ from _pytest.config.argparsing import Parser
|
||||||
from _pytest.deprecated import check_ispytest
|
from _pytest.deprecated import check_ispytest
|
||||||
from _pytest.deprecated import FSCOLLECTOR_GETHOOKPROXY_ISINITPATH
|
from _pytest.deprecated import FSCOLLECTOR_GETHOOKPROXY_ISINITPATH
|
||||||
from _pytest.deprecated import INSTANCE_COLLECTOR
|
from _pytest.deprecated import INSTANCE_COLLECTOR
|
||||||
|
from _pytest.deprecated import NOSE_SUPPORT_METHOD
|
||||||
from _pytest.fixtures import FuncFixtureInfo
|
from _pytest.fixtures import FuncFixtureInfo
|
||||||
from _pytest.main import Session
|
from _pytest.main import Session
|
||||||
from _pytest.mark import MARK_GEN
|
from _pytest.mark import MARK_GEN
|
||||||
|
@ -872,19 +873,23 @@ class Class(PyCollector):
|
||||||
"""Inject a hidden autouse, function scoped fixture into the collected class object
|
"""Inject a hidden autouse, function scoped fixture into the collected class object
|
||||||
that invokes setup_method/teardown_method if either or both are available.
|
that invokes setup_method/teardown_method if either or both are available.
|
||||||
|
|
||||||
Using a fixture to invoke this methods ensures we play nicely and unsurprisingly with
|
Using a fixture to invoke these methods ensures we play nicely and unsurprisingly with
|
||||||
other fixtures (#517).
|
other fixtures (#517).
|
||||||
"""
|
"""
|
||||||
has_nose = self.config.pluginmanager.has_plugin("nose")
|
has_nose = self.config.pluginmanager.has_plugin("nose")
|
||||||
setup_name = "setup_method"
|
setup_name = "setup_method"
|
||||||
setup_method = _get_first_non_fixture_func(self.obj, (setup_name,))
|
setup_method = _get_first_non_fixture_func(self.obj, (setup_name,))
|
||||||
|
emit_nose_setup_warning = False
|
||||||
if setup_method is None and has_nose:
|
if setup_method is None and has_nose:
|
||||||
setup_name = "setup"
|
setup_name = "setup"
|
||||||
|
emit_nose_setup_warning = True
|
||||||
setup_method = _get_first_non_fixture_func(self.obj, (setup_name,))
|
setup_method = _get_first_non_fixture_func(self.obj, (setup_name,))
|
||||||
teardown_name = "teardown_method"
|
teardown_name = "teardown_method"
|
||||||
teardown_method = getattr(self.obj, teardown_name, None)
|
teardown_method = getattr(self.obj, teardown_name, None)
|
||||||
|
emit_nose_teardown_warning = False
|
||||||
if teardown_method is None and has_nose:
|
if teardown_method is None and has_nose:
|
||||||
teardown_name = "teardown"
|
teardown_name = "teardown"
|
||||||
|
emit_nose_teardown_warning = True
|
||||||
teardown_method = getattr(self.obj, teardown_name, None)
|
teardown_method = getattr(self.obj, teardown_name, None)
|
||||||
if setup_method is None and teardown_method is None:
|
if setup_method is None and teardown_method is None:
|
||||||
return
|
return
|
||||||
|
@ -900,10 +905,24 @@ class Class(PyCollector):
|
||||||
if setup_method is not None:
|
if setup_method is not None:
|
||||||
func = getattr(self, setup_name)
|
func = getattr(self, setup_name)
|
||||||
_call_with_optional_argument(func, method)
|
_call_with_optional_argument(func, method)
|
||||||
|
if emit_nose_setup_warning:
|
||||||
|
warnings.warn(
|
||||||
|
NOSE_SUPPORT_METHOD.format(
|
||||||
|
nodeid=request.node.nodeid, method="setup"
|
||||||
|
),
|
||||||
|
stacklevel=2,
|
||||||
|
)
|
||||||
yield
|
yield
|
||||||
if teardown_method is not None:
|
if teardown_method is not None:
|
||||||
func = getattr(self, teardown_name)
|
func = getattr(self, teardown_name)
|
||||||
_call_with_optional_argument(func, method)
|
_call_with_optional_argument(func, method)
|
||||||
|
if emit_nose_teardown_warning:
|
||||||
|
warnings.warn(
|
||||||
|
NOSE_SUPPORT_METHOD.format(
|
||||||
|
nodeid=request.node.nodeid, method="teardown"
|
||||||
|
),
|
||||||
|
stacklevel=2,
|
||||||
|
)
|
||||||
|
|
||||||
self.obj.__pytest_setup_method = xunit_setup_method_fixture
|
self.obj.__pytest_setup_method = xunit_setup_method_fixture
|
||||||
|
|
||||||
|
|
|
@ -233,7 +233,8 @@ def test_importing_instance_is_deprecated(pytester: Pytester) -> None:
|
||||||
from _pytest.python import Instance # noqa: F401
|
from _pytest.python import Instance # noqa: F401
|
||||||
|
|
||||||
|
|
||||||
def test_nose_deprecated(pytester: Pytester) -> None:
|
@pytest.mark.filterwarnings("default")
|
||||||
|
def test_nose_deprecated_with_setup(pytester: Pytester) -> None:
|
||||||
pytest.importorskip("nose")
|
pytest.importorskip("nose")
|
||||||
pytester.makepyfile(
|
pytester.makepyfile(
|
||||||
"""
|
"""
|
||||||
|
@ -253,9 +254,39 @@ def test_nose_deprecated(pytester: Pytester) -> None:
|
||||||
output = pytester.runpytest()
|
output = pytester.runpytest()
|
||||||
message = [
|
message = [
|
||||||
"*PytestRemovedIn8Warning: Support for nose tests is deprecated and will be removed in a future release.",
|
"*PytestRemovedIn8Warning: Support for nose tests is deprecated and will be removed in a future release.",
|
||||||
"*test_nose_deprecated.py::test_omits_warnings is using nose method: `setup_fn_no_op` (setup)",
|
"*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.",
|
"*PytestRemovedIn8Warning: Support for nose tests is deprecated and will be removed in a future release.",
|
||||||
"*test_nose_deprecated.py::test_omits_warnings is using nose method: `teardown_fn_no_op` (teardown)",
|
"*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()
|
||||||
|
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.stdout.fnmatch_lines(message)
|
||||||
output.assert_outcomes(passed=1)
|
output.assert_outcomes(passed=1)
|
||||||
|
|
Loading…
Reference in New Issue