0p3r4t0r
0p3r4t0r

Reputation: 693

How do I run a doctest from Cython?

The Setup

  1. Let's say I have a script fib.py. With some doctests in it.

    def fib(n):
        """Return the nth number in the Fibonacci sequence.
    
        >>> fib(0)
        0.0
        >>> fib(1)
        1.0
        >>> fib(4)
        3.0
        >>> fib(7)
        13.0
        """
        a, b = 0.0, 1.0
        for i in range(n):
            a, b = a + b, a
        return a
    
    if __name__ == "__main__":
        import doctest
        doctest.testmod()
    

    Everything works as expected and I can confirm that the tests are running by checking the output of python3 fib.py -v.

  2. Alright, now I'm going to translate this into Cython, and for good measure I'll even remove the if __name__ == '__main__' conditional. Let's call our Cython file fib.pyx

    #cython: language_level=3
    
    def fib(int n):
        """Return the nth number in the Fibonacci sequence.
    
        >>> fib(0)
        0.0
        >>> fib(1)
        1.0
        >>> fib(4)
        3.0
        >>> fib(7)
        13.0
        """
        cdef int i
        cdef double a=0.0, b=1.0
        for i in range(n):
            a, b = a + b, a
        return a
    
    import doctest
    doctest.testmod()
    
  3. Of course we need to compile our Cython. For me that's

    cython --embed fib.pyx
    gcc $(python-config --cflags) $(python-config --ldflags) fib.c
    

    This produces a.out.

  4. If I try ./a.out -v I get . . .

    1 items had no tests:
        __main__
    0 tests in 1 items.
    0 passed and 0 failed.
    Test passed.
    

What happened to my tests?

(Potentially) helpful links.

Upvotes: 1

Views: 244

Answers (1)

0p3r4t0r
0p3r4t0r

Reputation: 693

Alright, there were a few problems here . . .

First I wasn't really compiling properly. The final result should be a .so file on MacOs/Linux systems and a .pyd file on linux.

Building a Cython module

You can quickly compile by writing a setup.py file

from distutils.core import setup
from Cython.Build import cythonize

setup(ext_modules=cythonize('fib.pyx'))

Depending on your OS and python version running

python setup.py build_ext --inplace

will produce something like fib.cpython-37m-x86_64-linux-gnu.so

For more info see the relevant Cython docs.

Install pytest modules

pip install pytest
pip install pytest-cython

Running the tests

From the directory where your compiled Cython lives run . . .

pytest --doctest-cython -v

The -v is of course verbose and provides additional output.

From pytest --help | grep cython we can see what this command is doing.

cython:
  --doctest-cython      run doctests in all .so and .pyd modules
  --cython-ignore-import-errors

Upvotes: 1

Related Questions