Embedding PyPy (DEPRECATED)

PyPy has a very minimal and a very strange embedding interface, based on the usage of cffi and the philosophy that Python is a better language than C. It was developed in collaboration with Roberto De Ioris from the uwsgi project. The PyPy uwsgi plugin is a good example of using the embedding API.

NOTE: You need a PyPy compiled with the option --shared, i.e. with a libpypy-c.so or pypy-c.dll file. This is the default in recent versions of PyPy.

Note

The interface described in this page is kept for backward compatibility. From PyPy 4.1, it is recommended to use instead CFFI’s native embedding support, which gives a simpler approach that works on CPython as well as PyPy.

The resulting shared library exports very few functions, however they are enough to accomplish everything you need, provided you follow a few principles. The API is:

void rpython_startup_code(void);

This is a function that you have to call (once) before calling anything else. It initializes the RPython/PyPy GC and does a bunch of necessary startup code. This function cannot fail.

int pypy_setup_home(char* home, int verbose);

This function searches the PyPy standard library starting from the given “PyPy home directory”. The arguments are:

  • home: path to an executable inside the pypy directory (can be a .so name, can be made up). Used to look up the standard library, and is also set as sys.executable. From PyPy 5.5, you can just say NULL here, as long as the libpypy-c.so/dylib/dll is itself inside this directory.

  • verbose: if non-zero, it will print error messages to stderr

Function returns 0 on success or -1 on failure, can be called multiple times until the library is found.

void pypy_init_threads(void);

Initialize threads. Only need to be called if there are any threads involved. Must be called after pypy_setup_home()

int pypy_execute_source(char* source);

Execute the Python source code given in the source argument. In case of exceptions, it will print the Python traceback to stderr and return 1, otherwise return 0. You should really do your own error handling in the source. It’ll acquire the GIL.

Note: this is meant to be called only once or a few times at most. See the more complete example below. In PyPy <= 2.6.0, the globals dictionary is reused across multiple calls, giving potentially strange results (e.g. objects dying too early). In PyPy >= 2.6.1, you get a new globals dictionary for every call (but then, all globals dictionaries are all kept alive forever, in sys._pypy_execute_source).

int pypy_execute_source_ptr(char* source, void* ptr);

Note

Not available in PyPy <= 2.2.1

Just like the above, except it registers a magic argument in the source scope as c_argument, where void* is encoded as Python int.

void pypy_thread_attach(void);

In case your application uses threads that are initialized outside of PyPy, you need to call this function to tell the PyPy GC to track this thread. Note that this function is not thread-safe itself, so you need to guard it with a mutex.

Minimal example

Note that this API is a lot more minimal than say CPython C API, so at first it’s obvious to think that you can’t do much. However, the trick is to do all the logic in Python and expose it via cffi callbacks. We write a little C program:

#include "PyPy.h"
#include <stdio.h>
#include <stdlib.h>

static char source[] = "print 'hello from pypy'";

int main(void)
{
    int