This file provides guidance for agents when working with code in this repository.
Python bindings for Boost.Histogram, a header-only C++14
histogramming library. This is a hybrid Python/C++ project: pybind11 wraps the C++ library into a
compiled _core extension module, and a pure-Python layer in src/boost_histogram/ provides the
user-facing API on top of it.
Prefer uv run <cmd> — it rebuilds the C++ extension as needed before running.
| Task | Command |
|---|---|
| Install for dev | uv sync (or pip install -ve. --group dev) |
| Run tests | uv run pytest |
| Run one test | uv run pytest tests/test_histogram.py::test_name |
| Tests in parallel, no benchmark | uv run pytest -n auto --benchmark-disable |
| Lint / format / typecheck | prek -a --quiet |
| Type check only | uv run mypy (strict on src/, examples/) |
| Build + serve docs | nox -s docs -- serve |
| C++ (CMake) build + test | cmake --workflow default |
nox -l lists all sessions. prek is used instead of pre-commit run.
The C++ build needs git submodules (extern/): git submodule update --init --depth 10.
pytest-benchmarkis a required plugin; CI passes--benchmark-disable. Benchmark tests live intests/test_benchmark_*.py.filterwarnings = errorandxfail_strict = true— warnings fail tests, and unexpected xpasses fail.- Property-based tests use Hypothesis (
tests/test_pbt.py); some systems needCI=1to pass health checks. - Python 3.14t (free-threading) is supported; thread-safety tests are in
tests/test_threaded_fill.py.
The C++ extension exposes raw types under _core submodules (_core.hist, _core.axis,
_core.storage, _core.accumulators, _core.algorithm, _core.axis.transform) — see
src/module.cpp. These raw C++ objects are wrapped by Python classes in src/boost_histogram/.
The bridge is in src/boost_histogram/_utils.py:
@register({cpp_type, ...})decorates a Python class to claim ownership of one or more C++ types.cast(self, cpp_object, ParentClass)converts a raw C++ object into the right Python wrapper by walking subclasses ofParentClassand matching the registered C++ type. Classes that can't be constructed directly from the C++ object provide a_convert_cppclassmethod (pybind11 can't downcast — see the comment in_cast_make_object).- The
_familyattribute lets downstream libraries (e.g. Hist) subclass these wrappers and havecastreturn their subclass instead.boost_histogramis the fallback family. This is why most wrapper classes are decorated and carry_family.
When adding a new axis/storage/accumulator wrapper, follow this pattern: register the C++ type, set
_family, and add a _convert_cpp if direct construction doesn't work.
histogram.py— theHistogramclass wrapping_core.hist, plus UHI indexing (loc,rebin,sum,underflow,overflowfromtag.py),__getitem__/__setitem__, projection, views.axis/__init__.py— axis wrappers (Regular,Variable,Integer,IntCategory,StrCategory,Boolean) andAxesTuple;axis/transform.py— log/sqrt/pow/function transforms.storage.py,accumulators.py,view.py— storage types, accumulators, and NumPy structured-array views (WeightedSumView,MeanView,WeightedMeanView).numpy.py— drop-in replacements fornumpy.histogram*functions.serialization/— pickle/serialization helpers for axes and storages.
src/register_*.cpp— each registers one category (axes, storages, histograms, accumulators, transforms, algorithms) into the_coremodule defined insrc/module.cpp.include/bh_python/— the binding headers (fill logic, pickling, metadata, NumPy interop, etc.).extern/histogram/and otherextern/*are git submodules (Boost headers); don't edit them.nox -s bump_boost -- <version>updates them..pyistubs for the compiled module live insrc/boost_histogram/_core/.
from __future__ import annotationsis required at the top of every Python file (ruff-enforced).- Use
boost_histogram._compat.typing.Self, nottyping.Self/typing_extensions.Self(banned-api). - mypy runs in strict mode on
src/andexamples/; tests are exempt from untyped-def rules. - Version is dynamic from git tags via
setuptools_scm, generated at build time intoboost_histogram/version.py(do not commit/edit it).