Skip to content

Commit 3039391

Browse files
authored
Update documentation on how pytest.warns affects DeprecationWarning #9291 (#10141)
Co-authored-by: Dani Sancas <[email protected]> On-behalf-of: @clarityai-eng <[email protected]> Signed-off-by: Tatiana Ovary <[email protected]>
1 parent bec2b8e commit 3039391

File tree

3 files changed

+47
-18
lines changed

3 files changed

+47
-18
lines changed

changelog/9291.doc.rst

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Update documentation on how :func:`pytest.warns` affects :class:`DeprecationWarning`.

doc/en/how-to/capture-warnings.rst

+31-11
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,8 @@ Running pytest now produces this output:
4242
-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
4343
======================= 1 passed, 1 warning in 0.12s =======================
4444
45+
.. _`controlling-warnings`:
46+
4547
Controlling warnings
4648
--------------------
4749

@@ -176,11 +178,14 @@ using an external system.
176178
DeprecationWarning and PendingDeprecationWarning
177179
------------------------------------------------
178180

179-
180181
By default pytest will display ``DeprecationWarning`` and ``PendingDeprecationWarning`` warnings from
181182
user code and third-party libraries, as recommended by :pep:`565`.
182183
This helps users keep their code modern and avoid breakages when deprecated warnings are effectively removed.
183184

185+
However, in the specific case where users capture any type of warnings in their test, either with
186+
:func:`pytest.warns`, :func:`pytest.deprecated_call` or using the :ref:`recwarn <recwarn>` fixture,
187+
no warning will be displayed at all.
188+
184189
Sometimes it is useful to hide some specific deprecation warnings that happen in code that you have no control over
185190
(such as third-party libraries), in which case you might use the warning filters options (ini or marks) to ignore
186191
those warnings.
@@ -197,6 +202,9 @@ For example:
197202
This will ignore all warnings of type ``DeprecationWarning`` where the start of the message matches
198203
the regular expression ``".*U.*mode is deprecated"``.
199204

205+
See :ref:`@pytest.mark.filterwarnings <filterwarnings>` and
206+
:ref:`Controlling warnings <controlling-warnings>` for more examples.
207+
200208
.. note::
201209

202210
If warnings are configured at the interpreter level, using
@@ -245,10 +253,10 @@ when called with a ``17`` argument.
245253
Asserting warnings with the warns function
246254
------------------------------------------
247255

248-
249-
250256
You can check that code raises a particular warning using :func:`pytest.warns`,
251-
which works in a similar manner to :ref:`raises <assertraises>`:
257+
which works in a similar manner to :ref:`raises <assertraises>` (except that
258+
:ref:`raises <assertraises>` does not capture all exceptions, only the
259+
``expected_exception``):
252260

253261
.. code-block:: python
254262
@@ -261,8 +269,8 @@ which works in a similar manner to :ref:`raises <assertraises>`:
261269
with pytest.warns(UserWarning):
262270
warnings.warn("my warning", UserWarning)
263271
264-
The test will fail if the warning in question is not raised. The keyword
265-
argument ``match`` to assert that the exception matches a text or regex::
272+
The test will fail if the warning in question is not raised. Use the keyword
273+
argument ``match`` to assert that the warning matches a text or regex::
266274

267275
>>> with warns(UserWarning, match='must be 0 or None'):
268276
... warnings.warn("value must be 0 or None", UserWarning)
@@ -359,20 +367,32 @@ Additional use cases of warnings in tests
359367

360368
Here are some use cases involving warnings that often come up in tests, and suggestions on how to deal with them:
361369

362-
- To ensure that **at least one** warning is emitted, use:
370+
- To ensure that **at least one** of the indicated warnings is issued, use:
363371

364372
.. code-block:: python
365373
366-
with pytest.warns():
374+
def test_warning():
375+
with pytest.warns((RuntimeWarning, UserWarning)):
376+
...
377+
378+
- To ensure that **only** certain warnings are issued, use:
379+
380+
.. code-block:: python
381+
382+
def test_warning(recwarn):
367383
...
384+
assert len(recwarn) == 1
385+
user_warning = recwarn.pop(UserWarning)
386+
assert issubclass(user_warning.category, UserWarning)
368387
369388
- To ensure that **no** warnings are emitted, use:
370389

371390
.. code-block:: python
372391
373-
with warnings.catch_warnings():
374-
warnings.simplefilter("error")
375-
...
392+
def test_warning():
393+
with warnings.catch_warnings():
394+
warnings.simplefilter("error")
395+
...
376396
377397
- To suppress warnings, use:
378398

src/_pytest/recwarn.py

+15-7
Original file line numberDiff line numberDiff line change
@@ -112,15 +112,15 @@ def warns( # noqa: F811
112112
) -> Union["WarningsChecker", Any]:
113113
r"""Assert that code raises a particular class of warning.
114114
115-
Specifically, the parameter ``expected_warning`` can be a warning class or
116-
sequence of warning classes, and the code inside the ``with`` block must issue a warning of that class or
117-
classes.
115+
Specifically, the parameter ``expected_warning`` can be a warning class or sequence
116+
of warning classes, and the code inside the ``with`` block must issue at least one
117+
warning of that class or classes.
118118
119-
This helper produces a list of :class:`warnings.WarningMessage` objects,
120-
one for each warning raised.
119+
This helper produces a list of :class:`warnings.WarningMessage` objects, one for
120+
each warning raised (regardless of whether it is an ``expected_warning`` or not).
121121
122-
This function can be used as a context manager, or any of the other ways
123-
:func:`pytest.raises` can be used::
122+
This function can be used as a context manager, which will capture all the raised
123+
warnings inside it::
124124
125125
>>> import pytest
126126
>>> with pytest.warns(RuntimeWarning):
@@ -141,6 +141,14 @@ def warns( # noqa: F811
141141
...
142142
Failed: DID NOT WARN. No warnings of type ...UserWarning... were emitted...
143143
144+
**Using with** ``pytest.mark.parametrize``
145+
146+
When using :ref:`pytest.mark.parametrize ref` it is possible to parametrize tests
147+
such that some runs raise a warning and others do not.
148+
149+
This could be achieved in the same way as with exceptions, see
150+
:ref:`parametrizing_conditional_raising` for an example.
151+
144152
"""
145153
__tracebackhide__ = True
146154
if not args:

0 commit comments

Comments
 (0)