219 lines
7.1 KiB
ReStructuredText
219 lines
7.1 KiB
ReStructuredText
|
.. _`warnings`:
|
||
|
|
||
|
Warnings Capture
|
||
|
================
|
||
|
|
||
|
.. versionadded:: 3.1
|
||
|
|
||
|
Starting from version ``3.1``, pytest now automatically catches all warnings during test execution
|
||
|
and displays them at the end of the session::
|
||
|
|
||
|
# content of test_show_warnings.py
|
||
|
import warnings
|
||
|
|
||
|
def deprecated_function():
|
||
|
warnings.warn("this function is deprecated, use another_function()", DeprecationWarning)
|
||
|
return 1
|
||
|
|
||
|
def test_one():
|
||
|
assert deprecated_function() == 1
|
||
|
|
||
|
Running pytest now produces this output::
|
||
|
|
||
|
$ pytest test_show_warnings.py
|
||
|
.
|
||
|
============================== warnings summary ===============================
|
||
|
test_show_warning.py::test_one
|
||
|
C:\pytest\.tmp\test_show_warning.py:4: DeprecationWarning: this function is deprecated, use another_function()
|
||
|
warnings.warn("this function is deprecated, use another_function()", DeprecationWarning)
|
||
|
|
||
|
-- Docs: http://doc.pytest.org/en/latest/warnings.html
|
||
|
1 passed, 1 warnings in 0.01 seconds
|
||
|
|
||
|
The ``-W`` flag can be passed to control which warnings will be displayed or even turn
|
||
|
them into errors::
|
||
|
|
||
|
$ pytest -q test_show_warning.py -W error::DeprecationWarning
|
||
|
F
|
||
|
================================== FAILURES ===================================
|
||
|
__________________________________ test_one ___________________________________
|
||
|
|
||
|
def test_one():
|
||
|
> assert deprecated_function() == 1
|
||
|
|
||
|
test_show_warning.py:8:
|
||
|
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
|
||
|
|
||
|
def deprecated_function():
|
||
|
> warnings.warn("this function is deprecated, use another_function()", DeprecationWarning)
|
||
|
E DeprecationWarning: this function is deprecated, use another_function()
|
||
|
|
||
|
test_show_warning.py:4: DeprecationWarning
|
||
|
1 failed in 0.02 seconds
|
||
|
|
||
|
The same option can be set in the ``pytest.ini`` file using the ``filterwarnings`` ini option.
|
||
|
For example, the configuration below will ignore all deprecation warnings, but will transform
|
||
|
all other warnings into errors.
|
||
|
|
||
|
.. code-block:: ini
|
||
|
|
||
|
[pytest]
|
||
|
filterwarnings =
|
||
|
error
|
||
|
ignore::DeprecationWarning
|
||
|
|
||
|
|
||
|
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.
|
||
|
|
||
|
*Credits go to Florian Schulze for the reference implementation in the* `pytest-warnings`_
|
||
|
*plugin.*
|
||
|
|
||
|
.. _`-W option`: https://docs.python.org/3/using/cmdline.html?highlight=#cmdoption-W
|
||
|
.. _warnings.simplefilter: https://docs.python.org/3/library/warnings.html#warnings.simplefilter
|
||
|
.. _`pytest-warnings`: https://github.com/fschulze/pytest-warnings
|
||
|
|
||
|
.. _`asserting warnings`:
|
||
|
|
||
|
.. _assertwarnings:
|
||
|
|
||
|
.. _`asserting warnings with the warns function`:
|
||
|
|
||
|
.. _warns:
|
||
|
|
||
|
Asserting warnings with the warns function
|
||
|
-----------------------------------------------
|
||
|
|
||
|
.. versionadded:: 2.8
|
||
|
|
||
|
You can check that code raises a particular warning using ``pytest.warns``,
|
||
|
which works in a similar manner to :ref:`raises <assertraises>`::
|
||
|
|
||
|
import warnings
|
||
|
import pytest
|
||
|
|
||
|
def test_warning():
|
||
|
with pytest.warns(UserWarning):
|
||
|
warnings.warn("my warning", UserWarning)
|
||
|
|
||
|
The test will fail if the warning in question is not raised.
|
||
|
|
||
|
You can also call ``pytest.warns`` on a function or code string::
|
||
|
|
||
|
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
|
||
|
additional information::
|
||
|
|
||
|
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).
|
||
|
|
||
|
.. note::
|
||
|
``DeprecationWarning`` and ``PendingDeprecationWarning`` are treated
|
||
|
differently; see :ref:`ensuring_function_triggers`.
|
||
|
|
||
|
.. _`recording warnings`:
|
||
|
|
||
|
.. _recwarn:
|
||
|
|
||
|
Recording warnings
|
||
|
------------------------
|
||
|
|
||
|
You can record raised warnings either using ``pytest.warns`` or with
|
||
|
the ``recwarn`` fixture.
|
||
|
|
||
|
To record with ``pytest.warns`` without asserting anything about the warnings,
|
||
|
pass ``None`` as the expected warning type::
|
||
|
|
||
|
with pytest.warns(None) as record:
|
||
|
warnings.warn("user", UserWarning)
|
||
|
warnings.warn("runtime", RuntimeWarning)
|
||
|
|
||
|
assert len(record) == 2
|
||
|
assert str(record[0].message) == "user"
|
||
|
assert str(record[1].message) == "runtime"
|
||
|
|
||
|
The ``recwarn`` fixture will record warnings for the whole function::
|
||
|
|
||
|
import warnings
|
||
|
|
||
|
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
|
||
|
|
||
|
Both ``recwarn`` and ``pytest.warns`` return the same interface for recorded
|
||
|
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
|
||
|
warnings, or index into it to get a particular recorded warning. It also
|
||
|
provides these methods:
|
||
|
|
||
|
.. autoclass:: _pytest.recwarn.WarningsRecorder()
|
||
|
:members:
|
||
|
|
||
|
Each recorded warning has the attributes ``message``, ``category``,
|
||
|
``filename``, ``lineno``, ``file``, and ``line``. The ``category`` is the
|
||
|
class of the warning. The ``message`` is the warning itself; calling
|
||
|
``str(message)`` will return the actual message of the warning.
|
||
|
|
||
|
.. note::
|
||
|
:class:`RecordedWarning` was changed from a plain class to a namedtuple in pytest 3.1
|
||
|
|
||
|
.. note::
|
||
|
``DeprecationWarning`` and ``PendingDeprecationWarning`` are treated
|
||
|
differently; see :ref:`ensuring_function_triggers`.
|
||
|
|
||
|
.. _`ensuring a function triggers a deprecation warning`:
|
||
|
|
||
|
.. _ensuring_function_triggers:
|
||
|
|
||
|
Ensuring a function triggers a deprecation warning
|
||
|
-------------------------------------------------------
|
||
|
|
||
|
You can also call a global helper for checking
|
||
|
that a certain function call triggers a ``DeprecationWarning`` or
|
||
|
``PendingDeprecationWarning``::
|
||
|
|
||
|
import pytest
|
||
|
|
||
|
def test_global():
|
||
|
pytest.deprecated_call(myfunction, 17)
|
||
|
|
||
|
By default, ``DeprecationWarning`` and ``PendingDeprecationWarning`` will not be
|
||
|
caught when using ``pytest.warns`` or ``recwarn`` because default Python warnings filters hide
|
||
|
them. If you wish to record them in your own code, use the
|
||
|
command ``warnings.simplefilter('always')``::
|
||
|
|
||
|
import warnings
|
||
|
import pytest
|
||
|
|
||
|
def test_deprecation(recwarn):
|
||
|
warnings.simplefilter('always')
|
||
|
warnings.warn("deprecated", DeprecationWarning)
|
||
|
assert len(recwarn) == 1
|
||
|
assert recwarn.pop(DeprecationWarning)
|
||
|
|
||
|
You can also use it as a contextmanager::
|
||
|
|
||
|
def test_global():
|
||
|
with pytest.deprecated_call():
|
||
|
myobject.deprecated_method()
|