Building from source¶
mew is built with CMake using scikit-build-core, and the C++ extension uses nanobind.
Prerequisites¶
One-time setup¶
$ uv sync --all-extras
$ uvx prek install
uv sync builds the C++ extension into the project’s .venv via scikit-build-core.
The [tool.uv] config in pyproject.toml opts the project out of build isolation, so nanobind include paths incompile_commands.json survive wheel builds.
This is useful for C++ language servers like clangd.
Rebuilding after a C++ change¶
$ uv sync --reinstall-package=mew # editable install picks up the rebuilt .so
Alternatively, rebuild using CMake directly:
$ cmake --build build
Test, lint, type-check¶
$ uv run pytest tests/ -q
$ uvx prek run --all-files
$ uvx ty check src/mew/ tests/
These steps run in CI (.github/workflows/ci.yml) across Linux, macOS, and Windows on Python 3.11–3.14.
AddressSanitizer¶
Build a separate ASAN wheel (lands in build/asan/, leaving the Release wheel
alone; a plain uv sync afterwards swaps the editable install back to Release):
$ MEW_ASAN=1 uv sync --all-groups --reinstall-package=mew
uv run pytest alone does not preload the ASAN runtime, so the test process
aborts at the first import of an ASAN-built extension. Preload it explicitly:
# Linux: preload the ASAN runtime *and* libc++. libc++ must be preloaded too,
# otherwise its container-overflow annotations don't line up with the
# instrumented build and ASAN reports false positives.
MEW_ASAN=1 LD_PRELOAD="$(clang -print-file-name=libclang_rt.asan.so) $(clang -print-file-name=libc++.so)" \
ASAN_OPTIONS="detect_leaks=0:halt_on_error=1" uv run --all-groups pytest --capture no
# for macOS, there's a wrapper script to work around SIP.
scripts/asan-pytest.sh
Building the documentation locally¶
$ uv pip install -e '.[docs]'
$ uv run sphinx-build -W --keep-going -b html docs docs/_build/html
$ open docs/_build/html/index.html
The -W flag mirrors readthedocs’ fail_on_warning: true switch.