Contributing
Development Setup
pybasin uses uv for dependency management. After cloning the repository, a single command installs everything:
git clone https://github.com/adrianwix/pybasin.git
cd pybasinWorkspace
uv sync --all-groups
source .venv/bin/activate
This creates a virtual environment with all dependency groups -- dev tools, documentation, case studies, and experiments -- so every part of the codebase is immediately usable.
Repository Structure
The workspace is a monorepo containing two publishable packages:
- pybasin (
src/pybasin/) -- the main basin stability library - zigode (
src/zigode/) -- a Zig-compiled native ODE solver (separatepyproject.toml)
Both are managed under a single uv workspace, sharing one lockfile while remaining independently publishable.
Alongside these packages live several directories that are not published:
thesis_utils/-- thesis-specific plotting utilities (depend oncpsmehelper)case_studies/-- research case studies validating pybasin against MATLAB bSTABbenchmarks/-- performance benchmarkstests/-- unit and integration testsdocs/-- MkDocs documentation source
Dependency Management
Core runtime dependencies are declared in [project.dependencies] in the root pyproject.toml. Keep these minimal -- only packages needed for import pybasin to work without errors.
Optional features live under [project.optional-dependencies]:
| Extra | Packages | Purpose |
|---|---|---|
jax |
jax, diffrax | JaxSolver |
interactive |
plotly, dash, dash-mantine-components | InteractivePlotter |
tsfresh |
tsfresh | TsfreshFeatureExtractor |
nolds |
nolds | NoldsFeatureExtractor |
torchode |
torchode | TorchOdeSolver |
all |
all of the above | Everything |
Development-only tools (ruff, pyright, pytest, type stubs, etc.) go in [dependency-groups] under dev, docs, case-studies, or experiments. These are never installed by end users.
To add a new runtime dependency:
Never edit pyproject.toml manually for adding dependencies.
Adding an Optional Feature
When a new feature depends on a package that should not be required for all users:
- Add the package to a new or existing extra in
[project.optional-dependencies] - Guard the import with
try/except ImportErrorin the module (seenolds_feature_extractor.pyfor the pattern) - Raise a clear
ImportErrorwith the install command if the user tries to use the feature without the package - Add the extra to the
allgroup
Code Quality
Run all checks (linter, formatter, type checker) in one command:
This executes ruff lint, ruff format, and pyright across the codebase. All three must pass before merging.
Testing
uv run pytest # all tests
uv run pytest tests/unit/ # unit tests only
uv run pytest tests/integration/ # integration tests only
uv run pytest --cov=src/pybasin # with coverage
Integration tests compare pybasin results against the original MATLAB bSTAB implementation.
Adding a New Case Study
- Create a new directory under
case_studies/ - Define the ODE system (subclass
ODESystemorJaxODESystem) - Create a setup function returning sampler, solver, and ODE system configuration
- Write a main script that runs
BasinStabilityEstimator.estimate_bs() - Add a corresponding integration test under
tests/integration/ - Document the case study under
docs/case-studies/