Use Sphinx doctest with :Example:

Question:

Consider the following function:

# in mymodule.py:

def myfunc(num,mystring):
    """
    replicates a string

    :param num: a positive integer
    :param mystring: a string
    :return: string concatenated with itself num times

    :Example:
        >>> num = 3
        >>> mystring = "lol"
        >>> myfunc(num, mystring)
            "lollollol"
    """
    return num*mystring

How can I make Sphinx doctest work, in order to verify the example code in

:Example:ยด actually does work?
Whenever I run
make doctest`

it says that 3 tests were run, but 1 fails. Deleting the last two rows, starting with

myfunc(num, mystring),

it says that 2 tests were run sucessfully. So I must be doing something wrong with that line. But what?

EDIT Here’s the terminal output (traceback) for the full code; it seems that somehow it can’t find the function for which I’ve written the docstring and I’m running the doctest:

Running Sphinx v1.8.3
loading pickled environment... done
building [mo]: targets for 0 po files that are out of date
building [doctest]: targets for 1 source files that are out of date
updating environment: [] 0 added, 1 changed, 0 removed
reading sources... [100%] index                                                 
looking for now-outdated files... none found
pickling environment... done
checking consistency... done
running tests...

Document: index
---------------
**********************************************************************
File "index.rst", line ?, in default
Failed example:
    myfunc(num, mystring)
Exception raised:
    Traceback (most recent call last):
      File "/usr/lib/python3.6/doctest.py", line 1330, in __run
        compileflags, 1), test.globs)
      File "<doctest default[2]>", line 1, in <module>
        myfunc(num, mystring)
    NameError: name 'myfunc' is not defined
**********************************************************************
1 items had failures:
   1 of   3 in default
3 tests in 1 items.
2 passed and 1 failed.
***Test Failed*** 1 failures.

Doctest summary
===============
    3 tests
    1 failure in tests
    0 failures in setup code
    0 failures in cleanup code
build finished with problems.
Makefile:19: recipe for target 'doctest' failed
Asked By: l7ll7

||

Answers:

On my terminal and outside Sphinx, I have to left align “lollollol” and use simple quotes in order to successfully run doctest:

    :Example:
        >>> num = 3
        >>> mystring = "lol"
        >>> myfunc(num, mystring)
        'lollollol'
Answered By: aflp91

Sphinx+doctest is not importing the module. You can either help him in the docstring:

    :Example:
        >>> from mymodule import myfunc
        >>> myfunc(3, 'lol')
        'lollollol'

or add this in conf.py:

doctest_global_setup = '''
#if required, modif sys.path:
import sys
sys.path.append('../directory_containing_mymodule/')
from mymodule import *
'''

cf. https://www.sphinx-doc.org/en/master/usage/extensions/doctest.html

I’ll be interested to hear if there are simpler answers.

Answered By: Demi-Lune

As Demi-Lune has already said, one needs to add the filepath of your .py files to the conf.py file. But this should not be only passed to the command

doctest_global_setup='''.... import sys'''

but rather add it to the general conf.py Path setup by declaring

import os
import sys
sys.path.insert(0, os.path.abspath('.'))

substituting '.' by your absolute path. (You may also leave the '.' and add your module.py files to the source-folder of your sphinx project. Though I would not recommend this for larger projects.)

Then you only need to declare in the conf.py file

doctest_global_setup='from module import *'

Now you may write in your module.py function

def foo():
   """
   >>>foo()
   ['bar','fafa','bara']
   """
   return ['bar','fafa','bara']

The perk of declaring the path for the whole conf.py file is that other extensions such as autodoc can also detect your module.py. In this case you only need to write in your .rst file

..autofunction:: module.foo()

It will take foo() from module.py and execute the doctest commands.

Answered By: Jakob

I’m pretty sure this kind of example will be correctly found and evaluated by Sybil with this in your conftest.py:

from sybil import Sybil
from sybil.parsers.doctest import DocTestParser

pytest_collect_file = Sybil(
    parsers=[DocTestParser()],
    patterns=['*.py'],
).pytest()
Answered By: Chris Withers
Categories: questions Tags: , ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.