# 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](https://docs.astral.sh/uv/)** - **[Rust toolchain](https://rustup.rs/)** — required to compile the `openpkpd._core` extension. Install once with: ```bash curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh ``` On Windows, download and run `rustup-init.exe` from [rustup.rs](https://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 ```bash 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: ```bash 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: ```bash 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: ```bash 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 ```bash # 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: ```bash 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: ```bash uv run ruff check src/ tests/ uv run ruff format src/ tests/ ``` Type annotations are checked with **mypy**: ```bash uv run mypy src/ ``` Pre-commit hooks run both automatically on `git commit`: ```bash just install-hooks ``` ## Building documentation ```bash 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 {doc}`installer build guide `. ## Performance-oriented development For contributors working on runtime improvements, see the {doc}`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 {doc}`/user_guide/index` 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).