Add docs for the warnings functionality
This commit is contained in:
parent
fa56114115
commit
eabe3eed6b
|
@ -18,7 +18,7 @@ Full pytest documentation
|
||||||
monkeypatch
|
monkeypatch
|
||||||
tmpdir
|
tmpdir
|
||||||
capture
|
capture
|
||||||
recwarn
|
warnings
|
||||||
doctest
|
doctest
|
||||||
mark
|
mark
|
||||||
skipping
|
skipping
|
||||||
|
|
|
@ -240,3 +240,23 @@ Builtin configuration file options
|
||||||
By default, pytest will stop searching for ``conftest.py`` files upwards
|
By default, pytest will stop searching for ``conftest.py`` files upwards
|
||||||
from ``pytest.ini``/``tox.ini``/``setup.cfg`` of the project if any,
|
from ``pytest.ini``/``tox.ini``/``setup.cfg`` of the project if any,
|
||||||
or up to the file-system root.
|
or up to the file-system root.
|
||||||
|
|
||||||
|
|
||||||
|
.. confval:: filterwarnings
|
||||||
|
|
||||||
|
.. versionadded:: 3.1
|
||||||
|
|
||||||
|
Sets a list of filters and actions that should be taken for matched
|
||||||
|
warnings. By default all warnings emitted during the test session
|
||||||
|
will be displayed in a summary at the end of the test session.
|
||||||
|
|
||||||
|
.. code-block:: ini
|
||||||
|
|
||||||
|
# content of pytest.ini
|
||||||
|
[pytest]
|
||||||
|
filterwarnings =
|
||||||
|
error
|
||||||
|
ignore::DeprecationWarning
|
||||||
|
|
||||||
|
This tells pytest to ignore deprecation warnings and turn all other warnings
|
||||||
|
into errors. For more information please refer to :ref:`warnings`.
|
||||||
|
|
|
@ -1,142 +1,3 @@
|
||||||
.. _`asserting warnings`:
|
:orphan:
|
||||||
|
|
||||||
.. _assertwarnings:
|
This page has been moved, please see :ref:`assertwarnings`.
|
||||||
|
|
||||||
Asserting Warnings
|
|
||||||
=====================================================
|
|
||||||
|
|
||||||
.. _`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()
|
|
||||||
|
|
|
@ -0,0 +1,218 @@
|
||||||
|
.. _`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()
|
Loading…
Reference in New Issue