From eabe3eed6b853b68b54cffe295adaf73be468eef Mon Sep 17 00:00:00 2001 From: Bruno Oliveira Date: Mon, 20 Mar 2017 23:35:01 -0300 Subject: [PATCH] Add docs for the warnings functionality --- doc/en/contents.rst | 2 +- doc/en/customize.rst | 20 ++++ doc/en/recwarn.rst | 143 +--------------------------- doc/en/warnings.rst | 218 +++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 241 insertions(+), 142 deletions(-) create mode 100644 doc/en/warnings.rst diff --git a/doc/en/contents.rst b/doc/en/contents.rst index d7f900810..f6a561839 100644 --- a/doc/en/contents.rst +++ b/doc/en/contents.rst @@ -18,7 +18,7 @@ Full pytest documentation monkeypatch tmpdir capture - recwarn + warnings doctest mark skipping diff --git a/doc/en/customize.rst b/doc/en/customize.rst index c6d3eb473..4421889db 100644 --- a/doc/en/customize.rst +++ b/doc/en/customize.rst @@ -240,3 +240,23 @@ Builtin configuration file options By default, pytest will stop searching for ``conftest.py`` files upwards from ``pytest.ini``/``tox.ini``/``setup.cfg`` of the project if any, 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`. diff --git a/doc/en/recwarn.rst b/doc/en/recwarn.rst index 823ba945b..513af0d45 100644 --- a/doc/en/recwarn.rst +++ b/doc/en/recwarn.rst @@ -1,142 +1,3 @@ -.. _`asserting warnings`: +:orphan: -.. _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 `:: - - 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 ` 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() +This page has been moved, please see :ref:`assertwarnings`. diff --git a/doc/en/warnings.rst b/doc/en/warnings.rst new file mode 100644 index 000000000..ae15e3129 --- /dev/null +++ b/doc/en/warnings.rst @@ -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 `:: + + 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 ` 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()