diff options
author | Vasudev Kamath <vasudev@copyninja.info> | 2016-06-26 20:30:11 +0530 |
---|---|---|
committer | Vasudev Kamath <vasudev@copyninja.info> | 2016-06-26 20:30:11 +0530 |
commit | bd10a8ff50d9d2408712f2751ad3f3fb2a2dd1fc (patch) | |
tree | e991250bf947c6ac5431d7bc04020cb6ba5ed945 /content/development | |
parent | fab28b782b745a25a844ad452402f18688a2fcb8 (diff) |
Added post on integrating Cython with setuptools
Diffstat (limited to 'content/development')
-rw-r--r-- | content/development/integrate_cython_setuptools.rst | 143 |
1 files changed, 143 insertions, 0 deletions
diff --git a/content/development/integrate_cython_setuptools.rst b/content/development/integrate_cython_setuptools.rst new file mode 100644 index 0000000..04fa94d --- /dev/null +++ b/content/development/integrate_cython_setuptools.rst @@ -0,0 +1,143 @@ +Integrating Cython extension with setuptools and unit testing +############################################################# + +:date: 2016-06-26 19:54 +0530 +:slug: cython_setuptools +:tags: python, cython, setuptools, pbr +:author: copyninja +:summary: This post describes how to integrate a cython extension with + setuptools. + + +I was reviewing changes for `indic-trans +<https://github.com/libindic/indic-trans>`_ as part of GSoC 2016. The +module is an improvisation for our original transliteration module +which was doing its job by substitution. + +This new module uses machine learning of some sort and utilizes +*Cython*, *numpy* and *scipy*. Student had kept pre-compiled shared +library in the git tree to make sure it builds and passes the +test. But this was not correct way. I started looking at way to build +these files and remove it from the code base. + +There is a `cython documentation +<http://docs.cython.org/src/quickstart/build.html>`_ for distutils but +none for setuptools. Probably it is similar to other Python extension +integration into setuptools, but this was first time for me so after a +bit of searching and trial and error below is what I did. + +We need to use `Extensions` class from setuptools and give it path to +modules we want to build. In my case `beamsearch` and `viterbi` are 2 +modules. So I added following lines to setup.py + +.. code-block:: python + + from setuptools.extension import Extension + from Cython.Build import cythonize + + extensions = [ + Extension( + "indictrans._decode.beamsearch", + [ + "indictrans/_decode/beamsearch.pyx" + ], + include_dirs=[numpy.get_include()] + ), + Extension( + "indictrans._decode.viterbi", + [ + "indictrans/_decode/viterbi.pyx" + ], + include_dirs=[numpy.get_include()] + ) + + ] + +First argument to `Extensions` is the module name and second argument +is a list of files to be used in building the module. The additional +`inculde_dirs` argument is not normally necessary unless you are +working in virtualenv. In my system the build used to work without +this but it was failing in Travis CI, so added it to fix the CI +builds. OTOH it did work without this on Circle CI. + +Next is provide this `extensions` to `ext_modules` argument to `setup` +as shown below + +.. code-block:: python + + setup( + setup_requires=['pbr'], + pbr=True, + ext_modules=cythonize(extensions) + ) + +And for the reference here is full setup.py after modifications. + +.. code-block:: python + + #!/usr/bin/env python + + from setuptools import setup + from setuptools.extension import Extension + from Cython.Build import cythonize + + import numpy + + + extensions = [ + Extension( + "indictrans._decode.beamsearch", + [ + "indictrans/_decode/beamsearch.pyx" + ], + include_dirs=[numpy.get_include()] + ), + Extension( + "indictrans._decode.viterbi", + [ + "indictrans/_decode/viterbi.pyx" + ], + include_dirs=[numpy.get_include()] + ) + ] + + setup( + setup_requires=['pbr'], + pbr=True, + ext_modules=cythonize(extensions) + ) + +So now we can build the extensions (shared library) using following +command. + +.. code-block:: shell + + python setup.py build_ext + +Another challenge I faced was missing extension when running test. We +use pbr in above project and testrepository with subunit for running +tests. Looks like it does not build extensions by default so I +modified the Makefile to build the extension in place before running +test. The `travis` target of my Makefile is as follows. + +.. code-block:: make + + travis: + [ ! -d .testrepository ] || \ + find .testrepository -name "times.dbm*" -delete + python setup.py build_ext -i + python setup.py test --coverage \ + --coverage-package-name=indictrans + flake8 --max-complexity 10 indictrans + +I had to build the extension in place using `-i` switch. This is +because other wise the tests won't find the +`indictrans._decode.beamsearch` and `indictrans._decode.viterbi +modules`. What basically `-i` switch does is after building shared +library symlinks it to the module directory, in ourcase +`indictrans._decode` + +The test for existence of .testrepository folder is over come `this +bug <https://bugs.launchpad.net/testrepository/+bug/1229445>`_ in +testrepository which results in test failure when running tests using +`tox`. |