2017-03-21 10:35:01 +08:00
.. _`warnings`:
2021-03-15 16:22:11 +08:00
How to capture warnings
=======================
2017-03-21 10:35:01 +08:00
2019-04-28 23:37:58 +08:00
2017-03-21 10:35:01 +08:00
2017-05-30 05:59:34 +08:00
Starting from version `` 3.1 `` , pytest now automatically catches warnings during test execution
2019-04-12 19:50:26 +08:00
and displays them at the end of the session:
.. code-block :: python
2017-03-21 10:35:01 +08:00
# content of test_show_warnings.py
import warnings
2019-04-12 19:50:26 +08:00
2017-05-30 05:59:34 +08:00
def api_v1():
warnings.warn(UserWarning("api v1, should use functions from v2"))
2017-03-21 10:35:01 +08:00
return 1
2019-04-12 19:50:26 +08:00
2017-03-21 10:35:01 +08:00
def test_one():
2017-05-30 05:59:34 +08:00
assert api_v1() == 1
2017-03-21 10:35:01 +08:00
2018-11-24 13:41:22 +08:00
Running pytest now produces this output:
.. code-block :: pytest
2017-03-21 10:35:01 +08:00
$ pytest test_show_warnings.py
2017-11-23 23:33:41 +08:00
=========================== test session starts ============================
2020-07-09 05:51:01 +08:00
platform linux -- Python 3.x.y, pytest-6.x.y, py-1.x.y, pluggy-0.x.y
2019-01-31 00:25:38 +08:00
cachedir: $PYTHON_PREFIX/.pytest_cache
2019-04-15 22:24:17 +08:00
rootdir: $REGENDOC_TMPDIR
2017-07-04 07:29:13 +08:00
collected 1 item
2018-05-18 16:19:46 +08:00
2017-11-23 23:33:41 +08:00
test_show_warnings.py . [100%]
2018-05-18 16:19:46 +08:00
2017-11-23 23:33:41 +08:00
============================= warnings summary =============================
2018-10-27 21:07:54 +08:00
test_show_warnings.py::test_one
2019-04-15 22:24:17 +08:00
$REGENDOC_TMPDIR/test_show_warnings.py:5: UserWarning: api v1, should use functions from v2
2018-10-27 21:07:54 +08:00
warnings.warn(UserWarning("api v1, should use functions from v2"))
2018-05-18 16:19:46 +08:00
2020-07-07 18:39:35 +08:00
-- Docs: https://docs.pytest.org/en/stable/warnings.html
2019-11-19 23:43:51 +08:00
======================= 1 passed, 1 warning in 0.12s =======================
2017-03-21 10:35:01 +08:00
The `` -W `` flag can be passed to control which warnings will be displayed or even turn
2018-11-24 13:41:22 +08:00
them into errors:
.. code-block :: pytest
2017-03-21 10:35:01 +08:00
2017-05-30 05:59:34 +08:00
$ pytest -q test_show_warnings.py -W error::UserWarning
2017-11-23 23:33:41 +08:00
F [100%]
================================= FAILURES =================================
_________________________________ test_one _________________________________
2018-05-18 16:19:46 +08:00
2017-05-20 06:12:59 +08:00
def test_one():
2017-05-31 05:19:34 +08:00
> assert api_v1() == 1
2018-05-18 16:19:46 +08:00
2019-04-15 22:24:17 +08:00
test_show_warnings.py:10:
2018-05-18 16:19:46 +08:00
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
2017-05-31 05:19:34 +08:00
def api_v1():
> warnings.warn(UserWarning("api v1, should use functions from v2"))
E UserWarning: api v1, should use functions from v2
2018-05-18 16:19:46 +08:00
2019-04-15 22:24:17 +08:00
test_show_warnings.py:5: UserWarning
2020-03-11 22:23:25 +08:00
========================= short test summary info ==========================
FAILED test_show_warnings.py::test_one - UserWarning: api v1, should use ...
2019-09-18 21:11:59 +08:00
1 failed in 0.12s
2017-03-21 10:35:01 +08:00
2020-08-14 15:08:17 +08:00
The same option can be set in the `` pytest.ini `` or `` pyproject.toml `` file using the
`` filterwarnings `` ini option. For example, the configuration below will ignore all
user warnings and specific deprecation warnings matching a regex, but will transform
2017-03-21 10:35:01 +08:00
all other warnings into errors.
.. code-block :: ini
2020-08-14 15:08:17 +08:00
# pytest.ini
2017-03-21 10:35:01 +08:00
[pytest]
filterwarnings =
error
2017-05-30 05:59:34 +08:00
ignore::UserWarning
2020-08-14 15:08:17 +08:00
ignore:function ham\(\) is deprecated:DeprecationWarning
.. code-block :: toml
# pyproject.toml
[tool.pytest.ini_options]
filterwarnings = [
"error",
"ignore::UserWarning",
# note the use of single quote below to denote "raw" strings in TOML
'ignore:function ham\(\) is deprecated:DeprecationWarning',
]
2017-03-21 10:35:01 +08:00
When a warning matches more than one option in the list, the action for the last matching option
is performed.
Both `` -W `` command-line option and `` filterwarnings `` ini option are based on Python's own
`-W option`_ and `warnings.simplefilter`_ , so please refer to those sections in the Python
documentation for other examples and advanced usage.
2018-10-17 08:00:57 +08:00
.. _`filterwarnings`:
`` @pytest.mark.filterwarnings ``
-------------------------------
2019-04-28 23:37:58 +08:00
2018-10-17 08:00:57 +08:00
You can use the `` @pytest.mark.filterwarnings `` to add warning filters to specific test items,
allowing you to have finer control of which warnings should be captured at test, class or
even module level:
.. code-block :: python
import warnings
def api_v1():
warnings.warn(UserWarning("api v1, should use functions from v2"))
return 1
@pytest.mark.filterwarnings("ignore:api v1")
def test_one():
assert api_v1() == 1
Filters applied using a mark take precedence over filters passed on the command line or configured
by the `` filterwarnings `` ini option.
You may apply a filter to all tests of a class by using the `` filterwarnings `` mark as a class
2020-07-10 20:50:03 +08:00
decorator or to all tests in a module by setting the :globalvar: `pytestmark` variable:
2018-10-17 08:00:57 +08:00
.. code-block :: python
# turns all warnings into errors for this module
pytestmark = pytest.mark.filterwarnings("error")
*Credits go to Florian Schulze for the reference implementation in the* `pytest-warnings`_
*plugin.*
2019-07-16 04:36:48 +08:00
.. _`-W option`: https://docs.python.org/3/using/cmdline.html#cmdoption-w
2018-10-17 08:00:57 +08:00
.. _warnings.simplefilter: https://docs.python.org/3/library/warnings.html#warnings.simplefilter
.. _`pytest-warnings`: https://github.com/fschulze/pytest-warnings
Disabling warnings summary
--------------------------
2018-09-04 04:52:44 +08:00
Although not recommended, you can use the `` --disable-warnings `` command-line option to suppress the
warning summary entirely from the test run output.
2018-09-04 20:30:13 +08:00
Disabling warning capture entirely
----------------------------------
This plugin is enabled by default but can be disabled entirely in your `` pytest.ini `` file with:
.. code-block :: ini
[pytest]
addopts = -p no:warnings
Or passing `` -p no:warnings `` in the command-line. This might be useful if your test suites handles warnings
using an external system.
.. _`deprecation-warnings`:
2018-09-04 04:52:44 +08:00
DeprecationWarning and PendingDeprecationWarning
------------------------------------------------
2019-04-28 23:37:58 +08:00
2018-10-17 08:00:57 +08:00
By default pytest will display `` DeprecationWarning `` and `` PendingDeprecationWarning `` warnings from
2019-01-04 08:50:36 +08:00
user code and third-party libraries, as recommended by `PEP-0565 <https://www.python.org/dev/peps/pep-0565> `_ .
2018-10-17 08:00:57 +08:00
This helps users keep their code modern and avoid breakages when deprecated warnings are effectively removed.
2018-09-04 04:52:44 +08:00
2018-09-22 19:27:53 +08:00
Sometimes it is useful to hide some specific deprecation warnings that happen in code that you have no control over
2018-10-17 08:00:57 +08:00
(such as third-party libraries), in which case you might use the warning filters options (ini or marks) to ignore
those warnings.
2018-09-22 19:27:53 +08:00
For example:
2018-09-04 04:52:44 +08:00
.. code-block :: ini
[pytest]
filterwarnings =
2018-09-22 19:27:53 +08:00
ignore:.*U.* mode is deprecated:DeprecationWarning
2018-10-17 08:00:57 +08:00
This will ignore all warnings of type `` DeprecationWarning `` where the start of the message matches
the regular expression `` ".*U.*mode is deprecated" `` .
2018-09-22 19:27:53 +08:00
.. note ::
2019-08-07 04:25:54 +08:00
2018-09-22 19:27:53 +08:00
If warnings are configured at the interpreter level, using
the `PYTHONWARNINGS <https://docs.python.org/3/using/cmdline.html#envvar-PYTHONWARNINGS> `_ environment variable or the
`` -W `` command-line option, pytest will not configure any filters by default.
2018-09-04 04:52:44 +08:00
2018-10-17 08:00:57 +08:00
Also pytest doesn't follow `` PEP-0506 `` suggestion of resetting all warning filters because
it might break test suites that configure warning filters themselves
2018-09-04 20:30:13 +08:00
by calling `` warnings.simplefilter `` (see issue `#2430 <https://github.com/pytest-dev/pytest/issues/2430> `_
for an example of that).
2018-03-23 00:02:30 +08:00
2018-10-17 08:00:57 +08:00
.. _`ensuring a function triggers a deprecation warning`:
2017-07-21 09:02:21 +08:00
2018-10-17 08:00:57 +08:00
.. _ensuring_function_triggers:
2017-07-21 09:02:21 +08:00
2018-10-17 08:00:57 +08:00
Ensuring code triggers a deprecation warning
--------------------------------------------
2017-07-21 09:02:21 +08:00
2019-12-23 18:38:27 +08:00
You can also use :func: `pytest.deprecated_call` for checking
2018-10-17 08:00:57 +08:00
that a certain function call triggers a `` DeprecationWarning `` or
2019-04-12 19:50:26 +08:00
`` PendingDeprecationWarning `` :
.. code-block :: python
2017-07-21 09:02:21 +08:00
2018-10-17 08:00:57 +08:00
import pytest
2017-07-21 09:02:21 +08:00
2019-04-12 19:50:26 +08:00
2019-12-23 18:38:27 +08:00
def test_myfunction_deprecated():
with pytest.deprecated_call():
myfunction(17)
This test will fail if `` myfunction `` does not issue a deprecation warning
when called with a `` 17 `` argument.
2018-01-22 04:43:00 +08:00
2019-04-12 19:50:26 +08:00
2017-05-30 05:59:34 +08:00
2017-03-21 10:35:01 +08:00
.. _`asserting warnings`:
.. _assertwarnings:
.. _`asserting warnings with the warns function`:
.. _warns:
Asserting warnings with the warns function
2019-02-02 10:48:29 +08:00
------------------------------------------
2017-03-21 10:35:01 +08:00
2019-04-28 23:37:58 +08:00
2017-03-21 10:35:01 +08:00
2020-11-19 22:44:59 +08:00
You can check that code raises a particular warning using func:`pytest.warns` ,
2019-04-12 19:50:26 +08:00
which works in a similar manner to :ref: `raises <assertraises>` :
.. code-block :: python
2017-03-21 10:35:01 +08:00
import warnings
import pytest
2019-04-12 19:50:26 +08:00
2017-03-21 10:35:01 +08:00
def test_warning():
with pytest.warns(UserWarning):
warnings.warn("my warning", UserWarning)
2017-09-07 16:28:52 +08:00
The test will fail if the warning in question is not raised. The keyword
argument `` match `` to assert that the exception matches a text or regex::
>>> with warns(UserWarning, match='must be 0 or None'):
... warnings.warn("value must be 0 or None", UserWarning)
>>> with warns(UserWarning, match=r'must be \d+$'):
... warnings.warn("value must be 42", UserWarning)
>>> with warns(UserWarning, match=r'must be \d+$'):
... warnings.warn("this is not here", UserWarning)
Traceback (most recent call last):
...
Failed: DID NOT WARN. No warnings of type ...UserWarning... was emitted...
2017-03-21 10:35:01 +08:00
2020-11-19 22:44:59 +08:00
You can also call func:`pytest.warns` on a function or code string:
2017-03-21 10:35:01 +08:00
2019-08-07 04:25:54 +08:00
.. code-block :: python
2017-03-21 10:35:01 +08:00
pytest.warns(expected_warning, func, *args, * *kwargs)
pytest.warns(expected_warning, "func(*args, * *kwargs)")
The function also returns a list of all raised warnings (as
`` warnings.WarningMessage `` objects), which you can query for
2019-04-12 19:50:26 +08:00
additional information:
.. code-block :: python
2017-03-21 10:35:01 +08:00
with pytest.warns(RuntimeWarning) as record:
warnings.warn("another warning", RuntimeWarning)
# check that only one warning was raised
assert len(record) == 1
# check that the message matches
assert record[0].message.args[0] == "another warning"
Alternatively, you can examine raised warnings in detail using the
:ref: `recwarn <recwarn>` fixture (see below).
2021-06-12 22:38:24 +08:00
The :ref: `recwarn <recwarn>` fixture automatically ensures to reset the warnings
filter at the end of the test, so no global state is leaked.
2017-03-21 10:35:01 +08:00
.. _`recording warnings`:
.. _recwarn:
Recording warnings
2019-02-02 10:48:29 +08:00
------------------
2017-03-21 10:35:01 +08:00
2020-11-19 22:44:59 +08:00
You can record raised warnings either using func:`pytest.warns` or with
2017-03-21 10:35:01 +08:00
the `` recwarn `` fixture.
2020-11-19 22:44:59 +08:00
To record with func:`pytest.warns` without asserting anything about the warnings,
2021-05-15 22:15:43 +08:00
pass no arguments as the expected warning type and it will default to a generic Warning:
2019-04-12 19:50:26 +08:00
.. code-block :: python
2017-03-21 10:35:01 +08:00
2021-05-15 22:15:43 +08:00
with pytest.warns() as record:
2017-03-21 10:35:01 +08:00
warnings.warn("user", UserWarning)
warnings.warn("runtime", RuntimeWarning)
assert len(record) == 2
assert str(record[0].message) == "user"
assert str(record[1].message) == "runtime"
2019-04-12 19:50:26 +08:00
The `` recwarn `` fixture will record warnings for the whole function:
.. code-block :: python
2017-03-21 10:35:01 +08:00
import warnings
2019-04-12 19:50:26 +08:00
2017-03-21 10:35:01 +08:00
def test_hello(recwarn):
warnings.warn("hello", UserWarning)
assert len(recwarn) == 1
w = recwarn.pop(UserWarning)
assert issubclass(w.category, UserWarning)
assert str(w.message) == "hello"
assert w.filename
assert w.lineno
2020-11-19 22:44:59 +08:00
Both `` recwarn `` and func:`pytest.warns` return the same interface for recorded
2017-03-21 10:35:01 +08:00
warnings: a WarningsRecorder instance. To view the recorded warnings, you can
iterate over this instance, call `` len `` on it to get the number of recorded
2018-02-28 05:26:40 +08:00
warnings, or index into it to get a particular recorded warning.
2017-03-21 10:35:01 +08:00
2018-02-28 05:26:40 +08:00
.. currentmodule :: _pytest.warnings
2017-03-21 10:35:01 +08:00
2020-09-06 16:52:30 +08:00
Full API: :class: `~_pytest.recwarn.WarningsRecorder` .
2017-03-21 10:35:01 +08:00
2019-02-02 10:48:29 +08:00
.. _custom_failure_messages:
Custom failure messages
-----------------------
Recording warnings provides an opportunity to produce custom test
failure messages for when no warnings are issued or other conditions
are met.
.. code-block :: python
def test():
with pytest.warns(Warning) as record:
f()
if not record:
2019-02-06 05:04:26 +08:00
pytest.fail("Expected a warning!")
2019-02-02 10:48:29 +08:00
If no warnings are issued when calling `` f `` , then `` not record `` will
2020-11-19 22:44:59 +08:00
evaluate to `` True `` . You can then call :func: `pytest.fail` with a
2019-02-02 10:48:29 +08:00
custom error message.
2018-09-15 02:58:22 +08:00
.. _internal-warnings:
2018-09-04 00:36:12 +08:00
Internal pytest warnings
------------------------
pytest may generate its own warnings in some situations, such as improper usage or deprecated features.
For example, pytest will emit a warning if it encounters a class that matches :confval: `python_classes` but also
defines an `` __init__ `` constructor, as this prevents the class from being instantiated:
.. code-block :: python
# content of test_pytest_warnings.py
class Test:
def __init__(self):
pass
def test_foo(self):
assert 1 == 1
2018-11-24 13:41:22 +08:00
.. code-block :: pytest
2018-09-04 00:36:12 +08:00
$ pytest test_pytest_warnings.py -q
2018-09-06 05:06:32 +08:00
============================= warnings summary =============================
2018-10-27 21:07:54 +08:00
test_pytest_warnings.py:1
2019-06-01 00:01:05 +08:00
$REGENDOC_TMPDIR/test_pytest_warnings.py:1: PytestCollectionWarning: cannot collect test class 'Test' because it has a __init__ constructor (from: test_pytest_warnings.py)
2018-10-27 21:07:54 +08:00
class Test:
2018-09-04 00:36:12 +08:00
2020-07-07 18:39:35 +08:00
-- Docs: https://docs.pytest.org/en/stable/warnings.html
2019-11-19 23:43:51 +08:00
1 warning in 0.12s
2018-09-04 00:36:12 +08:00
These warnings might be filtered using the same builtin mechanisms used to filter other types of warnings.
2018-09-15 02:58:22 +08:00
Please read our :ref: `backwards-compatibility` to learn how we proceed about deprecating and eventually removing
features.
2018-09-04 00:36:12 +08:00
2020-07-23 08:36:51 +08:00
The full list of warnings is listed in :ref: `the reference documentation <warnings ref>` .