Metadata-Version: 2.4
Name: easybind
Version: 0.1.6
Summary: Self-registering nanobind helpers (import as easybind)
Keywords: easybind,nanobind,bindings,pymergetic
Author-Email: PymergeticOS Maintainers <raudzus@pymergetic.com>
License-Expression: Apache-2.0
License-File: LICENSE
License-File: NOTICE
Classifier: Development Status :: 4 - Beta
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Programming Language :: Python :: 3.14
Classifier: Programming Language :: C++
Classifier: Operating System :: POSIX :: Linux
Classifier: Typing :: Typed
Project-URL: Homepage, https://github.com/pymergetic/easybind
Project-URL: Repository, https://github.com/pymergetic/easybind
Project-URL: Issues, https://github.com/pymergetic/easybind/issues
Requires-Python: >=3.11
Provides-Extra: dev
Requires-Dist: pytest>=7.0.0; extra == "dev"
Requires-Dist: build>=1.0.0; extra == "dev"
Requires-Dist: twine>=5.0.0; extra == "dev"
Description-Content-Type: text/markdown

# easybind

Simple self-registering helpers for distributed nanobind bindings.

## Install

```bash
pip install easybind
```

```python
import easybind
from easybind import sample  # optional demo module
```

**PyPI project:** [`easybind`](https://pypi.org/project/easybind/) (same name as the **`import`**).

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

### Local dev / clangd

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

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

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

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

- `easybind` (core helpers and macros)
- `easybind.module` (module tree API)
- `easybind.sample` (demo bindings)

## Build-time SDK
`easybind` provides CMake helpers for hybrid extensions:

- `easybind::build_interface` (INTERFACE): baseline C++20 + PIC + shared include paths
- `easybind_add_extension(target ...)`: wraps `nanobind_add_module(... NB_SHARED ...)`

Example:
```cmake
find_package(easybind CONFIG REQUIRED)
easybind_add_extension(my_module src_bind/my_pkg/__cpp__/module.cpp)
target_link_libraries(my_module PRIVATE easybind::easybind)
```

## 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 `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)
```cpp
#pragma once

#include <string>

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

### 2) Bind it in a separate file (module node)
```cpp
#include <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.
```cpp
#include <easybind/bind.hpp>

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

### 4) Extend from another file
```cpp
#include <easybind/bind.hpp>

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

