6. Python Bindings Development
Structure
Native extension:
bindings/python/src/dtl/*.cppHigh-level API:
bindings/python/src/dtl/__init__.pyTests:
bindings/python/tests/
Layering model
pybind11 C++ layer exposes low-level native operations
__init__.pyprovides Pythonic wrappers and compatibility helperstests validate behavior, versions, and edge cases
API design expectations
preserve stable high-level API names and signatures when possible
keep version metadata consistent with package/native version sources
avoid hidden behavior differences between sync and async APIs
Lifetime and memory safety
use RAII wrappers for native request/window/handle ownership
ensure callbacks do not outlive owning Python objects unsafely
when exposing NumPy views, keep the owner object alive
distributed_span in Python
Python exposes a first-class DistributedSpan factory and typed native wrappers (DistributedSpan_*).
source owners must be retained in span wrappers to prevent dangling storage
NumPy
local_view()for spans must keep span wrapper ownership aliveavoid caching span-derived local views across structural owner changes
Running tests
Use non-MPI/non-CUDA sweep when validating broad API behavior:
MPI4PY_RC_INITIALIZE=0 \
PYTHONPATH=<build-dir>/bindings/python \
python3 -m pytest bindings/python/tests -q -m 'not mpi and not cuda'
Common pitfalls
importing wrong module path during local test runs
mismatched type conversions for scalar dtypes
async handles returned without clear lifecycle wrappers