315 lines
		
	
	
		
			9.3 KiB
		
	
	
	
		
			ReStructuredText
		
	
	
	
			
		
		
	
	
			315 lines
		
	
	
		
			9.3 KiB
		
	
	
	
		
			ReStructuredText
		
	
	
	
.. _doctest:
 | 
						|
 | 
						|
How to run doctests
 | 
						|
=========================================================
 | 
						|
 | 
						|
By default, all files matching the ``test*.txt`` pattern will
 | 
						|
be run through the python standard :mod:`doctest` module.  You
 | 
						|
can change the pattern by issuing:
 | 
						|
 | 
						|
.. code-block:: bash
 | 
						|
 | 
						|
    pytest --doctest-glob="*.rst"
 | 
						|
 | 
						|
on the command line. ``--doctest-glob`` can be given multiple times in the command-line.
 | 
						|
 | 
						|
If you then have a text file like this:
 | 
						|
 | 
						|
.. code-block:: text
 | 
						|
 | 
						|
    # content of test_example.txt
 | 
						|
 | 
						|
    hello this is a doctest
 | 
						|
    >>> x = 3
 | 
						|
    >>> x
 | 
						|
    3
 | 
						|
 | 
						|
then you can just invoke ``pytest`` directly:
 | 
						|
 | 
						|
.. code-block:: pytest
 | 
						|
 | 
						|
    $ pytest
 | 
						|
    =========================== test session starts ============================
 | 
						|
    platform linux -- Python 3.x.y, pytest-8.x.y, pluggy-1.x.y
 | 
						|
    rootdir: /home/sweet/project
 | 
						|
    collected 1 item
 | 
						|
 | 
						|
    test_example.txt .                                                   [100%]
 | 
						|
 | 
						|
    ============================ 1 passed in 0.12s =============================
 | 
						|
 | 
						|
By default, pytest will collect ``test*.txt`` files looking for doctest directives, but you
 | 
						|
can pass additional globs using the ``--doctest-glob`` option (multi-allowed).
 | 
						|
 | 
						|
In addition to text files, you can also execute doctests directly from docstrings of your classes
 | 
						|
and functions, including from test modules:
 | 
						|
 | 
						|
.. code-block:: python
 | 
						|
 | 
						|
    # content of mymodule.py
 | 
						|
    def something():
 | 
						|
        """a doctest in a docstring
 | 
						|
        >>> something()
 | 
						|
        42
 | 
						|
        """
 | 
						|
        return 42
 | 
						|
 | 
						|
.. code-block:: bash
 | 
						|
 | 
						|
    $ pytest --doctest-modules
 | 
						|
    =========================== test session starts ============================
 | 
						|
    platform linux -- Python 3.x.y, pytest-8.x.y, pluggy-1.x.y
 | 
						|
    rootdir: /home/sweet/project
 | 
						|
    collected 2 items
 | 
						|
 | 
						|
    mymodule.py .                                                        [ 50%]
 | 
						|
    test_example.txt .                                                   [100%]
 | 
						|
 | 
						|
    ============================ 2 passed in 0.12s =============================
 | 
						|
 | 
						|
You can make these changes permanent in your project by
 | 
						|
putting them into a pytest.ini file like this:
 | 
						|
 | 
						|
.. code-block:: ini
 | 
						|
 | 
						|
    # content of pytest.ini
 | 
						|
    [pytest]
 | 
						|
    addopts = --doctest-modules
 | 
						|
 | 
						|
 | 
						|
Encoding
 | 
						|
--------
 | 
						|
 | 
						|
The default encoding is **UTF-8**, but you can specify the encoding
 | 
						|
that will be used for those doctest files using the
 | 
						|
``doctest_encoding`` ini option:
 | 
						|
 | 
						|
.. code-block:: ini
 | 
						|
 | 
						|
    # content of pytest.ini
 | 
						|
    [pytest]
 | 
						|
    doctest_encoding = latin1
 | 
						|
 | 
						|
.. _using doctest options:
 | 
						|
 | 
						|
Using 'doctest' options
 | 
						|
-----------------------
 | 
						|
 | 
						|
Python's standard :mod:`doctest` module provides some :ref:`options <python:option-flags-and-directives>`
 | 
						|
to configure the strictness of doctest tests. In pytest, you can enable those flags using the
 | 
						|
configuration file.
 | 
						|
 | 
						|
For example, to make pytest ignore trailing whitespaces and ignore
 | 
						|
lengthy exception stack traces you can just write:
 | 
						|
 | 
						|
.. code-block:: ini
 | 
						|
 | 
						|
    [pytest]
 | 
						|
    doctest_optionflags = NORMALIZE_WHITESPACE IGNORE_EXCEPTION_DETAIL
 | 
						|
 | 
						|
Alternatively, options can be enabled by an inline comment in the doc test
 | 
						|
itself:
 | 
						|
 | 
						|
.. code-block:: rst
 | 
						|
 | 
						|
    >>> something_that_raises()  # doctest: +IGNORE_EXCEPTION_DETAIL
 | 
						|
    Traceback (most recent call last):
 | 
						|
    ValueError: ...
 | 
						|
 | 
						|
pytest also introduces new options:
 | 
						|
 | 
						|
* ``ALLOW_UNICODE``: when enabled, the ``u`` prefix is stripped from unicode
 | 
						|
  strings in expected doctest output. This allows doctests to run in Python 2
 | 
						|
  and Python 3 unchanged.
 | 
						|
 | 
						|
* ``ALLOW_BYTES``: similarly, the ``b`` prefix is stripped from byte strings
 | 
						|
  in expected doctest output.
 | 
						|
 | 
						|
* ``NUMBER``: when enabled, floating-point numbers only need to match as far as
 | 
						|
  the precision you have written in the expected doctest output. The numbers are
 | 
						|
  compared using :func:`pytest.approx` with relative tolerance equal to the
 | 
						|
  precision. For example, the following output would only need to match to 2
 | 
						|
  decimal places when comparing ``3.14`` to
 | 
						|
  ``pytest.approx(math.pi, rel=10**-2)``::
 | 
						|
 | 
						|
      >>> math.pi
 | 
						|
      3.14
 | 
						|
 | 
						|
  If you wrote ``3.1416`` then the actual output would need to match to
 | 
						|
  approximately 4 decimal places; and so on.
 | 
						|
 | 
						|
  This avoids false positives caused by limited floating-point precision, like
 | 
						|
  this::
 | 
						|
 | 
						|
      Expected:
 | 
						|
          0.233
 | 
						|
      Got:
 | 
						|
          0.23300000000000001
 | 
						|
 | 
						|
  ``NUMBER`` also supports lists of floating-point numbers -- in fact, it
 | 
						|
  matches floating-point numbers appearing anywhere in the output, even inside
 | 
						|
  a string! This means that it may not be appropriate to enable globally in
 | 
						|
  ``doctest_optionflags`` in your configuration file.
 | 
						|
 | 
						|
  .. versionadded:: 5.1
 | 
						|
 | 
						|
 | 
						|
Continue on failure
 | 
						|
-------------------
 | 
						|
 | 
						|
By default, pytest would report only the first failure for a given doctest. If
 | 
						|
you want to continue the test even when you have failures, do:
 | 
						|
 | 
						|
.. code-block:: bash
 | 
						|
 | 
						|
    pytest --doctest-modules --doctest-continue-on-failure
 | 
						|
 | 
						|
 | 
						|
Output format
 | 
						|
-------------
 | 
						|
 | 
						|
You can change the diff output format on failure for your doctests
 | 
						|
by using one of standard doctest modules format in options
 | 
						|
(see :data:`python:doctest.REPORT_UDIFF`, :data:`python:doctest.REPORT_CDIFF`,
 | 
						|
:data:`python:doctest.REPORT_NDIFF`, :data:`python:doctest.REPORT_ONLY_FIRST_FAILURE`):
 | 
						|
 | 
						|
.. code-block:: bash
 | 
						|
 | 
						|
    pytest --doctest-modules --doctest-report none
 | 
						|
    pytest --doctest-modules --doctest-report udiff
 | 
						|
    pytest --doctest-modules --doctest-report cdiff
 | 
						|
    pytest --doctest-modules --doctest-report ndiff
 | 
						|
    pytest --doctest-modules --doctest-report only_first_failure
 | 
						|
 | 
						|
 | 
						|
pytest-specific features
 | 
						|
------------------------
 | 
						|
 | 
						|
Some features are provided to make writing doctests easier or with better integration with
 | 
						|
your existing test suite. Keep in mind however that by using those features you will make
 | 
						|
your doctests incompatible with the standard ``doctests`` module.
 | 
						|
 | 
						|
Using fixtures
 | 
						|
^^^^^^^^^^^^^^
 | 
						|
 | 
						|
It is possible to use fixtures using the ``getfixture`` helper:
 | 
						|
 | 
						|
.. code-block:: text
 | 
						|
 | 
						|
    # content of example.rst
 | 
						|
    >>> tmp = getfixture('tmp_path')
 | 
						|
    >>> ...
 | 
						|
    >>>
 | 
						|
 | 
						|
Note that the fixture needs to be defined in a place visible by pytest, for example, a `conftest.py`
 | 
						|
file or plugin; normal python files containing docstrings are not normally scanned for fixtures
 | 
						|
unless explicitly configured by :confval:`python_files`.
 | 
						|
 | 
						|
Also, the :ref:`usefixtures <usefixtures>` mark and fixtures marked as :ref:`autouse <autouse>` are supported
 | 
						|
when executing text doctest files.
 | 
						|
 | 
						|
 | 
						|
.. _`doctest_namespace`:
 | 
						|
 | 
						|
'doctest_namespace' fixture
 | 
						|
^^^^^^^^^^^^^^^^^^^^^^^^^^^
 | 
						|
 | 
						|
The ``doctest_namespace`` fixture can be used to inject items into the
 | 
						|
namespace in which your doctests run. It is intended to be used within
 | 
						|
your own fixtures to provide the tests that use them with context.
 | 
						|
 | 
						|
``doctest_namespace`` is a standard ``dict`` object into which you
 | 
						|
place the objects you want to appear in the doctest namespace:
 | 
						|
 | 
						|
.. code-block:: python
 | 
						|
 | 
						|
    # content of conftest.py
 | 
						|
    import numpy
 | 
						|
 | 
						|
 | 
						|
    @pytest.fixture(autouse=True)
 | 
						|
    def add_np(doctest_namespace):
 | 
						|
        doctest_namespace["np"] = numpy
 | 
						|
 | 
						|
which can then be used in your doctests directly:
 | 
						|
 | 
						|
.. code-block:: python
 | 
						|
 | 
						|
    # content of numpy.py
 | 
						|
    def arange():
 | 
						|
        """
 | 
						|
        >>> a = np.arange(10)
 | 
						|
        >>> len(a)
 | 
						|
        10
 | 
						|
        """
 | 
						|
 | 
						|
Note that like the normal ``conftest.py``, the fixtures are discovered in the directory tree conftest is in.
 | 
						|
Meaning that if you put your doctest with your source code, the relevant conftest.py needs to be in the same directory tree.
 | 
						|
Fixtures will not be discovered in a sibling directory tree!
 | 
						|
 | 
						|
Skipping tests
 | 
						|
^^^^^^^^^^^^^^
 | 
						|
 | 
						|
For the same reasons one might want to skip normal tests, it is also possible to skip
 | 
						|
tests inside doctests.
 | 
						|
 | 
						|
To skip a single check inside a doctest you can use the standard
 | 
						|
:data:`doctest.SKIP` directive:
 | 
						|
 | 
						|
.. code-block:: python
 | 
						|
 | 
						|
    def test_random(y):
 | 
						|
        """
 | 
						|
        >>> random.random()  # doctest: +SKIP
 | 
						|
        0.156231223
 | 
						|
 | 
						|
        >>> 1 + 1
 | 
						|
        2
 | 
						|
        """
 | 
						|
 | 
						|
This will skip the first check, but not the second.
 | 
						|
 | 
						|
pytest also allows using the standard pytest functions :func:`pytest.skip` and
 | 
						|
:func:`pytest.xfail` inside doctests, which might be useful because you can
 | 
						|
then skip/xfail tests based on external conditions:
 | 
						|
 | 
						|
 | 
						|
.. code-block:: text
 | 
						|
 | 
						|
    >>> import sys, pytest
 | 
						|
    >>> if sys.platform.startswith('win'):
 | 
						|
    ...     pytest.skip('this doctest does not work on Windows')
 | 
						|
    ...
 | 
						|
    >>> import fcntl
 | 
						|
    >>> ...
 | 
						|
 | 
						|
However using those functions is discouraged because it reduces the readability of the
 | 
						|
docstring.
 | 
						|
 | 
						|
.. note::
 | 
						|
 | 
						|
    :func:`pytest.skip` and :func:`pytest.xfail` behave differently depending
 | 
						|
    if the doctests are in a Python file (in docstrings) or a text file containing
 | 
						|
    doctests intermingled with text:
 | 
						|
 | 
						|
    * Python modules (docstrings): the functions only act in that specific docstring,
 | 
						|
      letting the other docstrings in the same module execute as normal.
 | 
						|
 | 
						|
    * Text files: the functions will skip/xfail the checks for the rest of the entire
 | 
						|
      file.
 | 
						|
 | 
						|
 | 
						|
Alternatives
 | 
						|
------------
 | 
						|
 | 
						|
While the built-in pytest support provides a good set of functionalities for using
 | 
						|
doctests, if you use them extensively you might be interested in those external packages
 | 
						|
which add many more features, and include pytest integration:
 | 
						|
 | 
						|
* `pytest-doctestplus <https://github.com/astropy/pytest-doctestplus>`__: provides
 | 
						|
  advanced doctest support and enables the testing of reStructuredText (".rst") files.
 | 
						|
 | 
						|
* `Sybil <https://sybil.readthedocs.io>`__: provides a way to test examples in
 | 
						|
  your documentation by parsing them from the documentation source and evaluating
 | 
						|
  the parsed examples as part of your normal test run.
 |