Contributing to cpm#
Thank you for contributing to cpm. This guide explains how to set up your environment, make changes, and submit a pull request.
Prerequisites#
Python
>=3.12pipgit
Local setup#
Fork the repository and clone your fork.
Create and activate a virtual environment.
Install the package in editable mode:
pip install -e .
(Optional, for docs work) Install the documentation dependencies:
pip install -e ".[docs]"
(Optional) Install numba, which compiles the built-in models (
cpm.applications) and the kernels incpm.models.kernels:
pip install -e ".[numba]"
cpm has to work, with the same results, with and without numba, so changes to the models are tested both ways (see Testing).
Development workflow (with direct access to repository)#
Create a branch from
main.Make focused changes with clear commit history. See commit message conventions below.
Run tests locally before opening a pull request.
Update documentation and changelog when relevant.
Open a Pull Request on GitHub.
Development workflow (without direct access)#
Fork the repository.
(optional) Create a branch from
main.Make focused changes with clear commit history. See commit message conventions below.
Run tests locally before opening a pull request.
Update documentation and changelog when relevant.
Open a Pull Request on GitHub.
Branch naming convention#
Start your branch name with one of:
feature/for adding, refactoring, or removing a featurebugfix/for fixing a bughotfix/for urgent, temporary, or process-exception changestest/for experiments and test-related workdocs/for adding documentation or examples.
Example:
feature/add-hierarchical-export
Code style and quality#
Format Python code with Black.
Keep code readable and focused; avoid unrelated refactors in the same PR.
Use NumPy-style docstrings where applicable.
Keep public API changes backward-compatible where possible.
Testing#
Run the test suite from the repository root:
pytest
If you changed specific functionality, also run targeted tests first (for example, under test/models/ or test/optimisation/).
If you changed the models (cpm.models, cpm.applications) or anything they use, also run the tests with and without numba, and the benchmark suite:
python scripts/local_tests.py
It runs the test suite with numba (if it is installed), with CPM_DISABLE_JIT=1 (as if numba were not installed), and with NUMBA_DISABLE_JIT=1, and then benchmarks/run.py.
numba caches compiled code in the __pycache__ folders under cpm/, and only recompiles a function when its own file changes. After changing cpm/models/kernels.py (yourself, or by pulling), the compiled loops in cpm/applications/_sessions.py still use the old kernels until you delete the cached *.nbi and *.nbc files; scripts/local_tests.py deletes them before it runs.
Documentation#
The documentation is built with Sphinx and the PyData theme.
It has two sources: the docstrings in cpm/, which make up the API reference, and the pages under docs/.
Building the documentation#
pip install -e ".[docs]"
python -m sphinx -W --keep-going -b html docs docs/_build/html
Open docs/_build/html/index.html in a browser.
While you write, sphinx-autobuild rebuilds the pages and reloads the browser on every change:
sphinx-autobuild docs docs/_build/html --watch cpm --ignore "*/api/generated/*" --ignore "*/_static/thumbnails/*"
The build must finish without warnings: CI runs it with -W.
Where things live#
Folder |
Contents |
|---|---|
|
installation, quickstart, core concepts, troubleshooting |
|
the numbered learning path, as Jupyter notebooks |
|
research examples, as Jupyter notebooks, grouped by domain in |
|
short guides for specific tasks |
|
the API reference pages; add new public objects to the |
|
citing, changelog, roadmap, contributing, license |
|
checks run in CI, and tools for notebooks |
Docstrings#
Docstrings use the NumPy style and reStructuredText, not Markdown:
math:
:math:`lpha`inline, and a.. math::block for equations. Docstrings with a backslash must be raw strings (r"""...""").links to cpm objects:
:class:`~cpm.generators.Wrapper`,:func:`~cpm.datasets.load_bandit_data`; in a “See Also” section, just the name:cpm.generators.Wrapper : description.other links:
`text <https://example.org>`__.`single backticks`show code.
python docs/scripts/md2rst_docstrings.py --check cpm finds Markdown left in docstrings, and python docs/scripts/check_api_coverage.py finds public objects missing from the API reference.
To link an API page to the tutorials that use the object, add it to API_TUTORIAL_LINKS in docs/conf.py.
Notebooks#
Tutorials and examples are Jupyter notebooks, rendered with their stored outputs; they are not run when the documentation is built. Each notebook follows the same structure:
a short
#title, followed by a line with the level, the time it takes, the prerequisites, the cpm components used, and the data,a “What you’ll learn” list,
one setup cell that imports cpm, prints
cpm.__version__, and sets a random seed,the content, with headings that do not skip levels,
a
## Summary and next stepssection, and a## Referencessection.
Link to the API with [`Wrapper`](#cpm.generators.Wrapper), and to other pages with relative links to their files, such as [Tutorial 1](../tutorials/first-model.ipynb), so that the links also work when the notebook is opened in Jupyter.
In examples, tag the cell whose figure should be the gallery thumbnail with thumbnail.
Notebooks must not write files into docs/.
Before committing a notebook, run it from top to bottom in a fresh kernel, then clean and check it:
jupyter nbconvert --to notebook --execute --inplace docs/tutorials/first-model.ipynb
python docs/scripts/clean_notebooks.py docs/tutorials/first-model.ipynb
python docs/scripts/check_notebooks.py
A new example also needs a card in docs/examples/index.md, and a new tutorial one in docs/tutorials/index.md.
Commit messages#
Please follow Conventional Commits.
Examples:
feat(models): add drift-bias parameterfix(optimisation): handle empty boundsdocs(api): clarify hierarchical fitting inputs
Pull requests#
When opening a PR:
Keep the PR scope small and focused.
Include a clear description of what changed and why.
Link related issues.
Add/update tests for behavior changes.
Update docs when user-facing behavior changes.
Before requesting review, verify:
Tests pass locally.
The documentation builds without warnings if you changed docstrings or pages.
No unrelated files are included.
Troubleshooting and getting help#
If you run into issues at any point, please reach out. We are happy to help with anything.
For faster support, please include:
What you were trying to do
The exact error message or traceback
Your Python version and operating system
Steps to reproduce the issue
Best ways to get help:
Open a GitHub issue for bugs, setup problems, or unclear behavior
Open a draft PR if you want feedback while you are still working
Ask your question directly in the PR conversation if it is related to your change
Build and release notes#
To prepare a release:
Set the version in
cpm/__version__.pyand date its section inCHANGELOG.md.Build and check the source distribution and wheel:
pip install build twine python -m build twine check dist/*
After merging into
main, tag the release with the bare version (for example0.26.0, notv0.26.0); the documentation links to the source at this tag.
Publishing to PyPI is maintainer-only and typically done with:
twine upload dist/*