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:[email protected]
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
[email protected]
http://mail.python.org/mailman/listinfo/cython-devel