• Stars
    star
    115
  • Rank 304,151 (Top 7 %)
  • Language
    Python
  • License
    Other
  • Created over 9 years ago
  • Updated over 8 years ago

Reviews

There are no reviews yet. Be the first to send feedback to the community and the maintainers!

Repository Details

A simple example Python + CFFI package (including testing, development, and packaging)

cffi-example: an example project showing how to use Python's CFFI

A complete project which demonstrates how to use CFFI 1.0 during development of a modern Python package:

  • Development
  • Testing across Python interpreters (Py2, Py3, PyPy)
  • Packaging and distribution

Status

This repository is the result of a weeks worth of frustrated googling. I don't think anything is too misleading, but I would deeply appreciate feedback from anyone who actually knows what's going on.

Examples

  • cffi_example/person.py and cffi_example/build_person.py is an example of a Python class which wraps a C class, including proper memory management and passing around string buffers:

    >>> p = Person(u"Alex", u"Smith", 72) # --> calls person_create(...)
    >>> p.get_full_name() # --> calls person_get_full_name(p, buf, len(buf))
    u"Alex Smith"
    
  • cffi_example/fnmatch.py and cffi_example/build_fnmatch.py is an example of wrapping a shared library (in this case libc's fnmatch):

    >>> fnmatch("f*", "foo") # --> calls libc's fnmatch
    True
    

Development

  1. Clone the repository:

    $ git clone [email protected]:wolever/python-cffi-example.git
    
  2. Make sure that cffi, py.test, and tox are installed:

    $ pip install -r requirements-testing.txt
    
  3. Run python setup.py develop to build development versions of the modules:

    $ python setup.py develop
    ...
    Finished processing dependencies for cffi-example==0.1
    
  4. Test locally with py.test:

    $ py.test test/
    =========================== test session starts ===========================
    platform darwin -- Python 2.7.2 -- py-1.4.28 -- pytest-2.7.1
    rootdir: /Users/wolever/code/python-cffi-example, inifile:
    collected 7 items
    
    test/test_fnmatch.py ....
    test/test_person.py ...
    
    ======================== 7 passed in 0.03 seconds =========================
    
  5. Test against multiple Python environments using tox:

    $ tox
    ...
    _________________________________ summary _________________________________
    py26: commands succeeded
    py27: commands succeeded
    py33: commands succeeded
    pypy: commands succeeded
    congratulations :)
    
  6. I prefer to use make to clean and rebuild libraries during development (since it's faster than setup.py develop):

    $ make clean
    ...
    $ make
    python cffi_example/build_person.py
    python cffi_example/build_fnmatch.py
    

Packaging

This example uses CFFI's recommended combination of setuptools and cffi_modules:

$ cat setup.py
from setuptools import setup

setup(
    ...
    install_requires=["cffi>=1.0.0"],
    setup_requires=["cffi>=1.0.0"],
    cffi_modules=[
        "./cffi_example/build_person.py:ffi",
        "./cffi_example/build_fnmatch.py:ffi",
    ],
)

This will cause the modules to be built with setup.py develop or setup.py build, and installed with setup.py install.

Note: Many examples you'll see online use either the distutils ext_modules=[cffi_example.ffi.distribute_extension()] method, or the more complex keywords_with_side_effects method. To the best of my knowledge these methods are only necessary with CFFI < 1.0 or distutils. dstufft has written a fantastic post — https://caremad.io/2014/11/distributing-a-cffi-project/ — which details the drawbacks of the ext_modules method and explains the keywords_with_side_effects method, but I believe it was written before CFFI 1.0 so it does not include the now preferred cffi_modules method.

Distribution

Distribution is just like any other Python package, with the obvious caveat that wheels will be platform-specific:

$ python setup.py sdist bdist_wheel
...
$ ls dist/
cffi-example-0.1.tar.gz
cffi_example-0.1-cp27-none-macosx_10_8_intel.whl

And the package can be uploaded to PyPI using upload:

$ python setup.py sdist upload

Note that users of the source package will need to have cffi (and a C compiler, and development headers of any libraries you're linking against) installed to build and install your package.

Note also that the MANIFEST.in file will need to be updated to include any new source or headers you may add during development. The tox tests will catch this error, but it may not be obvious how to correct it.

Caveats

  • Doesn't yet cover using dlopen(...) to dynamically load .so files because I haven't figured out any best practices for building custom shared libraries along with a Python package's lifecycle, and the CFFI documentation on loading dynamic libraries covers the details of making the lib.dlopen(...) call.
  • Using make to build modules during development is less than ideal. Please post here if there's a better way to do this: http://stackoverflow.com/q/30823397/71522

More Repositories

1

parameterized

Parameterized testing with any Python test framework
Python
829
star
2

pip2pi

pip2pi builds a PyPI-compatible package repository from pip requirements
Python
750
star
3

pprintpp

pprint++: a drop-in replacement for pprint that's actually pretty
Python
408
star
4

autorepr

Easily implement __repr__, __str__, and __unicode__ methods
Python
49
star
5

git-blast

git-blast: show git branches sorted by last commit date
Python
38
star
6

browsercast

An IPython notebook plugin which facilitates lecture recording and playback.
JavaScript
34
star
7

pg-histogram

PostgreSQL functions for generating text-based histograms
PLpgSQL
31
star
8

wayslack

The Wayslack Machine: incrementally archive Slack messages and files using Slack's team export format
Python
23
star
9

Protocol-Informatics

Patches to the Protocol Informatics project to make it work with a numpy.
C
20
star
10

django-switchuser

django-switchuser makes it easy for an administrator to switch to temporarily switch to another account by visiting /su.
Python
16
star
11

libzbar-cffi

Python cffi-based bindings for the zbar QR decoder (Py2, Py3, and PyPy)
C
13
star
12

remora

remora: less insane JavaScript templating
JavaScript
13
star
13

dwdj

A collection of useful Django utilities.
Python
9
star
14

libqrencode-cffi

Fast, robust, and less incomplete Python cffi-based bindings for libqrencode
C
7
star
15

vcslog

Logs interactions with version control systems
Python
7
star
16

monte-carlo-monopoly

A Monte Carlo Monopoly simulation
C
6
star
17

openssl-x509-scripts

Scripts for creating an x509 certificate authority and using it to create and sign certificates.
4
star
18

nfa2regex

Converts NFAs (and DFAs) to a regular expressions using the state removal method.
Go
4
star
19

gevent-helpers

A collection of utilities which are helpful while developing with gevent
Python
4
star
20

jquery-wakeful

A REST-aware RPC protocol and jQuery based client
Python
3
star
21

dupecert

Duplicates SSL certificates
Python
3
star
22

safesort

Safely sort heterogeneous collections on Python 2 and 3
Python
3
star
23

pycon-slides

App which handles uploading of PyCon speaker slides
Python
3
star
24

git-ibisect

git-ibisect: interactively run git-bisect
Python
3
star
25

facebook-archive-parser

A fast Python-based parser for Facebook's archive format
Jupyter Notebook
3
star
26

python-smart-imports.vim

(WORK IN PROGRESS) python-smart-imports.vim - intelligently adds imports to Python files
Python
2
star
27

logging-assertions

Easily make assertions about logged messages in tests
Python
2
star
28

randchk

Randomly checksum files to ensure the integrity of backups.
Python
2
star
29

react-use-async-result

Simple, Sound, Type-Safe Promises in React Components
TypeScript
2
star
30

backup-chk

(WORK IN PROGRESS) incrementally verify backup integrity, with specific support for Time Machine
Go
1
star
31

onioncrypt

onioncrypt: encrypt a file with multiple levels of encryption to multiple people.
Python
1
star
32

clog-ansible

Ansible playbook for clog configuration
1
star
33

djto-testing-micropatterns-talk

Notes from my Django Toronto Testing Micropatterns talk
1
star
34

python-safe_cmp

safe_cmp: safe comparisons (total ordering) for any object in Python 3
Python
1
star
35

homebrew-git-blast

Homebrew Tap for git-blast
Ruby
1
star
36

postgres-functions

A collection of useful PostgreSQL functions
PLpgSQL
1
star
37

pg-change-logs

Automatically manages audit logs for Postgres databases
PLpgSQL
1
star
38

python-test-helper

A modular, composable interface for libraries to expose testing tools
1
star
39

songdb

An improved song database for #LoserKaraoke
JavaScript
1
star
40

wsgi-cloudflare-proxy-fix

Sets REMOTE_ADDR to the correct value when behind Cloudflare, based on the X-Real-IP header, when requests originate from Cloudflare's IP range.
Python
1
star