I bumped into a slighty surprising behaviour in scikit-learn and it took me a bit of time to realize that the root cause is that the same warning is issued twice, once directly in the test function and once inside a pytest.warns context. There appears to be some race condition that makes the test fail when run with enough iterations. Not sure pytest-run-parallel can do much about it but I thought I would report it here first.
Wild-guessing, maybe per-module __warningregistry__ is still a global (in contrary the per-thread warnings.filters since Python 3.14 and python/cpython#130010)? My understanding is that per-module __warningregistry__ is used on top of the warnings.filter to decide whether to issue repeated warnings.
Here is a reproducer:
# test.py
import warnings
import pytest
import my_module
def test_pytest_warns():
my_module.function_that_warns()
with pytest.warns(UserWarning):
my_module.function_that_warns()
# my_module.py
import warnings
def function_that_warns():
warnings.warn('bla')
pytest test.py --parallel-threads 4 --iterations 100
Output:
============================================================================================================= test session starts ==============================================================================================================
platform linux -- Python 3.14.2, pytest-9.0.1, pluggy-1.6.0
rootdir: /tmp
plugins: run-parallel-0.8.0, cov-7.0.0, repeat-0.9.4, xdist-3.8.0
collected 1 item
Collected 1 items to run in parallel
test.py e [100%]
==================================================================================================================== ERRORS ====================================================================================================================
______________________________________________________________________________________________________ ERROR at call of test_pytest_warns ______________________________________________________________________________________________________
def test_pytest_warns():
my_module.function_that_warns()
> with pytest.warns(UserWarning):
^^^^^^^^^^^^^^^^^^^^^^^^^
E Failed: DID NOT WARN. No warnings of type (<class 'UserWarning'>,) were emitted.
E Emitted warnings: [].
test.py:10: Failed
=============================================================================================================== warnings summary ===============================================================================================================
test.py: 286 warnings
/tmp/my_module.py:4: UserWarning: bla
warnings.warn('bla')
-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
********************************************************************************************************** pytest-run-parallel report **********************************************************************************************************
All tests were run in parallel! 🎉
=========================================================================================================== short test summary info ============================================================================================================
PARALLEL FAILED test.py::test_pytest_warns - Failed: DID NOT WARN. No warnings of type (<class 'UserWarning'>,) were emitted.
======================================================================================================== 286 warnings, 1 error in 0.07s ========================================================================================================
Possible work-arounds:
- make sure to use
with pytest.warns to capture the first warning as well
- mark test as thread-unsafe
- use
--mark-warnings-as-unsafe
I bumped into a slighty surprising behaviour in scikit-learn and it took me a bit of time to realize that the root cause is that the same warning is issued twice, once directly in the test function and once inside a
pytest.warnscontext. There appears to be some race condition that makes the test fail when run with enough iterations. Not sure pytest-run-parallel can do much about it but I thought I would report it here first.Wild-guessing, maybe per-module
__warningregistry__is still a global (in contrary the per-threadwarnings.filterssince Python 3.14 and python/cpython#130010)? My understanding is that per-module__warningregistry__is used on top of thewarnings.filterto decide whether to issue repeated warnings.Here is a reproducer:
Output:
Possible work-arounds:
with pytest.warnsto capture the first warning as well--mark-warnings-as-unsafe