Skip to content

Commit 72a3990

Browse files
committed
Show deprecation warnings by default if no other filters are configured
Fix pytest-dev#2908
1 parent 01699e9 commit 72a3990

File tree

5 files changed

+130
-25
lines changed

5 files changed

+130
-25
lines changed

changelog/2908.feature.rst

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
``DeprecationWarning`` and ``PendingDeprecationWarning`` are now shown by default if no other warning filter is
2+
configured. This makes pytest compliant with
3+
`PEP-0506 <https://www.python.org/dev/peps/pep-0565/#recommended-filter-settings-for-test-runners>`_.

doc/en/warnings.rst

Lines changed: 26 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -36,8 +36,6 @@ Running pytest now produces this output::
3636
-- Docs: http://doc.pytest.org/en/latest/warnings.html
3737
=================== 1 passed, 1 warnings in 0.12 seconds ===================
3838

39-
Pytest by default catches all warnings except for ``DeprecationWarning`` and ``PendingDeprecationWarning``.
40-
4139
The ``-W`` flag can be passed to control which warnings will be displayed or even turn
4240
them into errors::
4341

@@ -78,6 +76,32 @@ Both ``-W`` command-line option and ``filterwarnings`` ini option are based on P
7876
`-W option`_ and `warnings.simplefilter`_, so please refer to those sections in the Python
7977
documentation for other examples and advanced usage.
8078

79+
Disabling warning summary
80+
-------------------------
81+
82+
Although not recommended, you can use the ``--disable-warnings`` command-line option to suppress the
83+
warning summary entirely from the test run output.
84+
85+
86+
DeprecationWarning and PendingDeprecationWarning
87+
------------------------------------------------
88+
89+
.. versionadded:: 3.8
90+
91+
By default pytest will display ``DeprecationWarning`` and ``PendingDeprecationWarning`` if no other warning filters
92+
are configured. This complies with `PEP-0506 <https://www.python.org/dev/peps/pep-0565/#recommended-filter-settings-for-test-runners>`_ which suggests that those warnings should
93+
be shown by default by test runners.
94+
95+
To disable this behavior, you might define any warnings filter either in the command-line or in the ini file, but
96+
if you don't have any other warnings to filter you can use:
97+
98+
.. code-block:: ini
99+
100+
[pytest]
101+
filterwarnings =
102+
ignore::DeprecationWarning
103+
ignore::PendingDeprecationWarning
104+
81105
82106
.. _`filterwarnings`:
83107

src/_pytest/warnings.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
from __future__ import absolute_import, division, print_function
22

3+
import sys
34
import warnings
45
from contextlib import contextmanager
56

@@ -69,6 +70,8 @@ def catch_warnings_for_item(config, ihook, item):
6970
args = config.getoption("pythonwarnings") or []
7071
inifilters = config.getini("filterwarnings")
7172
with warnings.catch_warnings(record=True) as log:
73+
filters_configured = args or inifilters or sys.warnoptions
74+
7275
for arg in args:
7376
warnings._setoption(arg)
7477

@@ -79,6 +82,11 @@ def catch_warnings_for_item(config, ihook, item):
7982
for mark in item.iter_markers(name="filterwarnings"):
8083
for arg in mark.args:
8184
warnings._setoption(arg)
85+
filters_configured = True
86+
87+
if not filters_configured:
88+
warnings.filterwarnings("always", category=DeprecationWarning)
89+
warnings.filterwarnings("always", category=PendingDeprecationWarning)
8290

8391
yield
8492

testing/python/collect.py

Lines changed: 20 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -8,10 +8,6 @@
88
from _pytest.main import EXIT_NOTESTSCOLLECTED
99
from _pytest.nodes import Collector
1010

11-
ignore_parametrized_marks = pytest.mark.filterwarnings(
12-
"ignore:Applying marks directly to parameters"
13-
)
14-
1511

1612
class TestModule(object):
1713
def test_failing_import(self, testdir):
@@ -456,6 +452,13 @@ def test_setuplist():
456452

457453

458454
class TestFunction(object):
455+
@pytest.fixture
456+
def ignore_parametrized_marks_args(self):
457+
"""Provides arguments to pytester.runpytest() to ignore the warning about marks being applied directly
458+
to parameters.
459+
"""
460+
return ("-W", "ignore:Applying marks directly to parameters")
461+
459462
def test_getmodulecollector(self, testdir):
460463
item = testdir.getitem("def test_func(): pass")
461464
modcol = item.getparent(pytest.Module)
@@ -669,7 +672,7 @@ def test_it(fix1):
669672
rec = testdir.inline_run()
670673
rec.assertoutcome(passed=1)
671674

672-
@ignore_parametrized_marks
675+
@pytest.mark.filterwarnings("ignore:Applying marks directly to parameters")
673676
def test_parametrize_with_mark(self, testdir):
674677
items = testdir.getitems(
675678
"""
@@ -755,8 +758,7 @@ def test2(self, x, y):
755758
assert colitems[2].name == "test2[a-c]"
756759
assert colitems[3].name == "test2[b-c]"
757760

758-
@ignore_parametrized_marks
759-
def test_parametrize_skipif(self, testdir):
761+
def test_parametrize_skipif(self, testdir, ignore_parametrized_marks_args):
760762
testdir.makepyfile(
761763
"""
762764
import pytest
@@ -768,11 +770,10 @@ def test_skip_if(x):
768770
assert x < 2
769771
"""
770772
)
771-
result = testdir.runpytest()
773+
result = testdir.runpytest(*ignore_parametrized_marks_args)
772774
result.stdout.fnmatch_lines("* 2 passed, 1 skipped in *")
773775

774-
@ignore_parametrized_marks
775-
def test_parametrize_skip(self, testdir):
776+
def test_parametrize_skip(self, testdir, ignore_parametrized_marks_args):
776777
testdir.makepyfile(
777778
"""
778779
import pytest
@@ -784,11 +785,10 @@ def test_skip(x):
784785
assert x < 2
785786
"""
786787
)
787-
result = testdir.runpytest()
788+
result = testdir.runpytest(*ignore_parametrized_marks_args)
788789
result.stdout.fnmatch_lines("* 2 passed, 1 skipped in *")
789790

790-
@ignore_parametrized_marks
791-
def test_parametrize_skipif_no_skip(self, testdir):
791+
def test_parametrize_skipif_no_skip(self, testdir, ignore_parametrized_marks_args):
792792
testdir.makepyfile(
793793
"""
794794
import pytest
@@ -800,11 +800,10 @@ def test_skipif_no_skip(x):
800800
assert x < 2
801801
"""
802802
)
803-
result = testdir.runpytest()
803+
result = testdir.runpytest(*ignore_parametrized_marks_args)
804804
result.stdout.fnmatch_lines("* 1 failed, 2 passed in *")
805805

806-
@ignore_parametrized_marks
807-
def test_parametrize_xfail(self, testdir):
806+
def test_parametrize_xfail(self, testdir, ignore_parametrized_marks_args):
808807
testdir.makepyfile(
809808
"""
810809
import pytest
@@ -816,11 +815,10 @@ def test_xfail(x):
816815
assert x < 2
817816
"""
818817
)
819-
result = testdir.runpytest()
818+
result = testdir.runpytest(*ignore_parametrized_marks_args)
820819
result.stdout.fnmatch_lines("* 2 passed, 1 xfailed in *")
821820

822-
@ignore_parametrized_marks
823-
def test_parametrize_passed(self, testdir):
821+
def test_parametrize_passed(self, testdir, ignore_parametrized_marks_args):
824822
testdir.makepyfile(
825823
"""
826824
import pytest
@@ -832,11 +830,10 @@ def test_xfail(x):
832830
pass
833831
"""
834832
)
835-
result = testdir.runpytest()
833+
result = testdir.runpytest(*ignore_parametrized_marks_args)
836834
result.stdout.fnmatch_lines("* 2 passed, 1 xpassed in *")
837835

838-
@ignore_parametrized_marks
839-
def test_parametrize_xfail_passed(self, testdir):
836+
def test_parametrize_xfail_passed(self, testdir, ignore_parametrized_marks_args):
840837
testdir.makepyfile(
841838
"""
842839
import pytest
@@ -848,7 +845,7 @@ def test_passed(x):
848845
pass
849846
"""
850847
)
851-
result = testdir.runpytest()
848+
result = testdir.runpytest(*ignore_parametrized_marks_args)
852849
result.stdout.fnmatch_lines("* 3 passed in *")
853850

854851
def test_function_original_name(self, testdir):

testing/test_warnings.py

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -326,6 +326,7 @@ def pytest_warning_captured(self, warning_message, when, item):
326326
@pytest.mark.filterwarnings("always")
327327
def test_collection_warnings(testdir):
328328
"""
329+
Check that we also capture warnings issued during test collection (#3251).
329330
"""
330331
testdir.makepyfile(
331332
"""
@@ -346,3 +347,75 @@ def test_foo():
346347
"* 1 passed, 1 warnings*",
347348
]
348349
)
350+
351+
352+
class TestDeprecationWarningsByDefault:
353+
"""
354+
Note: all pytest runs are executed in a subprocess so we don't inherit warning filters
355+
from pytest's own test suite
356+
"""
357+
358+
def create_file(self, testdir, mark=""):
359+
testdir.makepyfile(
360+
"""
361+
import pytest, warnings
362+
363+
warnings.warn(DeprecationWarning("collection"))
364+
365+
{mark}
366+
def test_foo():
367+
warnings.warn(PendingDeprecationWarning("test run"))
368+
""".format(
369+
mark=mark
370+
)
371+
)
372+
373+
def test_shown_by_default(self, testdir):
374+
self.create_file(testdir)
375+
result = testdir.runpytest_subprocess()
376+
result.stdout.fnmatch_lines(
377+
[
378+
"*== %s ==*" % WARNINGS_SUMMARY_HEADER,
379+
"*test_shown_by_default.py:3: DeprecationWarning: collection",
380+
"*test_shown_by_default.py:7: PendingDeprecationWarning: test run",
381+
"* 1 passed, 2 warnings*",
382+
]
383+
)
384+
385+
def test_hidden_by_ini(self, testdir):
386+
self.create_file(testdir)
387+
testdir.makeini(
388+
"""
389+
[pytest]
390+
filterwarnings = once::UserWarning
391+
"""
392+
)
393+
result = testdir.runpytest_subprocess()
394+
assert WARNINGS_SUMMARY_HEADER not in result.stdout.str()
395+
396+
def test_hidden_by_mark(self, testdir):
397+
"""Should hide the deprecation warning from the function, but the warning during collection should
398+
be displayed normally.
399+
"""
400+
self.create_file(
401+
testdir, mark='@pytest.mark.filterwarnings("once::UserWarning")'
402+
)
403+
result = testdir.runpytest_subprocess()
404+
result.stdout.fnmatch_lines(
405+
[
406+
"*== %s ==*" % WARNINGS_SUMMARY_HEADER,
407+
"*test_hidden_by_mark.py:3: DeprecationWarning: collection",
408+
"* 1 passed, 1 warnings*",
409+
]
410+
)
411+
412+
def test_hidden_by_cmdline(self, testdir):
413+
self.create_file(testdir)
414+
result = testdir.runpytest_subprocess("-W", "once::UserWarning")
415+
assert WARNINGS_SUMMARY_HEADER not in result.stdout.str()
416+
417+
def test_hidden_by_system(self, testdir, monkeypatch):
418+
self.create_file(testdir)
419+
monkeypatch.setenv(str("PYTHONWARNINGS"), str("once::UserWarning"))
420+
result = testdir.runpytest_subprocess()
421+
assert WARNINGS_SUMMARY_HEADER not in result.stdout.str()

0 commit comments

Comments
 (0)