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.4.tar.gz (52.9 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.4-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.4-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.4-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.4-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.4.tar.gz.

File metadata

  • Download URL: pymergetic_easybind-0.3.4.tar.gz
  • Upload date:
  • Size: 52.9 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.4.tar.gz
Algorithm Hash digest
SHA256 c1db5ecd240aee19991d4d1fb2a1795441541583e193af78579fe22705af1fd2
MD5 1631f51586e0ae34bee58bb0832e16f7
BLAKE2b-256 a09e8984386a36f949c9b68304c73a4aba98157512ac624b2b6db1f167704089

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for pymergetic_easybind-0.3.4-cp314-cp314-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl
Algorithm Hash digest
SHA256 ff2bc89f792341be5bb1a5b0e6cf8b7a3837034a46bebf5cce12ce64078ff8bc
MD5 a385397789d5391949a1ecfb09c69e0e
BLAKE2b-256 7b31f5d44f9fa2104b494b92357399c95d0f674111995edd5498c755d5643470

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for pymergetic_easybind-0.3.4-cp313-cp313-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl
Algorithm Hash digest
SHA256 8cf7518e104c46560f6dd39be86baac5169fa9cd694bbae48afbd42c51776207
MD5 0d0ae77e10a2851dfc1f711fd711d0a4
BLAKE2b-256 dc248d42edf03c350e77502bf50cba50a3651c2559f93eb8a7d716689732c4bd

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for pymergetic_easybind-0.3.4-cp312-cp312-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl
Algorithm Hash digest
SHA256 6a777daf5e844d48ca80bbd5e939e3da5c4fd5ca02a68825ad480419c40c1064
MD5 7aaa06981cb95b7f1f11ff0ccde8793c
BLAKE2b-256 7b5b3c3619a02662fda652e83ac073bbdd5b2c29340d07d4ee0bc83294a8f325

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for pymergetic_easybind-0.3.4-cp311-cp311-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl
Algorithm Hash digest
SHA256 4b920fe6c13d6433bb46c0977d7a466012aa8e843c7a81a9ea0118b287cdc789
MD5 47c7864af004d6c60e10fa4bee5f60a6
BLAKE2b-256 11ecee397a2e214f5cd4674f29a48f5c9786a3049d4a07b67e899964c82ca279

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