From ab40696007b9f2313e26d0bcf67eb04fbb9d0efc Mon Sep 17 00:00:00 2001 From: Bruno Oliveira Date: Thu, 6 Sep 2018 18:02:36 -0300 Subject: [PATCH] -W now takes precedence over filters in ini files Fix #3946 --- changelog/3946.bugfix.rst | 2 ++ src/_pytest/warnings.py | 12 ++++++----- testing/test_warnings.py | 44 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 53 insertions(+), 5 deletions(-) create mode 100644 changelog/3946.bugfix.rst diff --git a/changelog/3946.bugfix.rst b/changelog/3946.bugfix.rst new file mode 100644 index 000000000..1b5248b4c --- /dev/null +++ b/changelog/3946.bugfix.rst @@ -0,0 +1,2 @@ +Warning filters passed as command line options using ``-W`` now take precedence over filters defined in ``ini`` +configuration files. diff --git a/src/_pytest/warnings.py b/src/_pytest/warnings.py index 6c4b921fa..fb303a20f 100644 --- a/src/_pytest/warnings.py +++ b/src/_pytest/warnings.py @@ -67,17 +67,19 @@ def catch_warnings_for_item(config, ihook, when, item): Each warning captured triggers the ``pytest_warning_captured`` hook. """ - args = config.getoption("pythonwarnings") or [] + cmdline_filters = config.getoption("pythonwarnings") or [] inifilters = config.getini("filterwarnings") with warnings.catch_warnings(record=True) as log: - filters_configured = args or inifilters or sys.warnoptions - - for arg in args: - warnings._setoption(arg) + filters_configured = bool(cmdline_filters or inifilters or sys.warnoptions) + # filters should have this precedence: mark, cmdline options, ini + # filters should be applied in the inverse order of precedence for arg in inifilters: _setoption(warnings, arg) + for arg in cmdline_filters: + warnings._setoption(arg) + if item is not None: for mark in item.iter_markers(name="filterwarnings"): for arg in mark.args: diff --git a/testing/test_warnings.py b/testing/test_warnings.py index 3f748d666..975605b5e 100644 --- a/testing/test_warnings.py +++ b/testing/test_warnings.py @@ -430,6 +430,50 @@ def test_hide_pytest_internal_warnings(testdir, ignore_pytest_warnings): ) +@pytest.mark.parametrize("ignore_on_cmdline", [True, False]) +def test_option_precedence_cmdline_over_ini(testdir, ignore_on_cmdline): + """filters defined in the command-line should take precedence over filters in ini files (#3946).""" + testdir.makeini( + """ + [pytest] + filterwarnings = error + """ + ) + testdir.makepyfile( + """ + import warnings + def test(): + warnings.warn(UserWarning('hello')) + """ + ) + args = ["-W", "ignore"] if ignore_on_cmdline else [] + result = testdir.runpytest(*args) + if ignore_on_cmdline: + result.stdout.fnmatch_lines(["* 1 passed in*"]) + else: + result.stdout.fnmatch_lines(["* 1 failed in*"]) + + +def test_option_precedence_mark(testdir): + """Filters defined by marks should always take precedence (#3946).""" + testdir.makeini( + """ + [pytest] + filterwarnings = ignore + """ + ) + testdir.makepyfile( + """ + import pytest, warnings + @pytest.mark.filterwarnings('error') + def test(): + warnings.warn(UserWarning('hello')) + """ + ) + result = testdir.runpytest("-W", "ignore") + result.stdout.fnmatch_lines(["* 1 failed in*"]) + + class TestDeprecationWarningsByDefault: """ Note: all pytest runs are executed in a subprocess so we don't inherit warning filters