'Make pytest fail on ResourceWarning (unclosed files)

Some of my tests need to ensure open files are closed. Let's use the simplest example:

# test_example.py
import pytest

@pytest.mark.filterwarnings('error::ResourceWarning')
def test_resourcewarning():
    open('/dev/null')

When I run pytest, the warning is thrown and even printed in the test output, but the test still passes:

$ pytest
============================ test session starts =============================
platform darwin -- Python 3.10.2, pytest-7.1.1, pluggy-1.0.0
rootdir: /path/to/project
collected 1 item

test_example.py .                                                      [100%]

============================== warnings summary ==============================
test_example.py::test_resourcewarning
  /path/to/python/site-packages/_pytest/unraisableexception.py:78: PytestUnrai
sableExceptionWarning: Exception ignored in: <_io.FileIO [closed]>

  Traceback (most recent call last):
    File "/path/to/project/test_example.py", line 5, in test_resourcewarning
      open('/dev/null')
  ResourceWarning: unclosed file <_io.TextIOWrapper name='/dev/null' mode='r' 
encoding='UTF-8'>

    warnings.warn(pytest.PytestUnraisableExceptionWarning(msg))

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
======================== 1 passed, 1 warning in 0.01s ========================

Removing @pytest.mark.filterwarnings or changing the warning type to something unrelated (like DeprecationWarning) results in the test passing without printing any warnings at all, so clearly this is catching the warning - but it seems to be subsequently caught by pytest. Pytest then throws pytest.PytestUnraisableExceptionWarning, which doesn't fail because I wasn't filtering for that. If I do filter for pytest.PytestUnraisableExceptionWarning the test also passes, because it isn't looking for the original ResourceWarning.

The only solution I can think of is to filter for both:

@pytest.mark.filterwarnings('error::ResourceWarning')
@pytest.mark.filterwarnings('error::pytest.PytestUnraisableExceptionWarning')

But at this point it doesn't make any sense to me, even after trawling through docs and google search results I don't understand how filtering for warnings is supposed to work if pytest is just going to swallow them and make me capture its own warnings to actually register a test failure, and so the only logical conclusion is that I don't know what I'm doing (or that this is a bug).

What am I missing?



Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source