yakazimir / simple-cython-example

A small project template that shows how to wrap C code into python using cython, along with other packaging concepts

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

simple-cython-example

Build Status

A small template project that acts as a working tutorial on how to wrap C code into python using cython, and integrate the extensions into an installable module. Developed around python 2.7, but written for compatibility with python 3.x.

A cython pyx file is included that implements a few C functions which can accept and return standard python data types and numpy ndarrays. These are compiled, wrapped, and integrated into the module using a standard setup.py script.

In addition to concrete examples of cython syntax, this repo also illustrates a working project structure with a working setup.py configuration (using setuptools) for Python projects with C extension modules, along with basic unit tests (together with a working Travis-CI config).

Building

First, install numpy and cython (using pip or from a package manager) if you don't already have them.

Then just run python setup.py develop to build the project in-place.

The module (with its wrapped C functions c_hello, factorial, array_sum, and tessellation) will then be importable in python:

>>> from cython_example_proj import c_hello, factorial, array_sum, tessellation

Testing

The unit test file test_cython_examples.py can be run directly, or (if you have nose installed), can be run automatically by running nosetests in the top level directory.

Automated testing is peformed with Travis CI, a free service that integrates with github and tests this library on python versions 2.7 and 3.2. All that is required for this is to commit a .travis.yml configuration file and mark the repository for testing in your Travis CI account.

Then, each time you push a branch to github, tests will be executed automatically. The results of the tests can be e-mailed to you. The results of the latest test will be shown at the bottom of every pull request forked from your repository, and will be reflected in any build status images you embed (like this one: Build Status).

Wrapped example functions

4 examples functions are defined in wrapped.pyx:

  • A direct wrapping of a simple C "hello world" function, implemented in cfunc.c
  • A C function to compute the factorial of a python integer, built using Cython syntax
  • A C function to compute the sum of a numpy ndarray
  • A C function to compute and return the tessellation structure (ndarray) of the pixels of an inputted digital image (ndarray). This is a re-implementation of first half of the main method used in the STL Tools library.

Benchmarks

For a quick benchmark of the two ndarray functions listed, run python timings.py. This will show timings of the wrapped C functions vs. numpy+python and/or pure python implementations of the same functions.

-----------------------------------------------------------
Initialized array for sum; starting comparison:
-----------------------------------------------------------
cython finished : 0.0239799022675 s
numpy finished : 0.024649143219 s
python finished : 14.2366518974 s

-----------------------------------------------------------
Initialized array for tessellate; starting comparison:
-----------------------------------------------------------
cython finished : 0.3423628807067871 s
python+numpy finished : 48.1245310307 s

So the cython-generated C implementation of array_sum is on parity with numpy.sum, and are are each much faster than the pure python implementation.

The C implementation of tessellate is much faster than the python+numpy implementation. Using this information, I've written a complete c-extension for STL Tools.

Profiling function

If you're interested in possibily rewriting some or part of a module as a compiled extension, you should profile the execution of your module first. The Python standard library module cProfile can help you with this.

Unfortunately, sorting the output of cProfile using their API leaves a few options to be desired. Namely: sorting by percall time (cumtime divided by ncalls).

profile.py shows an example of a work-around to this. Re-define the f() function to execute functions from your library, and a profile will be printed, broken down by function, that is sorted by percall.

About

A small project template that shows how to wrap C code into python using cython, along with other packaging concepts


Languages

Language:Python 98.8%Language:C 1.2%