HPy Quickstart

This section shows how to quickly get started with HPy by creating a simple HPy extension from scratch.

Install latest HPy release:

python3 -m pip install hpy

Alternatively, you can also install HPy from the development repository:

python3 -m pip install git+https://github.com/hpyproject/hpy.git#egg=hpy

Create a new directory for the new HPy extension. Location and name of the directory do not matter. Add the following two files:

// quickstart.c

// This header file is the entrypoint to the HPy API:
#include "hpy.h"

// HPy method: the HPyDef_METH macro generates some boilerplate code,
// the same code can be also written manually if desired
HPyDef_METH(say_hello, "say_hello", HPyFunc_NOARGS)
static HPy say_hello_impl(HPyContext *ctx, HPy self)
    // Methods take HPyContext, which must be passed as the first argument to
    // all HPy API functions. Other than that HPyUnicode_FromString does the
    // same thing as PyUnicode_FromString.
    // HPy type represents a "handle" to a Python object, but may not be
    // a pointer to the object itself. It should be fully "opaque" to the
    // users. Try uncommenting the following two lines to see the difference
    // from PyObject*:
    // if (self == self)
    //      HPyUnicode_FromString(ctx, "Surprise? Try HPy_Is(ctx, self, self)");

    return HPyUnicode_FromString(ctx, "Hello world");

static HPyDef *QuickstartMethods[] = {
    &say_hello, // 'say_hello' generated for us by the HPyDef_METH macro

static HPyModuleDef quickstart_def = {
    .doc = "HPy Quickstart Example",
    .defines = QuickstartMethods,

// The Python interpreter will create the module for us from the
// HPyModuleDef specification. Additional initialization can be
// done in the HPy_mod_exec slot
HPy_MODINIT(quickstart, quickstart_def)
# setup.py

from setuptools import setup, Extension
from os import path

DIR = path.dirname(__file__)
        Extension('quickstart', sources=[path.join(DIR, 'quickstart.c')]),

Build the extension:

python3 setup.py --hpy-abi=universal develop

Try it out – start Python console in the same directory and type:

    import quickstart
    assert quickstart.say_hello() == "Hello world"

Notice the shared library that was created by running setup.py:

> ls *.so

It does not have Python version encoded in it. If you happen to have GraalPy or PyPy installation that supports given HPy version, you can try running the same extension on it. For example, start $GRAALVM_HOME/bin/graalpy in the same directory and type the same Python code: the extension should load and work just fine.

Where to go next?