Skip to content

Commit df9e94f

Browse files
authored
Change deprecation warnings into errors for 7.0 release, using a new mechanism (#9309)
2 parents 4fd897a + a172a41 commit df9e94f

File tree

11 files changed

+89
-35
lines changed

11 files changed

+89
-35
lines changed

changelog/7480.improvement.rst

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
A deprecation scheduled to be removed in a major version X (e.g. pytest 7, 8, 9, ...) now uses warning category `PytestRemovedInXWarning`,
2+
a subclass of :class:`~pytest.PytestDeprecationWarning`,
3+
instead of :class:`PytestDeprecationWarning` directly.
4+
5+
See :ref:`backwards-compatibility` for more details.

changelog/9308.breaking.rst

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
**PytestRemovedIn7Warning deprecation warnings are now errors by default.**
2+
3+
Following our plan to remove deprecated features with as little disruption as
4+
possible, all warnings of type ``PytestRemovedIn7Warning `` now generate errors
5+
instead of warning messages by default.
6+
7+
**The affected features will be effectively removed in pytest 7.1**, so please consult the
8+
:ref:`deprecations` section in the docs for directions on how to update existing code.
9+
10+
In the pytest ``7.0.X`` series, it is possible to change the errors back into warnings as a
11+
stopgap measure by adding this to your ``pytest.ini`` file:
12+
13+
.. code-block:: ini
14+
15+
[pytest]
16+
filterwarnings =
17+
ignore::pytest.PytestRemovedIn7Warning
18+
19+
But this will stop working when pytest ``7.1`` is released.
20+
21+
**If you have concerns** about the removal of a specific feature, please add a
22+
comment to :issue:`9308`.

doc/en/backwards-compatibility.rst

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,9 @@ b) transitional: the old and new API don't conflict
2222

2323
We will only start the removal of deprecated functionality in major releases (e.g. if we deprecate something in 3.0 we will start to remove it in 4.0), and keep it around for at least two minor releases (e.g. if we deprecate something in 3.9 and 4.0 is the next release, we start to remove it in 5.0, not in 4.0).
2424

25-
When the deprecation expires (e.g. 4.0 is released), we won't remove the deprecated functionality immediately, but will use the standard warning filters to turn them into **errors** by default. This approach makes it explicit that removal is imminent, and still gives you time to turn the deprecated feature into a warning instead of an error so it can be dealt with in your own time. In the next minor release (e.g. 4.1), the feature will be effectively removed.
25+
A deprecated feature scheduled to be removed in major version X will use the warning class `PytestRemovedInXWarning` (a subclass of `~pytest.PytestDeprecationwarning`).
26+
27+
When the deprecation expires (e.g. 4.0 is released), we won't remove the deprecated functionality immediately, but will use the standard warning filters to turn `PytestRemovedInXWarning` (e.g. `PytestRemovedIn4Warning`) into **errors** by default. This approach makes it explicit that removal is imminent, and still gives you time to turn the deprecated feature into a warning instead of an error so it can be dealt with in your own time. In the next minor release (e.g. 4.1), the feature will be effectively removed.
2628

2729

2830
c) true breakage: should only be considered when normal transition is unreasonably unsustainable and would offset important development/features by years.

src/_pytest/deprecated.py

Lines changed: 22 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@
1111
from warnings import warn
1212

1313
from _pytest.warning_types import PytestDeprecationWarning
14+
from _pytest.warning_types import PytestRemovedIn7Warning
15+
from _pytest.warning_types import PytestRemovedIn8Warning
1416
from _pytest.warning_types import UnformattedWarning
1517

1618
# set of plugins which have been integrated into the core; we use this list to ignore
@@ -23,103 +25,106 @@
2325

2426

2527
FILLFUNCARGS = UnformattedWarning(
26-
PytestDeprecationWarning,
28+
PytestRemovedIn7Warning,
2729
"{name} is deprecated, use "
2830
"function._request._fillfixtures() instead if you cannot avoid reaching into internals.",
2931
)
3032

3133
PYTEST_COLLECT_MODULE = UnformattedWarning(
32-
PytestDeprecationWarning,
34+
PytestRemovedIn7Warning,
3335
"pytest.collect.{name} was moved to pytest.{name}\n"
3436
"Please update to the new name.",
3537
)
3638

39+
# This can be* removed pytest 8, but it's harmless and common, so no rush to remove.
40+
# * If you're in the future: "could have been".
3741
YIELD_FIXTURE = PytestDeprecationWarning(
3842
"@pytest.yield_fixture is deprecated.\n"
3943
"Use @pytest.fixture instead; they are the same."
4044
)
4145

42-
MINUS_K_DASH = PytestDeprecationWarning(
46+
MINUS_K_DASH = PytestRemovedIn7Warning(
4347
"The `-k '-expr'` syntax to -k is deprecated.\nUse `-k 'not expr'` instead."
4448
)
4549

46-
MINUS_K_COLON = PytestDeprecationWarning(
50+
MINUS_K_COLON = PytestRemovedIn7Warning(
4751
"The `-k 'expr:'` syntax to -k is deprecated.\n"
4852
"Please open an issue if you use this and want a replacement."
4953
)
5054

51-
WARNING_CAPTURED_HOOK = PytestDeprecationWarning(
55+
WARNING_CAPTURED_HOOK = PytestRemovedIn7Warning(
5256
"The pytest_warning_captured is deprecated and will be removed in a future release.\n"
5357
"Please use pytest_warning_recorded instead."
5458
)
5559

56-
WARNING_CMDLINE_PREPARSE_HOOK = PytestDeprecationWarning(
60+
WARNING_CMDLINE_PREPARSE_HOOK = PytestRemovedIn8Warning(
5761
"The pytest_cmdline_preparse hook is deprecated and will be removed in a future release. \n"
5862
"Please use pytest_load_initial_conftests hook instead."
5963
)
6064

61-
FSCOLLECTOR_GETHOOKPROXY_ISINITPATH = PytestDeprecationWarning(
65+
FSCOLLECTOR_GETHOOKPROXY_ISINITPATH = PytestRemovedIn8Warning(
6266
"The gethookproxy() and isinitpath() methods of FSCollector and Package are deprecated; "
6367
"use self.session.gethookproxy() and self.session.isinitpath() instead. "
6468
)
6569

66-
STRICT_OPTION = PytestDeprecationWarning(
70+
STRICT_OPTION = PytestRemovedIn8Warning(
6771
"The --strict option is deprecated, use --strict-markers instead."
6872
)
6973

74+
# This deprecation is never really meant to be removed.
7075
PRIVATE = PytestDeprecationWarning("A private pytest class or function was used.")
7176

72-
UNITTEST_SKIP_DURING_COLLECTION = PytestDeprecationWarning(
77+
UNITTEST_SKIP_DURING_COLLECTION = PytestRemovedIn8Warning(
7378
"Raising unittest.SkipTest to skip tests during collection is deprecated. "
7479
"Use pytest.skip() instead."
7580
)
7681

77-
ARGUMENT_PERCENT_DEFAULT = PytestDeprecationWarning(
82+
ARGUMENT_PERCENT_DEFAULT = PytestRemovedIn8Warning(
7883
'pytest now uses argparse. "%default" should be changed to "%(default)s"',
7984
)
8085

8186
ARGUMENT_TYPE_STR_CHOICE = UnformattedWarning(
82-
PytestDeprecationWarning,
87+
PytestRemovedIn8Warning,
8388
"`type` argument to addoption() is the string {typ!r}."
8489
" For choices this is optional and can be omitted, "
8590
" but when supplied should be a type (for example `str` or `int`)."
8691
" (options: {names})",
8792
)
8893

8994
ARGUMENT_TYPE_STR = UnformattedWarning(
90-
PytestDeprecationWarning,
95+
PytestRemovedIn8Warning,
9196
"`type` argument to addoption() is the string {typ!r}, "
9297
" but when supplied should be a type (for example `str` or `int`)."
9398
" (options: {names})",
9499
)
95100

96101

97102
HOOK_LEGACY_PATH_ARG = UnformattedWarning(
98-
PytestDeprecationWarning,
103+
PytestRemovedIn8Warning,
99104
"The ({pylib_path_arg}: py.path.local) argument is deprecated, please use ({pathlib_path_arg}: pathlib.Path)\n"
100105
"see https://docs.pytest.org/en/latest/deprecations.html"
101106
"#py-path-local-arguments-for-hooks-replaced-with-pathlib-path",
102107
)
103108

104109
NODE_CTOR_FSPATH_ARG = UnformattedWarning(
105-
PytestDeprecationWarning,
110+
PytestRemovedIn8Warning,
106111
"The (fspath: py.path.local) argument to {node_type_name} is deprecated. "
107112
"Please use the (path: pathlib.Path) argument instead.\n"
108113
"See https://docs.pytest.org/en/latest/deprecations.html"
109114
"#fspath-argument-for-node-constructors-replaced-with-pathlib-path",
110115
)
111116

112-
WARNS_NONE_ARG = PytestDeprecationWarning(
117+
WARNS_NONE_ARG = PytestRemovedIn8Warning(
113118
"Passing None to catch any warning has been deprecated, pass no arguments instead:\n"
114119
" Replace pytest.warns(None) by simply pytest.warns()."
115120
)
116121

117122
KEYWORD_MSG_ARG = UnformattedWarning(
118-
PytestDeprecationWarning,
123+
PytestRemovedIn8Warning,
119124
"pytest.{func}(msg=...) is now deprecated, use pytest.{func}(reason=...) instead",
120125
)
121126

122-
INSTANCE_COLLECTOR = PytestDeprecationWarning(
127+
INSTANCE_COLLECTOR = PytestRemovedIn8Warning(
123128
"The pytest.Instance collector type is deprecated and is no longer used. "
124129
"See https://docs.pytest.org/en/latest/deprecations.html#the-pytest-instance-collector",
125130
)

src/_pytest/warning_types.py

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,13 +42,26 @@ class PytestCollectionWarning(PytestWarning):
4242
__module__ = "pytest"
4343

4444

45-
@final
4645
class PytestDeprecationWarning(PytestWarning, DeprecationWarning):
4746
"""Warning class for features that will be removed in a future version."""
4847

4948
__module__ = "pytest"
5049

5150

51+
@final
52+
class PytestRemovedIn7Warning(PytestDeprecationWarning):
53+
"""Warning class for features that will be removed in pytest 7."""
54+
55+
__module__ = "pytest"
56+
57+
58+
@final
59+
class PytestRemovedIn8Warning(PytestDeprecationWarning):
60+
"""Warning class for features that will be removed in pytest 8."""
61+
62+
__module__ = "pytest"
63+
64+
5265
@final
5366
class PytestExperimentalApiWarning(PytestWarning, FutureWarning):
5467
"""Warning category used to denote experiments in pytest.

src/_pytest/warnings.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,8 @@ def catch_warnings_for_item(
4949
warnings.filterwarnings("always", category=DeprecationWarning)
5050
warnings.filterwarnings("always", category=PendingDeprecationWarning)
5151

52+
warnings.filterwarnings("error", category=pytest.PytestRemovedIn7Warning)
53+
5254
apply_warning_filters(config_filters, cmdline_filters)
5355

5456
# apply filters from "filterwarnings" marks

src/pytest/__init__.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,8 @@
6868
from _pytest.warning_types import PytestConfigWarning
6969
from _pytest.warning_types import PytestDeprecationWarning
7070
from _pytest.warning_types import PytestExperimentalApiWarning
71+
from _pytest.warning_types import PytestRemovedIn7Warning
72+
from _pytest.warning_types import PytestRemovedIn8Warning
7173
from _pytest.warning_types import PytestUnhandledCoroutineWarning
7274
from _pytest.warning_types import PytestUnhandledThreadExceptionWarning
7375
from _pytest.warning_types import PytestUnknownMarkWarning
@@ -127,6 +129,8 @@
127129
"PytestConfigWarning",
128130
"PytestDeprecationWarning",
129131
"PytestExperimentalApiWarning",
132+
"PytestRemovedIn7Warning",
133+
"PytestRemovedIn8Warning",
130134
"Pytester",
131135
"PytestPluginManager",
132136
"PytestUnhandledCoroutineWarning",

testing/deprecated_test.py

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -115,7 +115,7 @@ def test_foo(): pass
115115
result.stdout.fnmatch_lines(
116116
[
117117
"'unknown' not found in `markers` configuration option",
118-
"*PytestDeprecationWarning: The --strict option is deprecated, use --strict-markers instead.",
118+
"*PytestRemovedIn8Warning: The --strict option is deprecated, use --strict-markers instead.",
119119
]
120120
)
121121

@@ -154,7 +154,7 @@ def test_raising_unittest_skiptest_during_collection_is_deprecated(
154154
result = pytester.runpytest()
155155
result.stdout.fnmatch_lines(
156156
[
157-
"*PytestDeprecationWarning: Raising unittest.SkipTest*",
157+
"*PytestRemovedIn8Warning: Raising unittest.SkipTest*",
158158
]
159159
)
160160

@@ -213,7 +213,7 @@ def test_skipping_msg():
213213
result = pytester.runpytest(p)
214214
result.stdout.fnmatch_lines(
215215
[
216-
"*PytestDeprecationWarning: pytest.skip(msg=...) is now deprecated, "
216+
"*PytestRemovedIn8Warning: pytest.skip(msg=...) is now deprecated, "
217217
"use pytest.skip(reason=...) instead",
218218
'*pytest.skip(msg="skippedmsg")*',
219219
]
@@ -232,7 +232,7 @@ def test_failing_msg():
232232
result = pytester.runpytest(p)
233233
result.stdout.fnmatch_lines(
234234
[
235-
"*PytestDeprecationWarning: pytest.fail(msg=...) is now deprecated, "
235+
"*PytestRemovedIn8Warning: pytest.fail(msg=...) is now deprecated, "
236236
"use pytest.fail(reason=...) instead",
237237
'*pytest.fail(msg="failedmsg")',
238238
]
@@ -251,7 +251,7 @@ def test_exit_msg():
251251
result = pytester.runpytest(p)
252252
result.stdout.fnmatch_lines(
253253
[
254-
"*PytestDeprecationWarning: pytest.exit(msg=...) is now deprecated, "
254+
"*PytestRemovedIn8Warning: pytest.exit(msg=...) is now deprecated, "
255255
"use pytest.exit(reason=...) instead",
256256
]
257257
)
@@ -269,7 +269,7 @@ def pytest_cmdline_preparse(config, args):
269269
result = pytester.runpytest()
270270
result.stdout.fnmatch_lines(
271271
[
272-
"*PytestDeprecationWarning: The pytest_cmdline_preparse hook is deprecated*",
272+
"*PytestRemovedIn8Warning: The pytest_cmdline_preparse hook is deprecated*",
273273
"*Please use pytest_load_initial_conftests hook instead.*",
274274
]
275275
)

testing/test_mark.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -831,7 +831,9 @@ def test_two(): assert 1
831831
def test_three(): assert 1
832832
"""
833833
)
834-
reprec = pytester.inline_run("-k", "test_two:", threepass)
834+
reprec = pytester.inline_run(
835+
"-Wignore::pytest.PytestRemovedIn7Warning", "-k", "test_two:", threepass
836+
)
835837
passed, skipped, failed = reprec.listoutcomes()
836838
assert len(passed) == 2
837839
assert not failed

testing/test_terminal.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -682,7 +682,9 @@ def test_three():
682682
pass
683683
"""
684684
)
685-
result = pytester.runpytest("-k", "test_two:", testpath)
685+
result = pytester.runpytest(
686+
"-Wignore::pytest.PytestRemovedIn7Warning", "-k", "test_two:", testpath
687+
)
686688
result.stdout.fnmatch_lines(
687689
["collected 3 items / 1 deselected / 2 selected", "*test_deselected.py ..*"]
688690
)

0 commit comments

Comments
 (0)