{"id":25948719,"url":"https://github.com/sciexp/python-nix-template","last_synced_at":"2026-02-17T18:08:14.330Z","repository":{"id":279876051,"uuid":"927894653","full_name":"sciexp/python-nix-template","owner":"sciexp","description":"❄️ (om)nix template for python workspace monorepos +/- pyo3 extension modules with uv2nix and flake-parts 🐍","archived":false,"fork":false,"pushed_at":"2025-04-12T07:41:09.000Z","size":494,"stargazers_count":3,"open_issues_count":15,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-04-12T08:34:58.849Z","etag":null,"topics":["conda","containers","devcontainer","functional-programming","just","monorepo","nix","nix-flake","oci","pixi","pyo3","python","python3","railway-oriented-programming","runtime-typechecking","static-typechecking","template-project","uv"],"latest_commit_sha":null,"homepage":"","language":"Nix","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/sciexp.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":".github/CODE_OF_CONDUCT.md","threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":".github/SECURITY.md","support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2025-02-05T18:07:25.000Z","updated_at":"2025-03-21T17:55:46.000Z","dependencies_parsed_at":"2025-02-28T08:18:42.378Z","dependency_job_id":"be315cc3-0c58-4bb5-8b60-5e7c6b24e821","html_url":"https://github.com/sciexp/python-nix-template","commit_stats":null,"previous_names":["cameronraysmith/python-nix-template"],"tags_count":12,"template":true,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sciexp%2Fpython-nix-template","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sciexp%2Fpython-nix-template/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sciexp%2Fpython-nix-template/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sciexp%2Fpython-nix-template/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/sciexp","download_url":"https://codeload.github.com/sciexp/python-nix-template/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248607969,"owners_count":21132643,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["conda","containers","devcontainer","functional-programming","just","monorepo","nix","nix-flake","oci","pixi","pyo3","python","python3","railway-oriented-programming","runtime-typechecking","static-typechecking","template-project","uv"],"created_at":"2025-03-04T11:01:59.338Z","updated_at":"2026-02-17T18:08:14.323Z","avatar_url":"https://github.com/sciexp.png","language":"Nix","readme":"# python-nix-template\n\nA nix template for python packages managed with\n[uv2nix](https://github.com/pyproject-nix/uv2nix) and\n[flake-parts](https://github.com/hercules-ci/flake-parts).\nThe structure mirrors those in the [omnix registry](#credits) to the extent possible with python and its ecosystem.\n\n## Template usage\n\nYou can use [omnix](https://omnix.page/om/init.html)[^omnix] to initialize this template:\n\n```sh\nnix --accept-flake-config run github:juspay/omnix -- \\\ninit github:sciexp/python-nix-template -o new-python-project\n```\n\n[^omnix]: If you have omnix installed you just need `om init ...` and not `nix run ... -- init`\n\ntl;dr\n\n\u003cdetails\u003e\u003csummary\u003einstantiate a monorepo variant of the template\u003c/summary\u003e\n\n```sh\nPROJECT_DIRECTORY=pnt-mono \u0026\u0026 \\\nPROJECT_SNAKE_CASE=$(echo \"$PROJECT_DIRECTORY\" | tr '-' '_') \u0026\u0026 \\\nPARAMS=$(cat \u003c\u003cEOF\n{\n  \"package-name-kebab-case\": \"$PROJECT_DIRECTORY\",\n  \"package-name-snake-case\": \"$PROJECT_SNAKE_CASE\",\n  \"monorepo-package\": true,\n  \"pyo3-package\": true,\n  \"git-org\": \"pnt-mono\",\n  \"author\": \"Pnt Mono\",\n  \"author-email\": \"mono@pnt.org\",\n  \"project-description\": \"A Python monorepo project using Nix and uv2nix\",\n  \"vscode\": true,\n  \"github-ci\": true,\n  \"docs\": true,\n  \"nix-template\": false\n}\nEOF\n) \u0026\u0026 \\\nnix --accept-flake-config run github:juspay/omnix/v1.3.2 -- init github:sciexp/python-nix-template/main -o \"$PROJECT_DIRECTORY\" --non-interactive --params \"$PARAMS\" \u0026\u0026 \\\n(command -v direnv \u003e/dev/null 2\u003e\u00261 \u0026\u0026 direnv revoke \"./$PROJECT_DIRECTORY/\" || true) \u0026\u0026 \\\ncd \"$PROJECT_DIRECTORY\" \u0026\u0026 \\\ngit init \u0026\u0026 \\\ngit commit --allow-empty -m \"initial commit (empty)\" \u0026\u0026 \\\ngit add . \u0026\u0026 \\\nfor pkg in packages/*/; do [ -f \"$pkg/pyproject.toml\" ] \u0026\u0026 (cd \"$pkg\" \u0026\u0026 nix run github:NixOS/nixpkgs/nixos-unstable#uv -- lock); done \u0026\u0026 \\\ngit add . \u0026\u0026 \\\nnix develop --accept-flake-config -c just test-all\n```\n\n\u003c/details\u003e\n\nYou can run `direnv allow` to enter the shell environment that contains\ndevelopment dependencies or `nix develop --accept-flake-config` to enter (or add\n`-c command` to execute individual commands within) the development shell.\n\n\u003cdetails\u003e\u003csummary\u003einstantiate a single-package variant of the template\u003c/summary\u003e\n\n```sh\nPROJECT_DIRECTORY=pnt-new \u0026\u0026 \\\nPROJECT_SNAKE_CASE=$(echo \"$PROJECT_DIRECTORY\" | tr '-' '_') \u0026\u0026 \\\nPARAMS=$(cat \u003c\u003cEOF\n{\n  \"package-name-kebab-case\": \"$PROJECT_DIRECTORY\",\n  \"package-name-snake-case\": \"$PROJECT_SNAKE_CASE\",\n  \"monorepo-package\": false,\n  \"pyo3-package\": false,\n  \"git-org\": \"pnt-new\",\n  \"author\": \"Pnt New\",\n  \"author-email\": \"new@pnt.org\",\n  \"project-description\": \"A Python project using Nix and uv2nix\",\n  \"vscode\": true,\n  \"github-ci\": true,\n  \"docs\": true,\n  \"nix-template\": false\n}\nEOF\n) \u0026\u0026 \\\nnix --accept-flake-config run github:juspay/omnix/v1.3.2 -- init github:sciexp/python-nix-template/main -o \"$PROJECT_DIRECTORY\" --non-interactive --params \"$PARAMS\" \u0026\u0026 \\\n(command -v direnv \u003e/dev/null 2\u003e\u00261 \u0026\u0026 direnv revoke \"./$PROJECT_DIRECTORY/\" || true) \u0026\u0026 \\\ncd \"$PROJECT_DIRECTORY\" \u0026\u0026 \\\ngit init \u0026\u0026 \\\ngit commit --allow-empty -m \"initial commit (empty)\" \u0026\u0026 \\\ngit add . \u0026\u0026 \\\nfor pkg in packages/*/; do [ -f \"$pkg/pyproject.toml\" ] \u0026\u0026 (cd \"$pkg\" \u0026\u0026 nix run github:NixOS/nixpkgs/nixos-unstable#uv -- lock); done \u0026\u0026 \\\ngit add . \u0026\u0026 \\\nnix develop --accept-flake-config -c just test-all\n```\n\n\u003c/details\u003e\n\nexcept you may want to update the git ref/rev of the template if you need to pin to a\nparticular version:\n\n- `github:sciexp/python-nix-template/main`\n- `github:sciexp/python-nix-template/v0.1.0`\n- `github:sciexp/python-nix-template/3289dla`\n- `github:sciexp/python-nix-template/devbranch`.\n\n### Quick start\n\n#### Nix-managed environment\n\nThe template supports three types of development environments:\n\n1. nix devshell\n2. python virtualenv via uv\n3. conda environments via pixi\n\nThe intended workflow is to run\n\n```sh\nmake bootstrap\n```\n\nonly the very first time you are setting up one of these templates.\nThis will verify you have the [nix package manager](https://nix.dev) and [direnv](https://direnv.net/) installed.\nRegistration of the repository contents requires creating a git repository, for example with\n\n```sh\ngit init \u0026\u0026 git commit --allow-empty -m \"initial commit (empty)\" \u0026\u0026 git add .\n```\n\nbut does not require committing.\nAfter this running\n\n```sh\ndirenv allow\n```\n\nwill ensure you have all development tools on a project directory-specific version of your PATH variable.\nThese include the `just` task runner, which provides an alternative to using [GNU Make](https://www.gnu.org/software/make/) as a task runner.\nSee the [task runner](#task-runner) section for a listing of development commands.\n\nYou should now be able to run `just test-all` to confirm all package tests pass in the devshell environment, or `just test \u003cpackage-name\u003e` to test a specific package.\n\n\u003e [!NOTE]\n\u003e This template uses an independent-lock pattern where each package under\n\u003e `packages/` maintains its own `pyproject.toml` and `uv.lock`. There is no root\n\u003e `pyproject.toml` or uv workspace. After instantiation, lock each package\n\u003e individually:\n\u003e\n\u003e ```sh\n\u003e for pkg in packages/*/; do [ -f \"$pkg/pyproject.toml\" ] \u0026\u0026 (cd \"$pkg\" \u0026\u0026 uv lock); done\n\u003e ```\n\nIf you choose to modify packages or add dependencies, run `just uv-lock \u003cpackage-name\u003e` to update the lock file for that specific package.\n\n#### Python virtualenv\n\n1. Create and sync virtual environment:\n\n   ```sh\n   just venv\n   source .venv/bin/activate\n   ```\n\n2. Run tests:\n\n   ```sh\n   just test\n   ```\n\n3. Run linting:\n\n   ```sh\n   just lint\n   ```\n\n4. Build package:\n\n   ```sh\n   just build\n   ```\n\n## Features\n\n- Modern python packaging with `pyproject.toml`\n- Fast dependency management with `uv`\n- Reproducible developer environments and builds with `nix` and `uv2nix`\n- conda ecosystem compatibility via `pixi`\n\n\u003cdetails\u003e\u003csummary\u003eOptional packages\u003c/summary\u003e\n\nThe template includes optional packages controlled by omnix template parameters.\nBoth default to false for the single-package variant and can be set to true individually or together.\n\n*pnt-functional* (`monorepo-package` parameter) provides a brief illustration of functional programming patterns in Python.\nIt demonstrates railway-oriented programming with `expression` for type-safe error handling, effect tracking via monad transformers for composable side effects, runtime type checking with `beartype`, pure functions and immutable data types, and composition of effectful functions using monadic bind operations.\nSee [packages/pnt-functional](./packages/pnt-functional) for details.\n\n*pnt-cli* (`pyo3-package` parameter) is a Rust extension module demonstrating Python-Rust interop via [pyo3](https://pyo3.rs) and [maturin](https://www.maturin.rs).\nIt exposes Rust functions callable from Python through a compiled native module (`pnt_cli._native`).\nThe Rust side is organized as a Cargo workspace with a core library crate and a pyo3 binding crate under `packages/pnt-cli/crates/`.\nOn the Nix side, the build uses [crane](https://github.com/ipetkov/crane) for incremental Rust compilation caching and [crane-maturin](https://github.com/vlaci/crane-maturin) for producing maturin-compatible wheels.\nThe resulting artifact is installed into the uv2nix package set via `pyproject-nix`'s `nixpkgsPrebuilt`, avoiding duplicate Rust compilation during Nix evaluation.\nSee [packages/pnt-cli](./packages/pnt-cli) and [nix/packages/pnt-cli](./nix/packages/pnt-cli) for the implementation.\n\n\u003c/details\u003e\n\n## Development\n\n### Prerequisites\n\nIf you'd like to develop `python-nix-template` you'll need the [nix package manager](https://nix.dev).\nYou can optionally make use of [direnv](https://direnv.net/) to automatically activate the environment.\nThe project includes a Makefile to help bootstrap your development environment.\n\nIt provides:\n\n1. Installation of the nix package manager using the Determinate Systems installer\n2. Installation of direnv for automatic environment activation\n3. Link to instructions for shell configuration\n\nTo get started, run:\n\n```shell\nmake bootstrap\n```\n\nRun `make` alone for a listing of available targets.\n\nAfter nix and direnv are installed, you can either run `direnv allow` or `nix develop` to enter a [development shell](./nix/modules/devshell.nix) that will contain necessary system-level dependencies.\n\n### Task runner\n\nThis project uses [`just`](https://just.systems/man/en/) as a task runner, which is provided in the [development shell](#prerequisites).\nList available commands by running `just` alone.\n\n\u003cdetails\u003e\n\u003csummary\u003ejust recipes\u003c/summary\u003e\n\n```sh\nAvailable recipes:\n    default                                            # List all recipes\n\n    [CI/CD]\n    ci-build-category system category                  # Build a category of nix flake outputs for CI matrix\n    ci-check package                                   # Run all checks for a package (lint, typecheck, test)\n    ci-lint package                                    # Run linting for a package\n    ci-sync package                                    # Sync dependencies for a package via uv\n    ci-test package                                    # Run tests for a package\n    ci-typecheck package                               # Run type checking for a package\n    gcloud-context                                     # Set gcloud context\n    gh-docs-build branch=`git branch --show-current` debug=\"false\" # Trigger docs build job remotely on GitHub (requires workflow on main)\n    gh-docs-cancel run_id=\"\"                           # Cancel a running docs workflow\n    gh-docs-logs run_id=\"\" job=\"\"                       # View logs for a specific docs workflow run\n    gh-docs-rerun run_id=\"\" failed_only=\"true\"         # Re-run a failed docs workflow\n    gh-docs-watch run_id=\"\"                            # Watch a specific docs workflow run\n    gh-workflow-status workflow=\"deploy-docs.yaml\" branch=`git branch --show-current` limit=\"5\" # View recent workflow runs status\n    ghsecrets repo=\"sciexp/python-nix-template\"        # Update github secrets for repo from environment variables\n    ghvars repo=\"sciexp/python-nix-template\"           # Update github vars for repo from environment variables\n    list-packages-json                                 # Discover packages as JSON array for CI matrix\n    list-workflows                                     # List available workflows and associated jobs using act\n    pre-commit                                         # Run pre-commit hooks (see pre-commit.nix and note the yaml is git-ignored)\n    scan-secrets                                       # Scan repository for hardcoded secrets\n    scan-staged                                        # Scan staged files for hardcoded secrets (pre-commit)\n    test-docs-build branch=`git branch --show-current` # Test build-docs job locally with act\n    test-docs-deploy branch=`git branch --show-current` # Test full deploy-docs workflow locally with act\n\n    [conda]\n    conda-build package=\"python-nix-template\"          # Package commands (conda)\n    conda-check package=\"python-nix-template\"          # Run all checks in conda environment (lint, type, test)\n    conda-env package=\"python-nix-template\"            # Create and sync conda environment with pixi\n    conda-lint package=\"python-nix-template\"           # Run linting in conda environment with pixi\n    conda-lint-fix package=\"python-nix-template\"       # Run linting and fix errors in conda environment with pixi\n    conda-lock package=\"python-nix-template\"           # Update conda environment\n    conda-test package=\"python-nix-template\"           # Run tests in conda environment with pixi\n    conda-type package=\"python-nix-template\"           # Run type checking in conda environment with pixi\n    pixi-lock package=\"python-nix-template\"            # Update pixi lockfile\n\n    [containers]\n    container-build-production CONTAINER=\"pnt-cli\"     # Build production container image\n    container-load-production CONTAINER=\"pnt-cli\"      # Load production container to local Docker daemon\n    container-matrix                                   # Display container CI matrix\n    container-push-production CONTAINER=\"pnt-cli\" VERSION=\"0.0.0\" +TAGS=\"\" # Push production container manifest (requires registry auth)\n\n    [docs]\n    data-sync                                          # Sync data from drive (using encrypted service account)\n    docs-build                                         # Build docs\n    docs-check                                         # Check docs\n    docs-deploy-preview branch=`git branch --show-current` # Deploy documentation to Cloudflare Workers (preview)\n    docs-deploy-production                             # Deploy documentation to Cloudflare Workers (production)\n    docs-deployments                                   # List recent Cloudflare Workers deployments\n    docs-dev                                           # Run local docs deployment\n    docs-extensions                                    # Add quartodoc extension\n    docs-local                                         # Preview docs locally\n    docs-reference                                     # Build quartodoc API reference\n    docs-sync                                          # Sync docs freeze data to DVC remote\n    docs-tail                                          # Tail live logs from Cloudflare Workers\n    docs-versions                                      # List recent Cloudflare Workers versions\n\n    [nix]\n    ci                                                 # Run CI checks locally with `om ci`\n    dev                                                # Enter the Nix development shell\n    flake-check                                        # Validate the Nix flake configuration for the current system\n    flake-update                                       # Update all flake inputs to their latest versions\n\n    [python]\n    check package=\"python-nix-template\"                # Run all checks for a package (lint, type, test)\n    lint package=\"python-nix-template\"                 # Run linting for a package\n    lint-all                                           # Run linting for all packages\n    lint-fix package=\"python-nix-template\"             # Run linting and fix errors for a package\n    test package=\"python-nix-template\"                 # Run tests for a package\n    test-all                                           # Run tests for all packages\n    type package=\"python-nix-template\"                 # Run type checking for a package\n    uv-build package=\"python-nix-template\"             # Build a package with uv\n    uv-lock package=\"python-nix-template\"              # Update lockfile for a package\n    uv-sync package=\"python-nix-template\"              # Sync a package environment with uv\n\n    [release]\n    preview-version base-branch package-path           # Preview release version for a package (dry-run semantic-release with merge simulation)\n    release-package package-name dry-run=\"false\"       # Run semantic-release for a package\n    test-package-release package-name=\"python-nix-template\" branch=\"main\" # Test package release\n    test-release                                       # Release testing with bun\n    test-release-as-main                               # Test release as if on main branch\n    test-release-direct                                # Test release directly on release branch\n    test-release-on-current-branch                     # Test release with explicit branch override\n    update-version package-name version                # Update version for a specific package across all relevant files\n\n    [rust]\n    cargo-build package=\"pnt-cli\"                      # Build Rust crates for a package\n    cargo-check package=\"pnt-cli\"                      # Run all Rust checks (clippy, test)\n    cargo-clippy package=\"pnt-cli\"                     # Run Rust clippy lints\n    cargo-nextest package=\"pnt-cli\"                    # Run Rust tests via cargo-nextest\n    cargo-test package=\"pnt-cli\"                       # Run Rust tests via cargo test\n\n    [secrets]\n    check-secrets                                      # Check secrets are available in sops environment\n    dvc-run +command                                   # Helper: Run any DVC command with decrypted service account\n    edit-secrets                                       # Edit shared secrets file\n    export-secrets                                     # Export unique secrets to dotenv format using sops\n    gcp-enable-drive-api                               # Enable Google Drive API in GCP project\n    gcp-sa-create                                      # Create GCP service account for DVC access (run once)\n    gcp-sa-key-delete key_id                           # Delete a specific service account key\n    gcp-sa-key-download                                # Download service account key (for key rotation)\n    gcp-sa-key-encrypt                                 # Encrypt service account key with sops\n    gcp-sa-key-rotate                                  # Rotate service account key\n    gcp-sa-keys-list                                   # List existing service account keys (for auditing)\n    gcp-sa-storage-user                                # Grant Storage Object User role for GCS access\n    get-secret key                                     # Show specific secret value from shared secrets\n    new-secret file                                    # Create a new sops encrypted file\n    rotate-secret secret_name                          # Rotate a specific secret interactively\n    run-with-secrets +command                          # Run command with all shared secrets as environment variables\n    set-secret secret_name secret_value                # Add or update a secret non-interactively\n    show-secrets                                       # Show existing secrets using sops\n    sops-add-key                                       # Add existing age key to local configuration\n    sops-init                                          # Initialize sops age key for new developers\n    updatekeys                                         # Update keys for existing secrets files after adding new recipients\n    validate-secrets                                   # Validate all sops encrypted files can be decrypted\n\n    [template]\n    template-init                                      # Initialize new project from template\n    template-verify                                    # Verify template functionality by creating and checking a test project\n```\n\n\u003c/details\u003e\n\n## Credits\n\n### Python\n\n- [beartype](https://github.com/beartype/beartype) -- gradual runtime type checking\n- [Expression](https://github.com/dbrattli/Expression) -- functional programming abstractions for Python\n\n### Python in Nix\n\n- [uv2nix](https://github.com/pyproject-nix/uv2nix) -- Nix integration for uv-managed Python workspaces\n- [pyproject.nix](https://github.com/pyproject-nix/pyproject.nix) -- Nix library for Python project management, used by uv2nix for build-system resolution\n- [pyproject-build-systems](https://github.com/pyproject-nix/build-system-pkgs) -- pre-built Python build-system packages for Nix\n\n### Rust in Nix\n\n- [crane](https://github.com/ipetkov/crane) -- Nix library for building Rust projects with incremental compilation caching\n- [crane-maturin](https://github.com/vlaci/crane-maturin) -- crane extension for building maturin/pyo3 Python-Rust packages\n- [rust-overlay](https://github.com/oxalica/rust-overlay) -- Nix overlay providing nightly and stable Rust toolchains\n\n### Nix\n\n\u003cdetails\u003e\u003csummary\u003eomnix registry and flake-parts ecosystem\u003c/summary\u003e\n\nSee the [omnix registry flake](https://github.com/juspay/omnix/blob/1.0.0/crates/omnix-init/registry/flake.nix)\n\n- [srid/haskell-template](https://github.com/srid/haskell-template)\n- [srid/rust-nix-template](https://github.com/srid/rust-nix-template)\n- [hercules-ci/flake-parts](https://github.com/hercules-ci/flake-parts)\n\n\u003c/details\u003e\n","funding_links":[],"categories":["Nix"],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsciexp%2Fpython-nix-template","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fsciexp%2Fpython-nix-template","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsciexp%2Fpython-nix-template/lists"}