Hi again,

I am just wondering how to do unit testing on extensions built using
Cython with py.test.

My problem: The extension module I am working on is installed in our
global python environment (inside the build slaves as well as on local
machines) already. Before installing a new version of the extension
module, I'd like to run the unit tests. However, that way the original
module is tested.

I am trying to illustrate.

Doing TDD I create a new module which will fail the test:


    torsten@sharokan:~/foo$ cat foo.pyx
    def it_works():
        return False

    torsten@sharokan:~/foo$ cat tests/test_foo.py
    import pprint, foo

    def test_foo():
        pprint.pprint(foo.__file__)
        assert foo.it_works()

    torsten@sharokan:~/foo$ py.test -v tests
    ============================================================ test
    session starts
    ============================================================
    platform linux2 -- Python 2.7.3 -- pytest-2.3.4 --
    /opt/dynasdk/loco2-precise/bin/python
    plugins: cov, capturelog
    collected 0 items / 1 errors

    ==================================================================
    ERRORS
    ===================================================================
    ____________________________________________________ ERROR
    collecting tests/test_foo.py
    _____________________________________________________
    tests/test_foo.py:1: in <module>
    >   import sys, pprint, foo
    E   ImportError: No module named foo
    ========================================================== 1 error
    in 0.01 seconds
    ==========================================================

Sure, module foo does not exists. I could use pyximport, but I want to
check that the extension itself is correctly built.
Easily done:

    torsten@sharokan:~/foo$ python setup.py build_ext -i
    running build_ext
    cythoning foo.pyx to foo.c
    building 'foo' extension
    creating build
    creating build/temp.linux-x86_64-2.7
    gcc -pthread -fno-strict-aliasing -g -O2 -DNDEBUG -g -fwrapv -O3
    -Wall -Wstrict-prototypes -fPIC
    -I/opt/dynasdk/loco2-precise/include/python2.7 -c foo.c -o
    build/temp.linux-x86_64-2.7/foo.o
    gcc -pthread -shared build/temp.linux-x86_64-2.7/foo.o
    -L/opt/dynasdk/loco2-precise/lib -lpython2.7 -o /home/torsten/foo/foo.so

But alas, py.test still will not find foo.so, which is now installed
into the current directory (due to using the "-i" flag to build_ext).
Workaround: Overwrite PYTHONPATH:

    torsten@sharokan:~/foo$ PYTHONPATH=`pwd` py.test
    ============================================================ test
    session starts
    ============================================================
    platform linux2 -- Python 2.7.3 -- pytest-2.3.4
    plugins: cov, capturelog
    collected 1 items

    tests/test_foo.py F

    =================================================================
    FAILURES
    ==================================================================
    _________________________________________________________________
    test_foo
    __________________________________________________________________

        def test_foo():
            pprint.pprint(foo.__file__)
    >       assert foo.it_works()
    E       assert <built-in function it_works>()
    E        +  where <built-in function it_works> = foo.it_works

    tests/test_foo.py:5: AssertionError
    --------------------------------------------------------------
    Captured stdout
    --------------------------------------------------------------
    '/home/torsten/foo/foo.so'
    ========================================================= 1 failed
    in 0.02 seconds
    ==========================================================

Now it really loads our extension module and the failure is actually
genuine. Let's assume we have the old version installed in our current
Python environment:

    torsten@sharokan:~/foo$ python setup.py install
    [...]
    creating
    
/usr/opt/dynasdk/loco2-precise/lib/python2.7/site-packages/foo-0.0-py2.7-linux-x86_64.egg
    Extracting foo-0.0-py2.7-linux-x86_64.egg to
    /usr/opt/dynasdk/loco2-precise/lib/python2.7/site-packages
    Adding foo 0.0 to easy-install.pth file

    Installed
    
/usr/opt/dynasdk/loco2-precise/lib/python2.7/site-packages/foo-0.0-py2.7-linux-x86_64.egg
    [...]

Great. Now let's implement the feature that our test checks:

    torsten@sharokan:~/foo$ vim foo.pyx
    torsten@sharokan:~/foo$ cat foo.pyx
    def it_works():
        return True

The unit tests should pass now, after we rebuilt the extension:

    torsten@sharokan:~/foo$ python setup.py build_ext -i
    running build_ext
    cythoning foo.pyx to foo.c
    building 'foo' extension
    gcc -pthread -fno-strict-aliasing -g -O2 -DNDEBUG -g -fwrapv -O3
    -Wall -Wstrict-prototypes -fPIC
    -I/opt/dynasdk/loco2-precise/include/python2.7 -c foo.c -o
    build/temp.linux-x86_64-2.7/foo.o
    gcc -pthread -shared build/temp.linux-x86_64-2.7/foo.o
    -L/opt/dynasdk/loco2-precise/lib -lpython2.7 -o /home/torsten/foo/foo.so
    torsten@sharokan:~/foo$ PYTHONPATH=`pwd` py.test
    ============================================================ test
    session starts
    ============================================================
    platform linux2 -- Python 2.7.3 -- pytest-2.3.4
    plugins: cov, capturelog
    collected 1 items

    tests/test_foo.py F

    =================================================================
    FAILURES
    ==================================================================
    _________________________________________________________________
    test_foo
    __________________________________________________________________

        def test_foo():
            pprint.pprint(foo.__file__)
    >       assert foo.it_works()
    E       assert <built-in function it_works>()
    E        +  where <built-in function it_works> = foo.it_works

    tests/test_foo.py:5: AssertionError
    --------------------------------------------------------------
    Captured stdout
    --------------------------------------------------------------
    
'/opt/dynasdk/loco2-precise/lib/python2.7/site-packages/foo-0.0-py2.7-linux-x86_64.egg/foo.so'
    ========================================================= 1 failed
    in 0.02 seconds
    ==========================================================

Unfortunately, it doesn't. The unit tests actually uses the installed
version of the library, which we only want to replace after our tests pass.

Let's try it another way: By creating a virtualenv just for our tests,
we should be fine:

    torsten@sharokan:~/foo$ virtualenv --system-site-packages fooenv
    New python executable in fooenv/bin/python
    Please make sure you remove any previous custom paths from your
    /home/torsten/.pydistutils.cfg file.
    Installing setuptools............done.
    Installing pip...............done.
    torsten@sharokan:~/foo$ . fooenv/bin/activate
    (fooenv)torsten@sharokan:~/foo$ pip install --upgrade .
    Unpacking /home/torsten/foo
      Running setup.py egg_info for package from file:///home/torsten/foo
       
    Downloading/unpacking Cython from
    
http://pypi.python.org/packages/source/C/Cython/Cython-0.19.tar.gz#md5=76989337dee4cf7afdcb5cde514423f8
    (from foo==0.0)
      Downloading Cython-0.19.tar.gz (1.4MB): 270kB downloaded
    ...

Good start, but I don't want to recreate the whole thing inside the
virtualenv fooenv. This would pull Cython, numpy, scipy, paramiko and more.

Any hint how to ensure that we are testing the local version of that
extension instead of the installed one?

Thanks, Torsten

-- 
DYNAmore Gesellschaft fuer Ingenieurdienstleistungen mbH
Torsten Landschoff

Office Dresden
Tel: +49-(0)351-4519587
Fax: +49-(0)351-4519561

mailto:torsten.landsch...@dynamore.de
http://www.dynamore.de

DYNAmore Gesellschaft für FEM Ingenieurdienstleistungen mbH
Registration court: Stuttgart, HRB 733694
Managing director: Prof. Dr. Karl Schweizerhof, Dipl.-Math. Ulrich Franz

_______________________________________________
cython-devel mailing list
cython-devel@python.org
http://mail.python.org/mailman/listinfo/cython-devel

Reply via email to