Can't Configure Warnings Module In Pytest_configure

by ADMIN 52 views

Introduction

Pytest is a popular testing framework for Python that provides a lot of flexibility and customization options. However, sometimes even with all the options available, we can still run into issues that are hard to solve. In this article, we will explore one such issue - configuring warnings module in pytest_configure.

The Problem

We are using pytest since version 2.5 and it usually works great. However, today we ran into a nasty problem with pytest-based testing. We are trying to elevate a specific warning class to be handled as error (instead of giving us thousands of lines as "warnings summary"). Our goal is to get the traceback of the deprecated usage.

Code Example

Here is some example code that shows how we used warnings in pytest 3.0, which is now broken:

import warnings

from app import MyDeprecationWarning


def pytest_configure():
    # Configure app specific warning as error.
    warnings.filterwarnings("error", category=MyDeprecationWarning)
import warnings

import pytest

from app import MyDeprecationWarning


def test_deprecated():
    with pytest.raises(MyDeprecationWarning):
        warnings.warn("Stuff deprecated", category=MyDeprecationWarning)
class MyDeprecationWarning(DeprecationWarning):
    pass

Output of Code Example

When we run the test, we get the following output:

$ uv run pytest
==================================================== test session starts =====================================================
platform linux -- Python 3.7.9, pytest-3.0.7, py-1.11.0, pluggy-0.4.0
rootdir: /home/torsten.landschoff/tmp/2025-03-10/warnings, inifile:
collected 1 items 

test_depwarn.py .

================================================== 1 passed in 0.01 seconds ==================================================

However, when we upgrade to pytest 7.4.4, we get the following output:

$ uv run pytest
==================================================== test session starts =====================================================
platform linux -- Python 3.13.1, pytest-7.4.4, pluggy-1.2.0
rootdir: /home/torsten.landschoff/tmp/2025-03-10/warnings
collected 1 item                                                                                                             

test_depwarn.py F                                                                                                      [100%]

========================================================== FAILURES ==========================================================
______________________________________________________ test_deprecated _______________________________________________________

    def test_deprecated():
>       with pytest.raises(MyDeprecationWarning):
E       Failed: DID NOT RAISE <class 'app.MyDeprecationWarning'>

test_depwarn.py:9: Failed
====================================================== warnings summary ======================================================
test_depwarn.py::test_deprecated
  /home/torsten.landschoff/tmp/2025-03-10/warnings/test_depwarn.py:10: MyDeprecationWarning: Stuff deprecated
    warnings.warn("Stuff deprecated", category=MyDeprecationWarning)

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
================================================== short test summary info ===================================================
FAILED test_depwarn.py::test_deprecated - Failed: DID NOT RAISE <class 'app.MyDeprecationWarning'>
================================================ 1 failed, 1 warning in 0.02s ================================================

Analysis

It appears that it is impossible to configure warnings in pytest_configure now, as it is wrapped with warnings.catch_warnings() (currently in _pytest/warnings.py).

Solution

One possible solution is to configure warnings in pytest.ini by setting filterwarnings, for example by setting:

[pytest]
filterwarnings =
    error::app.MyAppDeprecationWarning

However, this is broken consistently with built-in Python warning control:

ERROR: while parsing the following warning configuration:

  error::app.MyAppDeprecationWarning

This error occurred:

Traceback (most recent call last):
  File "/home/torsten.landschoff/tmp/2025-03-10/warnings/.venv/lib/python3.13/site-packages/_pytest/config/__init__.py", line 1761, in parse_warning_filter
    category: Type[Warning] = _resolve_warning_category(category_)
                              ~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^
  File "/home/torsten.landschoff/tmp/2025-03-10/warnings/.venv/lib/python3.13/site-packages/_pytest/config/__init__.py", line 1799, in _resolve_warning_category
    m = __import__(module, None, None, [klass])
ModuleNotFoundError: No module named 'app'

Conclusion

In conclusion, configuring warnings module in pytest_configure is not possible now, as it is wrapped with warnings.catch_warnings(). One possible solution is to configure warnings in pytest.ini by setting filterwarnings, but this is broken consistently with built-in Python warning control.

Recommendation

I think that:

  • warning filters set up in the pytest_configure hook should take effect IMHO (they currently don't)
  • failing that, there should at least be a way to set up warning filters for application/library warning classes

Q: What is the issue with configuring warnings module in pytest_configure?

A: The issue is that pytest_configure is wrapped with warnings.catch_warnings(), which prevents the warning filters from taking effect.

Q: Why is this a problem?

A: This is a problem because it makes it difficult to configure warnings in pytest, especially when using custom warning classes.

Q: What are some possible solutions to this issue?

A: One possible solution is to configure warnings in pytest.ini by setting filterwarnings. However, this is broken consistently with built-in Python warning control.

Q: What is the recommended solution to this issue?

A: I think that warning filters set up in the pytest_configure hook should take effect IMHO (they currently don't). Failing that, there should at least be a way to set up warning filters for application/library warning classes.

Q: How can I configure warnings in pytest.ini?

A: You can configure warnings in pytest.ini by setting filterwarnings. For example:

[pytest]
filterwarnings =
    error::app.MyAppDeprecationWarning

However, this is broken consistently with built-in Python warning control.

Q: What is the error message when trying to configure warnings in pytest.ini?

A: The error message is:

ERROR: while parsing the following warning configuration:

  error::app.MyAppDeprecationWarning

This error occurred:

Traceback (most recent call last):
  File "/home/torsten.landschoff/tmp/2025-03-10/warnings/.venv/lib/python3.13/site-packages/_pytest/config/__init__.py", line 1761, in parse_warning_filter
    category: Type[Warning] = _resolve_warning_category(category_)
                              ~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^
  File "/home/torsten.landschoff/tmp/2025-03-10/warnings/.venv/lib/python3.13/site-packages/_pytest/config/__init__.py", line 1799, in _resolve_warning_category
    m = __import__(module, None, None, [klass])
ModuleNotFoundError: No module named 'app'

Q: How can I configure warnings for application/library warning classes?

A: Unfortunately, this is not currently possible in pytest. However, you can use a regex to match the warning class:

warnings.filterwarnings("error", category=DeprecationWarning, module=r"myapp\.")

Q: What is the best way to configure warnings in pytest?

A: The best way to configure warnings in pytest is to use the pytest_configure hook to set up warning filters. This will ensure that the warning filters take effect and that you can configure warnings for application/library warning classes.

Q: How can I configure warnings in pytest_configure?

A: You can configure warnings in pytest_configure by using the warnings.filterwarnings function. For example:

def pytest_configure(config):
    warnings.filterwarnings("error", category=MyAppDeprecationWarning)

This will configure the MyAppDeprecationWarning class to be treated as an error.