Build and Test
This project uses a Python build backend that configures and builds the C++ core with CMake.
Local setup
Activate the Python environment you use for development before running import checks or tests. Editable installs should use the normal rebuild behavior so native C++ changes are reflected in Python runtime checks.
python -m pip install --upgrade pip
python -m pip install -e .[dev]
If your environment does not provide extras, install the minimal tools directly:
MIFROST_BUILD_BACKENDS=pymimir python -m pip install -e .[pymimir]
python -m pip install pytest mkdocs mkdocs-material
Build and install
Use a named build mode for each local purpose. configure.py and cbuild.py
read these modes from local_build_dirs.py, so the default directories,
configs, benchmark toggle, and default build targets stay in one place:
local-release:build/local-release,Release, targetalllocal-debug:build/local-debug,Debug, targetallstubs:build/stubs,Release, targetmifrost_core_module_stubsci:build/ci,Release, targetmifrost_testsbench:build/bench-release,Release, benchmarks enabled, targetmifrost_bench_hgraph
Avoid ad hoc root-level build directories like build_*_probe unless they are
short-lived ignored experiments.
Dev package staging
A dev-mode build stages an importable mifrost package: the native extension
modules, the shared libraries they load at runtime, and the generated stubs.
MIFROST_DEV_PACKAGE_ROOT controls where that package is written.
- Plain CMake builds stage into
<build-dir>/python, so each configuration keeps its artifacts to itself. - The scikit-build-core editable install and
--mode stubsstage intosrc/, because an editable install imports from the source tree and packaging reads the generatedsrc/mifrost/*.pyifiles afterwards.
Sharing one staging root between build directories with different compile
settings is what makes a sanitizer or Debug build replace the shared library
that another build directory's already linked tests and benchmarks load. The
symptom is not a build error; it is spurious sanitizer reports, slow
benchmarks, or an aborted stub generation in the other build tree. Configure
rejects that overlap and names both build directories. Pass
-DMIFROST_DEV_PACKAGE_ROOT=<dir> to move a build elsewhere.
If you do build a sanitizer or Debug tree that stages into src/, rebuild the
editable install afterwards so the source tree holds Release artifacts again.
The Python helpers treat those modes as the canonical local build roots:
configure.pyprepares a build tree and installs dependencies.cbuild.pyonly builds an already configured tree.build_backend.pyowns editable/wheel build-time environment setup.
You can still pass --build_dir, --config, or --target for short-lived
experiments, but prefer --mode for checked-in commands and reproducible
developer workflows.
Install the package (this triggers a full native build):
python -m pip install -v ".[backends]"
For editable development:
python -m pip install -e ".[backends]"
The Python build backend builds both native adapters by default. Set
MIFROST_BUILD_BACKENDS to core, pymimir, pytyr, or both to exercise a
specific installation variant. This controls native targets; the matching
project extra controls runtime planner dependencies.
The CMake helper exposes the same selection directly:
python configure.py --mode local-release --backends pytyr
For explicit CMake-driven local builds, the blessed layout is:
python configure.py --mode local-release
python cbuild.py --mode local-release
Use the debug mode when you need a debug tree:
python configure.py --mode local-debug
python cbuild.py --mode local-debug
Generated stubs
src/mifrost/_core.pyi is generated by nanobind, not hand-edited. The file is
ignored in version control, but the packaging flow still expects it to exist:
- CI generates it before the source distribution and wheel jobs run.
pyproject.tomlincludes it in the source distribution, so the wheel build path can package the generated stub.- Local editable or stub-oriented work should regenerate it from the CMake target rather than editing the file directly.
Local generation commands:
python configure.py --mode stubs
python cbuild.py --mode stubs
python scripts/validate_generated_stub.py
The validation script is the same guard used by CI. It confirms that the stub file was produced, is non-empty, and is valid Python syntax.
Run tests
Run the full Python test suite:
python -m pytest
Run a single test module while iterating:
python -m pytest tests/encoding/test_color_encoder.py -q
Run the C++ test target through the CI-like mode:
python configure.py --mode ci
python cbuild.py --mode ci
ctest --test-dir build/ci -R mifrost_tests --output-on-failure
Build the benchmark target:
python configure.py --mode bench
python cbuild.py --mode bench
Build docs
Strict docs build (fails on warnings):
mkdocs build --strict