Contributing
This guide covers the dev-side workflow: setting up an environment, the build pipeline, the Makefile + pre-commit conventions, and the release flow. End-user install instructions live in README.md.
Quick start
Clone with submodules and create a conda env:
git clone --recursive https://github.com/vinecopulib/pyvinecopulib.git cd pyvinecopulib make env-conda # creates the `pyvinecopulib` conda env conda activate pyvinecopulib
Install development dependencies and the package in editable mode, plus pre-commit hooks:
make dev-setupIterate:
make quick-check # ruff + ty + fast tests make check-all # lint + type-check + tests with coverage
Repository layout
Path |
What lives there |
|---|---|
|
Pure-Python package source ( |
|
nanobind bindings + binding-side headers. |
|
Vendored C++ submodules: |
|
pytest test suite. |
|
Jupyter notebooks rendered into the docs by nbsphinx. |
|
Sphinx source. |
|
Maintainer-facing utilities (see below). |
|
Build-internal tooling invoked by CMake. Don’t run these directly. |
How the build works
pip install -e . --no-build-isolation (the editable install) drives the
full pipeline:
CMake configure:
scripts/build/find_libclang.pylocates a libclang shared library (PyPI package, conda env, orLIBCLANG_PATHoverride).CMake build, pre-compile:
scripts/build/generate_docstring.pyparses the C++ headers inlib/and writessrc/include/docstr.hpp.CMake build, compile:
nanobind_add_modulelinkssrc/pyvinecopulib_ext.cppagainst the freshly generateddocstr.hpp.CMake POST_BUILD:
scripts/build/generate_stubs.pystages the assembled package in a tempdir and writessrc/pyvinecopulib/__init__.pyifrom the live extension.
Both docstr.hpp and __init__.pyi are gitignored — the build is the
single source of truth. With editable.rebuild = true in
pyproject.toml, importing pyvinecopulib after a C++ edit triggers a
rebuild and refresh on the spot.
Makefile cheatsheet
make help lists everything. Most-used:
Command |
Purpose |
|---|---|
|
One-shot: install dev/doc/examples extras + pre-commit hooks. |
|
Fast feedback: lint + type-check + tests without coverage. |
|
Pre-push: lint + type-check + tests with coverage. |
|
Test variants. |
|
Ruff. |
|
ty. |
|
Build HTML documentation. |
|
Live-reload server ( |
|
Wipe Python caches and build dirs. |
|
Re-execute notebooks (used by the docs/release flow; runs |
Pre-commit hooks
Hooks run on every commit. Manage with make pre-commit-install /
make pre-commit. The configured set:
ruff — Python lint + format.
ty — Astral’s type checker (local hook; needs
tyon PATH, which the dev env install provides).clang-format — C++ in
src/(Google style;docstr.hppexcluded).cmake-format — CMake formatting.
General whitespace / YAML / TOML / JSON checks.
CI overview
.github/workflows/pypi.yml is the single workflow. Jobs:
build— cibuildwheel matrix (16 wheels: Linux glibc/musl, macOS arm64, Windows × cp39/cp310/cp311/cp312-ABI3).check_wheels— counts and twine-checks wheel artifacts.verify_docs_build— RTD-equivalent doc build with-W(warnings as errors). Uploadsdocs-htmlartifact for PR review.install_and_unit_test— installs each wheel and runs pytest + notebook tests.regenerate_notebooks— fires on PRs tomain(or any PR labelledregenerate-notebooks). Re-executes notebooks via the wheel and auto-commits the refreshed outputs back to the PR branch with[skip ci].build_sdist— lints, type-checks, builds the sdist, installs from it as a sanity check.upload_to_pypi— publishes on tag push.
Release process
Day-to-day flow:
Feature branches → PR →
dev. CI runs everything except notebook regen.When
devis ready: open a PRdev → main. Theregenerate_notebooksjob re-executes notebooks and commits the refreshed outputs to the PR branch automatically.Merge
dev → main, then tag the merge commit onmain. Theupload_to_pypijob publishes wheels + sdist to PyPI.Read the Docs picks up the new tag automatically and rebuilds the
stableversion against the published wheel. No manual gh-pages deploy step.
make release-check runs the relevant local subset before opening the
release PR.
Code style
Python: PEP 8 (ruff-enforced).
C++: Google style (clang-format-enforced).
src/include/docstr.hppis excluded — it’s a build artifact.Type hints: required on Python source; ty checks them.
Docstrings: required on public functions.
Troubleshooting
docstr.hpplooks stale or import fails after C++ changes: re-runpip install -e . --no-build-isolation—editable.rebuild = truehandles most cases, but a fresh manual install fixes anything weird.Build issues:
make debug-buildfor verbose output.Project status:
make statusshows git + Python + installed deps.Nuclear option:
make git-clean(⚠️ removes everything not tracked by git).
Tips
Run
make quick-checkearly and often.Pre-commit hooks fix most formatting issues automatically; just re-stage and commit again.
Notebook output noise: don’t commit re-executed notebooks from a local editable build (they capture absolute paths from the editable rebuild print). Let the CI
regenerate_notebooksjob own that.