Change pytest deprecation warnings into errors for 6.0 release (#7362)

Co-authored-by: Hugo van Kemenade <hugovk@users.noreply.github.com>
This commit is contained in:
Bruno Oliveira 2020-07-22 21:36:51 -03:00 committed by GitHub
parent a9799f0b35
commit 7ec6401ffa
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
19 changed files with 122 additions and 84 deletions

View File

@ -0,0 +1,23 @@
**PytestDeprecationWarning are now errors by default.**
Following our plan to remove deprecated features with as little disruption as
possible, all warnings of type ``PytestDeprecationWarning`` now generate errors
instead of warning messages.
**The affected features will be effectively removed in pytest 6.1**, so please consult the
`Deprecations and Removals <https://docs.pytest.org/en/latest/deprecations.html>`__
section in the docs for directions on how to update existing code.
In the pytest ``6.0.X`` series, it is possible to change the errors back into warnings as a
stopgap measure by adding this to your ``pytest.ini`` file:
.. code-block:: ini
[pytest]
filterwarnings =
ignore::pytest.PytestDeprecationWarning
But this will stop working when pytest ``6.1`` is released.
**If you have concerns** about the removal of a specific feature, please add a
comment to `#5584 <https://github.com/pytest-dev/pytest/issues/5584>`__.

View File

@ -1024,10 +1024,45 @@ When set (regardless of value), pytest will use color in terminal output.
Exceptions
----------
UsageError
~~~~~~~~~~
.. autoclass:: _pytest.config.UsageError()
:show-inheritance:
.. _`warnings ref`:
Warnings
--------
Custom warnings generated in some situations such as improper usage or deprecated features.
.. autoclass:: pytest.PytestWarning
:show-inheritance:
.. autoclass:: pytest.PytestAssertRewriteWarning
:show-inheritance:
.. autoclass:: pytest.PytestCacheWarning
:show-inheritance:
.. autoclass:: pytest.PytestCollectionWarning
:show-inheritance:
.. autoclass:: pytest.PytestConfigWarning
:show-inheritance:
.. autoclass:: pytest.PytestDeprecationWarning
:show-inheritance:
.. autoclass:: pytest.PytestExperimentalApiWarning
:show-inheritance:
.. autoclass:: pytest.PytestUnhandledCoroutineWarning
:show-inheritance:
.. autoclass:: pytest.PytestUnknownMarkWarning
:show-inheritance:
Consult the :ref:`internal-warnings` section in the documentation for more information.
.. _`ini options ref`:

View File

@ -381,8 +381,6 @@ custom error message.
Internal pytest warnings
------------------------
pytest may generate its own warnings in some situations, such as improper usage or deprecated features.
For example, pytest will emit a warning if it encounters a class that matches :confval:`python_classes` but also
@ -415,31 +413,4 @@ These warnings might be filtered using the same builtin mechanisms used to filte
Please read our :ref:`backwards-compatibility` to learn how we proceed about deprecating and eventually removing
features.
The following warning types are used by pytest and are part of the public API:
.. autoclass:: pytest.PytestWarning
:show-inheritance:
.. autoclass:: pytest.PytestAssertRewriteWarning
:show-inheritance:
.. autoclass:: pytest.PytestCacheWarning
:show-inheritance:
.. autoclass:: pytest.PytestCollectionWarning
:show-inheritance:
.. autoclass:: pytest.PytestConfigWarning
:show-inheritance:
.. autoclass:: pytest.PytestDeprecationWarning
:show-inheritance:
.. autoclass:: pytest.PytestExperimentalApiWarning
:show-inheritance:
.. autoclass:: pytest.PytestUnhandledCoroutineWarning
:show-inheritance:
.. autoclass:: pytest.PytestUnknownMarkWarning
:show-inheritance:
The full list of warnings is listed in :ref:`the reference documentation <warnings ref>`.

View File

@ -46,7 +46,6 @@ from _pytest.compat import TYPE_CHECKING
from _pytest.config import _PluggyPlugin
from _pytest.config import Config
from _pytest.config.argparsing import Parser
from _pytest.deprecated import FILLFUNCARGS
from _pytest.deprecated import FIXTURE_POSITIONAL_ARGUMENTS
from _pytest.deprecated import FUNCARGNAMES
from _pytest.mark import ParameterSet
@ -361,7 +360,8 @@ def reorder_items_atscope(
def fillfixtures(function: "Function") -> None:
""" fill missing funcargs for a test function. """
warnings.warn(FILLFUNCARGS, stacklevel=2)
# Uncomment this after 6.0 release (#7361)
# warnings.warn(FILLFUNCARGS, stacklevel=2)
try:
request = function._request
except AttributeError:

View File

@ -12,7 +12,6 @@ import py.path
from pluggy import HookspecMarker
from .deprecated import COLLECT_DIRECTORY_HOOK
from .deprecated import WARNING_CAPTURED_HOOK
from _pytest.compat import TYPE_CHECKING
if TYPE_CHECKING:
@ -737,7 +736,9 @@ def pytest_terminal_summary(
"""
@hookspec(historic=True, warn_on_impl=WARNING_CAPTURED_HOOK)
# Uncomment this after 6.0 release (#7361)
# @hookspec(historic=True, warn_on_impl=WARNING_CAPTURED_HOOK)
@hookspec(historic=True)
def pytest_warning_captured(
warning_message: "warnings.WarningMessage",
when: "Literal['config', 'collect', 'runtest']",

View File

@ -1,6 +1,5 @@
""" generic mechanism for marking and selecting python functions. """
import typing
import warnings
from typing import AbstractSet
from typing import List
from typing import Optional
@ -23,8 +22,6 @@ from _pytest.config import ExitCode
from _pytest.config import hookimpl
from _pytest.config import UsageError
from _pytest.config.argparsing import Parser
from _pytest.deprecated import MINUS_K_COLON
from _pytest.deprecated import MINUS_K_DASH
from _pytest.store import StoreKey
if TYPE_CHECKING:
@ -181,12 +178,14 @@ def deselect_by_keyword(items: "List[Item]", config: Config) -> None:
if keywordexpr.startswith("-"):
# To be removed in pytest 7.0.0.
warnings.warn(MINUS_K_DASH, stacklevel=2)
# Uncomment this after 6.0 release (#7361)
# warnings.warn(MINUS_K_DASH, stacklevel=2)
keywordexpr = "not " + keywordexpr[1:]
selectuntil = False
if keywordexpr[-1:] == ":":
# To be removed in pytest 7.0.0.
warnings.warn(MINUS_K_COLON, stacklevel=2)
# Uncomment this after 6.0 release (#7361)
# warnings.warn(MINUS_K_COLON, stacklevel=2)
selectuntil = True
keywordexpr = keywordexpr[:-1]

View File

@ -78,7 +78,7 @@ class PytestUnhandledCoroutineWarning(PytestWarning):
class PytestUnknownMarkWarning(PytestWarning):
"""Warning emitted on use of unknown markers.
See https://docs.pytest.org/en/stable/mark.html for details.
See :ref:`mark` for details.
"""
__module__ = "pytest"

View File

@ -105,6 +105,8 @@ def catch_warnings_for_item(
warnings.filterwarnings("always", category=DeprecationWarning)
warnings.filterwarnings("always", category=PendingDeprecationWarning)
warnings.filterwarnings("error", category=pytest.PytestDeprecationWarning)
# filters should have this precedence: mark, cmdline options, ini
# filters should be applied in the inverse order of precedence
for arg in inifilters:

View File

@ -1,11 +1,9 @@
import sys
import warnings
from types import ModuleType
from typing import Any
from typing import List
import pytest
from _pytest.deprecated import PYTEST_COLLECT_MODULE
COLLECT_FAKEMODULE_ATTRIBUTES = [
@ -33,7 +31,8 @@ class FakeCollectModule(ModuleType):
def __getattr__(self, name: str) -> Any:
if name not in self.__all__:
raise AttributeError(name)
warnings.warn(PYTEST_COLLECT_MODULE.format(name=name), stacklevel=2)
# Uncomment this after 6.0 release (#7361)
# warnings.warn(PYTEST_COLLECT_MODULE.format(name=name), stacklevel=2)
return getattr(pytest, name)

View File

@ -302,10 +302,10 @@ class TestGeneralUsage:
pass
class MyCollector(pytest.File):
def collect(self):
return [MyItem(name="xyz", parent=self)]
return [MyItem.from_parent(name="xyz", parent=self)]
def pytest_collect_file(path, parent):
if path.basename.startswith("conftest"):
return MyCollector(path, parent)
return MyCollector.from_parent(fspath=path, parent=parent)
"""
)
result = testdir.runpytest(c.basename + "::" + "xyz")

View File

@ -116,11 +116,11 @@ def dummy_yaml_custom_test(testdir):
def pytest_collect_file(parent, path):
if path.ext == ".yaml" and path.basename.startswith("test"):
return YamlFile(path, parent)
return YamlFile.from_parent(fspath=path, parent=parent)
class YamlFile(pytest.File):
def collect(self):
yield YamlItem(self.fspath.basename, self)
yield YamlItem.from_parent(name=self.fspath.basename, parent=self)
class YamlItem(pytest.Item):
def runtest(self):

View File

@ -28,6 +28,7 @@ def test_resultlog_is_deprecated(testdir):
)
@pytest.mark.skip(reason="should be reintroduced in 6.1: #7361")
@pytest.mark.parametrize("attribute", pytest.collect.__all__) # type: ignore
# false positive due to dynamic attribute
def test_pytest_collect_module_deprecated(attribute):
@ -117,7 +118,8 @@ def test_node_direct_ctor_warning() -> None:
assert w[0].filename == __file__
def test__fillfuncargs_is_deprecated() -> None:
@pytest.mark.skip(reason="should be reintroduced in 6.1: #7361")
def test_fillfuncargs_is_deprecated() -> None:
with pytest.warns(
pytest.PytestDeprecationWarning,
match="The `_fillfuncargs` function is deprecated",
@ -125,6 +127,7 @@ def test__fillfuncargs_is_deprecated() -> None:
pytest._fillfuncargs(mock.Mock())
@pytest.mark.skip(reason="should be reintroduced in 6.1: #7361")
def test_minus_k_dash_is_deprecated(testdir) -> None:
threepass = testdir.makepyfile(
test_threepass="""
@ -137,6 +140,7 @@ def test_minus_k_dash_is_deprecated(testdir) -> None:
result.stdout.fnmatch_lines(["*The `-k '-expr'` syntax*deprecated*"])
@pytest.mark.skip(reason="should be reintroduced in 6.1: #7361")
def test_minus_k_colon_is_deprecated(testdir) -> None:
threepass = testdir.makepyfile(
test_threepass="""

View File

@ -1,10 +1,15 @@
import pytest
class CustomItem(pytest.Item, pytest.File):
class CustomItem(pytest.Item):
def runtest(self):
pass
class CustomFile(pytest.File):
def collect(self):
yield CustomItem.from_parent(name="foo", parent=self)
def pytest_collect_file(path, parent):
return CustomItem(path, parent)
return CustomFile.from_parent(fspath=path, parent=parent)

View File

@ -3,11 +3,11 @@ import pytest
class MyFile(pytest.File):
def collect(self):
return [MyItem("hello", parent=self)]
return [MyItem.from_parent(name="hello", parent=self)]
def pytest_collect_file(path, parent):
return MyFile(path, parent)
return MyFile.from_parent(fspath=path, parent=parent)
class MyItem(pytest.Item):

View File

@ -762,7 +762,7 @@ class TestConftestCustomization:
pass
def pytest_pycollect_makemodule(path, parent):
if path.basename == "test_xyz.py":
return MyModule(path, parent)
return MyModule.from_parent(fspath=path, parent=parent)
"""
)
testdir.makepyfile("def test_some(): pass")
@ -836,7 +836,7 @@ class TestConftestCustomization:
pass
def pytest_pycollect_makeitem(collector, name, obj):
if name == "some":
return MyFunction(name, collector)
return MyFunction.from_parent(name=name, parent=collector)
"""
)
testdir.makepyfile("def some(): pass")
@ -873,7 +873,7 @@ class TestConftestCustomization:
def pytest_collect_file(path, parent):
if path.ext == ".narf":
return Module(path, parent)"""
return Module.from_parent(fspath=path, parent=parent)"""
)
testdir.makefile(
".narf",

View File

@ -282,7 +282,7 @@ class TestPrunetraceback:
"""
import pytest
def pytest_collect_file(path, parent):
return MyFile(path, parent)
return MyFile.from_parent(fspath=path, parent=parent)
class MyError(Exception):
pass
class MyFile(pytest.File):
@ -401,7 +401,7 @@ class TestCustomConftests:
pass
def pytest_collect_file(path, parent):
if path.ext == ".py":
return MyModule(path, parent)
return MyModule.from_parent(fspath=path, parent=parent)
"""
)
testdir.mkdir("sub")
@ -419,7 +419,7 @@ class TestCustomConftests:
pass
def pytest_collect_file(path, parent):
if path.ext == ".py":
return MyModule1(path, parent)
return MyModule1.from_parent(fspath=path, parent=parent)
"""
)
conf1.move(sub1.join(conf1.basename))
@ -430,7 +430,7 @@ class TestCustomConftests:
pass
def pytest_collect_file(path, parent):
if path.ext == ".py":
return MyModule2(path, parent)
return MyModule2.from_parent(fspath=path, parent=parent)
"""
)
conf2.move(sub2.join(conf2.basename))
@ -537,10 +537,10 @@ class TestSession:
return # ok
class SpecialFile(pytest.File):
def collect(self):
return [SpecialItem(name="check", parent=self)]
return [SpecialItem.from_parent(name="check", parent=self)]
def pytest_collect_file(path, parent):
if path.basename == %r:
return SpecialFile(fspath=path, parent=parent)
return SpecialFile.from_parent(fspath=path, parent=parent)
"""
% p.basename
)
@ -761,18 +761,23 @@ def test_matchnodes_two_collections_same_file(testdir):
class Plugin2(object):
def pytest_collect_file(self, path, parent):
if path.ext == ".abc":
return MyFile2(path, parent)
return MyFile2.from_parent(fspath=path, parent=parent)
def pytest_collect_file(path, parent):
if path.ext == ".abc":
return MyFile1(path, parent)
return MyFile1.from_parent(fspath=path, parent=parent)
class MyFile1(pytest.File):
def collect(self):
yield Item1.from_parent(name="item1", parent=self)
class MyFile1(pytest.Item, pytest.File):
def runtest(self):
pass
class MyFile2(pytest.File):
def collect(self):
return [Item2("hello", parent=self)]
yield Item2.from_parent(name="item2", parent=self)
class Item1(pytest.Item):
def runtest(self):
pass
class Item2(pytest.Item):
def runtest(self):
@ -783,7 +788,7 @@ def test_matchnodes_two_collections_same_file(testdir):
result = testdir.runpytest()
assert result.ret == 0
result.stdout.fnmatch_lines(["*2 passed*"])
res = testdir.runpytest("%s::hello" % p.basename)
res = testdir.runpytest("%s::item2" % p.basename)
res.stdout.fnmatch_lines(["*1 passed*"])

View File

@ -906,11 +906,8 @@ class TestNonPython:
import pytest
def pytest_collect_file(path, parent):
if path.ext == ".xyz":
return MyItem(path, parent)
return MyItem.from_parent(name=path.basename, parent=parent)
class MyItem(pytest.Item):
def __init__(self, path, parent):
super(MyItem, self).__init__(path.basename, parent)
self.fspath = path
def runtest(self):
raise ValueError(42)
def repr_failure(self, excinfo):
@ -1336,14 +1333,14 @@ def test_fancy_items_regression(testdir, run_and_parse):
class FunCollector(pytest.File):
def collect(self):
return [
FunItem('a', self),
NoFunItem('a', self),
NoFunItem('b', self),
FunItem.from_parent(name='a', parent=self),
NoFunItem.from_parent(name='a', parent=self),
NoFunItem.from_parent(name='b', parent=self),
]
def pytest_collect_file(path, parent):
if path.check(ext='.py'):
return FunCollector(path, parent)
return FunCollector.from_parent(fspath=path, parent=parent)
"""
)

View File

@ -1126,7 +1126,7 @@ def test_xfail_item(testdir):
pytest.xfail("Expected Failure")
def pytest_collect_file(path, parent):
return MyItem("foo", parent)
return MyItem.from_parent(name="foo", parent=parent)
"""
)
result = testdir.inline_run()
@ -1206,7 +1206,7 @@ def test_mark_xfail_item(testdir):
assert False
def pytest_collect_file(path, parent):
return MyItem("foo", parent)
return MyItem.from_parent(name="foo", parent=parent)
"""
)
result = testdir.inline_run()

View File

@ -520,9 +520,6 @@ class TestDeprecationWarningsByDefault:
@pytest.mark.parametrize("change_default", [None, "ini", "cmdline"])
@pytest.mark.skip(
reason="This test should be enabled again before pytest 6.0 is released"
)
def test_deprecation_warning_as_error(testdir, change_default):
"""This ensures that PytestDeprecationWarnings raised by pytest are turned into errors.