Skip to main content

Automatically build and install Python extension modules from C++ headers

Project description

magicbind

CI PyPI PyPI - Python Version License: MIT

The easy way to speed up Python bottlenecks with C++. No CMake, no build system, no boilerplate. Just point magicbind at your header and it takes care of the rest.

uv run magicbind add mylib.h

magicbind parses the header, generates nanobind glue code, compiles it with a bundled Zig compiler, and installs the extension into your Python environment.

Install

uv add magicbind

A C++ compiler is bundled via the ziglang package, so you don't need one installed.

Basic usage

Given a header:

// math_utils.h
#include <vector>

inline double sum(const std::vector<double>& values) {
    double s = 0;
    for (auto x : values) s += x;
    return s;
}
uv run magicbind add math_utils.h

Then use it from Python:

import math_utils

math_utils.sum([1, 2, 3])  # 6.0

If the implementation is in a .cpp file instead, magicbind auto-detects it. You can also pass sources explicitly:

uv run magicbind add math_utils.h --source math_utils.cpp

System libraries (optional)

To use a library installed on your system, pass --pkg with its pkg-config name:

uv run magicbind add image_ops.h --pkg opencv4 --system-compiler

--system-compiler is required when linking against system C++ libraries. The default Zig compiler is great for self-contained code, but system libraries like OpenCV were compiled with a different C++ runtime, so you need the system's g++ or clang++ to match.

On Linux and macOS you can use --pkg to resolve flags automatically via pkg-config. On Windows, pkg-config is not available; use --include, --lib, and --link to specify paths manually:

uv run magicbind add mylib.h \
  --include C:\mylib\include \
  --lib C:\mylib\lib \
  --link mylib \
  --system-compiler

On Windows, magicbind automatically configures the MSVC build environment via vswhere.exe. Visual Studio or the standalone Build Tools must be installed (select the "Desktop development with C++" workload).

Rebuilding

When you change the header or source, run:

uv run magicbind build          # rebuilds all modules
uv run magicbind build mylib    # rebuilds one module

This replays the original add command with the same flags and compiler, without you having to remember them.

OpenCV

magicbind ships built-in type casters for common OpenCV types:

// image_ops.h
#include <opencv2/core.hpp>

cv::Mat blur(const cv::Mat& src, int kernel_size = 5);
cv::Size image_size(const cv::Mat& src);
import numpy as np
import image_ops

img = np.zeros((480, 640, 3), dtype=np.uint8)
blurred = image_ops.blur(img, 11)   # numpy array
w, h = image_ops.image_size(img)    # tuple

Supported types: cv::Matnumpy.ndarray, cv::Point / cv::Size / cv::Rect / cv::Scalar ↔ tuple, and their typed variants (cv::Point2f, cv::Rect2d, etc.).

Jupyter

Write C++ directly in a notebook cell:

%load_ext magicbind
%%magicbind math_utils
#include <vector>

double sum(const std::vector<double>& v) {
    double s = 0;
    for (auto x : v) s += x;
    return s;
}
math_utils.sum([1.0, 2.0, 3.0])  # 6.0

The module is compiled and imported automatically. Re-running the cell recompiles and reloads. Requires magicbind in your environment.

Open In Colab

How it works

magicbind uses libclang to parse the header into an intermediate representation, generates a nanobind binding file, and compiles everything in a single zig c++ (or system compiler) invocation. Build artifacts go into .magicbind/build/ and the compiled extension is installed directly into site-packages.

Templates

Template functions and classes are not bound directly. Expose concrete overloads in your header:

template <typename T>
T clamp(T value, T lo, T hi);

// Expose concrete overloads:
inline int    clamp(int v,    int lo,    int hi)    { return ::clamp(v, lo, hi); }
inline float  clamp(float v,  float lo,  float hi)  { return ::clamp(v, lo, hi); }
inline double clamp(double v, double lo, double hi) { return ::clamp(v, lo, hi); }

All three are available in Python as mylib.clamp. The right overload is picked automatically based on the argument types.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

magicbind-0.2.6.tar.gz (22.4 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

magicbind-0.2.6-py3-none-any.whl (19.2 kB view details)

Uploaded Python 3

File details

Details for the file magicbind-0.2.6.tar.gz.

File metadata

  • Download URL: magicbind-0.2.6.tar.gz
  • Upload date:
  • Size: 22.4 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: uv/0.11.7 {"installer":{"name":"uv","version":"0.11.7","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

File hashes

Hashes for magicbind-0.2.6.tar.gz
Algorithm Hash digest
SHA256 44eaf87946e341c91a9a9ee3561ea0519d2312899fbc14df8313b71919a67c39
MD5 1cd149911439c159432247a230fd57bb
BLAKE2b-256 4a0687d6cf4b01c7e2025e0530cffd69ad7d56e20975b6b20effc72afe1c46f7

See more details on using hashes here.

File details

Details for the file magicbind-0.2.6-py3-none-any.whl.

File metadata

  • Download URL: magicbind-0.2.6-py3-none-any.whl
  • Upload date:
  • Size: 19.2 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: uv/0.11.7 {"installer":{"name":"uv","version":"0.11.7","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

File hashes

Hashes for magicbind-0.2.6-py3-none-any.whl
Algorithm Hash digest
SHA256 c043013270a075da6ec1d107ce7ab1cca29d3966e8f703125d6c84f714eefeac
MD5 589ffa8bb951d66cd0768310dde25496
BLAKE2b-256 d66831e8641f24e69f59fed24a813cc9a5472e107ef696daa30ed27205782982

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page