Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Document that with pytest.warns() captures all warnings, not just those it tests were emitted #9288

Closed
Kojoley opened this issue Nov 9, 2021 · 10 comments
Labels
plugin: warnings related to the warnings builtin plugin type: docs documentation improvement, missing or needing clarification

Comments

@Kojoley
Copy link

Kojoley commented Nov 9, 2021

I have a test that ensures a specific warning type is produced by a function, but since I switched to pytest.warns I no longer see Python 3.10 compatibility warnings in Pytest warnings summary the code was emitting before switching to pytest.warns. Is it expected behavior (in which case it contradicts https://docs.pytest.org/en/6.2.x/warnings.html#deprecationwarning-and-pendingdeprecationwarning) and how I can opt-out of hiding DeprecationWarnings by pytest.warns (there is nothing about that in the documentation https://docs.pytest.org/en/6.2.x/reference.html#pytest-warns)?

MVCE:

import pytest
import warnings

def test_warning():
    with pytest.warns(DeprecationWarning):
        with pytest.warns(UserWarning):  # catches UserWarning, but also every other type too
            warnings.warn("my warning", UserWarning)
            warnings.warn("some deprecation warning", DeprecationWarning)
================================== FAILURES ===================================
________________________________ test_warning _________________________________

    def test_warning():
>       with pytest.warns(DeprecationWarning):
E       Failed: DID NOT WARN. No warnings of type (<class 'DeprecationWarning'>,) was emitted. The list of emitted warnings is: [].
@Kojoley Kojoley changed the title pytest.warns hides non-expected warnings, even DeprecationWarning pytest.warns hides not expected warnings, even DeprecationWarning Nov 9, 2021
@Zac-HD Zac-HD added plugin: warnings related to the warnings builtin plugin type: question general question, might be closed after 2 weeks of inactivity labels Nov 10, 2021
@nicoddemus
Copy link
Member

nicoddemus commented Nov 10, 2021

Hi @Kojoley,

This is the expected behavior, pytest.warns acts as a net which captures all warnings inside the block, ensuring the given warning is raised, or failing otherwise.

We might add a note to https://docs.pytest.org/en/6.2.x/warnings.html#deprecationwarning-and-pendingdeprecationwarning to mention that behavior does not apply for code inside pytest.warns, what do you think?

@Kojoley
Copy link
Author

Kojoley commented Nov 10, 2021

The pytest.warns documentation does not say it will filter everything (actually it does not say it will filter anything at all), so it should be fixed too. It preferably should say how to make pytest.warns to not capture everything or an alternative solution, but I still myself have no idea how to achieve that with tools Pytest provides, could you please suggest anything?

@nicoddemus
Copy link
Member

The pytest.warns documentation does not say it will filter everything (actually it does not say it will filter anything at all), so it should be fixed too.

True, thanks!

I still myself have no idea how to achieve that with tools Pytest provides, could you please suggest anything?

Hmm I can't think of anything right now, pytest.warns uses warnings.catch_warnings under the covers, which by design captures all warnings.

@nicoddemus
Copy link
Member

nicoddemus commented Nov 10, 2021

Created #9291 to track the docs change.

@Kojoley
Copy link
Author

Kojoley commented Nov 10, 2021

If I understand correctly pytest.deprecated_call hides all warnings by design too?

Also, https://docs.pytest.org/en/6.2.x/warnings.html#warns says You can check that code raises a particular warning using func:pytest.warns, which works in a similar manner to raises: but raises does not hide all exceptions, example:

def test_raises():
    with pytest.raises(RuntimeError):              # passes,
        with pytest.raises(NotImplementedError):   # because this will not catch and hide the exception
            raise RuntimeError("some exception")

@nicoddemus
Copy link
Member

nicoddemus commented Nov 10, 2021

If I understand correctly pytest.deprecated_call hides all warnings by design too?

Yes. 👍

but raises does not hide all exceptions, example

Good point, we need to mention that difference in the docs too.

@Zac-HD Zac-HD added type: docs documentation improvement, missing or needing clarification and removed type: question general question, might be closed after 2 weeks of inactivity labels Nov 29, 2021
@Zac-HD Zac-HD changed the title pytest.warns hides not expected warnings, even DeprecationWarning Document that with pytest.warns() captures all warnings, not just those it tests were emitted Apr 21, 2022
@Zac-HD
Copy link
Member

Zac-HD commented Apr 21, 2022

Alternatively we could make pytest.warns() re-emit all captured warnings on exit, which might better match users' intuitions - including mine, from before I went and looked up warnings.catch_warnings(record=True).

@QuLogic
Copy link

QuLogic commented Jan 13, 2023

I think it would make sense to re-raise all unmatched warnings. For example, say you are testing your own deprecated code so you add pytest.warns(DeprecationWarning, match='something specific to your project'). Then one of your dependencies (or maybe some other part of your code) adds a deprecation that is only triggered by that original code's tests. Then you will be blind-sided if the second deprecation is removed first because you never saw it.

@zanieb
Copy link

zanieb commented Apr 4, 2023

Note that this also means that if you pass an incorrect value to warnings.warn it will hide the error. See #10865

@Zac-HD
Copy link
Member

Zac-HD commented Jul 3, 2023

As of #10937, expected in Pytest 8.0, we re-emit all non-matching warnings.

mgorny added a commit to mgorny/pydantic that referenced this issue Jan 30, 2024
Fix
`tests/test_validators.py::test_root_validator_allow_reuse_same_field`
to assert for both warnings emitted, including the Pydantic V1
deprecation warning.  Starting with pytest 8.0.0 (thanks to the fix for
pytest-dev/pytest#9288), `pytest.warns()` re-emits warnings that weren't
caught by the assertion, effectively causing the default run with
`-Werror` to fail.
MartinThoma pushed a commit to py-pdf/pypdf that referenced this issue Feb 4, 2024
Fix compatibility with pytest==8. 

Relevant upstream change: pytest-dev/pytest#9288

Fixes #2427
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
plugin: warnings related to the warnings builtin plugin type: docs documentation improvement, missing or needing clarification
Projects
None yet
Development

Successfully merging a pull request may close this issue.

5 participants