Skip to main content

Self-registering nanobind helpers (import as pymergetic.easybind)

Project description

easybind

Simple self-registering helpers for distributed nanobind bindings.

Install

pip install pymergetic-easybind

Platforms: PyPI ships manylinux (glibc 2.28+) and Windows amd64 wheels for CPython 3.11–3.14. macOS is not built in CI yet. On unsupported platforms pip may fall back to the sdist and require a local C++ toolchain.

import pymergetic.easybind
from pymergetic.easybind import sample  # optional demo module

PyPI project: pymergetic-easybind (install name). Import: pymergetic.easybind.

Version: Set by Git tags at build time (v0.1.0, …) via setuptools-scm; see RELEASING.md. At runtime, pymergetic.easybind._version.__version__ is written when the wheel is built (or use importlib.metadata.version("pymergetic-easybind")).

Local dev / clangd

An editable install configures CMake under ./build/ and generates build/compile_commands.json, which clangd picks up via .clangd — same database as the Python build, no second configure step:

uv pip install -e .    # or: pip install -e .

If you need compile_commands.json without pip, run scripts/clangd-update.sh (plain cmake -S . -B build …).

Python layer

The Python package is implemented as native extensions. It exposes:

  • pymergetic.easybind (core helpers and macros)
  • pymergetic.easybind.module (module tree API)
  • pymergetic.easybind.sample (demo bindings)

Build-time SDK

Installed wheels ship CMake helpers under pymergetic/easybind/cmake/:

  • easybind_pip.cmakeeasybind_pip_setup() finds Python, nanobind (pip), libeasybind, and include roots for #include <pymergetic/easybind/...>, then pulls in easybind_dependencies.cmake. Helpers: easybind_pip_link_magic_enum(target), easybind_pip_set_rpath_next_to_easybind(target easybind_pkg_dir).
  • easybind_dependencies.cmake — pins nanobind, magic_enum, reflect-cpp (same tags as this repo). Use easybind_fetch_third_party_deps() to pull all three, or easybind_fetch_nanobind() / easybind_fetch_magic_enum() / easybind_fetch_reflect_cpp() when you only need a subset (e.g. pip already provides nanobind, so call only easybind_fetch_magic_enum()).

Typical consumer bootstrap:

find_package(Python REQUIRED COMPONENTS Interpreter Development.Module)
execute_process(COMMAND "${Python_EXECUTABLE}" -c
  "import pathlib, pymergetic.easybind; print(pathlib.Path(pymergetic.easybind.__file__).resolve().parent / 'cmake' / 'easybind_pip.cmake')"
  OUTPUT_VARIABLE _eb_pip OUTPUT_STRIP_TRAILING_WHITESPACE COMMAND_ERROR_IS_FATAL ANY)
include("${_eb_pip}")
easybind_pip_setup()
easybind_fetch_magic_enum()   # if you include easybind headers that need magic_enum

When developing inside this repository, easybind_add_extension(...) is defined in the top-level CMakeLists.txt (not shipped in the wheel).

Devtools (release / pin bumps)

Implemented in pymergetic.common.devtools (pymergetic-common). Install via pymergetic-easybind (depends on common) or uv sync.

pymergetic-pin-pyproject --project-root packages/easybind --dry-run
pymergetic-release-tag --project-root packages/easybind --dry-run
pymergetic-wait-pypi --project-root packages/easybind

See pymergetic-common RELEASING.md and from pymergetic.common.devtools import ….

Core idea

  • Each namespace/module defines a ModuleNode and a bind callback.
  • The module entry point calls apply_init to run the callback and recurse.
  • Submodules are created on demand and registered in sys.modules.
  • Shared-object modules are marked so recursion stops at their boundary.
  • A minimal sample module lives at pymergetic.easybind.sample.

Developer note: layout rules

  • __init__.cpp marks the Python boundary (NB_MODULE) for a package/module.
  • node.cpp/.hpp is the pure C++ module-tree core.
  • ns_module.hpp defines the EASYBIND_NS_MODULE* macros.
  • Directory layout mirrors namespaces and Python modules.

Smallest possible example

1) Define a C++ type (normal code)

#pragma once

#include <string>

struct PeerInfo {
    std::string peer_id;
    int transport = 0;
};

2) Bind it in a separate file (module node)

#include <pymergetic/easybind/bind.hpp>

struct PeerInfo;  // forward declare or include the header

EASYBIND_NS_MODULE(my_pkg, m, false, {
    nanobind::class_<PeerInfo>(m, "PeerInfo")
        .def(nanobind::init<>())
        .def_rw("peer_id", &PeerInfo::peer_id)
        .def_rw("transport", &PeerInfo::transport);
});

3) Module entry point (shared-object boundary)

Use this only for the package that has its own .so and NB_MODULE entry point. Do not pair it with EASYBIND_NS_MODULE for the same my_pkg name. If you need to add bindings from another file, use EASYBIND_NS_MODULE_EXTEND to extend the same module node instead.

#include <pymergetic/easybind/bind.hpp>

EASYBIND_NS_MODULE_SHARED_OBJECT(my_pkg, my_pkg, m, true, {
    m.doc() = "my_pkg module";
});

4) Extend from another file

#include <pymergetic/easybind/bind.hpp>

EASYBIND_NS_MODULE_EXTEND(my_pkg, m, {
    m.def("ping", [] { return "pong"; });
});

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

pymergetic_easybind-0.3.5.tar.gz (53.1 kB view details)

Uploaded Source

Built Distributions

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

pymergetic_easybind-0.3.5-cp314-cp314-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl (295.6 kB view details)

Uploaded CPython 3.14manylinux: glibc 2.27+ x86-64manylinux: glibc 2.28+ x86-64

pymergetic_easybind-0.3.5-cp313-cp313-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl (295.5 kB view details)

Uploaded CPython 3.13manylinux: glibc 2.27+ x86-64manylinux: glibc 2.28+ x86-64

pymergetic_easybind-0.3.5-cp312-cp312-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl (295.5 kB view details)

Uploaded CPython 3.12manylinux: glibc 2.27+ x86-64manylinux: glibc 2.28+ x86-64

pymergetic_easybind-0.3.5-cp311-cp311-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl (295.9 kB view details)

Uploaded CPython 3.11manylinux: glibc 2.27+ x86-64manylinux: glibc 2.28+ x86-64

File details

Details for the file pymergetic_easybind-0.3.5.tar.gz.

File metadata

  • Download URL: pymergetic_easybind-0.3.5.tar.gz
  • Upload date:
  • Size: 53.1 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for pymergetic_easybind-0.3.5.tar.gz
Algorithm Hash digest
SHA256 e4e8d34dc1f2301a99a99ff4a67f225317755579ff4103a78d8a1caba2ec081f
MD5 2464a8664b8feaf023ed4bd1847d7052
BLAKE2b-256 87a218e343eadfb4d0ad045cc3d7ff9b88f90dbed8ac7a252d6505649a4b0b7a

See more details on using hashes here.

File details

Details for the file pymergetic_easybind-0.3.5-cp314-cp314-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl.

File metadata

File hashes

Hashes for pymergetic_easybind-0.3.5-cp314-cp314-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl
Algorithm Hash digest
SHA256 45e9efff71377e36bf71bbfe175f1beb2a5c108c8c4564d5001aafc27bda4f4e
MD5 f2aa58a039e8a53cc8bce784e700d5c6
BLAKE2b-256 18c7dc917e7c75cdcb1c969abaefc9ba6bee5880a7c8e0549bc8c0c93846d137

See more details on using hashes here.

File details

Details for the file pymergetic_easybind-0.3.5-cp313-cp313-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl.

File metadata

File hashes

Hashes for pymergetic_easybind-0.3.5-cp313-cp313-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl
Algorithm Hash digest
SHA256 b0a6dd5815673ea94d01a6da52919dbeb2b7f0bee442e9bfc4d881dd68080a63
MD5 d8296bcc0a78f7084304c915ef552129
BLAKE2b-256 2051739b0535b9e17fa66db973585fb290c10f24a3a2b499b4d8eba1a0bd4905

See more details on using hashes here.

File details

Details for the file pymergetic_easybind-0.3.5-cp312-cp312-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl.

File metadata

File hashes

Hashes for pymergetic_easybind-0.3.5-cp312-cp312-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl
Algorithm Hash digest
SHA256 55c1a44d85ccd985af81b805ae4b9dc0f45dbc05caa73bc1c9c475d7e8b3b0a6
MD5 25dd72a503ce3f9d60ff859b1676c4d6
BLAKE2b-256 8afb9b126e36aba762b8f8490af4858f479fba96bba8da3b10d433eb84a69c7e

See more details on using hashes here.

File details

Details for the file pymergetic_easybind-0.3.5-cp311-cp311-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl.

File metadata

File hashes

Hashes for pymergetic_easybind-0.3.5-cp311-cp311-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl
Algorithm Hash digest
SHA256 8a03485ddedd08f5417f91e10027767dde06499bb8dacebad743beaab5d91265
MD5 80b50e21b674c1057b5c5fdc68f0ba01
BLAKE2b-256 35d014468abc3f16aa069d454e9029283f9735473ba74a30875d47a10da02fd4

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