From 950e7819a2d020c3f91af20019870afa172ec10a Mon Sep 17 00:00:00 2001 From: isra17 Date: Mon, 15 Sep 2025 11:24:53 -0400 Subject: [PATCH] config: Do not fail if a warning filter category cannot be imported --- AUTHORS | 1 + changelog/13732.improvement.rst | 1 + src/_pytest/config/__init__.py | 18 ++++++++++++++++-- testing/test_config.py | 2 -- testing/test_warnings.py | 27 +++++++++++++++++++++++++++ 5 files changed, 45 insertions(+), 4 deletions(-) create mode 100644 changelog/13732.improvement.rst diff --git a/AUTHORS b/AUTHORS index f93de06c10d..52363a177bb 100644 --- a/AUTHORS +++ b/AUTHORS @@ -201,6 +201,7 @@ Ilya Konstantinov Ionuț Turturică Isaac Virshup Israel Fruchter +Israël Hallé Itxaso Aizpurua Iwan Briquemont Jaap Broekhuizen diff --git a/changelog/13732.improvement.rst b/changelog/13732.improvement.rst new file mode 100644 index 00000000000..07b3d620cf6 --- /dev/null +++ b/changelog/13732.improvement.rst @@ -0,0 +1 @@ +Previously, when filtering warnings, pytest would fail if the filter referenced a class that could not be imported. Now, this only outputs a message indicating the problem. diff --git a/src/_pytest/config/__init__.py b/src/_pytest/config/__init__.py index 0248f046407..8c80405a6ab 100644 --- a/src/_pytest/config/__init__.py +++ b/src/_pytest/config/__init__.py @@ -1965,6 +1965,8 @@ def parse_warning_filter( raise UsageError(error_template.format(error=str(e))) from None try: category: type[Warning] = _resolve_warning_category(category_) + except ImportError: + raise except Exception: exc_info = ExceptionInfo.from_current() exception_text = exc_info.getrepr(style="native") @@ -2023,7 +2025,19 @@ def apply_warning_filters( # Filters should have this precedence: cmdline options, config. # Filters should be applied in the inverse order of precedence. for arg in config_filters: - warnings.filterwarnings(*parse_warning_filter(arg, escape=False)) + try: + warnings.filterwarnings(*parse_warning_filter(arg, escape=False)) + except ImportError as e: + warnings.warn( + f"Failed to import filter module '{e.name}': {arg}", PytestConfigWarning + ) + continue for arg in cmdline_filters: - warnings.filterwarnings(*parse_warning_filter(arg, escape=True)) + try: + warnings.filterwarnings(*parse_warning_filter(arg, escape=True)) + except ImportError as e: + warnings.warn( + f"Failed to import filter module '{e.name}': {arg}", PytestConfigWarning + ) + continue diff --git a/testing/test_config.py b/testing/test_config.py index 3e8635fd1fc..f2cc139dffa 100644 --- a/testing/test_config.py +++ b/testing/test_config.py @@ -2400,8 +2400,6 @@ def test_parse_warning_filter( ":" * 5, # Invalid action. "FOO::", - # ImportError when importing the warning class. - "::test_parse_warning_filter_failure.NonExistentClass::", # Class is not a Warning subclass. "::list::", # Negative line number. diff --git a/testing/test_warnings.py b/testing/test_warnings.py index ff7ee4915c9..399ca586927 100644 --- a/testing/test_warnings.py +++ b/testing/test_warnings.py @@ -424,6 +424,33 @@ def test(): result.stdout.fnmatch_lines(["* 1 failed in*"]) +def test_accept_unknown_category(pytester: Pytester) -> None: + """Category types that can't be imported don't cause failure (#13732).""" + pytester.makeini( + """ + [pytest] + filterwarnings = + always:Failed to import filter module.*:pytest.PytestConfigWarning + ignore::foobar.Foobar + """ + ) + pytester.makepyfile( + """ + def test(): + pass + """ + ) + result = pytester.runpytest("-W", "ignore::bizbaz.Bizbaz") + result.stdout.fnmatch_lines( + [ + f"*== {WARNINGS_SUMMARY_HEADER} ==*", + "*PytestConfigWarning: Failed to import filter module 'foobar': ignore::foobar.Foobar", + "*PytestConfigWarning: Failed to import filter module 'bizbaz': ignore::bizbaz.Bizbaz", + "* 1 passed, * warning*", + ] + ) + + class TestDeprecationWarningsByDefault: """ Note: all pytest runs are executed in a subprocess so we don't inherit warning filters