Cppy (Python C++ Extension Headers)

1.3.1 · active · verified Mon Apr 13

Cppy is a small C++ header library designed to simplify the creation of Python extension modules. Its core feature is a `PyObject` smart pointer, which automates Python's reference counting mechanism and provides convenient methods for common object operations. The current version is 1.3.1. As a C++ header library, its release cadence is typically driven by CPython API changes or new convenience features rather than a fixed schedule.

Warnings

Install

Imports

Quickstart

To use Cppy, you write C++ code for your Python extension module and include the `cppy/cppy.h` header. This example shows a `setup.py` that would build a simple C++ extension. Cppy handles Python object reference counting through its `cppy::ptr` smart pointer. For a more direct integration with `setuptools`, you can import `CppyBuildExt` from the `cppy` package in your `setup.py` to automatically enforce C++11 and include the necessary headers. Alternatively, specify `cppy` as a build requirement in `pyproject.toml`.

import os
from setuptools import setup, Extension
from setuptools.command.build_ext import build_ext

# A minimal C++ source file that includes cppy
# In a real project, this would be in a separate .cpp file
cpp_source = '''
#include <Python.h>
#include <cppy/cppy.h>

static PyObject* greet_method(PyObject* self, PyObject* args) {
    const char* name;
    if (!PyArg_ParseTuple(args, "s", &name)) {
        return NULL;
    }
    std::string greeting = "Hello, " + std::string(name) + "!";
    cppy::ptr result_ptr(PyUnicode_FromString(greeting.c_str()));
    return result_ptr.release(); // release ownership to Python
}

static PyMethodDef methods[] = {
    {"greet", greet_method, METH_VARARGS, "Greet a person."},
    {NULL, NULL, 0, NULL}
};

static struct PyModuleDef mymodule = {
    PyModuleDef_HEAD_INIT,
    "_my_extension", // Name of the module
    NULL,            // Module documentation
    -1,              // Size of per-interpreter state of the module
    methods
};

PyMODINIT_FUNC PyInit__my_extension(void) {
    return PyModule_Create(&mymodule);
}
'''

# Write the C++ code to a temporary file for demonstration
with open('my_extension_module.cpp', 'w') as f:
    f.write(cpp_source)

class CustomBuildExt(build_ext):
    def build_extension(self, ext):
        # Example of setting C++ standard if not using CppyBuildExt directly
        # For cppy, C++11 is typically required.
        if self.compiler.compiler_type == 'msvc':
            ext.extra_compile_args = ['/std:c++11']
        else:
            ext.extra_compile_args = ['-std=c++11']
        super().build_extension(ext)

setup(
    name='my-cpp-extension',
    version='0.1.0',
    description='A simple C++ extension using cppy',
    ext_modules=[
        Extension(
            '_my_extension',
            sources=['my_extension_module.cpp'],
            include_dirs=[os.path.join(os.environ.get('VIRTUAL_ENV', '/usr/local'), 'include')], # Adjust if cppy headers not found
            language='c++'
        )
    ],
    # For real projects, you might use CppyBuildExt directly:
    # cmdclass={'build_ext': CppyBuildExt},
    # Or ensure cppy is in build-system.requires in pyproject.toml
    # and then 'from cppy import CppyBuildExt' in setup.py
    cmdclass={'build_ext': CustomBuildExt},
    setup_requires=['cppy'], # Ensure cppy is available during setup
    install_requires=[]
)

# To demonstrate usage after hypothetical build and installation:
# import _my_extension
# print(_my_extension.greet("World"))

view raw JSON →