Contributing

Contributions to OpenPKPD are welcome. This page describes how to set up a development environment, run the test suite, and submit a pull request.

Development setup

Prerequisites

  • Python 3.12+ and uv

  • Rust toolchain — required to compile the openpkpd._core extension. Install once with:

    curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
    

    On Windows, download and run rustup-init.exe from rustup.rs. The Rust toolchain is needed at build time only — end-users who install a pre-built wheel from PyPI do not need it.

Setup

git clone https://github.com/your-org/OpenPKPD.git
cd OpenPKPD

# Install all extras including dev tools
uv sync --all-extras

# Or, for the symbolic analytical-kernel test path specifically
uv sync --extra dev --extra symbolic

# Compile and install the Rust extension in-place
just build-core

# Verify
uv run pytest -q
just prewarm-symbolic-caches

Note: If you skip just build-core, the package will still import and all tests will pass — the pure-Python fallback is used automatically. The compiled extension only affects runtime performance of the log-likelihood inner loop.

just workflow and platform support

The repository includes a justfile for common contributor workflows. The recipes are intended to work on macOS, Linux, and Windows.

  • Recipes now select their own uv extras where needed, so commands like docs, GUI, plotting examples, and cluster examples do not rely on a pre-synced all-extras environment.

  • Shell-heavy operations have been moved into Python helpers under scripts/just/ to keep behavior as consistent as possible across platforms.

Typical usage:

just run-tests-unit
just prewarm-symbolic-caches
just lint
just build-docs-html
just run-example 01

Remaining external prerequisites depend on the recipe:

  • build-core / build-wheel require the Rust toolchain (rustup)

  • build-core-native-cvodes also requires the Rust toolchain and enables the optional native CVODES path

  • install-hooks requires git

  • build-docs-pdf requires a working LaTeX installation

  • watch-docs and the *-and-open recipes require browser/open support on the host

  • run-gui requires a working desktop/Qt environment

For the current native CVODES path, the development workflow is:

just build-core-native-cvodes
just smoke-native-cvodes

With that recipe, development mode allows the package to preload SUNDIALS shared libraries from both:

  • local Cargo build outputs

  • package-adjacent library directories such as openpkpd.libs / .libs

Released wheels should rely on packaged library directories only. Cargo-target discovery is intentionally development-only and is activated through OPENPKPD_NATIVE_DEV=1 by the just recipe above.

At the moment, native-cvodes is development-validated but not yet considered PyPI-wheel ready. The remaining work is wheel packaging for bundled SUNDIALS libraries across Linux, macOS, and Windows. Until that is finished, release validation should treat build-core-native-cvodes plus smoke-native-cvodes as a pre-publish smoke path rather than a publishable wheel guarantee.

For wheel-oriented work, the current first target is Linux:

just build-wheel-native-cvodes
just smoke-installed-native-cvodes-wheel

On Linux, maturin needs patchelf available to repair bundled shared-library references for the wheel. The repository CI should provide that for native wheel jobs; local contributor machines may need to install it explicitly.

Running tests

# All tests
uv run pytest -q

# Unit tests only (fast)
uv run pytest tests/unit/ -q

# Integration tests
uv run pytest tests/integration/ -v

# With coverage report
uv run pytest --cov=openpkpd --cov-report=html

For the symbolic analytical-kernel route, the intended local/CI workflow is:

uv sync --extra dev --extra symbolic
just prewarm-symbolic-caches
uv run pytest tests/unit/model/test_symbolic_eta.py tests/unit/estimation/test_bayes.py -q

Test categories:

Marker

Description

unit

Fast isolated component tests (<1 s each)

integration

End-to-end pipeline tests

regression

Comparison vs golden NONMEM output

slow

Tests taking >30 seconds

Code style

OpenPKPD uses ruff for linting and formatting:

uv run ruff check src/ tests/
uv run ruff format src/ tests/

Type annotations are checked with mypy:

uv run mypy src/

Pre-commit hooks run both automatically on git commit:

just install-hooks

Building documentation

just build-docs-html
# or: just build-docs-and-open

Building standalone installers

To package OpenPKPD as a self-contained desktop application (no Python required on the end-user machine), see the installer build guide.

Performance-oriented development

For contributors working on runtime improvements, see the developer performance guide.

It summarizes the repository’s preferred optimization style, existing profiling entry points, validation expectations, and current high-value hotspots.

Project structure

See the User Guide for an overview of major modules. Key files:

File

Role

src/openpkpd/api/model_builder.py

Fluent Python API

src/openpkpd/parser/control_stream.py

NM-TRAN parser

src/openpkpd/parser/code_compiler.py

$PK/$ERROR → Python

src/openpkpd/pk/analytical/

ADVAN1–4 closed-form solutions

src/openpkpd/estimation/

FO, FOCE, SAEM, IMP implementations

src/openpkpd/plots/

Diagnostic plot functions

Submitting a pull request

  1. Fork the repository and create a feature branch.

  2. Write tests for any new functionality.

  3. Ensure all tests pass and ruff/mypy report no errors.

  4. Open a pull request with a clear description of the change.

Licence

OpenPKPD is released under the GNU Affero General Public Licence v3 (AGPLv3).