From d98f59f572088ee4f113b73deb30788deee473df Mon Sep 17 00:00:00 2001 From: Cameron Smith Date: Mon, 19 Jan 2026 11:26:16 -0500 Subject: [PATCH 001/134] chore(beads): init Signed-off-by: Cameron Smith --- .beads/.gitignore | 48 +++++++++++++++++++++++++++++++++++++++ .beads/interactions.jsonl | 0 .beads/metadata.json | 4 ++++ .gitattributes | 3 +++ 4 files changed, 55 insertions(+) create mode 100644 .beads/.gitignore create mode 100644 .beads/interactions.jsonl create mode 100644 .beads/metadata.json diff --git a/.beads/.gitignore b/.beads/.gitignore new file mode 100644 index 0000000..a5014be --- /dev/null +++ b/.beads/.gitignore @@ -0,0 +1,48 @@ +# SQLite databases +*.db +*.db?* +*.db-journal +*.db-wal +*.db-shm + +# Daemon runtime files +daemon.lock +daemon.log +daemon.pid +bd.sock +sync-state.json +last-touched + +# Local version tracking (prevents upgrade notification spam after git ops) +.local_version + +# Legacy database files +db.sqlite +bd.db + +# Worktree redirect file (contains relative path to main repo's .beads/) +# Must not be committed as paths would be wrong in other clones +redirect + +# Merge artifacts (temporary files from 3-way merge) +beads.base.jsonl +beads.base.meta.json +beads.left.jsonl +beads.left.meta.json +beads.right.jsonl +beads.right.meta.json + +# Sync state (local-only, per-machine) +# These files are machine-specific and should not be shared across clones +.sync.lock +sync_base.jsonl + +# .beads +README.md +config.yaml + +# NOTE: Do NOT add negation patterns (e.g., !issues.jsonl) here. +# They would override fork protection in .git/info/exclude, allowing +# contributors to accidentally commit upstream issue databases. +# The JSONL files (issues.jsonl, interactions.jsonl) and config files +# are tracked by git by default since no pattern above ignores them. diff --git a/.beads/interactions.jsonl b/.beads/interactions.jsonl new file mode 100644 index 0000000..e69de29 diff --git a/.beads/metadata.json b/.beads/metadata.json new file mode 100644 index 0000000..c787975 --- /dev/null +++ b/.beads/metadata.json @@ -0,0 +1,4 @@ +{ + "database": "beads.db", + "jsonl_export": "issues.jsonl" +} \ No newline at end of file diff --git a/.gitattributes b/.gitattributes index f2289d1..6fa96e3 100644 --- a/.gitattributes +++ b/.gitattributes @@ -3,3 +3,6 @@ flake.lock linguist-generated=true uv.lock linguist-generated=true pixi.lock linguist-generated=true yarn.lock linguist-generated=true + +# Use bd merge for beads JSONL files +.beads/issues.jsonl merge=beads From 0c97d2e79faee87f725b7b0bb48412714fcb9de1 Mon Sep 17 00:00:00 2001 From: Cameron Smith Date: Mon, 19 Jan 2026 11:55:48 -0500 Subject: [PATCH 002/134] chore(issues): seed beads graph with workstream epics and tasks Add 3 epics and 11 child issues for python-nix-template evolution: - pnt-dre: Infrastructure alignment (5 tasks) - pnt-4jg: Dependency model migration (3 tasks) - pnt-btz: pyo3/Rust extension integration (3 tasks) pnt-btz depends on pnt-dre and pnt-4jg completion. --- .beads/issues.jsonl | 14 ++++++++++++++ 1 file changed, 14 insertions(+) create mode 100644 .beads/issues.jsonl diff --git a/.beads/issues.jsonl b/.beads/issues.jsonl new file mode 100644 index 0000000..21b0d3b --- /dev/null +++ b/.beads/issues.jsonl @@ -0,0 +1,14 @@ +{"id":"pnt-4jg","title":"Dependency model migration","description":"Migrate from single-lock uv workspace to independent-lock multi-package pattern following langchain/langgraph approach. Include pixi feature-based composition for conda ecosystem parity.","status":"open","priority":2,"issue_type":"epic","owner":"cameron.ray.smith@gmail.com","created_at":"2026-01-19T11:54:40.744055-05:00","created_by":"Cameron Smith","updated_at":"2026-01-19T11:54:40.744055-05:00"} +{"id":"pnt-4jg.1","title":"Remove uv workspace, adopt path dependencies","description":"Remove [tool.uv.workspace] from root pyproject.toml. Each package gets own pyproject.toml with [tool.uv.sources] for sibling references using path sources with editable=true. Follow langchain pattern.","status":"open","priority":2,"issue_type":"task","owner":"cameron.ray.smith@gmail.com","created_at":"2026-01-19T11:55:07.344057-05:00","created_by":"Cameron Smith","updated_at":"2026-01-19T11:55:07.344057-05:00","dependencies":[{"issue_id":"pnt-4jg.1","depends_on_id":"pnt-4jg","type":"parent-child","created_at":"2026-01-19T11:55:07.344659-05:00","created_by":"Cameron Smith"}]} +{"id":"pnt-4jg.2","title":"Configure pixi feature-based composition","description":"Implement pixi feature/environment pattern: [feature.X.dependencies] + [environments] composition. Single pixi.lock covering all environments. Per-feature task definitions. Target-specific dependencies for platform support.","status":"open","priority":2,"issue_type":"task","owner":"cameron.ray.smith@gmail.com","created_at":"2026-01-19T11:55:08.085592-05:00","created_by":"Cameron Smith","updated_at":"2026-01-19T11:55:08.085592-05:00","dependencies":[{"issue_id":"pnt-4jg.2","depends_on_id":"pnt-4jg","type":"parent-child","created_at":"2026-01-19T11:55:08.086155-05:00","created_by":"Cameron Smith"}]} +{"id":"pnt-4jg.3","title":"Document package distribution channels","description":"Document which packages support uv/pypi vs pixi/conda distribution. Note dependency graph differences between channels. Update README and package metadata.","status":"open","priority":2,"issue_type":"task","owner":"cameron.ray.smith@gmail.com","created_at":"2026-01-19T11:55:09.051203-05:00","created_by":"Cameron Smith","updated_at":"2026-01-19T11:55:09.051203-05:00","dependencies":[{"issue_id":"pnt-4jg.3","depends_on_id":"pnt-4jg","type":"parent-child","created_at":"2026-01-19T11:55:09.051857-05:00","created_by":"Cameron Smith"}]} +{"id":"pnt-btz","title":"pyo3/Rust extension integration","description":"Add Rust extension module support via maturin + pyo3, demonstrating Nix build integration with pyproject.nix maturinBuildHook and crane patterns.","status":"open","priority":2,"issue_type":"epic","owner":"cameron.ray.smith@gmail.com","created_at":"2026-01-19T11:54:41.426256-05:00","created_by":"Cameron Smith","updated_at":"2026-01-19T11:54:41.426256-05:00","dependencies":[{"issue_id":"pnt-btz","depends_on_id":"pnt-dre","type":"blocks","created_at":"2026-01-19T11:55:32.690895-05:00","created_by":"Cameron Smith"},{"issue_id":"pnt-btz","depends_on_id":"pnt-4jg","type":"blocks","created_at":"2026-01-19T11:55:32.812602-05:00","created_by":"Cameron Smith"}]} +{"id":"pnt-btz.1","title":"Create pnt-rust package scaffold","description":"Create packages/pnt-rust/ with Cargo.toml, pyproject.toml (maturin build-backend), src/lib.rs with pyo3 bindings. Minimal proof-of-concept function exposed to Python.","status":"open","priority":2,"issue_type":"task","owner":"cameron.ray.smith@gmail.com","created_at":"2026-01-19T11:55:17.885691-05:00","created_by":"Cameron Smith","updated_at":"2026-01-19T11:55:17.885691-05:00","dependencies":[{"issue_id":"pnt-btz.1","depends_on_id":"pnt-btz","type":"parent-child","created_at":"2026-01-19T11:55:17.886287-05:00","created_by":"Cameron Smith"}]} +{"id":"pnt-btz.2","title":"Configure maturin + pyproject.nix build","description":"Add nix module for pnt-rust using rustPlatform.maturinBuildHook. Configure cargoDeps via fetchCargoVendor. Set PYO3_PYTHON env var to prevent path-dependent rebuilds.","status":"open","priority":2,"issue_type":"task","owner":"cameron.ray.smith@gmail.com","created_at":"2026-01-19T11:55:18.885252-05:00","created_by":"Cameron Smith","updated_at":"2026-01-19T11:55:18.885252-05:00","dependencies":[{"issue_id":"pnt-btz.2","depends_on_id":"pnt-btz","type":"parent-child","created_at":"2026-01-19T11:55:18.885818-05:00","created_by":"Cameron Smith"}]} +{"id":"pnt-btz.3","title":"Validate Rust + Python nix integration","description":"Verify nix build produces working wheel. Test import from Python. Document integration pattern for downstream projects. Identify gaps requiring custom solutions.","status":"open","priority":2,"issue_type":"task","owner":"cameron.ray.smith@gmail.com","created_at":"2026-01-19T11:55:19.746622-05:00","created_by":"Cameron Smith","updated_at":"2026-01-19T11:55:19.746622-05:00","dependencies":[{"issue_id":"pnt-btz.3","depends_on_id":"pnt-btz","type":"parent-child","created_at":"2026-01-19T11:55:19.74722-05:00","created_by":"Cameron Smith"}]} +{"id":"pnt-dre","title":"Infrastructure alignment","description":"Align Makefile, justfile, scripts/, and CI with vanixiets and typescript-nix-template patterns. Makefile bootstrap-only, grouped justfile recipes, cached-ci-job CI pattern, omnix template integration.","status":"open","priority":2,"issue_type":"epic","owner":"cameron.ray.smith@gmail.com","created_at":"2026-01-19T11:54:39.841346-05:00","created_by":"Cameron Smith","updated_at":"2026-01-19T11:54:39.841346-05:00"} +{"id":"pnt-dre.1","title":"Refactor Makefile to bootstrap-only pattern","description":"Restrict Makefile to bootstrap targets only: install-nix, install-direnv, verify, setup-user, check-secrets, clean. Move all other targets to justfile.","status":"open","priority":2,"issue_type":"task","owner":"cameron.ray.smith@gmail.com","created_at":"2026-01-19T11:54:54.237851-05:00","created_by":"Cameron Smith","updated_at":"2026-01-19T11:54:54.237851-05:00","dependencies":[{"issue_id":"pnt-dre.1","depends_on_id":"pnt-dre","type":"parent-child","created_at":"2026-01-19T11:54:54.238477-05:00","created_by":"Cameron Smith"}]} +{"id":"pnt-dre.2","title":"Adopt grouped justfile recipe pattern","description":"Reorganize justfile with grouped recipes and section headers following vanixiets pattern: nix, python, conda, docs, secrets, ci/cd groups. Add help comments for each recipe.","status":"open","priority":2,"issue_type":"task","owner":"cameron.ray.smith@gmail.com","created_at":"2026-01-19T11:54:55.145094-05:00","created_by":"Cameron Smith","updated_at":"2026-01-19T11:54:55.145094-05:00","dependencies":[{"issue_id":"pnt-dre.2","depends_on_id":"pnt-dre","type":"parent-child","created_at":"2026-01-19T11:54:55.145764-05:00","created_by":"Cameron Smith"}]} +{"id":"pnt-dre.3","title":"Reorganize scripts/ directory structure","description":"Move scripts into subdirectories: scripts/ci/, scripts/docs/, scripts/sops/. Update justfile and CI references.","status":"open","priority":2,"issue_type":"task","owner":"cameron.ray.smith@gmail.com","created_at":"2026-01-19T11:54:55.839371-05:00","created_by":"Cameron Smith","updated_at":"2026-01-19T11:54:55.839371-05:00","dependencies":[{"issue_id":"pnt-dre.3","depends_on_id":"pnt-dre","type":"parent-child","created_at":"2026-01-19T11:54:55.839951-05:00","created_by":"Cameron Smith"}]} +{"id":"pnt-dre.4","title":"Implement cached-ci-job composite action pattern","description":"Add .github/actions/cached-ci-job composite action following typescript-nix-template pattern. Content-addressed caching with hash-sources and force-run support. Update CI to use category-based matrix builds.","status":"open","priority":2,"issue_type":"task","owner":"cameron.ray.smith@gmail.com","created_at":"2026-01-19T11:54:56.79376-05:00","created_by":"Cameron Smith","updated_at":"2026-01-19T11:54:56.79376-05:00","dependencies":[{"issue_id":"pnt-dre.4","depends_on_id":"pnt-dre","type":"parent-child","created_at":"2026-01-19T11:54:56.794334-05:00","created_by":"Cameron Smith"}]} +{"id":"pnt-dre.5","title":"Add omnix template integration","description":"Configure om.templates in flake with parameter definitions. Add template-verify justfile recipe. Create .github/workflows/template.yaml for CI validation.","status":"open","priority":2,"issue_type":"task","owner":"cameron.ray.smith@gmail.com","created_at":"2026-01-19T11:54:57.668262-05:00","created_by":"Cameron Smith","updated_at":"2026-01-19T11:54:57.668262-05:00","dependencies":[{"issue_id":"pnt-dre.5","depends_on_id":"pnt-dre","type":"parent-child","created_at":"2026-01-19T11:54:57.66888-05:00","created_by":"Cameron Smith"}]} From 53040d04d6882cbdba8fd309677fedc2c3d6d10d Mon Sep 17 00:00:00 2001 From: Cameron Smith Date: Mon, 19 Jan 2026 12:20:22 -0500 Subject: [PATCH 003/134] chore(issues): add dependency chains and clarify bootstrap.sh stability --- .beads/issues.jsonl | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/.beads/issues.jsonl b/.beads/issues.jsonl index 21b0d3b..a6fe8e8 100644 --- a/.beads/issues.jsonl +++ b/.beads/issues.jsonl @@ -1,14 +1,14 @@ {"id":"pnt-4jg","title":"Dependency model migration","description":"Migrate from single-lock uv workspace to independent-lock multi-package pattern following langchain/langgraph approach. Include pixi feature-based composition for conda ecosystem parity.","status":"open","priority":2,"issue_type":"epic","owner":"cameron.ray.smith@gmail.com","created_at":"2026-01-19T11:54:40.744055-05:00","created_by":"Cameron Smith","updated_at":"2026-01-19T11:54:40.744055-05:00"} {"id":"pnt-4jg.1","title":"Remove uv workspace, adopt path dependencies","description":"Remove [tool.uv.workspace] from root pyproject.toml. Each package gets own pyproject.toml with [tool.uv.sources] for sibling references using path sources with editable=true. Follow langchain pattern.","status":"open","priority":2,"issue_type":"task","owner":"cameron.ray.smith@gmail.com","created_at":"2026-01-19T11:55:07.344057-05:00","created_by":"Cameron Smith","updated_at":"2026-01-19T11:55:07.344057-05:00","dependencies":[{"issue_id":"pnt-4jg.1","depends_on_id":"pnt-4jg","type":"parent-child","created_at":"2026-01-19T11:55:07.344659-05:00","created_by":"Cameron Smith"}]} {"id":"pnt-4jg.2","title":"Configure pixi feature-based composition","description":"Implement pixi feature/environment pattern: [feature.X.dependencies] + [environments] composition. Single pixi.lock covering all environments. Per-feature task definitions. Target-specific dependencies for platform support.","status":"open","priority":2,"issue_type":"task","owner":"cameron.ray.smith@gmail.com","created_at":"2026-01-19T11:55:08.085592-05:00","created_by":"Cameron Smith","updated_at":"2026-01-19T11:55:08.085592-05:00","dependencies":[{"issue_id":"pnt-4jg.2","depends_on_id":"pnt-4jg","type":"parent-child","created_at":"2026-01-19T11:55:08.086155-05:00","created_by":"Cameron Smith"}]} -{"id":"pnt-4jg.3","title":"Document package distribution channels","description":"Document which packages support uv/pypi vs pixi/conda distribution. Note dependency graph differences between channels. Update README and package metadata.","status":"open","priority":2,"issue_type":"task","owner":"cameron.ray.smith@gmail.com","created_at":"2026-01-19T11:55:09.051203-05:00","created_by":"Cameron Smith","updated_at":"2026-01-19T11:55:09.051203-05:00","dependencies":[{"issue_id":"pnt-4jg.3","depends_on_id":"pnt-4jg","type":"parent-child","created_at":"2026-01-19T11:55:09.051857-05:00","created_by":"Cameron Smith"}]} +{"id":"pnt-4jg.3","title":"Document package distribution channels","description":"Document which packages support uv/pypi vs pixi/conda distribution. Note dependency graph differences between channels. Update README and package metadata.","status":"open","priority":2,"issue_type":"task","owner":"cameron.ray.smith@gmail.com","created_at":"2026-01-19T11:55:09.051203-05:00","created_by":"Cameron Smith","updated_at":"2026-01-19T11:55:09.051203-05:00","dependencies":[{"issue_id":"pnt-4jg.3","depends_on_id":"pnt-4jg","type":"parent-child","created_at":"2026-01-19T11:55:09.051857-05:00","created_by":"Cameron Smith"},{"issue_id":"pnt-4jg.3","depends_on_id":"pnt-4jg.1","type":"blocks","created_at":"2026-01-19T12:20:13.557576-05:00","created_by":"Cameron Smith"},{"issue_id":"pnt-4jg.3","depends_on_id":"pnt-4jg.2","type":"blocks","created_at":"2026-01-19T12:20:16.147971-05:00","created_by":"Cameron Smith"}]} {"id":"pnt-btz","title":"pyo3/Rust extension integration","description":"Add Rust extension module support via maturin + pyo3, demonstrating Nix build integration with pyproject.nix maturinBuildHook and crane patterns.","status":"open","priority":2,"issue_type":"epic","owner":"cameron.ray.smith@gmail.com","created_at":"2026-01-19T11:54:41.426256-05:00","created_by":"Cameron Smith","updated_at":"2026-01-19T11:54:41.426256-05:00","dependencies":[{"issue_id":"pnt-btz","depends_on_id":"pnt-dre","type":"blocks","created_at":"2026-01-19T11:55:32.690895-05:00","created_by":"Cameron Smith"},{"issue_id":"pnt-btz","depends_on_id":"pnt-4jg","type":"blocks","created_at":"2026-01-19T11:55:32.812602-05:00","created_by":"Cameron Smith"}]} -{"id":"pnt-btz.1","title":"Create pnt-rust package scaffold","description":"Create packages/pnt-rust/ with Cargo.toml, pyproject.toml (maturin build-backend), src/lib.rs with pyo3 bindings. Minimal proof-of-concept function exposed to Python.","status":"open","priority":2,"issue_type":"task","owner":"cameron.ray.smith@gmail.com","created_at":"2026-01-19T11:55:17.885691-05:00","created_by":"Cameron Smith","updated_at":"2026-01-19T11:55:17.885691-05:00","dependencies":[{"issue_id":"pnt-btz.1","depends_on_id":"pnt-btz","type":"parent-child","created_at":"2026-01-19T11:55:17.886287-05:00","created_by":"Cameron Smith"}]} -{"id":"pnt-btz.2","title":"Configure maturin + pyproject.nix build","description":"Add nix module for pnt-rust using rustPlatform.maturinBuildHook. Configure cargoDeps via fetchCargoVendor. Set PYO3_PYTHON env var to prevent path-dependent rebuilds.","status":"open","priority":2,"issue_type":"task","owner":"cameron.ray.smith@gmail.com","created_at":"2026-01-19T11:55:18.885252-05:00","created_by":"Cameron Smith","updated_at":"2026-01-19T11:55:18.885252-05:00","dependencies":[{"issue_id":"pnt-btz.2","depends_on_id":"pnt-btz","type":"parent-child","created_at":"2026-01-19T11:55:18.885818-05:00","created_by":"Cameron Smith"}]} -{"id":"pnt-btz.3","title":"Validate Rust + Python nix integration","description":"Verify nix build produces working wheel. Test import from Python. Document integration pattern for downstream projects. Identify gaps requiring custom solutions.","status":"open","priority":2,"issue_type":"task","owner":"cameron.ray.smith@gmail.com","created_at":"2026-01-19T11:55:19.746622-05:00","created_by":"Cameron Smith","updated_at":"2026-01-19T11:55:19.746622-05:00","dependencies":[{"issue_id":"pnt-btz.3","depends_on_id":"pnt-btz","type":"parent-child","created_at":"2026-01-19T11:55:19.74722-05:00","created_by":"Cameron Smith"}]} +{"id":"pnt-btz.1","title":"Create pnt-rust package scaffold","description":"Create packages/pnt-rust/ with Cargo.toml, pyproject.toml (maturin build-backend), src/lib.rs with pyo3 bindings. Minimal proof-of-concept function exposed to Python.","status":"open","priority":2,"issue_type":"task","owner":"cameron.ray.smith@gmail.com","created_at":"2026-01-19T11:55:17.885691-05:00","created_by":"Cameron Smith","updated_at":"2026-01-19T11:55:17.885691-05:00","dependencies":[{"issue_id":"pnt-btz.1","depends_on_id":"pnt-btz","type":"parent-child","created_at":"2026-01-19T11:55:17.886287-05:00","created_by":"Cameron Smith"},{"issue_id":"pnt-btz.1","depends_on_id":"pnt-4jg.1","type":"blocks","created_at":"2026-01-19T12:20:18.940008-05:00","created_by":"Cameron Smith"}]} +{"id":"pnt-btz.2","title":"Configure maturin + pyproject.nix build","description":"Add nix module for pnt-rust using rustPlatform.maturinBuildHook. Configure cargoDeps via fetchCargoVendor. Set PYO3_PYTHON env var to prevent path-dependent rebuilds.","status":"open","priority":2,"issue_type":"task","owner":"cameron.ray.smith@gmail.com","created_at":"2026-01-19T11:55:18.885252-05:00","created_by":"Cameron Smith","updated_at":"2026-01-19T11:55:18.885252-05:00","dependencies":[{"issue_id":"pnt-btz.2","depends_on_id":"pnt-btz","type":"parent-child","created_at":"2026-01-19T11:55:18.885818-05:00","created_by":"Cameron Smith"},{"issue_id":"pnt-btz.2","depends_on_id":"pnt-btz.1","type":"blocks","created_at":"2026-01-19T12:20:08.210077-05:00","created_by":"Cameron Smith"}]} +{"id":"pnt-btz.3","title":"Validate Rust + Python nix integration","description":"Verify nix build produces working wheel. Test import from Python. Document integration pattern for downstream projects. Identify gaps requiring custom solutions.","status":"open","priority":2,"issue_type":"task","owner":"cameron.ray.smith@gmail.com","created_at":"2026-01-19T11:55:19.746622-05:00","created_by":"Cameron Smith","updated_at":"2026-01-19T11:55:19.746622-05:00","dependencies":[{"issue_id":"pnt-btz.3","depends_on_id":"pnt-btz","type":"parent-child","created_at":"2026-01-19T11:55:19.74722-05:00","created_by":"Cameron Smith"},{"issue_id":"pnt-btz.3","depends_on_id":"pnt-btz.2","type":"blocks","created_at":"2026-01-19T12:20:11.013516-05:00","created_by":"Cameron Smith"}]} {"id":"pnt-dre","title":"Infrastructure alignment","description":"Align Makefile, justfile, scripts/, and CI with vanixiets and typescript-nix-template patterns. Makefile bootstrap-only, grouped justfile recipes, cached-ci-job CI pattern, omnix template integration.","status":"open","priority":2,"issue_type":"epic","owner":"cameron.ray.smith@gmail.com","created_at":"2026-01-19T11:54:39.841346-05:00","created_by":"Cameron Smith","updated_at":"2026-01-19T11:54:39.841346-05:00"} {"id":"pnt-dre.1","title":"Refactor Makefile to bootstrap-only pattern","description":"Restrict Makefile to bootstrap targets only: install-nix, install-direnv, verify, setup-user, check-secrets, clean. Move all other targets to justfile.","status":"open","priority":2,"issue_type":"task","owner":"cameron.ray.smith@gmail.com","created_at":"2026-01-19T11:54:54.237851-05:00","created_by":"Cameron Smith","updated_at":"2026-01-19T11:54:54.237851-05:00","dependencies":[{"issue_id":"pnt-dre.1","depends_on_id":"pnt-dre","type":"parent-child","created_at":"2026-01-19T11:54:54.238477-05:00","created_by":"Cameron Smith"}]} {"id":"pnt-dre.2","title":"Adopt grouped justfile recipe pattern","description":"Reorganize justfile with grouped recipes and section headers following vanixiets pattern: nix, python, conda, docs, secrets, ci/cd groups. Add help comments for each recipe.","status":"open","priority":2,"issue_type":"task","owner":"cameron.ray.smith@gmail.com","created_at":"2026-01-19T11:54:55.145094-05:00","created_by":"Cameron Smith","updated_at":"2026-01-19T11:54:55.145094-05:00","dependencies":[{"issue_id":"pnt-dre.2","depends_on_id":"pnt-dre","type":"parent-child","created_at":"2026-01-19T11:54:55.145764-05:00","created_by":"Cameron Smith"}]} -{"id":"pnt-dre.3","title":"Reorganize scripts/ directory structure","description":"Move scripts into subdirectories: scripts/ci/, scripts/docs/, scripts/sops/. Update justfile and CI references.","status":"open","priority":2,"issue_type":"task","owner":"cameron.ray.smith@gmail.com","created_at":"2026-01-19T11:54:55.839371-05:00","created_by":"Cameron Smith","updated_at":"2026-01-19T11:54:55.839371-05:00","dependencies":[{"issue_id":"pnt-dre.3","depends_on_id":"pnt-dre","type":"parent-child","created_at":"2026-01-19T11:54:55.839951-05:00","created_by":"Cameron Smith"}]} +{"id":"pnt-dre.3","title":"Reorganize scripts/ directory structure","description":"Move scripts into subdirectories: scripts/ci/, scripts/docs/, scripts/sops/. IMPORTANT: scripts/bootstrap.sh must remain at stable path for curl one-liner URL. Update justfile and CI references.","status":"open","priority":2,"issue_type":"task","owner":"cameron.ray.smith@gmail.com","created_at":"2026-01-19T11:54:55.839371-05:00","created_by":"Cameron Smith","updated_at":"2026-01-19T12:20:05.527218-05:00","dependencies":[{"issue_id":"pnt-dre.3","depends_on_id":"pnt-dre","type":"parent-child","created_at":"2026-01-19T11:54:55.839951-05:00","created_by":"Cameron Smith"}]} {"id":"pnt-dre.4","title":"Implement cached-ci-job composite action pattern","description":"Add .github/actions/cached-ci-job composite action following typescript-nix-template pattern. Content-addressed caching with hash-sources and force-run support. Update CI to use category-based matrix builds.","status":"open","priority":2,"issue_type":"task","owner":"cameron.ray.smith@gmail.com","created_at":"2026-01-19T11:54:56.79376-05:00","created_by":"Cameron Smith","updated_at":"2026-01-19T11:54:56.79376-05:00","dependencies":[{"issue_id":"pnt-dre.4","depends_on_id":"pnt-dre","type":"parent-child","created_at":"2026-01-19T11:54:56.794334-05:00","created_by":"Cameron Smith"}]} {"id":"pnt-dre.5","title":"Add omnix template integration","description":"Configure om.templates in flake with parameter definitions. Add template-verify justfile recipe. Create .github/workflows/template.yaml for CI validation.","status":"open","priority":2,"issue_type":"task","owner":"cameron.ray.smith@gmail.com","created_at":"2026-01-19T11:54:57.668262-05:00","created_by":"Cameron Smith","updated_at":"2026-01-19T11:54:57.668262-05:00","dependencies":[{"issue_id":"pnt-dre.5","depends_on_id":"pnt-dre","type":"parent-child","created_at":"2026-01-19T11:54:57.66888-05:00","created_by":"Cameron Smith"}]} From e2d13ee43716ea034fb77ef53c0e42a4fef25e5d Mon Sep 17 00:00:00 2001 From: Cameron Smith Date: Wed, 28 Jan 2026 14:38:09 -0500 Subject: [PATCH 004/134] chore(gitignore): add bv Signed-off-by: Cameron Smith --- .gitignore | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index 090fc1c..f1cbc0a 100644 --- a/.gitignore +++ b/.gitignore @@ -98,4 +98,7 @@ node_modules/ *-sa.json # act -.artifacts/ \ No newline at end of file +.artifacts/ + +# bv (beads viewer) local config and caches +.bv/ From 52913d3e8ee0cde89ee4dca9094be4e9f4b732af Mon Sep 17 00:00:00 2001 From: Cameron Smith Date: Wed, 28 Jan 2026 14:44:41 -0500 Subject: [PATCH 005/134] chore(gitignore): allow markdown files in docs/ directory --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index f1cbc0a..9fff26b 100644 --- a/.gitignore +++ b/.gitignore @@ -12,6 +12,7 @@ *.pdb *.md !README.md +!docs/**/*.md logs/ ## Environments From c9db3e2fd61ed871add4c93a4f245fb53060266a Mon Sep 17 00:00:00 2001 From: Cameron Smith Date: Wed, 28 Jan 2026 14:44:52 -0500 Subject: [PATCH 006/134] docs(architecture): add crane + uv2nix + maturin integration design Document the target architecture for integrating Rust extension modules into the federated Python monorepo pattern. Key patterns covered: - Per-package Rust workspace (crates/ inside Python package) - crane buildDepsOnly for cargoArtifacts caching - uv2nix overlay injection for maturin builds - CI matrix with rust-deps/rust-checks/python-wheel categories References local exemplars: - ~/projects/rust-workspace/ironstar (crane patterns) - ~/projects/planning-workspace/langchain (federated Python) - ~/projects/nix-workspace/pyproject.nix (maturin support) --- .../architecture/crane-uv2nix-integration.md | 411 ++++++++++++++++++ 1 file changed, 411 insertions(+) create mode 100644 docs/notes/architecture/crane-uv2nix-integration.md diff --git a/docs/notes/architecture/crane-uv2nix-integration.md b/docs/notes/architecture/crane-uv2nix-integration.md new file mode 100644 index 0000000..c5f49a6 --- /dev/null +++ b/docs/notes/architecture/crane-uv2nix-integration.md @@ -0,0 +1,411 @@ +# Crane + uv2nix + maturin integration architecture + +This document describes the target architecture for integrating Rust extension modules into python-nix-template's federated Python monorepo pattern. + +## Context + +The template is migrating from a single-lock uv workspace (Cargo-style) to a federated independent-lock pattern (LangChain-style). +Some Python packages may contain Rust extension modules built via pyo3/maturin. +These Rust extensions may themselves be federated cargo workspaces with multiple crates. + +The goal is optimal build caching at both the Rust (crane's cargoArtifacts) and Python (uv2nix virtualenvs) levels while maintaining full federation—no root-level coordination required. + +## Reference implementations + +Local repositories demonstrating component patterns: + +- `~/projects/rust-workspace/ironstar` — crane + rust-flake patterns, cargoArtifacts sharing, CI matrix builds +- `~/projects/planning-workspace/langchain` — federated Python monorepo, per-package independence, path dependencies via `[tool.uv.sources]` +- `~/projects/planning-workspace/langgraph` — federated Python with PEP 420 namespace packages, PEP 735 dependency groups +- `~/projects/nix-workspace/uv` — uv workspace mechanics, Cargo-inspired design +- `~/projects/nix-workspace/uv2nix` — Python packaging via pyproject-nix overlays +- `~/projects/nix-workspace/pyproject.nix` — maturin build system support, importCargoLock +- `~/projects/maturin` — pyo3 build backend, cargo workspace integration via manifest-path + +## Target directory structure + +``` +python-nix-template/ +├── flake.nix # Top-level orchestration +├── nix/ +│ ├── modules/ +│ │ ├── python.nix # uv2nix integration, per-package overlays +│ │ └── rust/ # Shared crane utilities +│ │ ├── lib.nix # mkCraneLib, buildRustPackage helpers +│ │ └── overlays.nix # Cross-package Rust overlay composition +│ └── packages/ # Per-package Nix modules +│ ├── pnt-cli/ +│ │ ├── default.nix # Python + Rust composition +│ │ └── rust.nix # crane configuration for this package's crates +│ └── pnt-functional/ +│ └── default.nix # Pure Python package +│ +├── packages/ # Python packages (federated, independent locks) +│ ├── pnt-cli/ # Example: CLI with Rust backend +│ │ ├── pyproject.toml # maturin build-system, manifest-path binding +│ │ ├── uv.lock # Independent lock (optional) +│ │ ├── src/pnt_cli/ # Python wrapper code +│ │ └── crates/ # Federated Rust workspace for THIS package +│ │ ├── Cargo.toml # [workspace] members = ["pnt-cli-core", "pnt-cli-py"] +│ │ ├── Cargo.lock +│ │ ├── pnt-cli-core/ # Pure Rust library +│ │ │ └── Cargo.toml +│ │ └── pnt-cli-py/ # pyo3 extension module +│ │ └── Cargo.toml # depends on pnt-cli-core via workspace +│ │ +│ └── pnt-functional/ # Pure Python package +│ ├── pyproject.toml +│ └── src/pnt_functional/ +``` + +## Integration patterns + +### Pattern 1: Per-package Rust module (rust.nix) + +Each Python package with Rust extensions gets a `nix/packages/{name}/rust.nix` that encapsulates crane configuration. + +```nix +# nix/packages/pnt-cli/rust.nix +{ pkgs, crane, lib, ... }: +let + src = ../../../packages/pnt-cli/crates; + + # Standard crane pattern from ironstar + crane-lib = crane.mkLib pkgs; + + commonArgs = { + inherit src; + pname = "pnt-cli-rust"; + strictDeps = true; + CARGO_PROFILE = "release"; + nativeBuildInputs = [ pkgs.pkg-config ]; + buildInputs = lib.optionals pkgs.stdenv.isDarwin [ + pkgs.darwin.apple_sdk.frameworks.Security + ]; + }; + + # Shared dependency artifacts (expensive compilation cached) + cargoArtifacts = crane-lib.buildDepsOnly commonArgs; + +in { + # Export for Python package to consume + inherit cargoArtifacts; + + # Individual crate derivations (for testing, inspection) + pnt-cli-core = crane-lib.buildPackage (commonArgs // { + inherit cargoArtifacts; + cargoExtraArgs = "-p pnt-cli-core"; + }); + + # Vendored deps for maturin's cargo invocation + cargoVendorDir = crane-lib.vendorCargoDeps { inherit src; }; + + # Checks (clippy, tests) reusing cached artifacts + clippy = crane-lib.cargoClippy (commonArgs // { + inherit cargoArtifacts; + cargoClippyExtraArgs = "--all-targets -- --deny warnings"; + }); + + nextest = crane-lib.cargoNextest (commonArgs // { + inherit cargoArtifacts; + partitions = 1; + partitionType = "count"; + }); +} +``` + +Key principles from `~/projects/rust-workspace/ironstar/modules/rust.nix`: + +- Single `buildDepsOnly` call creates `cargoArtifacts` shared by all build targets +- `commonArgs` pattern ensures derivation hash consistency (see ironstar FAQ on constant rebuilds) +- `vendorCargoDeps` provides offline cargo builds without IFD + +### Pattern 2: Python package overlay (default.nix) + +The Python package Nix module composes the Rust derivation with uv2nix's overlay system. + +```nix +# nix/packages/pnt-cli/default.nix +{ pkgs, lib, crane, ... }: +let + rustPkgs = import ./rust.nix { inherit pkgs crane lib; }; + +in { + # Override for this package in the Python package set + overlay = final: prev: { + pnt-cli = prev.pnt-cli.overrideAttrs (old: { + # Inject pre-vendored Cargo deps (crane's vendoring, not rustPlatform's) + cargoVendorDir = rustPkgs.cargoVendorDir; + + # Reuse crane's cargoArtifacts for incremental builds + preBuild = '' + export CARGO_TARGET_DIR="${rustPkgs.cargoArtifacts}/target" + ''; + + nativeBuildInputs = old.nativeBuildInputs ++ [ + pkgs.cargo + pkgs.rustc + ] ++ final.resolveBuildSystem { + maturin = [ ]; + }; + + buildInputs = (old.buildInputs or [ ]) ++ + lib.optionals pkgs.stdenv.isDarwin [ + pkgs.darwin.apple_sdk.frameworks.Security + ]; + }); + }; + + # Export Rust checks for flake checks + checks = { + pnt-cli-clippy = rustPkgs.clippy; + pnt-cli-nextest = rustPkgs.nextest; + }; +} +``` + +### Pattern 3: Top-level Python module composition + +The `nix/modules/python.nix` composes all package overlays into the final Python set. + +```nix +# nix/modules/python.nix +{ inputs, ... }: +{ + perSystem = { pkgs, lib, system, ... }: + let + # Load each Python package independently (no root workspace) + loadPackage = name: path: + let + workspace = inputs.uv2nix.lib.workspace.loadWorkspace { + workspaceRoot = path; + }; + in { + inherit workspace; + overlay = workspace.mkPyprojectOverlay { sourcePreference = "sdist"; }; + }; + + packages = { + pnt-cli = loadPackage "pnt-cli" ../../packages/pnt-cli; + pnt-functional = loadPackage "pnt-functional" ../../packages/pnt-functional; + }; + + # Package-specific Nix modules with optional Rust overlays + packageModules = { + pnt-cli = import ../packages/pnt-cli { inherit pkgs lib; crane = inputs.crane; }; + pnt-functional = { overlay = _: _: { }; checks = { }; }; + }; + + # Compose all overlays + pythonBase = pkgs.callPackage inputs.pyproject-nix.build.packages { + python = pkgs.python312; + }; + + pythonSet = pythonBase.overrideScope (lib.composeManyExtensions [ + # uv2nix overlays for each package + packages.pnt-cli.overlay + packages.pnt-functional.overlay + # Custom Rust integration overlays + packageModules.pnt-cli.overlay + ]); + + in { + packages = { + pnt-cli = pythonSet.pnt-cli; + pnt-functional = pythonSet.pnt-functional; + }; + + checks = packageModules.pnt-cli.checks // packageModules.pnt-functional.checks; + }; +} +``` + +### Pattern 4: pyproject.toml maturin binding + +The Python package's pyproject.toml binds maturin to the specific pyo3 crate. + +```toml +# packages/pnt-cli/pyproject.toml +[build-system] +requires = ["maturin>=1.5"] +build-backend = "maturin" + +[project] +name = "pnt-cli" +version = "0.1.0" +requires-python = ">=3.11" +dependencies = [] + +[tool.maturin] +manifest-path = "crates/pnt-cli-py/Cargo.toml" +module-name = "pnt_cli._native" +features = ["pyo3/extension-module"] +python-source = "src" + +[tool.uv.sources] +# Path dependencies for local development (federated pattern) +pnt-functional = { path = "../pnt-functional", editable = true } + +[dependency-groups] +dev = ["pytest>=8.0", "mypy>=1.10"] +``` + +Key maturin configuration: + +- `manifest-path` points to the pyo3 crate within the Rust workspace +- `module-name` controls where the compiled extension appears in the Python package +- `python-source` tells maturin where Python code lives (alongside the native module) + +### Pattern 5: CI matrix strategy + +Extend ironstar's category-based CI to handle mixed packages. + +```yaml +# .github/workflows/ci.yaml +jobs: + nix-build: + strategy: + matrix: + include: + # Rust dependency caching (expensive, cached aggressively) + - package: pnt-cli + category: rust-deps + cache-key: rust-deps-${{ hashFiles('packages/pnt-cli/crates/Cargo.lock') }} + + # Rust checks (clippy, tests) + - package: pnt-cli + category: rust-checks + + # Python wheel build (depends on rust-deps) + - package: pnt-cli + category: python-wheel + + # Pure Python packages + - package: pnt-functional + category: python-wheel + + steps: + - uses: DeterminateSystems/nix-installer-action@main + - uses: DeterminateSystems/flake-checker-action@main + + - name: Build category + run: | + case "${{ matrix.category }}" in + rust-deps) + nix build ".#packages.x86_64-linux.${{ matrix.package }}-cargoArtifacts" + ;; + rust-checks) + nix build ".#checks.x86_64-linux.${{ matrix.package }}-clippy" + nix build ".#checks.x86_64-linux.${{ matrix.package }}-nextest" + ;; + python-wheel) + nix build ".#packages.x86_64-linux.${{ matrix.package }}" + ;; + esac +``` + +## Caching strategy + +The architecture achieves optimal caching through layered artifact reuse. + +### Layer 1: Rust dependency artifacts (cargoArtifacts) + +Crane's `buildDepsOnly` compiles all Cargo dependencies without project code. +This derivation changes only when `Cargo.lock` changes. +CI caches this derivation via Cachix or GitHub Actions cache. +Rebuild time: minutes → seconds when cached. + +### Layer 2: Rust project artifacts + +Crane's `buildPackage` with `inherit cargoArtifacts` compiles only project code. +Changes when Rust source files change. +Incremental: only changed crates recompile. + +### Layer 3: Python wheel + +Maturin produces a wheel containing the compiled `.so` and Python source. +uv2nix converts this to a Nix derivation. +Changes when Python source or Rust output changes. + +### Layer 4: Python virtualenv + +uv2nix's `mkVirtualEnv` composes all package wheels. +Changes when any dependency wheel changes. +For development, use editable installs to avoid full rebuilds. + +## Testing strategy + +Rust-level tests run via crane (cargoNextest) for fast iteration and artifact reuse. +Python-level tests run via pytest within the uv2nix virtualenv. +Integration tests exercise the full Python → Rust boundary. + +```nix +# In nix/packages/pnt-cli/default.nix +checks = { + # Rust unit tests (fast, cached) + pnt-cli-rust-unit = rustPkgs.nextest; + + # Rust lint (fast, cached) + pnt-cli-clippy = rustPkgs.clippy; + + # Python integration tests + pnt-cli-pytest = pythonSet.mkVirtualEnv "pnt-cli-test-env" { + pnt-cli = [ "dev" ]; + } // { + checkPhase = '' + pytest packages/pnt-cli/tests/ + ''; + }; +}; +``` + +## Migration path + +The implementation follows the beads epic dependency chain: + +1. **pnt-dre**: Infrastructure alignment (concurrent with pnt-4jg) + - Establishes nix/modules/ and nix/packages/ structure + - Aligns CI patterns with this architecture + +2. **pnt-4jg**: Dependency model migration (concurrent with pnt-dre) + - Removes root uv workspace + - Establishes per-package path dependencies + - Documents federated pattern + +3. **pnt-btz**: pyo3/Rust extension integration (after pnt-dre and pnt-4jg) + - Creates pnt-cli package scaffold with crates/ directory + - Implements rust.nix and default.nix patterns + - Validates full crane + uv2nix + maturin integration + +## Open questions + +### Cross-package Rust dependencies + +If multiple Python packages share Rust crates, options include: + +1. **Workspace-level Rust crates**: A shared `crates/` at repository root, imported by multiple Python packages +2. **Published crates**: Publish shared crates to crates.io or a private registry +3. **Path dependencies**: Use Cargo's workspace-level path dependencies across package boundaries + +The federated model prefers option 2 (published crates) for maximum independence, but option 1 may be pragmatic during development. + +### cargoArtifacts sharing across Python packages + +If multiple Python packages have Rust extensions with overlapping dependencies, we could share cargoArtifacts. +This requires a shared `Cargo.lock` or careful alignment of dependency versions. +Initial recommendation: keep cargoArtifacts per-package for simplicity, optimize later if build times warrant. + +### Editable development workflow + +For local development, developers want fast iteration without full Nix rebuilds. +Recommend: use `uv sync` + `maturin develop` outside Nix for iteration, Nix for CI and reproducible builds. +The Nix derivations serve as the source of truth; local development uses native tooling for speed. + +## References + +- ironstar crane patterns: `~/projects/rust-workspace/ironstar/modules/rust.nix` +- ironstar CI matrix: `~/projects/rust-workspace/ironstar/.github/workflows/ci.yaml` +- LangChain federation: `~/projects/planning-workspace/langchain/libs/` +- uv2nix overlay pattern: `~/projects/nix-workspace/uv2nix/doc/patterns/` +- pyproject.nix maturin: `~/projects/nix-workspace/pyproject.nix/doc/src/builders.md` +- maturin workspace support: `~/projects/maturin/guide/src/project_layout.md` From 5a7671eb60851777603a88b950a390a603886c66 Mon Sep 17 00:00:00 2001 From: Cameron Smith Date: Wed, 28 Jan 2026 14:45:03 -0500 Subject: [PATCH 007/134] chore(issues): update pnt-btz epic with architecture reference Align pnt-btz epic and tasks with the documented crane + uv2nix integration architecture in docs/notes/architecture/. Updates: - pnt-btz: reference architecture doc, list key patterns - pnt-btz.1: detail federated crates/ structure, maturin binding - pnt-btz.2: specify rust.nix and default.nix overlay patterns - pnt-btz.3: add validation checklist and CI matrix requirements --- .beads/issues.jsonl | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.beads/issues.jsonl b/.beads/issues.jsonl index a6fe8e8..297a96b 100644 --- a/.beads/issues.jsonl +++ b/.beads/issues.jsonl @@ -2,10 +2,10 @@ {"id":"pnt-4jg.1","title":"Remove uv workspace, adopt path dependencies","description":"Remove [tool.uv.workspace] from root pyproject.toml. Each package gets own pyproject.toml with [tool.uv.sources] for sibling references using path sources with editable=true. Follow langchain pattern.","status":"open","priority":2,"issue_type":"task","owner":"cameron.ray.smith@gmail.com","created_at":"2026-01-19T11:55:07.344057-05:00","created_by":"Cameron Smith","updated_at":"2026-01-19T11:55:07.344057-05:00","dependencies":[{"issue_id":"pnt-4jg.1","depends_on_id":"pnt-4jg","type":"parent-child","created_at":"2026-01-19T11:55:07.344659-05:00","created_by":"Cameron Smith"}]} {"id":"pnt-4jg.2","title":"Configure pixi feature-based composition","description":"Implement pixi feature/environment pattern: [feature.X.dependencies] + [environments] composition. Single pixi.lock covering all environments. Per-feature task definitions. Target-specific dependencies for platform support.","status":"open","priority":2,"issue_type":"task","owner":"cameron.ray.smith@gmail.com","created_at":"2026-01-19T11:55:08.085592-05:00","created_by":"Cameron Smith","updated_at":"2026-01-19T11:55:08.085592-05:00","dependencies":[{"issue_id":"pnt-4jg.2","depends_on_id":"pnt-4jg","type":"parent-child","created_at":"2026-01-19T11:55:08.086155-05:00","created_by":"Cameron Smith"}]} {"id":"pnt-4jg.3","title":"Document package distribution channels","description":"Document which packages support uv/pypi vs pixi/conda distribution. Note dependency graph differences between channels. Update README and package metadata.","status":"open","priority":2,"issue_type":"task","owner":"cameron.ray.smith@gmail.com","created_at":"2026-01-19T11:55:09.051203-05:00","created_by":"Cameron Smith","updated_at":"2026-01-19T11:55:09.051203-05:00","dependencies":[{"issue_id":"pnt-4jg.3","depends_on_id":"pnt-4jg","type":"parent-child","created_at":"2026-01-19T11:55:09.051857-05:00","created_by":"Cameron Smith"},{"issue_id":"pnt-4jg.3","depends_on_id":"pnt-4jg.1","type":"blocks","created_at":"2026-01-19T12:20:13.557576-05:00","created_by":"Cameron Smith"},{"issue_id":"pnt-4jg.3","depends_on_id":"pnt-4jg.2","type":"blocks","created_at":"2026-01-19T12:20:16.147971-05:00","created_by":"Cameron Smith"}]} -{"id":"pnt-btz","title":"pyo3/Rust extension integration","description":"Add Rust extension module support via maturin + pyo3, demonstrating Nix build integration with pyproject.nix maturinBuildHook and crane patterns.","status":"open","priority":2,"issue_type":"epic","owner":"cameron.ray.smith@gmail.com","created_at":"2026-01-19T11:54:41.426256-05:00","created_by":"Cameron Smith","updated_at":"2026-01-19T11:54:41.426256-05:00","dependencies":[{"issue_id":"pnt-btz","depends_on_id":"pnt-dre","type":"blocks","created_at":"2026-01-19T11:55:32.690895-05:00","created_by":"Cameron Smith"},{"issue_id":"pnt-btz","depends_on_id":"pnt-4jg","type":"blocks","created_at":"2026-01-19T11:55:32.812602-05:00","created_by":"Cameron Smith"}]} -{"id":"pnt-btz.1","title":"Create pnt-rust package scaffold","description":"Create packages/pnt-rust/ with Cargo.toml, pyproject.toml (maturin build-backend), src/lib.rs with pyo3 bindings. Minimal proof-of-concept function exposed to Python.","status":"open","priority":2,"issue_type":"task","owner":"cameron.ray.smith@gmail.com","created_at":"2026-01-19T11:55:17.885691-05:00","created_by":"Cameron Smith","updated_at":"2026-01-19T11:55:17.885691-05:00","dependencies":[{"issue_id":"pnt-btz.1","depends_on_id":"pnt-btz","type":"parent-child","created_at":"2026-01-19T11:55:17.886287-05:00","created_by":"Cameron Smith"},{"issue_id":"pnt-btz.1","depends_on_id":"pnt-4jg.1","type":"blocks","created_at":"2026-01-19T12:20:18.940008-05:00","created_by":"Cameron Smith"}]} -{"id":"pnt-btz.2","title":"Configure maturin + pyproject.nix build","description":"Add nix module for pnt-rust using rustPlatform.maturinBuildHook. Configure cargoDeps via fetchCargoVendor. Set PYO3_PYTHON env var to prevent path-dependent rebuilds.","status":"open","priority":2,"issue_type":"task","owner":"cameron.ray.smith@gmail.com","created_at":"2026-01-19T11:55:18.885252-05:00","created_by":"Cameron Smith","updated_at":"2026-01-19T11:55:18.885252-05:00","dependencies":[{"issue_id":"pnt-btz.2","depends_on_id":"pnt-btz","type":"parent-child","created_at":"2026-01-19T11:55:18.885818-05:00","created_by":"Cameron Smith"},{"issue_id":"pnt-btz.2","depends_on_id":"pnt-btz.1","type":"blocks","created_at":"2026-01-19T12:20:08.210077-05:00","created_by":"Cameron Smith"}]} -{"id":"pnt-btz.3","title":"Validate Rust + Python nix integration","description":"Verify nix build produces working wheel. Test import from Python. Document integration pattern for downstream projects. Identify gaps requiring custom solutions.","status":"open","priority":2,"issue_type":"task","owner":"cameron.ray.smith@gmail.com","created_at":"2026-01-19T11:55:19.746622-05:00","created_by":"Cameron Smith","updated_at":"2026-01-19T11:55:19.746622-05:00","dependencies":[{"issue_id":"pnt-btz.3","depends_on_id":"pnt-btz","type":"parent-child","created_at":"2026-01-19T11:55:19.74722-05:00","created_by":"Cameron Smith"},{"issue_id":"pnt-btz.3","depends_on_id":"pnt-btz.2","type":"blocks","created_at":"2026-01-19T12:20:11.013516-05:00","created_by":"Cameron Smith"}]} +{"id":"pnt-btz","title":"pyo3/Rust extension integration","description":"Add Rust extension module support via maturin + pyo3, demonstrating Nix build integration with crane cargoArtifacts sharing and uv2nix overlay composition.\n\nArchitecture documented in: docs/notes/architecture/crane-uv2nix-integration.md\n\nKey patterns:\n- Per-package Rust workspace (crates/ inside Python package)\n- crane buildDepsOnly for artifact caching\n- uv2nix overlay injection for maturin builds\n- CI matrix with rust-deps/rust-checks/python-wheel categories\n\nReference implementations:\n- ~/projects/rust-workspace/ironstar (crane patterns)\n- ~/projects/planning-workspace/langchain (federated Python)\n","status":"open","priority":2,"issue_type":"epic","owner":"cameron.ray.smith@gmail.com","created_at":"2026-01-19T11:54:41.426256-05:00","created_by":"Cameron Smith","updated_at":"2026-01-28T14:43:57.637638-05:00","dependencies":[{"issue_id":"pnt-btz","depends_on_id":"pnt-dre","type":"blocks","created_at":"2026-01-19T11:55:32.690895-05:00","created_by":"Cameron Smith"},{"issue_id":"pnt-btz","depends_on_id":"pnt-4jg","type":"blocks","created_at":"2026-01-19T11:55:32.812602-05:00","created_by":"Cameron Smith"}]} +{"id":"pnt-btz.1","title":"Create pnt-cli package scaffold with Rust crates","description":"Create packages/pnt-cli/ with federated structure:\n\nDirectory structure:\n- packages/pnt-cli/pyproject.toml (maturin build-backend, manifest-path binding)\n- packages/pnt-cli/src/pnt_cli/__init__.py (Python wrapper)\n- packages/pnt-cli/crates/Cargo.toml ([workspace] with member crates)\n- packages/pnt-cli/crates/pnt-cli-core/Cargo.toml (pure Rust library)\n- packages/pnt-cli/crates/pnt-cli-py/Cargo.toml (pyo3 bindings, depends on core)\n\npyproject.toml configuration:\n- [build-system] requires maturin\u003e=1.5\n- [tool.maturin] manifest-path = \"crates/pnt-cli-py/Cargo.toml\"\n- [tool.maturin] module-name = \"pnt_cli._native\"\n\nMinimal proof-of-concept: expose a simple function from Rust to Python.\n\nSee: docs/notes/architecture/crane-uv2nix-integration.md\n","status":"open","priority":2,"issue_type":"task","owner":"cameron.ray.smith@gmail.com","created_at":"2026-01-19T11:55:17.885691-05:00","created_by":"Cameron Smith","updated_at":"2026-01-28T14:43:57.882216-05:00","dependencies":[{"issue_id":"pnt-btz.1","depends_on_id":"pnt-btz","type":"parent-child","created_at":"2026-01-19T11:55:17.886287-05:00","created_by":"Cameron Smith"},{"issue_id":"pnt-btz.1","depends_on_id":"pnt-4jg.1","type":"blocks","created_at":"2026-01-19T12:20:18.940008-05:00","created_by":"Cameron Smith"}]} +{"id":"pnt-btz.2","title":"Implement crane + uv2nix Nix modules","description":"Create Nix modules implementing the crane + uv2nix integration pattern.\n\nFiles to create:\n- nix/packages/pnt-cli/rust.nix (crane configuration)\n- nix/packages/pnt-cli/default.nix (Python + Rust composition)\n- nix/modules/rust/lib.nix (shared crane utilities, optional)\n\nrust.nix pattern:\n- crane-lib.buildDepsOnly for cargoArtifacts caching\n- commonArgs pattern for derivation hash consistency\n- crane-lib.vendorCargoDeps for maturin's cargo invocation\n- Export cargoArtifacts, cargoVendorDir, clippy, nextest\n\ndefault.nix pattern:\n- Import rust.nix\n- Create overlay injecting cargoVendorDir and CARGO_TARGET_DIR\n- Export overlay and checks for flake composition\n\nUpdate nix/modules/python.nix:\n- Load pnt-cli workspace independently (federated pattern)\n- Compose Rust overlay with uv2nix overlays\n\nSee: docs/notes/architecture/crane-uv2nix-integration.md\n","status":"open","priority":2,"issue_type":"task","owner":"cameron.ray.smith@gmail.com","created_at":"2026-01-19T11:55:18.885252-05:00","created_by":"Cameron Smith","updated_at":"2026-01-28T14:43:58.112357-05:00","dependencies":[{"issue_id":"pnt-btz.2","depends_on_id":"pnt-btz","type":"parent-child","created_at":"2026-01-19T11:55:18.885818-05:00","created_by":"Cameron Smith"},{"issue_id":"pnt-btz.2","depends_on_id":"pnt-btz.1","type":"blocks","created_at":"2026-01-19T12:20:08.210077-05:00","created_by":"Cameron Smith"}]} +{"id":"pnt-btz.3","title":"Validate integration and update CI","description":"Validate the full crane + uv2nix + maturin integration and update CI.\n\nValidation checklist:\n- [ ] nix build .#pnt-cli produces working wheel\n- [ ] Python import succeeds: from pnt_cli._native import ...\n- [ ] Rust changes trigger minimal rebuilds (cargoArtifacts cached)\n- [ ] Python-only changes don't rebuild Rust\n- [ ] cargoClippy and cargoNextest checks pass\n\nCI updates (.github/workflows/ci.yaml):\n- Add rust-deps matrix category for cargoArtifacts caching\n- Add rust-checks matrix category for clippy/nextest\n- Ensure proper cache key based on Cargo.lock hash\n- Follow ironstar CI matrix pattern\n\nDocumentation updates:\n- Add usage example to README\n- Document development workflow (uv sync + maturin develop vs nix build)\n- Note editable install limitations\n\nSee: docs/notes/architecture/crane-uv2nix-integration.md\n","status":"open","priority":2,"issue_type":"task","owner":"cameron.ray.smith@gmail.com","created_at":"2026-01-19T11:55:19.746622-05:00","created_by":"Cameron Smith","updated_at":"2026-01-28T14:43:58.351336-05:00","dependencies":[{"issue_id":"pnt-btz.3","depends_on_id":"pnt-btz","type":"parent-child","created_at":"2026-01-19T11:55:19.74722-05:00","created_by":"Cameron Smith"},{"issue_id":"pnt-btz.3","depends_on_id":"pnt-btz.2","type":"blocks","created_at":"2026-01-19T12:20:11.013516-05:00","created_by":"Cameron Smith"}]} {"id":"pnt-dre","title":"Infrastructure alignment","description":"Align Makefile, justfile, scripts/, and CI with vanixiets and typescript-nix-template patterns. Makefile bootstrap-only, grouped justfile recipes, cached-ci-job CI pattern, omnix template integration.","status":"open","priority":2,"issue_type":"epic","owner":"cameron.ray.smith@gmail.com","created_at":"2026-01-19T11:54:39.841346-05:00","created_by":"Cameron Smith","updated_at":"2026-01-19T11:54:39.841346-05:00"} {"id":"pnt-dre.1","title":"Refactor Makefile to bootstrap-only pattern","description":"Restrict Makefile to bootstrap targets only: install-nix, install-direnv, verify, setup-user, check-secrets, clean. Move all other targets to justfile.","status":"open","priority":2,"issue_type":"task","owner":"cameron.ray.smith@gmail.com","created_at":"2026-01-19T11:54:54.237851-05:00","created_by":"Cameron Smith","updated_at":"2026-01-19T11:54:54.237851-05:00","dependencies":[{"issue_id":"pnt-dre.1","depends_on_id":"pnt-dre","type":"parent-child","created_at":"2026-01-19T11:54:54.238477-05:00","created_by":"Cameron Smith"}]} {"id":"pnt-dre.2","title":"Adopt grouped justfile recipe pattern","description":"Reorganize justfile with grouped recipes and section headers following vanixiets pattern: nix, python, conda, docs, secrets, ci/cd groups. Add help comments for each recipe.","status":"open","priority":2,"issue_type":"task","owner":"cameron.ray.smith@gmail.com","created_at":"2026-01-19T11:54:55.145094-05:00","created_by":"Cameron Smith","updated_at":"2026-01-19T11:54:55.145094-05:00","dependencies":[{"issue_id":"pnt-dre.2","depends_on_id":"pnt-dre","type":"parent-child","created_at":"2026-01-19T11:54:55.145764-05:00","created_by":"Cameron Smith"}]} From 65a2fc4897d35084cd15ae66f23a13023c79ef80 Mon Sep 17 00:00:00 2001 From: Cameron Smith Date: Mon, 2 Feb 2026 14:36:59 -0500 Subject: [PATCH 008/134] chore(issues): mark pnt-4jg.1 in_progress --- .beads/issues.jsonl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.beads/issues.jsonl b/.beads/issues.jsonl index 297a96b..0aa70ab 100644 --- a/.beads/issues.jsonl +++ b/.beads/issues.jsonl @@ -1,5 +1,5 @@ {"id":"pnt-4jg","title":"Dependency model migration","description":"Migrate from single-lock uv workspace to independent-lock multi-package pattern following langchain/langgraph approach. Include pixi feature-based composition for conda ecosystem parity.","status":"open","priority":2,"issue_type":"epic","owner":"cameron.ray.smith@gmail.com","created_at":"2026-01-19T11:54:40.744055-05:00","created_by":"Cameron Smith","updated_at":"2026-01-19T11:54:40.744055-05:00"} -{"id":"pnt-4jg.1","title":"Remove uv workspace, adopt path dependencies","description":"Remove [tool.uv.workspace] from root pyproject.toml. Each package gets own pyproject.toml with [tool.uv.sources] for sibling references using path sources with editable=true. Follow langchain pattern.","status":"open","priority":2,"issue_type":"task","owner":"cameron.ray.smith@gmail.com","created_at":"2026-01-19T11:55:07.344057-05:00","created_by":"Cameron Smith","updated_at":"2026-01-19T11:55:07.344057-05:00","dependencies":[{"issue_id":"pnt-4jg.1","depends_on_id":"pnt-4jg","type":"parent-child","created_at":"2026-01-19T11:55:07.344659-05:00","created_by":"Cameron Smith"}]} +{"id":"pnt-4jg.1","title":"Remove uv workspace, adopt path dependencies","description":"Remove [tool.uv.workspace] from root pyproject.toml. Each package gets own pyproject.toml with [tool.uv.sources] for sibling references using path sources with editable=true. Follow langchain pattern.","status":"in_progress","priority":2,"issue_type":"task","owner":"cameron.ray.smith@gmail.com","created_at":"2026-01-19T11:55:07.344057-05:00","created_by":"Cameron Smith","updated_at":"2026-02-02T14:36:54.635078-05:00","dependencies":[{"issue_id":"pnt-4jg.1","depends_on_id":"pnt-4jg","type":"parent-child","created_at":"2026-01-19T11:55:07.344659-05:00","created_by":"Cameron Smith"}]} {"id":"pnt-4jg.2","title":"Configure pixi feature-based composition","description":"Implement pixi feature/environment pattern: [feature.X.dependencies] + [environments] composition. Single pixi.lock covering all environments. Per-feature task definitions. Target-specific dependencies for platform support.","status":"open","priority":2,"issue_type":"task","owner":"cameron.ray.smith@gmail.com","created_at":"2026-01-19T11:55:08.085592-05:00","created_by":"Cameron Smith","updated_at":"2026-01-19T11:55:08.085592-05:00","dependencies":[{"issue_id":"pnt-4jg.2","depends_on_id":"pnt-4jg","type":"parent-child","created_at":"2026-01-19T11:55:08.086155-05:00","created_by":"Cameron Smith"}]} {"id":"pnt-4jg.3","title":"Document package distribution channels","description":"Document which packages support uv/pypi vs pixi/conda distribution. Note dependency graph differences between channels. Update README and package metadata.","status":"open","priority":2,"issue_type":"task","owner":"cameron.ray.smith@gmail.com","created_at":"2026-01-19T11:55:09.051203-05:00","created_by":"Cameron Smith","updated_at":"2026-01-19T11:55:09.051203-05:00","dependencies":[{"issue_id":"pnt-4jg.3","depends_on_id":"pnt-4jg","type":"parent-child","created_at":"2026-01-19T11:55:09.051857-05:00","created_by":"Cameron Smith"},{"issue_id":"pnt-4jg.3","depends_on_id":"pnt-4jg.1","type":"blocks","created_at":"2026-01-19T12:20:13.557576-05:00","created_by":"Cameron Smith"},{"issue_id":"pnt-4jg.3","depends_on_id":"pnt-4jg.2","type":"blocks","created_at":"2026-01-19T12:20:16.147971-05:00","created_by":"Cameron Smith"}]} {"id":"pnt-btz","title":"pyo3/Rust extension integration","description":"Add Rust extension module support via maturin + pyo3, demonstrating Nix build integration with crane cargoArtifacts sharing and uv2nix overlay composition.\n\nArchitecture documented in: docs/notes/architecture/crane-uv2nix-integration.md\n\nKey patterns:\n- Per-package Rust workspace (crates/ inside Python package)\n- crane buildDepsOnly for artifact caching\n- uv2nix overlay injection for maturin builds\n- CI matrix with rust-deps/rust-checks/python-wheel categories\n\nReference implementations:\n- ~/projects/rust-workspace/ironstar (crane patterns)\n- ~/projects/planning-workspace/langchain (federated Python)\n","status":"open","priority":2,"issue_type":"epic","owner":"cameron.ray.smith@gmail.com","created_at":"2026-01-19T11:54:41.426256-05:00","created_by":"Cameron Smith","updated_at":"2026-01-28T14:43:57.637638-05:00","dependencies":[{"issue_id":"pnt-btz","depends_on_id":"pnt-dre","type":"blocks","created_at":"2026-01-19T11:55:32.690895-05:00","created_by":"Cameron Smith"},{"issue_id":"pnt-btz","depends_on_id":"pnt-4jg","type":"blocks","created_at":"2026-01-19T11:55:32.812602-05:00","created_by":"Cameron Smith"}]} From 25f94ac706933b1d3693e62d0c586b9823663640 Mon Sep 17 00:00:00 2001 From: Cameron Smith Date: Mon, 2 Feb 2026 14:37:12 -0500 Subject: [PATCH 009/134] refactor(pyproject): remove uv workspace coordination Root pyproject.toml no longer declares [tool.uv.workspace] with members. Each package resolves independently with its own lock, following the LangChain federated model. Shared tool config (pytest, ruff, coverage) retained for IDE config discovery. --- pyproject.toml | 3 --- 1 file changed, 3 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index 2f17e4a..5f5b963 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,3 @@ -[tool.uv.workspace] -members = ["packages/*"] - [tool.pytest.ini_options] addopts = """ -rA From a899131c1413143d2a122a7051f8323e851d0f8e Mon Sep 17 00:00:00 2001 From: Cameron Smith Date: Mon, 2 Feb 2026 14:37:20 -0500 Subject: [PATCH 010/134] refactor(uv): remove root workspace lock file --- uv.lock | 2095 ------------------------------------------------------- 1 file changed, 2095 deletions(-) delete mode 100644 uv.lock diff --git a/uv.lock b/uv.lock deleted file mode 100644 index 8d38565..0000000 --- a/uv.lock +++ /dev/null @@ -1,2095 +0,0 @@ -version = 1 -revision = 3 -requires-python = ">=3.11, <3.13" - -[manifest] -members = [ - "pnt-functional", - "python-nix-template", -] - -[[package]] -name = "annotated-types" -version = "0.7.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/ee/67/531ea369ba64dcff5ec9c3402f9f51bf748cec26dde048a2f973a4eea7f5/annotated_types-0.7.0.tar.gz", hash = "sha256:aff07c09a53a08bc8cfccb9c85b05f1aa9a2a6f23728d790723543408344ce89", size = 16081, upload-time = "2024-05-20T21:33:25.928Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/78/b6/6307fbef88d9b5ee7421e68d78a9f162e0da4900bc5f5793f6d3d0e34fb8/annotated_types-0.7.0-py3-none-any.whl", hash = "sha256:1f02e8b43a8fbbc3f3e0d4f0f4bfc8131bcb4eebe8849b8e5c773f3a1c582a53", size = 13643, upload-time = "2024-05-20T21:33:24.1Z" }, -] - -[[package]] -name = "anyio" -version = "4.9.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "idna" }, - { name = "sniffio" }, - { name = "typing-extensions" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/95/7d/4c1bd541d4dffa1b52bd83fb8527089e097a106fc90b467a7313b105f840/anyio-4.9.0.tar.gz", hash = "sha256:673c0c244e15788651a4ff38710fea9675823028a6f08a5eda409e0c9840a028", size = 190949, upload-time = "2025-03-17T00:02:54.77Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/a1/ee/48ca1a7c89ffec8b6a0c5d02b89c305671d5ffd8d3c94acf8b8c408575bb/anyio-4.9.0-py3-none-any.whl", hash = "sha256:9f76d541cad6e36af7beb62e978876f3b41e3e04f2c1fbf0884604c0a9c4d93c", size = 100916, upload-time = "2025-03-17T00:02:52.713Z" }, -] - -[[package]] -name = "appnope" -version = "0.1.4" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/35/5d/752690df9ef5b76e169e68d6a129fa6d08a7100ca7f754c89495db3c6019/appnope-0.1.4.tar.gz", hash = "sha256:1de3860566df9caf38f01f86f65e0e13e379af54f9e4bee1e66b48f2efffd1ee", size = 4170, upload-time = "2024-02-06T09:43:11.258Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/81/29/5ecc3a15d5a33e31b26c11426c45c501e439cb865d0bff96315d86443b78/appnope-0.1.4-py2.py3-none-any.whl", hash = "sha256:502575ee11cd7a28c0205f379b525beefebab9d161b7c964670864014ed7213c", size = 4321, upload-time = "2024-02-06T09:43:09.663Z" }, -] - -[[package]] -name = "argon2-cffi" -version = "23.1.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "argon2-cffi-bindings" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/31/fa/57ec2c6d16ecd2ba0cf15f3c7d1c3c2e7b5fcb83555ff56d7ab10888ec8f/argon2_cffi-23.1.0.tar.gz", hash = "sha256:879c3e79a2729ce768ebb7d36d4609e3a78a4ca2ec3a9f12286ca057e3d0db08", size = 42798, upload-time = "2023-08-15T14:13:12.711Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/a4/6a/e8a041599e78b6b3752da48000b14c8d1e8a04ded09c88c714ba047f34f5/argon2_cffi-23.1.0-py3-none-any.whl", hash = "sha256:c670642b78ba29641818ab2e68bd4e6a78ba53b7eff7b4c3815ae16abf91c7ea", size = 15124, upload-time = "2023-08-15T14:13:10.752Z" }, -] - -[[package]] -name = "argon2-cffi-bindings" -version = "21.2.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "cffi" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/b9/e9/184b8ccce6683b0aa2fbb7ba5683ea4b9c5763f1356347f1312c32e3c66e/argon2-cffi-bindings-21.2.0.tar.gz", hash = "sha256:bb89ceffa6c791807d1305ceb77dbfacc5aa499891d2c55661c6459651fc39e3", size = 1779911, upload-time = "2021-12-01T08:52:55.68Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/d4/13/838ce2620025e9666aa8f686431f67a29052241692a3dd1ae9d3692a89d3/argon2_cffi_bindings-21.2.0-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:ccb949252cb2ab3a08c02024acb77cfb179492d5701c7cbdbfd776124d4d2367", size = 29658, upload-time = "2021-12-01T09:09:17.016Z" }, - { url = "https://files.pythonhosted.org/packages/b3/02/f7f7bb6b6af6031edb11037639c697b912e1dea2db94d436e681aea2f495/argon2_cffi_bindings-21.2.0-cp36-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9524464572e12979364b7d600abf96181d3541da11e23ddf565a32e70bd4dc0d", size = 80583, upload-time = "2021-12-01T09:09:19.546Z" }, - { url = "https://files.pythonhosted.org/packages/ec/f7/378254e6dd7ae6f31fe40c8649eea7d4832a42243acaf0f1fff9083b2bed/argon2_cffi_bindings-21.2.0-cp36-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b746dba803a79238e925d9046a63aa26bf86ab2a2fe74ce6b009a1c3f5c8f2ae", size = 86168, upload-time = "2021-12-01T09:09:21.445Z" }, - { url = "https://files.pythonhosted.org/packages/74/f6/4a34a37a98311ed73bb80efe422fed95f2ac25a4cacc5ae1d7ae6a144505/argon2_cffi_bindings-21.2.0-cp36-abi3-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:58ed19212051f49a523abb1dbe954337dc82d947fb6e5a0da60f7c8471a8476c", size = 82709, upload-time = "2021-12-01T09:09:18.182Z" }, - { url = "https://files.pythonhosted.org/packages/74/2b/73d767bfdaab25484f7e7901379d5f8793cccbb86c6e0cbc4c1b96f63896/argon2_cffi_bindings-21.2.0-cp36-abi3-musllinux_1_1_aarch64.whl", hash = "sha256:bd46088725ef7f58b5a1ef7ca06647ebaf0eb4baff7d1d0d177c6cc8744abd86", size = 83613, upload-time = "2021-12-01T09:09:22.741Z" }, - { url = "https://files.pythonhosted.org/packages/4f/fd/37f86deef67ff57c76f137a67181949c2d408077e2e3dd70c6c42912c9bf/argon2_cffi_bindings-21.2.0-cp36-abi3-musllinux_1_1_i686.whl", hash = "sha256:8cd69c07dd875537a824deec19f978e0f2078fdda07fd5c42ac29668dda5f40f", size = 84583, upload-time = "2021-12-01T09:09:24.177Z" }, - { url = "https://files.pythonhosted.org/packages/6f/52/5a60085a3dae8fded8327a4f564223029f5f54b0cb0455a31131b5363a01/argon2_cffi_bindings-21.2.0-cp36-abi3-musllinux_1_1_x86_64.whl", hash = "sha256:f1152ac548bd5b8bcecfb0b0371f082037e47128653df2e8ba6e914d384f3c3e", size = 88475, upload-time = "2021-12-01T09:09:26.673Z" }, - { url = "https://files.pythonhosted.org/packages/8b/95/143cd64feb24a15fa4b189a3e1e7efbaeeb00f39a51e99b26fc62fbacabd/argon2_cffi_bindings-21.2.0-cp36-abi3-win32.whl", hash = "sha256:603ca0aba86b1349b147cab91ae970c63118a0f30444d4bc80355937c950c082", size = 27698, upload-time = "2021-12-01T09:09:27.87Z" }, - { url = "https://files.pythonhosted.org/packages/37/2c/e34e47c7dee97ba6f01a6203e0383e15b60fb85d78ac9a15cd066f6fe28b/argon2_cffi_bindings-21.2.0-cp36-abi3-win_amd64.whl", hash = "sha256:b2ef1c30440dbbcba7a5dc3e319408b59676e2e039e2ae11a8775ecf482b192f", size = 30817, upload-time = "2021-12-01T09:09:30.267Z" }, - { url = "https://files.pythonhosted.org/packages/5a/e4/bf8034d25edaa495da3c8a3405627d2e35758e44ff6eaa7948092646fdcc/argon2_cffi_bindings-21.2.0-cp38-abi3-macosx_10_9_universal2.whl", hash = "sha256:e415e3f62c8d124ee16018e491a009937f8cf7ebf5eb430ffc5de21b900dad93", size = 53104, upload-time = "2021-12-01T09:09:31.335Z" }, -] - -[[package]] -name = "arrow" -version = "1.3.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "python-dateutil" }, - { name = "types-python-dateutil" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/2e/00/0f6e8fcdb23ea632c866620cc872729ff43ed91d284c866b515c6342b173/arrow-1.3.0.tar.gz", hash = "sha256:d4540617648cb5f895730f1ad8c82a65f2dad0166f57b75f3ca54759c4d67a85", size = 131960, upload-time = "2023-09-30T22:11:18.25Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/f8/ed/e97229a566617f2ae958a6b13e7cc0f585470eac730a73e9e82c32a3cdd2/arrow-1.3.0-py3-none-any.whl", hash = "sha256:c728b120ebc00eb84e01882a6f5e7927a53960aa990ce7dd2b10f39005a67f80", size = 66419, upload-time = "2023-09-30T22:11:16.072Z" }, -] - -[[package]] -name = "asttokens" -version = "3.0.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/4a/e7/82da0a03e7ba5141f05cce0d302e6eed121ae055e0456ca228bf693984bc/asttokens-3.0.0.tar.gz", hash = "sha256:0dcd8baa8d62b0c1d118b399b2ddba3c4aff271d0d7a9e0d4c1681c79035bbc7", size = 61978, upload-time = "2024-11-30T04:30:14.439Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/25/8a/c46dcc25341b5bce5472c718902eb3d38600a903b14fa6aeecef3f21a46f/asttokens-3.0.0-py3-none-any.whl", hash = "sha256:e3078351a059199dd5138cb1c706e6430c05eff2ff136af5eb4790f9d28932e2", size = 26918, upload-time = "2024-11-30T04:30:10.946Z" }, -] - -[[package]] -name = "async-lru" -version = "2.0.5" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/b2/4d/71ec4d3939dc755264f680f6c2b4906423a304c3d18e96853f0a595dfe97/async_lru-2.0.5.tar.gz", hash = "sha256:481d52ccdd27275f42c43a928b4a50c3bfb2d67af4e78b170e3e0bb39c66e5bb", size = 10380, upload-time = "2025-03-16T17:25:36.919Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/03/49/d10027df9fce941cb8184e78a02857af36360d33e1721df81c5ed2179a1a/async_lru-2.0.5-py3-none-any.whl", hash = "sha256:ab95404d8d2605310d345932697371a5f40def0487c03d6d0ad9138de52c9943", size = 6069, upload-time = "2025-03-16T17:25:35.422Z" }, -] - -[[package]] -name = "attrs" -version = "25.1.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/49/7c/fdf464bcc51d23881d110abd74b512a42b3d5d376a55a831b44c603ae17f/attrs-25.1.0.tar.gz", hash = "sha256:1c97078a80c814273a76b2a298a932eb681c87415c11dee0a6921de7f1b02c3e", size = 810562, upload-time = "2025-01-25T11:30:12.508Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/fc/30/d4986a882011f9df997a55e6becd864812ccfcd821d64aac8570ee39f719/attrs-25.1.0-py3-none-any.whl", hash = "sha256:c75a69e28a550a7e93789579c22aa26b0f5b83b75dc4e08fe092980051e1090a", size = 63152, upload-time = "2025-01-25T11:30:10.164Z" }, -] - -[[package]] -name = "babel" -version = "2.17.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/7d/6b/d52e42361e1aa00709585ecc30b3f9684b3ab62530771402248b1b1d6240/babel-2.17.0.tar.gz", hash = "sha256:0c54cffb19f690cdcc52a3b50bcbf71e07a808d1c80d549f2459b9d2cf0afb9d", size = 9951852, upload-time = "2025-02-01T15:17:41.026Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/b7/b8/3fe70c75fe32afc4bb507f75563d39bc5642255d1d94f1f23604725780bf/babel-2.17.0-py3-none-any.whl", hash = "sha256:4d0b53093fdfb4b21c92b5213dba5a1b23885afa8383709427046b21c366e5f2", size = 10182537, upload-time = "2025-02-01T15:17:37.39Z" }, -] - -[[package]] -name = "beartype" -version = "0.19.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/6f/e1/00515b97afa3993b4a314e4bc168fbde0917fd5845435cb6f16a19770746/beartype-0.19.0.tar.gz", hash = "sha256:de42dfc1ba5c3710fde6c3002e3bd2cad236ed4d2aabe876345ab0b4234a6573", size = 1294480, upload-time = "2024-09-26T07:06:17.308Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/64/69/f6db6e4cb2fe2f887dead40b76caa91af4844cb647dd2c7223bb010aa416/beartype-0.19.0-py3-none-any.whl", hash = "sha256:33b2694eda0daf052eb2aff623ed9a8a586703bbf0a90bbc475a83bbf427f699", size = 1039760, upload-time = "2024-09-26T07:06:13.546Z" }, -] - -[[package]] -name = "beautifulsoup4" -version = "4.13.4" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "soupsieve" }, - { name = "typing-extensions" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/d8/e4/0c4c39e18fd76d6a628d4dd8da40543d136ce2d1752bd6eeeab0791f4d6b/beautifulsoup4-4.13.4.tar.gz", hash = "sha256:dbb3c4e1ceae6aefebdaf2423247260cd062430a410e38c66f2baa50a8437195", size = 621067, upload-time = "2025-04-15T17:05:13.836Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/50/cd/30110dc0ffcf3b131156077b90e9f60ed75711223f306da4db08eff8403b/beautifulsoup4-4.13.4-py3-none-any.whl", hash = "sha256:9bbbb14bfde9d79f38b8cd5f8c7c85f4b8f2523190ebed90e950a8dea4cb1c4b", size = 187285, upload-time = "2025-04-15T17:05:12.221Z" }, -] - -[[package]] -name = "black" -version = "25.1.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "click" }, - { name = "mypy-extensions" }, - { name = "packaging" }, - { name = "pathspec" }, - { name = "platformdirs" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/94/49/26a7b0f3f35da4b5a65f081943b7bcd22d7002f5f0fb8098ec1ff21cb6ef/black-25.1.0.tar.gz", hash = "sha256:33496d5cd1222ad73391352b4ae8da15253c5de89b93a80b3e2c8d9a19ec2666", size = 649449, upload-time = "2025-01-29T04:15:40.373Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/7e/4f/87f596aca05c3ce5b94b8663dbfe242a12843caaa82dd3f85f1ffdc3f177/black-25.1.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:a39337598244de4bae26475f77dda852ea00a93bd4c728e09eacd827ec929df0", size = 1614372, upload-time = "2025-01-29T05:37:11.71Z" }, - { url = "https://files.pythonhosted.org/packages/e7/d0/2c34c36190b741c59c901e56ab7f6e54dad8df05a6272a9747ecef7c6036/black-25.1.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:96c1c7cd856bba8e20094e36e0f948718dc688dba4a9d78c3adde52b9e6c2299", size = 1442865, upload-time = "2025-01-29T05:37:14.309Z" }, - { url = "https://files.pythonhosted.org/packages/21/d4/7518c72262468430ead45cf22bd86c883a6448b9eb43672765d69a8f1248/black-25.1.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:bce2e264d59c91e52d8000d507eb20a9aca4a778731a08cfff7e5ac4a4bb7096", size = 1749699, upload-time = "2025-01-29T04:18:17.688Z" }, - { url = "https://files.pythonhosted.org/packages/58/db/4f5beb989b547f79096e035c4981ceb36ac2b552d0ac5f2620e941501c99/black-25.1.0-cp311-cp311-win_amd64.whl", hash = "sha256:172b1dbff09f86ce6f4eb8edf9dede08b1fce58ba194c87d7a4f1a5aa2f5b3c2", size = 1428028, upload-time = "2025-01-29T04:18:51.711Z" }, - { url = "https://files.pythonhosted.org/packages/83/71/3fe4741df7adf015ad8dfa082dd36c94ca86bb21f25608eb247b4afb15b2/black-25.1.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:4b60580e829091e6f9238c848ea6750efed72140b91b048770b64e74fe04908b", size = 1650988, upload-time = "2025-01-29T05:37:16.707Z" }, - { url = "https://files.pythonhosted.org/packages/13/f3/89aac8a83d73937ccd39bbe8fc6ac8860c11cfa0af5b1c96d081facac844/black-25.1.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:1e2978f6df243b155ef5fa7e558a43037c3079093ed5d10fd84c43900f2d8ecc", size = 1453985, upload-time = "2025-01-29T05:37:18.273Z" }, - { url = "https://files.pythonhosted.org/packages/6f/22/b99efca33f1f3a1d2552c714b1e1b5ae92efac6c43e790ad539a163d1754/black-25.1.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:3b48735872ec535027d979e8dcb20bf4f70b5ac75a8ea99f127c106a7d7aba9f", size = 1783816, upload-time = "2025-01-29T04:18:33.823Z" }, - { url = "https://files.pythonhosted.org/packages/18/7e/a27c3ad3822b6f2e0e00d63d58ff6299a99a5b3aee69fa77cd4b0076b261/black-25.1.0-cp312-cp312-win_amd64.whl", hash = "sha256:ea0213189960bda9cf99be5b8c8ce66bb054af5e9e861249cd23471bd7b0b3ba", size = 1440860, upload-time = "2025-01-29T04:19:12.944Z" }, - { url = "https://files.pythonhosted.org/packages/09/71/54e999902aed72baf26bca0d50781b01838251a462612966e9fc4891eadd/black-25.1.0-py3-none-any.whl", hash = "sha256:95e8176dae143ba9097f351d174fdaf0ccd29efb414b362ae3fd72bf0f710717", size = 207646, upload-time = "2025-01-29T04:15:38.082Z" }, -] - -[[package]] -name = "bleach" -version = "6.2.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "webencodings" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/76/9a/0e33f5054c54d349ea62c277191c020c2d6ef1d65ab2cb1993f91ec846d1/bleach-6.2.0.tar.gz", hash = "sha256:123e894118b8a599fd80d3ec1a6d4cc7ce4e5882b1317a7e1ba69b56e95f991f", size = 203083, upload-time = "2024-10-29T18:30:40.477Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/fc/55/96142937f66150805c25c4d0f31ee4132fd33497753400734f9dfdcbdc66/bleach-6.2.0-py3-none-any.whl", hash = "sha256:117d9c6097a7c3d22fd578fcd8d35ff1e125df6736f554da4e432fdd63f31e5e", size = 163406, upload-time = "2024-10-29T18:30:38.186Z" }, -] - -[package.optional-dependencies] -css = [ - { name = "tinycss2" }, -] - -[[package]] -name = "certifi" -version = "2025.4.26" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/e8/9e/c05b3920a3b7d20d3d3310465f50348e5b3694f4f88c6daf736eef3024c4/certifi-2025.4.26.tar.gz", hash = "sha256:0a816057ea3cdefcef70270d2c515e4506bbc954f417fa5ade2021213bb8f0c6", size = 160705, upload-time = "2025-04-26T02:12:29.51Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/4a/7e/3db2bd1b1f9e95f7cddca6d6e75e2f2bd9f51b1246e546d88addca0106bd/certifi-2025.4.26-py3-none-any.whl", hash = "sha256:30350364dfe371162649852c63336a15c70c6510c2ad5015b21c2345311805f3", size = 159618, upload-time = "2025-04-26T02:12:27.662Z" }, -] - -[[package]] -name = "cffi" -version = "1.17.1" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "pycparser" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/fc/97/c783634659c2920c3fc70419e3af40972dbaf758daa229a7d6ea6135c90d/cffi-1.17.1.tar.gz", hash = "sha256:1c39c6016c32bc48dd54561950ebd6836e1670f2ae46128f67cf49e789c52824", size = 516621, upload-time = "2024-09-04T20:45:21.852Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/6b/f4/927e3a8899e52a27fa57a48607ff7dc91a9ebe97399b357b85a0c7892e00/cffi-1.17.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:a45e3c6913c5b87b3ff120dcdc03f6131fa0065027d0ed7ee6190736a74cd401", size = 182264, upload-time = "2024-09-04T20:43:51.124Z" }, - { url = "https://files.pythonhosted.org/packages/6c/f5/6c3a8efe5f503175aaddcbea6ad0d2c96dad6f5abb205750d1b3df44ef29/cffi-1.17.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:30c5e0cb5ae493c04c8b42916e52ca38079f1b235c2f8ae5f4527b963c401caf", size = 178651, upload-time = "2024-09-04T20:43:52.872Z" }, - { url = "https://files.pythonhosted.org/packages/94/dd/a3f0118e688d1b1a57553da23b16bdade96d2f9bcda4d32e7d2838047ff7/cffi-1.17.1-cp311-cp311-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f75c7ab1f9e4aca5414ed4d8e5c0e303a34f4421f8a0d47a4d019ceff0ab6af4", size = 445259, upload-time = "2024-09-04T20:43:56.123Z" }, - { url = "https://files.pythonhosted.org/packages/2e/ea/70ce63780f096e16ce8588efe039d3c4f91deb1dc01e9c73a287939c79a6/cffi-1.17.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a1ed2dd2972641495a3ec98445e09766f077aee98a1c896dcb4ad0d303628e41", size = 469200, upload-time = "2024-09-04T20:43:57.891Z" }, - { url = "https://files.pythonhosted.org/packages/1c/a0/a4fa9f4f781bda074c3ddd57a572b060fa0df7655d2a4247bbe277200146/cffi-1.17.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:46bf43160c1a35f7ec506d254e5c890f3c03648a4dbac12d624e4490a7046cd1", size = 477235, upload-time = "2024-09-04T20:44:00.18Z" }, - { url = "https://files.pythonhosted.org/packages/62/12/ce8710b5b8affbcdd5c6e367217c242524ad17a02fe5beec3ee339f69f85/cffi-1.17.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a24ed04c8ffd54b0729c07cee15a81d964e6fee0e3d4d342a27b020d22959dc6", size = 459721, upload-time = "2024-09-04T20:44:01.585Z" }, - { url = "https://files.pythonhosted.org/packages/ff/6b/d45873c5e0242196f042d555526f92aa9e0c32355a1be1ff8c27f077fd37/cffi-1.17.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:610faea79c43e44c71e1ec53a554553fa22321b65fae24889706c0a84d4ad86d", size = 467242, upload-time = "2024-09-04T20:44:03.467Z" }, - { url = "https://files.pythonhosted.org/packages/1a/52/d9a0e523a572fbccf2955f5abe883cfa8bcc570d7faeee06336fbd50c9fc/cffi-1.17.1-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:a9b15d491f3ad5d692e11f6b71f7857e7835eb677955c00cc0aefcd0669adaf6", size = 477999, upload-time = "2024-09-04T20:44:05.023Z" }, - { url = "https://files.pythonhosted.org/packages/44/74/f2a2460684a1a2d00ca799ad880d54652841a780c4c97b87754f660c7603/cffi-1.17.1-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:de2ea4b5833625383e464549fec1bc395c1bdeeb5f25c4a3a82b5a8c756ec22f", size = 454242, upload-time = "2024-09-04T20:44:06.444Z" }, - { url = "https://files.pythonhosted.org/packages/f8/4a/34599cac7dfcd888ff54e801afe06a19c17787dfd94495ab0c8d35fe99fb/cffi-1.17.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:fc48c783f9c87e60831201f2cce7f3b2e4846bf4d8728eabe54d60700b318a0b", size = 478604, upload-time = "2024-09-04T20:44:08.206Z" }, - { url = "https://files.pythonhosted.org/packages/34/33/e1b8a1ba29025adbdcda5fb3a36f94c03d771c1b7b12f726ff7fef2ebe36/cffi-1.17.1-cp311-cp311-win32.whl", hash = "sha256:85a950a4ac9c359340d5963966e3e0a94a676bd6245a4b55bc43949eee26a655", size = 171727, upload-time = "2024-09-04T20:44:09.481Z" }, - { url = "https://files.pythonhosted.org/packages/3d/97/50228be003bb2802627d28ec0627837ac0bf35c90cf769812056f235b2d1/cffi-1.17.1-cp311-cp311-win_amd64.whl", hash = "sha256:caaf0640ef5f5517f49bc275eca1406b0ffa6aa184892812030f04c2abf589a0", size = 181400, upload-time = "2024-09-04T20:44:10.873Z" }, - { url = "https://files.pythonhosted.org/packages/5a/84/e94227139ee5fb4d600a7a4927f322e1d4aea6fdc50bd3fca8493caba23f/cffi-1.17.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:805b4371bf7197c329fcb3ead37e710d1bca9da5d583f5073b799d5c5bd1eee4", size = 183178, upload-time = "2024-09-04T20:44:12.232Z" }, - { url = "https://files.pythonhosted.org/packages/da/ee/fb72c2b48656111c4ef27f0f91da355e130a923473bf5ee75c5643d00cca/cffi-1.17.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:733e99bc2df47476e3848417c5a4540522f234dfd4ef3ab7fafdf555b082ec0c", size = 178840, upload-time = "2024-09-04T20:44:13.739Z" }, - { url = "https://files.pythonhosted.org/packages/cc/b6/db007700f67d151abadf508cbfd6a1884f57eab90b1bb985c4c8c02b0f28/cffi-1.17.1-cp312-cp312-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1257bdabf294dceb59f5e70c64a3e2f462c30c7ad68092d01bbbfb1c16b1ba36", size = 454803, upload-time = "2024-09-04T20:44:15.231Z" }, - { url = "https://files.pythonhosted.org/packages/1a/df/f8d151540d8c200eb1c6fba8cd0dfd40904f1b0682ea705c36e6c2e97ab3/cffi-1.17.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:da95af8214998d77a98cc14e3a3bd00aa191526343078b530ceb0bd710fb48a5", size = 478850, upload-time = "2024-09-04T20:44:17.188Z" }, - { url = "https://files.pythonhosted.org/packages/28/c0/b31116332a547fd2677ae5b78a2ef662dfc8023d67f41b2a83f7c2aa78b1/cffi-1.17.1-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d63afe322132c194cf832bfec0dc69a99fb9bb6bbd550f161a49e9e855cc78ff", size = 485729, upload-time = "2024-09-04T20:44:18.688Z" }, - { url = "https://files.pythonhosted.org/packages/91/2b/9a1ddfa5c7f13cab007a2c9cc295b70fbbda7cb10a286aa6810338e60ea1/cffi-1.17.1-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f79fc4fc25f1c8698ff97788206bb3c2598949bfe0fef03d299eb1b5356ada99", size = 471256, upload-time = "2024-09-04T20:44:20.248Z" }, - { url = "https://files.pythonhosted.org/packages/b2/d5/da47df7004cb17e4955df6a43d14b3b4ae77737dff8bf7f8f333196717bf/cffi-1.17.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b62ce867176a75d03a665bad002af8e6d54644fad99a3c70905c543130e39d93", size = 479424, upload-time = "2024-09-04T20:44:21.673Z" }, - { url = "https://files.pythonhosted.org/packages/0b/ac/2a28bcf513e93a219c8a4e8e125534f4f6db03e3179ba1c45e949b76212c/cffi-1.17.1-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:386c8bf53c502fff58903061338ce4f4950cbdcb23e2902d86c0f722b786bbe3", size = 484568, upload-time = "2024-09-04T20:44:23.245Z" }, - { url = "https://files.pythonhosted.org/packages/d4/38/ca8a4f639065f14ae0f1d9751e70447a261f1a30fa7547a828ae08142465/cffi-1.17.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:4ceb10419a9adf4460ea14cfd6bc43d08701f0835e979bf821052f1805850fe8", size = 488736, upload-time = "2024-09-04T20:44:24.757Z" }, - { url = "https://files.pythonhosted.org/packages/86/c5/28b2d6f799ec0bdecf44dced2ec5ed43e0eb63097b0f58c293583b406582/cffi-1.17.1-cp312-cp312-win32.whl", hash = "sha256:a08d7e755f8ed21095a310a693525137cfe756ce62d066e53f502a83dc550f65", size = 172448, upload-time = "2024-09-04T20:44:26.208Z" }, - { url = "https://files.pythonhosted.org/packages/50/b9/db34c4755a7bd1cb2d1603ac3863f22bcecbd1ba29e5ee841a4bc510b294/cffi-1.17.1-cp312-cp312-win_amd64.whl", hash = "sha256:51392eae71afec0d0c8fb1a53b204dbb3bcabcb3c9b807eedf3e1e6ccf2de903", size = 181976, upload-time = "2024-09-04T20:44:27.578Z" }, -] - -[[package]] -name = "charset-normalizer" -version = "3.4.2" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/e4/33/89c2ced2b67d1c2a61c19c6751aa8902d46ce3dacb23600a283619f5a12d/charset_normalizer-3.4.2.tar.gz", hash = "sha256:5baececa9ecba31eff645232d59845c07aa030f0c81ee70184a90d35099a0e63", size = 126367, upload-time = "2025-05-02T08:34:42.01Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/05/85/4c40d00dcc6284a1c1ad5de5e0996b06f39d8232f1031cd23c2f5c07ee86/charset_normalizer-3.4.2-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:be1e352acbe3c78727a16a455126d9ff83ea2dfdcbc83148d2982305a04714c2", size = 198794, upload-time = "2025-05-02T08:32:11.945Z" }, - { url = "https://files.pythonhosted.org/packages/41/d9/7a6c0b9db952598e97e93cbdfcb91bacd89b9b88c7c983250a77c008703c/charset_normalizer-3.4.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:aa88ca0b1932e93f2d961bf3addbb2db902198dca337d88c89e1559e066e7645", size = 142846, upload-time = "2025-05-02T08:32:13.946Z" }, - { url = "https://files.pythonhosted.org/packages/66/82/a37989cda2ace7e37f36c1a8ed16c58cf48965a79c2142713244bf945c89/charset_normalizer-3.4.2-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d524ba3f1581b35c03cb42beebab4a13e6cdad7b36246bd22541fa585a56cccd", size = 153350, upload-time = "2025-05-02T08:32:15.873Z" }, - { url = "https://files.pythonhosted.org/packages/df/68/a576b31b694d07b53807269d05ec3f6f1093e9545e8607121995ba7a8313/charset_normalizer-3.4.2-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:28a1005facc94196e1fb3e82a3d442a9d9110b8434fc1ded7a24a2983c9888d8", size = 145657, upload-time = "2025-05-02T08:32:17.283Z" }, - { url = "https://files.pythonhosted.org/packages/92/9b/ad67f03d74554bed3aefd56fe836e1623a50780f7c998d00ca128924a499/charset_normalizer-3.4.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fdb20a30fe1175ecabed17cbf7812f7b804b8a315a25f24678bcdf120a90077f", size = 147260, upload-time = "2025-05-02T08:32:18.807Z" }, - { url = "https://files.pythonhosted.org/packages/a6/e6/8aebae25e328160b20e31a7e9929b1578bbdc7f42e66f46595a432f8539e/charset_normalizer-3.4.2-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0f5d9ed7f254402c9e7d35d2f5972c9bbea9040e99cd2861bd77dc68263277c7", size = 149164, upload-time = "2025-05-02T08:32:20.333Z" }, - { url = "https://files.pythonhosted.org/packages/8b/f2/b3c2f07dbcc248805f10e67a0262c93308cfa149a4cd3d1fe01f593e5fd2/charset_normalizer-3.4.2-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:efd387a49825780ff861998cd959767800d54f8308936b21025326de4b5a42b9", size = 144571, upload-time = "2025-05-02T08:32:21.86Z" }, - { url = "https://files.pythonhosted.org/packages/60/5b/c3f3a94bc345bc211622ea59b4bed9ae63c00920e2e8f11824aa5708e8b7/charset_normalizer-3.4.2-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:f0aa37f3c979cf2546b73e8222bbfa3dc07a641585340179d768068e3455e544", size = 151952, upload-time = "2025-05-02T08:32:23.434Z" }, - { url = "https://files.pythonhosted.org/packages/e2/4d/ff460c8b474122334c2fa394a3f99a04cf11c646da895f81402ae54f5c42/charset_normalizer-3.4.2-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:e70e990b2137b29dc5564715de1e12701815dacc1d056308e2b17e9095372a82", size = 155959, upload-time = "2025-05-02T08:32:24.993Z" }, - { url = "https://files.pythonhosted.org/packages/a2/2b/b964c6a2fda88611a1fe3d4c400d39c66a42d6c169c924818c848f922415/charset_normalizer-3.4.2-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:0c8c57f84ccfc871a48a47321cfa49ae1df56cd1d965a09abe84066f6853b9c0", size = 153030, upload-time = "2025-05-02T08:32:26.435Z" }, - { url = "https://files.pythonhosted.org/packages/59/2e/d3b9811db26a5ebf444bc0fa4f4be5aa6d76fc6e1c0fd537b16c14e849b6/charset_normalizer-3.4.2-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:6b66f92b17849b85cad91259efc341dce9c1af48e2173bf38a85c6329f1033e5", size = 148015, upload-time = "2025-05-02T08:32:28.376Z" }, - { url = "https://files.pythonhosted.org/packages/90/07/c5fd7c11eafd561bb51220d600a788f1c8d77c5eef37ee49454cc5c35575/charset_normalizer-3.4.2-cp311-cp311-win32.whl", hash = "sha256:daac4765328a919a805fa5e2720f3e94767abd632ae410a9062dff5412bae65a", size = 98106, upload-time = "2025-05-02T08:32:30.281Z" }, - { url = "https://files.pythonhosted.org/packages/a8/05/5e33dbef7e2f773d672b6d79f10ec633d4a71cd96db6673625838a4fd532/charset_normalizer-3.4.2-cp311-cp311-win_amd64.whl", hash = "sha256:e53efc7c7cee4c1e70661e2e112ca46a575f90ed9ae3fef200f2a25e954f4b28", size = 105402, upload-time = "2025-05-02T08:32:32.191Z" }, - { url = "https://files.pythonhosted.org/packages/d7/a4/37f4d6035c89cac7930395a35cc0f1b872e652eaafb76a6075943754f095/charset_normalizer-3.4.2-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:0c29de6a1a95f24b9a1aa7aefd27d2487263f00dfd55a77719b530788f75cff7", size = 199936, upload-time = "2025-05-02T08:32:33.712Z" }, - { url = "https://files.pythonhosted.org/packages/ee/8a/1a5e33b73e0d9287274f899d967907cd0bf9c343e651755d9307e0dbf2b3/charset_normalizer-3.4.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cddf7bd982eaa998934a91f69d182aec997c6c468898efe6679af88283b498d3", size = 143790, upload-time = "2025-05-02T08:32:35.768Z" }, - { url = "https://files.pythonhosted.org/packages/66/52/59521f1d8e6ab1482164fa21409c5ef44da3e9f653c13ba71becdd98dec3/charset_normalizer-3.4.2-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:fcbe676a55d7445b22c10967bceaaf0ee69407fbe0ece4d032b6eb8d4565982a", size = 153924, upload-time = "2025-05-02T08:32:37.284Z" }, - { url = "https://files.pythonhosted.org/packages/86/2d/fb55fdf41964ec782febbf33cb64be480a6b8f16ded2dbe8db27a405c09f/charset_normalizer-3.4.2-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d41c4d287cfc69060fa91cae9683eacffad989f1a10811995fa309df656ec214", size = 146626, upload-time = "2025-05-02T08:32:38.803Z" }, - { url = "https://files.pythonhosted.org/packages/8c/73/6ede2ec59bce19b3edf4209d70004253ec5f4e319f9a2e3f2f15601ed5f7/charset_normalizer-3.4.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4e594135de17ab3866138f496755f302b72157d115086d100c3f19370839dd3a", size = 148567, upload-time = "2025-05-02T08:32:40.251Z" }, - { url = "https://files.pythonhosted.org/packages/09/14/957d03c6dc343c04904530b6bef4e5efae5ec7d7990a7cbb868e4595ee30/charset_normalizer-3.4.2-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:cf713fe9a71ef6fd5adf7a79670135081cd4431c2943864757f0fa3a65b1fafd", size = 150957, upload-time = "2025-05-02T08:32:41.705Z" }, - { url = "https://files.pythonhosted.org/packages/0d/c8/8174d0e5c10ccebdcb1b53cc959591c4c722a3ad92461a273e86b9f5a302/charset_normalizer-3.4.2-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:a370b3e078e418187da8c3674eddb9d983ec09445c99a3a263c2011993522981", size = 145408, upload-time = "2025-05-02T08:32:43.709Z" }, - { url = "https://files.pythonhosted.org/packages/58/aa/8904b84bc8084ac19dc52feb4f5952c6df03ffb460a887b42615ee1382e8/charset_normalizer-3.4.2-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:a955b438e62efdf7e0b7b52a64dc5c3396e2634baa62471768a64bc2adb73d5c", size = 153399, upload-time = "2025-05-02T08:32:46.197Z" }, - { url = "https://files.pythonhosted.org/packages/c2/26/89ee1f0e264d201cb65cf054aca6038c03b1a0c6b4ae998070392a3ce605/charset_normalizer-3.4.2-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:7222ffd5e4de8e57e03ce2cef95a4c43c98fcb72ad86909abdfc2c17d227fc1b", size = 156815, upload-time = "2025-05-02T08:32:48.105Z" }, - { url = "https://files.pythonhosted.org/packages/fd/07/68e95b4b345bad3dbbd3a8681737b4338ff2c9df29856a6d6d23ac4c73cb/charset_normalizer-3.4.2-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:bee093bf902e1d8fc0ac143c88902c3dfc8941f7ea1d6a8dd2bcb786d33db03d", size = 154537, upload-time = "2025-05-02T08:32:49.719Z" }, - { url = "https://files.pythonhosted.org/packages/77/1a/5eefc0ce04affb98af07bc05f3bac9094513c0e23b0562d64af46a06aae4/charset_normalizer-3.4.2-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:dedb8adb91d11846ee08bec4c8236c8549ac721c245678282dcb06b221aab59f", size = 149565, upload-time = "2025-05-02T08:32:51.404Z" }, - { url = "https://files.pythonhosted.org/packages/37/a0/2410e5e6032a174c95e0806b1a6585eb21e12f445ebe239fac441995226a/charset_normalizer-3.4.2-cp312-cp312-win32.whl", hash = "sha256:db4c7bf0e07fc3b7d89ac2a5880a6a8062056801b83ff56d8464b70f65482b6c", size = 98357, upload-time = "2025-05-02T08:32:53.079Z" }, - { url = "https://files.pythonhosted.org/packages/6c/4f/c02d5c493967af3eda9c771ad4d2bbc8df6f99ddbeb37ceea6e8716a32bc/charset_normalizer-3.4.2-cp312-cp312-win_amd64.whl", hash = "sha256:5a9979887252a82fefd3d3ed2a8e3b937a7a809f65dcb1e068b090e165bbe99e", size = 105776, upload-time = "2025-05-02T08:32:54.573Z" }, - { url = "https://files.pythonhosted.org/packages/20/94/c5790835a017658cbfabd07f3bfb549140c3ac458cfc196323996b10095a/charset_normalizer-3.4.2-py3-none-any.whl", hash = "sha256:7f56930ab0abd1c45cd15be65cc741c28b1c9a34876ce8c17a2fa107810c0af0", size = 52626, upload-time = "2025-05-02T08:34:40.053Z" }, -] - -[[package]] -name = "click" -version = "8.1.8" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "colorama", marker = "sys_platform == 'win32'" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/b9/2e/0090cbf739cee7d23781ad4b89a9894a41538e4fcf4c31dcdd705b78eb8b/click-8.1.8.tar.gz", hash = "sha256:ed53c9d8990d83c2a27deae68e4ee337473f6330c040a31d4225c9574d16096a", size = 226593, upload-time = "2024-12-21T18:38:44.339Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/7e/d4/7ebdbd03970677812aac39c869717059dbb71a4cfc033ca6e5221787892c/click-8.1.8-py3-none-any.whl", hash = "sha256:63c132bbbed01578a06712a2d1f497bb62d9c1c0d329b7903a866228027263b2", size = 98188, upload-time = "2024-12-21T18:38:41.666Z" }, -] - -[[package]] -name = "colorama" -version = "0.4.6" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/d8/53/6f443c9a4a8358a93a6792e2acffb9d9d5cb0a5cfd8802644b7b1c9a02e4/colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44", size = 27697, upload-time = "2022-10-25T02:36:22.414Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/d1/d6/3965ed04c63042e047cb6a3e6ed1a63a35087b6a609aa3a15ed8ac56c221/colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6", size = 25335, upload-time = "2022-10-25T02:36:20.889Z" }, -] - -[[package]] -name = "comm" -version = "0.2.2" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "traitlets" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/e9/a8/fb783cb0abe2b5fded9f55e5703015cdf1c9c85b3669087c538dd15a6a86/comm-0.2.2.tar.gz", hash = "sha256:3fd7a84065306e07bea1773df6eb8282de51ba82f77c72f9c85716ab11fe980e", size = 6210, upload-time = "2024-03-12T16:53:41.133Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/e6/75/49e5bfe642f71f272236b5b2d2691cf915a7283cc0ceda56357b61daa538/comm-0.2.2-py3-none-any.whl", hash = "sha256:e6fb86cb70ff661ee8c9c14e7d36d6de3b4066f1441be4063df9c5009f0a64d3", size = 7180, upload-time = "2024-03-12T16:53:39.226Z" }, -] - -[[package]] -name = "coverage" -version = "7.6.12" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/0c/d6/2b53ab3ee99f2262e6f0b8369a43f6d66658eab45510331c0b3d5c8c4272/coverage-7.6.12.tar.gz", hash = "sha256:48cfc4641d95d34766ad41d9573cc0f22a48aa88d22657a1fe01dca0dbae4de2", size = 805941, upload-time = "2025-02-11T14:47:03.797Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/64/2d/da78abbfff98468c91fd63a73cccdfa0e99051676ded8dd36123e3a2d4d5/coverage-7.6.12-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:e18aafdfb3e9ec0d261c942d35bd7c28d031c5855dadb491d2723ba54f4c3015", size = 208464, upload-time = "2025-02-11T14:45:18.314Z" }, - { url = "https://files.pythonhosted.org/packages/31/f2/c269f46c470bdabe83a69e860c80a82e5e76840e9f4bbd7f38f8cebbee2f/coverage-7.6.12-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:66fe626fd7aa5982cdebad23e49e78ef7dbb3e3c2a5960a2b53632f1f703ea45", size = 208893, upload-time = "2025-02-11T14:45:19.881Z" }, - { url = "https://files.pythonhosted.org/packages/47/63/5682bf14d2ce20819998a49c0deadb81e608a59eed64d6bc2191bc8046b9/coverage-7.6.12-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0ef01d70198431719af0b1f5dcbefc557d44a190e749004042927b2a3fed0702", size = 241545, upload-time = "2025-02-11T14:45:22.215Z" }, - { url = "https://files.pythonhosted.org/packages/6a/b6/6b6631f1172d437e11067e1c2edfdb7238b65dff965a12bce3b6d1bf2be2/coverage-7.6.12-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:07e92ae5a289a4bc4c0aae710c0948d3c7892e20fd3588224ebe242039573bf0", size = 239230, upload-time = "2025-02-11T14:45:24.864Z" }, - { url = "https://files.pythonhosted.org/packages/c7/01/9cd06cbb1be53e837e16f1b4309f6357e2dfcbdab0dd7cd3b1a50589e4e1/coverage-7.6.12-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e695df2c58ce526eeab11a2e915448d3eb76f75dffe338ea613c1201b33bab2f", size = 241013, upload-time = "2025-02-11T14:45:27.203Z" }, - { url = "https://files.pythonhosted.org/packages/4b/26/56afefc03c30871326e3d99709a70d327ac1f33da383cba108c79bd71563/coverage-7.6.12-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:d74c08e9aaef995f8c4ef6d202dbd219c318450fe2a76da624f2ebb9c8ec5d9f", size = 239750, upload-time = "2025-02-11T14:45:29.577Z" }, - { url = "https://files.pythonhosted.org/packages/dd/ea/88a1ff951ed288f56aa561558ebe380107cf9132facd0b50bced63ba7238/coverage-7.6.12-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:e995b3b76ccedc27fe4f477b349b7d64597e53a43fc2961db9d3fbace085d69d", size = 238462, upload-time = "2025-02-11T14:45:31.096Z" }, - { url = "https://files.pythonhosted.org/packages/6e/d4/1d9404566f553728889409eff82151d515fbb46dc92cbd13b5337fa0de8c/coverage-7.6.12-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:b1f097878d74fe51e1ddd1be62d8e3682748875b461232cf4b52ddc6e6db0bba", size = 239307, upload-time = "2025-02-11T14:45:32.713Z" }, - { url = "https://files.pythonhosted.org/packages/12/c1/e453d3b794cde1e232ee8ac1d194fde8e2ba329c18bbf1b93f6f5eef606b/coverage-7.6.12-cp311-cp311-win32.whl", hash = "sha256:1f7ffa05da41754e20512202c866d0ebfc440bba3b0ed15133070e20bf5aeb5f", size = 211117, upload-time = "2025-02-11T14:45:34.228Z" }, - { url = "https://files.pythonhosted.org/packages/d5/db/829185120c1686fa297294f8fcd23e0422f71070bf85ef1cc1a72ecb2930/coverage-7.6.12-cp311-cp311-win_amd64.whl", hash = "sha256:e216c5c45f89ef8971373fd1c5d8d1164b81f7f5f06bbf23c37e7908d19e8558", size = 212019, upload-time = "2025-02-11T14:45:35.724Z" }, - { url = "https://files.pythonhosted.org/packages/e2/7f/4af2ed1d06ce6bee7eafc03b2ef748b14132b0bdae04388e451e4b2c529b/coverage-7.6.12-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:b172f8e030e8ef247b3104902cc671e20df80163b60a203653150d2fc204d1ad", size = 208645, upload-time = "2025-02-11T14:45:37.95Z" }, - { url = "https://files.pythonhosted.org/packages/dc/60/d19df912989117caa95123524d26fc973f56dc14aecdec5ccd7d0084e131/coverage-7.6.12-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:641dfe0ab73deb7069fb972d4d9725bf11c239c309ce694dd50b1473c0f641c3", size = 208898, upload-time = "2025-02-11T14:45:40.27Z" }, - { url = "https://files.pythonhosted.org/packages/bd/10/fecabcf438ba676f706bf90186ccf6ff9f6158cc494286965c76e58742fa/coverage-7.6.12-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0e549f54ac5f301e8e04c569dfdb907f7be71b06b88b5063ce9d6953d2d58574", size = 242987, upload-time = "2025-02-11T14:45:43.982Z" }, - { url = "https://files.pythonhosted.org/packages/4c/53/4e208440389e8ea936f5f2b0762dcd4cb03281a7722def8e2bf9dc9c3d68/coverage-7.6.12-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:959244a17184515f8c52dcb65fb662808767c0bd233c1d8a166e7cf74c9ea985", size = 239881, upload-time = "2025-02-11T14:45:45.537Z" }, - { url = "https://files.pythonhosted.org/packages/c4/47/2ba744af8d2f0caa1f17e7746147e34dfc5f811fb65fc153153722d58835/coverage-7.6.12-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bda1c5f347550c359f841d6614fb8ca42ae5cb0b74d39f8a1e204815ebe25750", size = 242142, upload-time = "2025-02-11T14:45:47.069Z" }, - { url = "https://files.pythonhosted.org/packages/e9/90/df726af8ee74d92ee7e3bf113bf101ea4315d71508952bd21abc3fae471e/coverage-7.6.12-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:1ceeb90c3eda1f2d8c4c578c14167dbd8c674ecd7d38e45647543f19839dd6ea", size = 241437, upload-time = "2025-02-11T14:45:48.602Z" }, - { url = "https://files.pythonhosted.org/packages/f6/af/995263fd04ae5f9cf12521150295bf03b6ba940d0aea97953bb4a6db3e2b/coverage-7.6.12-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:0f16f44025c06792e0fb09571ae454bcc7a3ec75eeb3c36b025eccf501b1a4c3", size = 239724, upload-time = "2025-02-11T14:45:51.333Z" }, - { url = "https://files.pythonhosted.org/packages/1c/8e/5bb04f0318805e190984c6ce106b4c3968a9562a400180e549855d8211bd/coverage-7.6.12-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:b076e625396e787448d27a411aefff867db2bffac8ed04e8f7056b07024eed5a", size = 241329, upload-time = "2025-02-11T14:45:53.19Z" }, - { url = "https://files.pythonhosted.org/packages/9e/9d/fa04d9e6c3f6459f4e0b231925277cfc33d72dfab7fa19c312c03e59da99/coverage-7.6.12-cp312-cp312-win32.whl", hash = "sha256:00b2086892cf06c7c2d74983c9595dc511acca00665480b3ddff749ec4fb2a95", size = 211289, upload-time = "2025-02-11T14:45:54.74Z" }, - { url = "https://files.pythonhosted.org/packages/53/40/53c7ffe3c0c3fff4d708bc99e65f3d78c129110d6629736faf2dbd60ad57/coverage-7.6.12-cp312-cp312-win_amd64.whl", hash = "sha256:7ae6eabf519bc7871ce117fb18bf14e0e343eeb96c377667e3e5dd12095e0288", size = 212079, upload-time = "2025-02-11T14:45:57.22Z" }, - { url = "https://files.pythonhosted.org/packages/fb/b2/f655700e1024dec98b10ebaafd0cedbc25e40e4abe62a3c8e2ceef4f8f0a/coverage-7.6.12-py3-none-any.whl", hash = "sha256:eb8668cfbc279a536c633137deeb9435d2962caec279c3f8cf8b91fff6ff8953", size = 200552, upload-time = "2025-02-11T14:47:01.999Z" }, -] - -[package.optional-dependencies] -toml = [ - { name = "tomli", marker = "python_full_version <= '3.11'" }, -] - -[[package]] -name = "debugpy" -version = "1.8.14" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/bd/75/087fe07d40f490a78782ff3b0a30e3968936854105487decdb33446d4b0e/debugpy-1.8.14.tar.gz", hash = "sha256:7cd287184318416850aa8b60ac90105837bb1e59531898c07569d197d2ed5322", size = 1641444, upload-time = "2025-04-10T19:46:10.981Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/67/e8/57fe0c86915671fd6a3d2d8746e40485fd55e8d9e682388fbb3a3d42b86f/debugpy-1.8.14-cp311-cp311-macosx_14_0_universal2.whl", hash = "sha256:1b2ac8c13b2645e0b1eaf30e816404990fbdb168e193322be8f545e8c01644a9", size = 2175064, upload-time = "2025-04-10T19:46:19.486Z" }, - { url = "https://files.pythonhosted.org/packages/3b/97/2b2fd1b1c9569c6764ccdb650a6f752e4ac31be465049563c9eb127a8487/debugpy-1.8.14-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:cf431c343a99384ac7eab2f763980724834f933a271e90496944195318c619e2", size = 3132359, upload-time = "2025-04-10T19:46:21.192Z" }, - { url = "https://files.pythonhosted.org/packages/c0/ee/b825c87ed06256ee2a7ed8bab8fb3bb5851293bf9465409fdffc6261c426/debugpy-1.8.14-cp311-cp311-win32.whl", hash = "sha256:c99295c76161ad8d507b413cd33422d7c542889fbb73035889420ac1fad354f2", size = 5133269, upload-time = "2025-04-10T19:46:23.047Z" }, - { url = "https://files.pythonhosted.org/packages/d5/a6/6c70cd15afa43d37839d60f324213843174c1d1e6bb616bd89f7c1341bac/debugpy-1.8.14-cp311-cp311-win_amd64.whl", hash = "sha256:7816acea4a46d7e4e50ad8d09d963a680ecc814ae31cdef3622eb05ccacf7b01", size = 5158156, upload-time = "2025-04-10T19:46:24.521Z" }, - { url = "https://files.pythonhosted.org/packages/d9/2a/ac2df0eda4898f29c46eb6713a5148e6f8b2b389c8ec9e425a4a1d67bf07/debugpy-1.8.14-cp312-cp312-macosx_14_0_universal2.whl", hash = "sha256:8899c17920d089cfa23e6005ad9f22582fd86f144b23acb9feeda59e84405b84", size = 2501268, upload-time = "2025-04-10T19:46:26.044Z" }, - { url = "https://files.pythonhosted.org/packages/10/53/0a0cb5d79dd9f7039169f8bf94a144ad3efa52cc519940b3b7dde23bcb89/debugpy-1.8.14-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f6bb5c0dcf80ad5dbc7b7d6eac484e2af34bdacdf81df09b6a3e62792b722826", size = 4221077, upload-time = "2025-04-10T19:46:27.464Z" }, - { url = "https://files.pythonhosted.org/packages/f8/d5/84e01821f362327bf4828728aa31e907a2eca7c78cd7c6ec062780d249f8/debugpy-1.8.14-cp312-cp312-win32.whl", hash = "sha256:281d44d248a0e1791ad0eafdbbd2912ff0de9eec48022a5bfbc332957487ed3f", size = 5255127, upload-time = "2025-04-10T19:46:29.467Z" }, - { url = "https://files.pythonhosted.org/packages/33/16/1ed929d812c758295cac7f9cf3dab5c73439c83d9091f2d91871e648093e/debugpy-1.8.14-cp312-cp312-win_amd64.whl", hash = "sha256:5aa56ef8538893e4502a7d79047fe39b1dae08d9ae257074c6464a7b290b806f", size = 5297249, upload-time = "2025-04-10T19:46:31.538Z" }, - { url = "https://files.pythonhosted.org/packages/97/1a/481f33c37ee3ac8040d3d51fc4c4e4e7e61cb08b8bc8971d6032acc2279f/debugpy-1.8.14-py2.py3-none-any.whl", hash = "sha256:5cd9a579d553b6cb9759a7908a41988ee6280b961f24f63336835d9418216a20", size = 5256230, upload-time = "2025-04-10T19:46:54.077Z" }, -] - -[[package]] -name = "decorator" -version = "5.2.1" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/43/fa/6d96a0978d19e17b68d634497769987b16c8f4cd0a7a05048bec693caa6b/decorator-5.2.1.tar.gz", hash = "sha256:65f266143752f734b0a7cc83c46f4618af75b8c5911b00ccb61d0ac9b6da0360", size = 56711, upload-time = "2025-02-24T04:41:34.073Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/4e/8c/f3147f5c4b73e7550fe5f9352eaa956ae838d5c51eb58e7a25b9f3e2643b/decorator-5.2.1-py3-none-any.whl", hash = "sha256:d316bb415a2d9e2d2b3abcc4084c6502fc09240e292cd76a76afc106a1c8e04a", size = 9190, upload-time = "2025-02-24T04:41:32.565Z" }, -] - -[[package]] -name = "defusedxml" -version = "0.7.1" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/0f/d5/c66da9b79e5bdb124974bfe172b4daf3c984ebd9c2a06e2b8a4dc7331c72/defusedxml-0.7.1.tar.gz", hash = "sha256:1bb3032db185915b62d7c6209c5a8792be6a32ab2fedacc84e01b52c51aa3e69", size = 75520, upload-time = "2021-03-08T10:59:26.269Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/07/6c/aa3f2f849e01cb6a001cd8554a88d4c77c5c1a31c95bdf1cf9301e6d9ef4/defusedxml-0.7.1-py2.py3-none-any.whl", hash = "sha256:a352e7e428770286cc899e2542b6cdaedb2b4953ff269a210103ec58f6198a61", size = 25604, upload-time = "2021-03-08T10:59:24.45Z" }, -] - -[[package]] -name = "executing" -version = "2.2.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/91/50/a9d80c47ff289c611ff12e63f7c5d13942c65d68125160cefd768c73e6e4/executing-2.2.0.tar.gz", hash = "sha256:5d108c028108fe2551d1a7b2e8b713341e2cb4fc0aa7dcf966fa4327a5226755", size = 978693, upload-time = "2025-01-22T15:41:29.403Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/7b/8f/c4d9bafc34ad7ad5d8dc16dd1347ee0e507a52c3adb6bfa8887e1c6a26ba/executing-2.2.0-py2.py3-none-any.whl", hash = "sha256:11387150cad388d62750327a53d3339fad4888b39a6fe233c3afbb54ecffd3aa", size = 26702, upload-time = "2025-01-22T15:41:25.929Z" }, -] - -[[package]] -name = "expression" -version = "5.6.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "typing-extensions" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/43/c7/bb061623b5815566bda69f5e9d156e38a97ebb383b8db3d2dedb26415466/expression-5.6.0.tar.gz", hash = "sha256:454f6fe138347194a43c7f878d958efe9b84b9cc770e462010c7a52e18058065", size = 59147, upload-time = "2025-02-19T09:37:37.432Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/6b/a2/656b8bebe495117342a8676ccabf52b3885ce11a856c8dfe1fbbdc250d2d/expression-5.6.0-py3-none-any.whl", hash = "sha256:f5c62e38186c9287e088dee9cf3939b0bbde21cb4c59571872154a53d33dd7c0", size = 69673, upload-time = "2025-02-19T09:37:35.476Z" }, -] - -[[package]] -name = "fastjsonschema" -version = "2.21.1" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/8b/50/4b769ce1ac4071a1ef6d86b1a3fb56cdc3a37615e8c5519e1af96cdac366/fastjsonschema-2.21.1.tar.gz", hash = "sha256:794d4f0a58f848961ba16af7b9c85a3e88cd360df008c59aac6fc5ae9323b5d4", size = 373939, upload-time = "2024-12-02T10:55:15.133Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/90/2b/0817a2b257fe88725c25589d89aec060581aabf668707a8d03b2e9e0cb2a/fastjsonschema-2.21.1-py3-none-any.whl", hash = "sha256:c9e5b7e908310918cf494a434eeb31384dd84a98b57a30bcb1f535015b554667", size = 23924, upload-time = "2024-12-02T10:55:07.599Z" }, -] - -[[package]] -name = "fqdn" -version = "1.5.1" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/30/3e/a80a8c077fd798951169626cde3e239adeba7dab75deb3555716415bd9b0/fqdn-1.5.1.tar.gz", hash = "sha256:105ed3677e767fb5ca086a0c1f4bb66ebc3c100be518f0e0d755d9eae164d89f", size = 6015, upload-time = "2021-03-11T07:16:29.08Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/cf/58/8acf1b3e91c58313ce5cb67df61001fc9dcd21be4fadb76c1a2d540e09ed/fqdn-1.5.1-py3-none-any.whl", hash = "sha256:3a179af3761e4df6eb2e026ff9e1a3033d3587bf980a0b1b2e1e5d08d7358014", size = 9121, upload-time = "2021-03-11T07:16:28.351Z" }, -] - -[[package]] -name = "greenlet" -version = "3.2.1" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/3f/74/907bb43af91782e0366b0960af62a8ce1f9398e4291cac7beaeffbee0c04/greenlet-3.2.1.tar.gz", hash = "sha256:9f4dd4b4946b14bb3bf038f81e1d2e535b7d94f1b2a59fdba1293cd9c1a0a4d7", size = 184475, upload-time = "2025-04-22T14:40:18.206Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/26/80/a6ee52c59f75a387ec1f0c0075cf7981fb4644e4162afd3401dabeaa83ca/greenlet-3.2.1-cp311-cp311-macosx_11_0_universal2.whl", hash = "sha256:aa30066fd6862e1153eaae9b51b449a6356dcdb505169647f69e6ce315b9468b", size = 268609, upload-time = "2025-04-22T14:26:58.208Z" }, - { url = "https://files.pythonhosted.org/packages/ad/11/bd7a900629a4dd0e691dda88f8c2a7bfa44d0c4cffdb47eb5302f87a30d0/greenlet-3.2.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7b0f3a0a67786facf3b907a25db80efe74310f9d63cc30869e49c79ee3fcef7e", size = 628776, upload-time = "2025-04-22T14:53:43.036Z" }, - { url = "https://files.pythonhosted.org/packages/46/f1/686754913fcc2707addadf815c884fd49c9f00a88e6dac277a1e1a8b8086/greenlet-3.2.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:64a4d0052de53ab3ad83ba86de5ada6aeea8f099b4e6c9ccce70fb29bc02c6a2", size = 640827, upload-time = "2025-04-22T14:54:57.409Z" }, - { url = "https://files.pythonhosted.org/packages/03/74/bef04fa04125f6bcae2c1117e52f99c5706ac6ee90b7300b49b3bc18fc7d/greenlet-3.2.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:852ef432919830022f71a040ff7ba3f25ceb9fe8f3ab784befd747856ee58530", size = 636752, upload-time = "2025-04-22T15:04:33.707Z" }, - { url = "https://files.pythonhosted.org/packages/aa/08/e8d493ab65ae1e9823638b8d0bf5d6b44f062221d424c5925f03960ba3d0/greenlet-3.2.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4818116e75a0dd52cdcf40ca4b419e8ce5cb6669630cb4f13a6c384307c9543f", size = 635993, upload-time = "2025-04-22T14:27:04.408Z" }, - { url = "https://files.pythonhosted.org/packages/1f/9d/3a3a979f2b019fb756c9a92cd5e69055aded2862ebd0437de109cf7472a2/greenlet-3.2.1-cp311-cp311-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:9afa05fe6557bce1642d8131f87ae9462e2a8e8c46f7ed7929360616088a3975", size = 583927, upload-time = "2025-04-22T14:25:55.896Z" }, - { url = "https://files.pythonhosted.org/packages/59/21/a00d27d9abb914c1213926be56b2a2bf47999cf0baf67d9ef5b105b8eb5b/greenlet-3.2.1-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:5c12f0d17a88664757e81a6e3fc7c2452568cf460a2f8fb44f90536b2614000b", size = 1112891, upload-time = "2025-04-22T14:58:55.808Z" }, - { url = "https://files.pythonhosted.org/packages/20/c7/922082bf41f0948a78d703d75261d5297f3db894758317409e4677dc1446/greenlet-3.2.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:dbb4e1aa2000852937dd8f4357fb73e3911da426df8ca9b8df5db231922da474", size = 1138318, upload-time = "2025-04-22T14:28:09.451Z" }, - { url = "https://files.pythonhosted.org/packages/34/d7/e05aa525d824ec32735ba7e66917e944a64866c1a95365b5bd03f3eb2c08/greenlet-3.2.1-cp311-cp311-win_amd64.whl", hash = "sha256:cb5ee928ce5fedf9a4b0ccdc547f7887136c4af6109d8f2fe8e00f90c0db47f5", size = 295407, upload-time = "2025-04-22T14:58:42.319Z" }, - { url = "https://files.pythonhosted.org/packages/f0/d1/e4777b188a04726f6cf69047830d37365b9191017f54caf2f7af336a6f18/greenlet-3.2.1-cp312-cp312-macosx_11_0_universal2.whl", hash = "sha256:0ba2811509a30e5f943be048895a983a8daf0b9aa0ac0ead526dfb5d987d80ea", size = 270381, upload-time = "2025-04-22T14:25:43.69Z" }, - { url = "https://files.pythonhosted.org/packages/59/e7/b5b738f5679247ddfcf2179c38945519668dced60c3164c20d55c1a7bb4a/greenlet-3.2.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4245246e72352b150a1588d43ddc8ab5e306bef924c26571aafafa5d1aaae4e8", size = 637195, upload-time = "2025-04-22T14:53:44.563Z" }, - { url = "https://files.pythonhosted.org/packages/6c/9f/57968c88a5f6bc371364baf983a2e5549cca8f503bfef591b6dd81332cbc/greenlet-3.2.1-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:7abc0545d8e880779f0c7ce665a1afc3f72f0ca0d5815e2b006cafc4c1cc5840", size = 651381, upload-time = "2025-04-22T14:54:59.439Z" }, - { url = "https://files.pythonhosted.org/packages/40/81/1533c9a458e9f2ebccb3ae22f1463b2093b0eb448a88aac36182f1c2cd3d/greenlet-3.2.1-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:6dcc6d604a6575c6225ac0da39df9335cc0c6ac50725063fa90f104f3dbdb2c9", size = 646110, upload-time = "2025-04-22T15:04:35.739Z" }, - { url = "https://files.pythonhosted.org/packages/06/66/25f7e4b1468ebe4a520757f2e41c2a36a2f49a12e963431b82e9f98df2a0/greenlet-3.2.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2273586879affca2d1f414709bb1f61f0770adcabf9eda8ef48fd90b36f15d12", size = 648070, upload-time = "2025-04-22T14:27:05.976Z" }, - { url = "https://files.pythonhosted.org/packages/d7/4c/49d366565c4c4d29e6f666287b9e2f471a66c3a3d8d5066692e347f09e27/greenlet-3.2.1-cp312-cp312-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:ff38c869ed30fff07f1452d9a204ece1ec6d3c0870e0ba6e478ce7c1515acf22", size = 603816, upload-time = "2025-04-22T14:25:57.224Z" }, - { url = "https://files.pythonhosted.org/packages/04/15/1612bb61506f44b6b8b6bebb6488702b1fe1432547e95dda57874303a1f5/greenlet-3.2.1-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:e934591a7a4084fa10ee5ef50eb9d2ac8c4075d5c9cf91128116b5dca49d43b1", size = 1119572, upload-time = "2025-04-22T14:58:58.277Z" }, - { url = "https://files.pythonhosted.org/packages/cc/2f/002b99dacd1610e825876f5cbbe7f86740aa2a6b76816e5eca41c8457e85/greenlet-3.2.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:063bcf7f8ee28eb91e7f7a8148c65a43b73fbdc0064ab693e024b5a940070145", size = 1147442, upload-time = "2025-04-22T14:28:11.243Z" }, - { url = "https://files.pythonhosted.org/packages/c0/ba/82a2c3b9868644ee6011da742156247070f30e952f4d33f33857458450f2/greenlet-3.2.1-cp312-cp312-win_amd64.whl", hash = "sha256:7132e024ebeeeabbe661cf8878aac5d2e643975c4feae833142592ec2f03263d", size = 296207, upload-time = "2025-04-22T14:54:40.531Z" }, -] - -[[package]] -name = "griffe" -version = "1.7.3" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "colorama" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/a9/3e/5aa9a61f7c3c47b0b52a1d930302992229d191bf4bc76447b324b731510a/griffe-1.7.3.tar.gz", hash = "sha256:52ee893c6a3a968b639ace8015bec9d36594961e156e23315c8e8e51401fa50b", size = 395137, upload-time = "2025-04-23T11:29:09.147Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/58/c6/5c20af38c2a57c15d87f7f38bee77d63c1d2a3689f74fefaf35915dd12b2/griffe-1.7.3-py3-none-any.whl", hash = "sha256:c6b3ee30c2f0f17f30bcdef5068d6ab7a2a4f1b8bf1a3e74b56fffd21e1c5f75", size = 129303, upload-time = "2025-04-23T11:29:07.145Z" }, -] - -[[package]] -name = "h11" -version = "0.16.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/01/ee/02a2c011bdab74c6fb3c75474d40b3052059d95df7e73351460c8588d963/h11-0.16.0.tar.gz", hash = "sha256:4e35b956cf45792e4caa5885e69fba00bdbc6ffafbfa020300e549b208ee5ff1", size = 101250, upload-time = "2025-04-24T03:35:25.427Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl", hash = "sha256:63cf8bbe7522de3bf65932fda1d9c2772064ffb3dae62d55932da54b31cb6c86", size = 37515, upload-time = "2025-04-24T03:35:24.344Z" }, -] - -[[package]] -name = "httpcore" -version = "1.0.9" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "certifi" }, - { name = "h11" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/06/94/82699a10bca87a5556c9c59b5963f2d039dbd239f25bc2a63907a05a14cb/httpcore-1.0.9.tar.gz", hash = "sha256:6e34463af53fd2ab5d807f399a9b45ea31c3dfa2276f15a2c3f00afff6e176e8", size = 85484, upload-time = "2025-04-24T22:06:22.219Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl", hash = "sha256:2d400746a40668fc9dec9810239072b40b4484b640a8c38fd654a024c7a1bf55", size = 78784, upload-time = "2025-04-24T22:06:20.566Z" }, -] - -[[package]] -name = "httpx" -version = "0.28.1" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "anyio" }, - { name = "certifi" }, - { name = "httpcore" }, - { name = "idna" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/b1/df/48c586a5fe32a0f01324ee087459e112ebb7224f646c0b5023f5e79e9956/httpx-0.28.1.tar.gz", hash = "sha256:75e98c5f16b0f35b567856f597f06ff2270a374470a5c2392242528e3e3e42fc", size = 141406, upload-time = "2024-12-06T15:37:23.222Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl", hash = "sha256:d909fcccc110f8c7faf814ca82a9a4d816bc5a6dbfea25d6591d6985b8ba59ad", size = 73517, upload-time = "2024-12-06T15:37:21.509Z" }, -] - -[[package]] -name = "hypothesis" -version = "6.127.6" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "attrs" }, - { name = "sortedcontainers" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/3b/73/109fbf6f9a76db10ebdbff69b3aba59e3b9ade6fd0702811a9be796702f3/hypothesis-6.127.6.tar.gz", hash = "sha256:9b5292f3f2d505bf0f3e060b1c12f3643fa9b7cd036f41f3456c5f7cc7f73164", size = 419736, upload-time = "2025-03-04T02:38:46.242Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/d7/3f/c9d2506f026137bba258c736c9383d1ce198b2e57894411393a111943601/hypothesis-6.127.6-py3-none-any.whl", hash = "sha256:4967702ee2f8c8d7d0d50f14940c3496bd32ac8b8a2b362ace34c722e842d00b", size = 483286, upload-time = "2025-03-04T02:38:43.287Z" }, -] - -[[package]] -name = "idna" -version = "3.10" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/f1/70/7703c29685631f5a7590aa73f1f1d3fa9a380e654b86af429e0934a32f7d/idna-3.10.tar.gz", hash = "sha256:12f65c9b470abda6dc35cf8e63cc574b1c52b11df2c86030af0ac09b01b13ea9", size = 190490, upload-time = "2024-09-15T18:07:39.745Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/76/c6/c88e154df9c4e1a2a66ccf0005a88dfb2650c1dffb6f5ce603dfbd452ce3/idna-3.10-py3-none-any.whl", hash = "sha256:946d195a0d259cbba61165e88e65941f16e9b36ea6ddb97f00452bae8b1287d3", size = 70442, upload-time = "2024-09-15T18:07:37.964Z" }, -] - -[[package]] -name = "importlib-metadata" -version = "8.7.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "zipp" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/76/66/650a33bd90f786193e4de4b3ad86ea60b53c89b669a5c7be931fac31cdb0/importlib_metadata-8.7.0.tar.gz", hash = "sha256:d13b81ad223b890aa16c5471f2ac3056cf76c5f10f82d6f9292f0b415f389000", size = 56641, upload-time = "2025-04-27T15:29:01.736Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/20/b0/36bd937216ec521246249be3bf9855081de4c5e06a0c9b4219dbeda50373/importlib_metadata-8.7.0-py3-none-any.whl", hash = "sha256:e5dd1551894c77868a30651cef00984d50e1002d06942a7101d34870c5f02afd", size = 27656, upload-time = "2025-04-27T15:29:00.214Z" }, -] - -[[package]] -name = "importlib-resources" -version = "6.5.2" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/cf/8c/f834fbf984f691b4f7ff60f50b514cc3de5cc08abfc3295564dd89c5e2e7/importlib_resources-6.5.2.tar.gz", hash = "sha256:185f87adef5bcc288449d98fb4fba07cea78bc036455dd44c5fc4a2fe78fed2c", size = 44693, upload-time = "2025-01-03T18:51:56.698Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/a4/ed/1f1afb2e9e7f38a545d628f864d562a5ae64fe6f7a10e28ffb9b185b4e89/importlib_resources-6.5.2-py3-none-any.whl", hash = "sha256:789cfdc3ed28c78b67a06acb8126751ced69a3d5f79c095a98298cd8a760ccec", size = 37461, upload-time = "2025-01-03T18:51:54.306Z" }, -] - -[[package]] -name = "iniconfig" -version = "2.0.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/d7/4b/cbd8e699e64a6f16ca3a8220661b5f83792b3017d0f79807cb8708d33913/iniconfig-2.0.0.tar.gz", hash = "sha256:2d91e135bf72d31a410b17c16da610a82cb55f6b0477d1a902134b24a455b8b3", size = 4646, upload-time = "2023-01-07T11:08:11.254Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/ef/a6/62565a6e1cf69e10f5727360368e451d4b7f58beeac6173dc9db836a5b46/iniconfig-2.0.0-py3-none-any.whl", hash = "sha256:b6a85871a79d2e3b22d2d1b94ac2824226a63c6b741c88f7ae975f18b6778374", size = 5892, upload-time = "2023-01-07T11:08:09.864Z" }, -] - -[[package]] -name = "ipykernel" -version = "6.29.5" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "appnope", marker = "sys_platform == 'darwin'" }, - { name = "comm" }, - { name = "debugpy" }, - { name = "ipython" }, - { name = "jupyter-client" }, - { name = "jupyter-core" }, - { name = "matplotlib-inline" }, - { name = "nest-asyncio" }, - { name = "packaging" }, - { name = "psutil" }, - { name = "pyzmq" }, - { name = "tornado" }, - { name = "traitlets" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/e9/5c/67594cb0c7055dc50814b21731c22a601101ea3b1b50a9a1b090e11f5d0f/ipykernel-6.29.5.tar.gz", hash = "sha256:f093a22c4a40f8828f8e330a9c297cb93dcab13bd9678ded6de8e5cf81c56215", size = 163367, upload-time = "2024-07-01T14:07:22.543Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/94/5c/368ae6c01c7628438358e6d337c19b05425727fbb221d2a3c4303c372f42/ipykernel-6.29.5-py3-none-any.whl", hash = "sha256:afdb66ba5aa354b09b91379bac28ae4afebbb30e8b39510c9690afb7a10421b5", size = 117173, upload-time = "2024-07-01T14:07:19.603Z" }, -] - -[[package]] -name = "ipython" -version = "9.0.1" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "colorama", marker = "sys_platform == 'win32'" }, - { name = "decorator" }, - { name = "ipython-pygments-lexers" }, - { name = "jedi" }, - { name = "matplotlib-inline" }, - { name = "pexpect", marker = "sys_platform != 'emscripten' and sys_platform != 'win32'" }, - { name = "prompt-toolkit" }, - { name = "pygments" }, - { name = "stack-data" }, - { name = "traitlets" }, - { name = "typing-extensions", marker = "python_full_version < '3.12'" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/9d/33/1901c9a842b301d8674f367dee597e654e402548a903faf7280aae8fc2d4/ipython-9.0.1.tar.gz", hash = "sha256:377ea91c8226b48dc9021ac9846a64761abc7ddf74c5efe38e6eb06f6e052f3a", size = 4365847, upload-time = "2025-03-03T08:17:03.618Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/28/39/fda74f8215ef94a812dd780073c61a826a88a01e51f627a3454f7ae6951d/ipython-9.0.1-py3-none-any.whl", hash = "sha256:3e878273824b52e0a2280ed84f8193aba8c4ba9a6f45a438348a3d5ef1a34bd0", size = 600186, upload-time = "2025-03-03T08:17:01.485Z" }, -] - -[[package]] -name = "ipython-pygments-lexers" -version = "1.1.1" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "pygments" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/ef/4c/5dd1d8af08107f88c7f741ead7a40854b8ac24ddf9ae850afbcf698aa552/ipython_pygments_lexers-1.1.1.tar.gz", hash = "sha256:09c0138009e56b6854f9535736f4171d855c8c08a563a0dcd8022f78355c7e81", size = 8393, upload-time = "2025-01-17T11:24:34.505Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/d9/33/1f075bf72b0b747cb3288d011319aaf64083cf2efef8354174e3ed4540e2/ipython_pygments_lexers-1.1.1-py3-none-any.whl", hash = "sha256:a9462224a505ade19a605f71f8fa63c2048833ce50abc86768a0d81d876dc81c", size = 8074, upload-time = "2025-01-17T11:24:33.271Z" }, -] - -[[package]] -name = "ipywidgets" -version = "8.1.6" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "comm" }, - { name = "ipython" }, - { name = "jupyterlab-widgets" }, - { name = "traitlets" }, - { name = "widgetsnbextension" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/aa/98/4074d9cb7e89f7ee387b41e9a4b74c8e0d6196e90b910af1cc674e1cdd3d/ipywidgets-8.1.6.tar.gz", hash = "sha256:d8ace49c66f14419fc66071371b99d01bed230bbc15d8a60233b18bfbd782851", size = 116764, upload-time = "2025-04-10T13:02:35.733Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/53/b8/62952729573d983d9433faacf62a52ee2e8cf46504418061ad1739967abe/ipywidgets-8.1.6-py3-none-any.whl", hash = "sha256:446e7630a1d025bdc7635e1169fcc06f2ce33b5bd41c2003edeb4a47c8d4bbb1", size = 139808, upload-time = "2025-04-10T13:02:33.904Z" }, -] - -[[package]] -name = "isoduration" -version = "20.11.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "arrow" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/7c/1a/3c8edc664e06e6bd06cce40c6b22da5f1429aa4224d0c590f3be21c91ead/isoduration-20.11.0.tar.gz", hash = "sha256:ac2f9015137935279eac671f94f89eb00584f940f5dc49462a0c4ee692ba1bd9", size = 11649, upload-time = "2020-11-01T11:00:00.312Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/7b/55/e5326141505c5d5e34c5e0935d2908a74e4561eca44108fbfb9c13d2911a/isoduration-20.11.0-py3-none-any.whl", hash = "sha256:b2904c2a4228c3d44f409c8ae8e2370eb21a26f7ac2ec5446df141dde3452042", size = 11321, upload-time = "2020-11-01T10:59:58.02Z" }, -] - -[[package]] -name = "jedi" -version = "0.19.2" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "parso" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/72/3a/79a912fbd4d8dd6fbb02bf69afd3bb72cf0c729bb3063c6f4498603db17a/jedi-0.19.2.tar.gz", hash = "sha256:4770dc3de41bde3966b02eb84fbcf557fb33cce26ad23da12c742fb50ecb11f0", size = 1231287, upload-time = "2024-11-11T01:41:42.873Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/c0/5a/9cac0c82afec3d09ccd97c8b6502d48f165f9124db81b4bcb90b4af974ee/jedi-0.19.2-py2.py3-none-any.whl", hash = "sha256:a8ef22bde8490f57fe5c7681a3c83cb58874daf72b4784de3cce5b6ef6edb5b9", size = 1572278, upload-time = "2024-11-11T01:41:40.175Z" }, -] - -[[package]] -name = "jinja2" -version = "3.1.6" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "markupsafe" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/df/bf/f7da0350254c0ed7c72f3e33cef02e048281fec7ecec5f032d4aac52226b/jinja2-3.1.6.tar.gz", hash = "sha256:0137fb05990d35f1275a587e9aee6d56da821fc83491a0fb838183be43f66d6d", size = 245115, upload-time = "2025-03-05T20:05:02.478Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/62/a1/3d680cbfd5f4b8f15abc1d571870c5fc3e594bb582bc3b64ea099db13e56/jinja2-3.1.6-py3-none-any.whl", hash = "sha256:85ece4451f492d0c13c5dd7c13a64681a86afae63a5f347908daf103ce6d2f67", size = 134899, upload-time = "2025-03-05T20:05:00.369Z" }, -] - -[[package]] -name = "json5" -version = "0.12.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/12/be/c6c745ec4c4539b25a278b70e29793f10382947df0d9efba2fa09120895d/json5-0.12.0.tar.gz", hash = "sha256:0b4b6ff56801a1c7dc817b0241bca4ce474a0e6a163bfef3fc594d3fd263ff3a", size = 51907, upload-time = "2025-04-03T16:33:13.201Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/41/9f/3500910d5a98549e3098807493851eeef2b89cdd3032227558a104dfe926/json5-0.12.0-py3-none-any.whl", hash = "sha256:6d37aa6c08b0609f16e1ec5ff94697e2cbbfbad5ac112afa05794da9ab7810db", size = 36079, upload-time = "2025-04-03T16:33:11.927Z" }, -] - -[[package]] -name = "jsonpointer" -version = "3.0.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/6a/0a/eebeb1fa92507ea94016a2a790b93c2ae41a7e18778f85471dc54475ed25/jsonpointer-3.0.0.tar.gz", hash = "sha256:2b2d729f2091522d61c3b31f82e11870f60b68f43fbc705cb76bf4b832af59ef", size = 9114, upload-time = "2024-06-10T19:24:42.462Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/71/92/5e77f98553e9e75130c78900d000368476aed74276eb8ae8796f65f00918/jsonpointer-3.0.0-py2.py3-none-any.whl", hash = "sha256:13e088adc14fca8b6aa8177c044e12701e6ad4b28ff10e65f2267a90109c9942", size = 7595, upload-time = "2024-06-10T19:24:40.698Z" }, -] - -[[package]] -name = "jsonschema" -version = "4.23.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "attrs" }, - { name = "jsonschema-specifications" }, - { name = "referencing" }, - { name = "rpds-py" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/38/2e/03362ee4034a4c917f697890ccd4aec0800ccf9ded7f511971c75451deec/jsonschema-4.23.0.tar.gz", hash = "sha256:d71497fef26351a33265337fa77ffeb82423f3ea21283cd9467bb03999266bc4", size = 325778, upload-time = "2024-07-08T18:40:05.546Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/69/4a/4f9dbeb84e8850557c02365a0eee0649abe5eb1d84af92a25731c6c0f922/jsonschema-4.23.0-py3-none-any.whl", hash = "sha256:fbadb6f8b144a8f8cf9f0b89ba94501d143e50411a1278633f56a7acf7fd5566", size = 88462, upload-time = "2024-07-08T18:40:00.165Z" }, -] - -[package.optional-dependencies] -format-nongpl = [ - { name = "fqdn" }, - { name = "idna" }, - { name = "isoduration" }, - { name = "jsonpointer" }, - { name = "rfc3339-validator" }, - { name = "rfc3986-validator" }, - { name = "uri-template" }, - { name = "webcolors" }, -] - -[[package]] -name = "jsonschema-specifications" -version = "2025.4.1" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "referencing" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/bf/ce/46fbd9c8119cfc3581ee5643ea49464d168028cfb5caff5fc0596d0cf914/jsonschema_specifications-2025.4.1.tar.gz", hash = "sha256:630159c9f4dbea161a6a2205c3011cc4f18ff381b189fff48bb39b9bf26ae608", size = 15513, upload-time = "2025-04-23T12:34:07.418Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/01/0e/b27cdbaccf30b890c40ed1da9fd4a3593a5cf94dae54fb34f8a4b74fcd3f/jsonschema_specifications-2025.4.1-py3-none-any.whl", hash = "sha256:4653bffbd6584f7de83a67e0d620ef16900b390ddc7939d56684d6c81e33f1af", size = 18437, upload-time = "2025-04-23T12:34:05.422Z" }, -] - -[[package]] -name = "jupyter" -version = "1.1.1" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "ipykernel" }, - { name = "ipywidgets" }, - { name = "jupyter-console" }, - { name = "jupyterlab" }, - { name = "nbconvert" }, - { name = "notebook" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/58/f3/af28ea964ab8bc1e472dba2e82627d36d470c51f5cd38c37502eeffaa25e/jupyter-1.1.1.tar.gz", hash = "sha256:d55467bceabdea49d7e3624af7e33d59c37fff53ed3a350e1ac957bed731de7a", size = 5714959, upload-time = "2024-08-30T07:15:48.299Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/38/64/285f20a31679bf547b75602702f7800e74dbabae36ef324f716c02804753/jupyter-1.1.1-py2.py3-none-any.whl", hash = "sha256:7a59533c22af65439b24bbe60373a4e95af8f16ac65a6c00820ad378e3f7cc83", size = 2657, upload-time = "2024-08-30T07:15:47.045Z" }, -] - -[[package]] -name = "jupyter-cache" -version = "1.0.1" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "attrs" }, - { name = "click" }, - { name = "importlib-metadata" }, - { name = "nbclient" }, - { name = "nbformat" }, - { name = "pyyaml" }, - { name = "sqlalchemy" }, - { name = "tabulate" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/bb/f7/3627358075f183956e8c4974603232b03afd4ddc7baf72c2bc9fff522291/jupyter_cache-1.0.1.tar.gz", hash = "sha256:16e808eb19e3fb67a223db906e131ea6e01f03aa27f49a7214ce6a5fec186fb9", size = 32048, upload-time = "2024-11-15T16:03:55.322Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/64/6b/67b87da9d36bff9df7d0efbd1a325fa372a43be7158effaf43ed7b22341d/jupyter_cache-1.0.1-py3-none-any.whl", hash = "sha256:9c3cafd825ba7da8b5830485343091143dff903e4d8c69db9349b728b140abf6", size = 33907, upload-time = "2024-11-15T16:03:54.021Z" }, -] - -[[package]] -name = "jupyter-client" -version = "8.6.3" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "jupyter-core" }, - { name = "python-dateutil" }, - { name = "pyzmq" }, - { name = "tornado" }, - { name = "traitlets" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/71/22/bf9f12fdaeae18019a468b68952a60fe6dbab5d67cd2a103cac7659b41ca/jupyter_client-8.6.3.tar.gz", hash = "sha256:35b3a0947c4a6e9d589eb97d7d4cd5e90f910ee73101611f01283732bd6d9419", size = 342019, upload-time = "2024-09-17T10:44:17.613Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/11/85/b0394e0b6fcccd2c1eeefc230978a6f8cb0c5df1e4cd3e7625735a0d7d1e/jupyter_client-8.6.3-py3-none-any.whl", hash = "sha256:e8a19cc986cc45905ac3362915f410f3af85424b4c0905e94fa5f2cb08e8f23f", size = 106105, upload-time = "2024-09-17T10:44:15.218Z" }, -] - -[[package]] -name = "jupyter-console" -version = "6.6.3" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "ipykernel" }, - { name = "ipython" }, - { name = "jupyter-client" }, - { name = "jupyter-core" }, - { name = "prompt-toolkit" }, - { name = "pygments" }, - { name = "pyzmq" }, - { name = "traitlets" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/bd/2d/e2fd31e2fc41c14e2bcb6c976ab732597e907523f6b2420305f9fc7fdbdb/jupyter_console-6.6.3.tar.gz", hash = "sha256:566a4bf31c87adbfadf22cdf846e3069b59a71ed5da71d6ba4d8aaad14a53539", size = 34363, upload-time = "2023-03-06T14:13:31.02Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/ca/77/71d78d58f15c22db16328a476426f7ac4a60d3a5a7ba3b9627ee2f7903d4/jupyter_console-6.6.3-py3-none-any.whl", hash = "sha256:309d33409fcc92ffdad25f0bcdf9a4a9daa61b6f341177570fdac03de5352485", size = 24510, upload-time = "2023-03-06T14:13:28.229Z" }, -] - -[[package]] -name = "jupyter-core" -version = "5.7.2" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "platformdirs" }, - { name = "pywin32", marker = "platform_python_implementation != 'PyPy' and sys_platform == 'win32'" }, - { name = "traitlets" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/00/11/b56381fa6c3f4cc5d2cf54a7dbf98ad9aa0b339ef7a601d6053538b079a7/jupyter_core-5.7.2.tar.gz", hash = "sha256:aa5f8d32bbf6b431ac830496da7392035d6f61b4f54872f15c4bd2a9c3f536d9", size = 87629, upload-time = "2024-03-12T12:37:35.652Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/c9/fb/108ecd1fe961941959ad0ee4e12ee7b8b1477247f30b1fdfd83ceaf017f0/jupyter_core-5.7.2-py3-none-any.whl", hash = "sha256:4f7315d2f6b4bcf2e3e7cb6e46772eba760ae459cd1f59d29eb57b0a01bd7409", size = 28965, upload-time = "2024-03-12T12:37:32.36Z" }, -] - -[[package]] -name = "jupyter-events" -version = "0.12.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "jsonschema", extra = ["format-nongpl"] }, - { name = "packaging" }, - { name = "python-json-logger" }, - { name = "pyyaml" }, - { name = "referencing" }, - { name = "rfc3339-validator" }, - { name = "rfc3986-validator" }, - { name = "traitlets" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/9d/c3/306d090461e4cf3cd91eceaff84bede12a8e52cd821c2d20c9a4fd728385/jupyter_events-0.12.0.tar.gz", hash = "sha256:fc3fce98865f6784c9cd0a56a20644fc6098f21c8c33834a8d9fe383c17e554b", size = 62196, upload-time = "2025-02-03T17:23:41.485Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/e2/48/577993f1f99c552f18a0428731a755e06171f9902fa118c379eb7c04ea22/jupyter_events-0.12.0-py3-none-any.whl", hash = "sha256:6464b2fa5ad10451c3d35fabc75eab39556ae1e2853ad0c0cc31b656731a97fb", size = 19430, upload-time = "2025-02-03T17:23:38.643Z" }, -] - -[[package]] -name = "jupyter-lsp" -version = "2.2.5" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "jupyter-server" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/85/b4/3200b0b09c12bc3b72d943d923323c398eff382d1dcc7c0dbc8b74630e40/jupyter-lsp-2.2.5.tar.gz", hash = "sha256:793147a05ad446f809fd53ef1cd19a9f5256fd0a2d6b7ce943a982cb4f545001", size = 48741, upload-time = "2024-04-09T17:59:44.918Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/07/e0/7bd7cff65594fd9936e2f9385701e44574fc7d721331ff676ce440b14100/jupyter_lsp-2.2.5-py3-none-any.whl", hash = "sha256:45fbddbd505f3fbfb0b6cb2f1bc5e15e83ab7c79cd6e89416b248cb3c00c11da", size = 69146, upload-time = "2024-04-09T17:59:43.388Z" }, -] - -[[package]] -name = "jupyter-server" -version = "2.15.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "anyio" }, - { name = "argon2-cffi" }, - { name = "jinja2" }, - { name = "jupyter-client" }, - { name = "jupyter-core" }, - { name = "jupyter-events" }, - { name = "jupyter-server-terminals" }, - { name = "nbconvert" }, - { name = "nbformat" }, - { name = "overrides" }, - { name = "packaging" }, - { name = "prometheus-client" }, - { name = "pywinpty", marker = "os_name == 'nt'" }, - { name = "pyzmq" }, - { name = "send2trash" }, - { name = "terminado" }, - { name = "tornado" }, - { name = "traitlets" }, - { name = "websocket-client" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/61/8c/df09d4ab646141f130f9977b32b206ba8615d1969b2eba6a2e84b7f89137/jupyter_server-2.15.0.tar.gz", hash = "sha256:9d446b8697b4f7337a1b7cdcac40778babdd93ba614b6d68ab1c0c918f1c4084", size = 725227, upload-time = "2024-12-20T13:02:42.654Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/e2/a2/89eeaf0bb954a123a909859fa507fa86f96eb61b62dc30667b60dbd5fdaf/jupyter_server-2.15.0-py3-none-any.whl", hash = "sha256:872d989becf83517012ee669f09604aa4a28097c0bd90b2f424310156c2cdae3", size = 385826, upload-time = "2024-12-20T13:02:37.785Z" }, -] - -[[package]] -name = "jupyter-server-terminals" -version = "0.5.3" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "pywinpty", marker = "os_name == 'nt'" }, - { name = "terminado" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/fc/d5/562469734f476159e99a55426d697cbf8e7eb5efe89fb0e0b4f83a3d3459/jupyter_server_terminals-0.5.3.tar.gz", hash = "sha256:5ae0295167220e9ace0edcfdb212afd2b01ee8d179fe6f23c899590e9b8a5269", size = 31430, upload-time = "2024-03-12T14:37:03.049Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/07/2d/2b32cdbe8d2a602f697a649798554e4f072115438e92249624e532e8aca6/jupyter_server_terminals-0.5.3-py3-none-any.whl", hash = "sha256:41ee0d7dc0ebf2809c668e0fc726dfaf258fcd3e769568996ca731b6194ae9aa", size = 13656, upload-time = "2024-03-12T14:37:00.708Z" }, -] - -[[package]] -name = "jupyterlab" -version = "4.4.1" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "async-lru" }, - { name = "httpx" }, - { name = "ipykernel" }, - { name = "jinja2" }, - { name = "jupyter-core" }, - { name = "jupyter-lsp" }, - { name = "jupyter-server" }, - { name = "jupyterlab-server" }, - { name = "notebook-shim" }, - { name = "packaging" }, - { name = "setuptools" }, - { name = "tornado" }, - { name = "traitlets" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/f6/55/3ef7e6bfe988d7df3d453cc27912846d50590c90790848594f7228c89569/jupyterlab-4.4.1.tar.gz", hash = "sha256:c75c4f33056fbd84f0b31eb44622a00c7a5f981b85adfeb198a83721f0465808", size = 23028447, upload-time = "2025-04-22T18:22:33.423Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/29/82/c8784597c5a03426c1ef20c48aff37e8cfe050ab5ca87f0d51069f02b362/jupyterlab-4.4.1-py3-none-any.whl", hash = "sha256:989bca3f9cf2d04b2022e7e657e2df6d4aca808b364810d31c4865edd968a5f7", size = 12292928, upload-time = "2025-04-22T18:22:25.831Z" }, -] - -[[package]] -name = "jupyterlab-pygments" -version = "0.3.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/90/51/9187be60d989df97f5f0aba133fa54e7300f17616e065d1ada7d7646b6d6/jupyterlab_pygments-0.3.0.tar.gz", hash = "sha256:721aca4d9029252b11cfa9d185e5b5af4d54772bb8072f9b7036f4170054d35d", size = 512900, upload-time = "2023-11-23T09:26:37.44Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/b1/dd/ead9d8ea85bf202d90cc513b533f9c363121c7792674f78e0d8a854b63b4/jupyterlab_pygments-0.3.0-py3-none-any.whl", hash = "sha256:841a89020971da1d8693f1a99997aefc5dc424bb1b251fd6322462a1b8842780", size = 15884, upload-time = "2023-11-23T09:26:34.325Z" }, -] - -[[package]] -name = "jupyterlab-server" -version = "2.27.3" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "babel" }, - { name = "jinja2" }, - { name = "json5" }, - { name = "jsonschema" }, - { name = "jupyter-server" }, - { name = "packaging" }, - { name = "requests" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/0a/c9/a883ce65eb27905ce77ace410d83587c82ea64dc85a48d1f7ed52bcfa68d/jupyterlab_server-2.27.3.tar.gz", hash = "sha256:eb36caca59e74471988f0ae25c77945610b887f777255aa21f8065def9e51ed4", size = 76173, upload-time = "2024-07-16T17:02:04.149Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/54/09/2032e7d15c544a0e3cd831c51d77a8ca57f7555b2e1b2922142eddb02a84/jupyterlab_server-2.27.3-py3-none-any.whl", hash = "sha256:e697488f66c3db49df675158a77b3b017520d772c6e1548c7d9bcc5df7944ee4", size = 59700, upload-time = "2024-07-16T17:02:01.115Z" }, -] - -[[package]] -name = "jupyterlab-widgets" -version = "3.0.14" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/a1/94/766b8199e8a902a4c5ee12a9407a348bbabe9fa22400758576b153d17d8e/jupyterlab_widgets-3.0.14.tar.gz", hash = "sha256:bad03e59546869f026e537e0d170e454259e6dc7048e14041707ca31e523c8a1", size = 203815, upload-time = "2025-04-10T13:00:40.522Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/64/7a/f2479ba401e02f7fcbd3fc6af201eac888eaa188574b8e9df19452ab4972/jupyterlab_widgets-3.0.14-py3-none-any.whl", hash = "sha256:54c33e3306b7fca139d165d6190dc6c0627aafa5d14adfc974a4e9a3d26cb703", size = 213999, upload-time = "2025-04-10T13:00:38.626Z" }, -] - -[[package]] -name = "markdown-it-py" -version = "3.0.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "mdurl" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/38/71/3b932df36c1a044d397a1f92d1cf91ee0a503d91e470cbd670aa66b07ed0/markdown-it-py-3.0.0.tar.gz", hash = "sha256:e3f60a94fa066dc52ec76661e37c851cb232d92f9886b15cb560aaada2df8feb", size = 74596, upload-time = "2023-06-03T06:41:14.443Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/42/d7/1ec15b46af6af88f19b8e5ffea08fa375d433c998b8a7639e76935c14f1f/markdown_it_py-3.0.0-py3-none-any.whl", hash = "sha256:355216845c60bd96232cd8d8c40e8f9765cc86f46880e43a8fd22dc1a1a8cab1", size = 87528, upload-time = "2023-06-03T06:41:11.019Z" }, -] - -[[package]] -name = "markupsafe" -version = "3.0.2" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/b2/97/5d42485e71dfc078108a86d6de8fa46db44a1a9295e89c5d6d4a06e23a62/markupsafe-3.0.2.tar.gz", hash = "sha256:ee55d3edf80167e48ea11a923c7386f4669df67d7994554387f84e7d8b0a2bf0", size = 20537, upload-time = "2024-10-18T15:21:54.129Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/6b/28/bbf83e3f76936960b850435576dd5e67034e200469571be53f69174a2dfd/MarkupSafe-3.0.2-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:9025b4018f3a1314059769c7bf15441064b2207cb3f065e6ea1e7359cb46db9d", size = 14353, upload-time = "2024-10-18T15:21:02.187Z" }, - { url = "https://files.pythonhosted.org/packages/6c/30/316d194b093cde57d448a4c3209f22e3046c5bb2fb0820b118292b334be7/MarkupSafe-3.0.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:93335ca3812df2f366e80509ae119189886b0f3c2b81325d39efdb84a1e2ae93", size = 12392, upload-time = "2024-10-18T15:21:02.941Z" }, - { url = "https://files.pythonhosted.org/packages/f2/96/9cdafba8445d3a53cae530aaf83c38ec64c4d5427d975c974084af5bc5d2/MarkupSafe-3.0.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2cb8438c3cbb25e220c2ab33bb226559e7afb3baec11c4f218ffa7308603c832", size = 23984, upload-time = "2024-10-18T15:21:03.953Z" }, - { url = "https://files.pythonhosted.org/packages/f1/a4/aefb044a2cd8d7334c8a47d3fb2c9f328ac48cb349468cc31c20b539305f/MarkupSafe-3.0.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a123e330ef0853c6e822384873bef7507557d8e4a082961e1defa947aa59ba84", size = 23120, upload-time = "2024-10-18T15:21:06.495Z" }, - { url = "https://files.pythonhosted.org/packages/8d/21/5e4851379f88f3fad1de30361db501300d4f07bcad047d3cb0449fc51f8c/MarkupSafe-3.0.2-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1e084f686b92e5b83186b07e8a17fc09e38fff551f3602b249881fec658d3eca", size = 23032, upload-time = "2024-10-18T15:21:07.295Z" }, - { url = "https://files.pythonhosted.org/packages/00/7b/e92c64e079b2d0d7ddf69899c98842f3f9a60a1ae72657c89ce2655c999d/MarkupSafe-3.0.2-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:d8213e09c917a951de9d09ecee036d5c7d36cb6cb7dbaece4c71a60d79fb9798", size = 24057, upload-time = "2024-10-18T15:21:08.073Z" }, - { url = "https://files.pythonhosted.org/packages/f9/ac/46f960ca323037caa0a10662ef97d0a4728e890334fc156b9f9e52bcc4ca/MarkupSafe-3.0.2-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:5b02fb34468b6aaa40dfc198d813a641e3a63b98c2b05a16b9f80b7ec314185e", size = 23359, upload-time = "2024-10-18T15:21:09.318Z" }, - { url = "https://files.pythonhosted.org/packages/69/84/83439e16197337b8b14b6a5b9c2105fff81d42c2a7c5b58ac7b62ee2c3b1/MarkupSafe-3.0.2-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:0bff5e0ae4ef2e1ae4fdf2dfd5b76c75e5c2fa4132d05fc1b0dabcd20c7e28c4", size = 23306, upload-time = "2024-10-18T15:21:10.185Z" }, - { url = "https://files.pythonhosted.org/packages/9a/34/a15aa69f01e2181ed8d2b685c0d2f6655d5cca2c4db0ddea775e631918cd/MarkupSafe-3.0.2-cp311-cp311-win32.whl", hash = "sha256:6c89876f41da747c8d3677a2b540fb32ef5715f97b66eeb0c6b66f5e3ef6f59d", size = 15094, upload-time = "2024-10-18T15:21:11.005Z" }, - { url = "https://files.pythonhosted.org/packages/da/b8/3a3bd761922d416f3dc5d00bfbed11f66b1ab89a0c2b6e887240a30b0f6b/MarkupSafe-3.0.2-cp311-cp311-win_amd64.whl", hash = "sha256:70a87b411535ccad5ef2f1df5136506a10775d267e197e4cf531ced10537bd6b", size = 15521, upload-time = "2024-10-18T15:21:12.911Z" }, - { url = "https://files.pythonhosted.org/packages/22/09/d1f21434c97fc42f09d290cbb6350d44eb12f09cc62c9476effdb33a18aa/MarkupSafe-3.0.2-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:9778bd8ab0a994ebf6f84c2b949e65736d5575320a17ae8984a77fab08db94cf", size = 14274, upload-time = "2024-10-18T15:21:13.777Z" }, - { url = "https://files.pythonhosted.org/packages/6b/b0/18f76bba336fa5aecf79d45dcd6c806c280ec44538b3c13671d49099fdd0/MarkupSafe-3.0.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:846ade7b71e3536c4e56b386c2a47adf5741d2d8b94ec9dc3e92e5e1ee1e2225", size = 12348, upload-time = "2024-10-18T15:21:14.822Z" }, - { url = "https://files.pythonhosted.org/packages/e0/25/dd5c0f6ac1311e9b40f4af06c78efde0f3b5cbf02502f8ef9501294c425b/MarkupSafe-3.0.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1c99d261bd2d5f6b59325c92c73df481e05e57f19837bdca8413b9eac4bd8028", size = 24149, upload-time = "2024-10-18T15:21:15.642Z" }, - { url = "https://files.pythonhosted.org/packages/f3/f0/89e7aadfb3749d0f52234a0c8c7867877876e0a20b60e2188e9850794c17/MarkupSafe-3.0.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e17c96c14e19278594aa4841ec148115f9c7615a47382ecb6b82bd8fea3ab0c8", size = 23118, upload-time = "2024-10-18T15:21:17.133Z" }, - { url = "https://files.pythonhosted.org/packages/d5/da/f2eeb64c723f5e3777bc081da884b414671982008c47dcc1873d81f625b6/MarkupSafe-3.0.2-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:88416bd1e65dcea10bc7569faacb2c20ce071dd1f87539ca2ab364bf6231393c", size = 22993, upload-time = "2024-10-18T15:21:18.064Z" }, - { url = "https://files.pythonhosted.org/packages/da/0e/1f32af846df486dce7c227fe0f2398dc7e2e51d4a370508281f3c1c5cddc/MarkupSafe-3.0.2-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:2181e67807fc2fa785d0592dc2d6206c019b9502410671cc905d132a92866557", size = 24178, upload-time = "2024-10-18T15:21:18.859Z" }, - { url = "https://files.pythonhosted.org/packages/c4/f6/bb3ca0532de8086cbff5f06d137064c8410d10779c4c127e0e47d17c0b71/MarkupSafe-3.0.2-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:52305740fe773d09cffb16f8ed0427942901f00adedac82ec8b67752f58a1b22", size = 23319, upload-time = "2024-10-18T15:21:19.671Z" }, - { url = "https://files.pythonhosted.org/packages/a2/82/8be4c96ffee03c5b4a034e60a31294daf481e12c7c43ab8e34a1453ee48b/MarkupSafe-3.0.2-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:ad10d3ded218f1039f11a75f8091880239651b52e9bb592ca27de44eed242a48", size = 23352, upload-time = "2024-10-18T15:21:20.971Z" }, - { url = "https://files.pythonhosted.org/packages/51/ae/97827349d3fcffee7e184bdf7f41cd6b88d9919c80f0263ba7acd1bbcb18/MarkupSafe-3.0.2-cp312-cp312-win32.whl", hash = "sha256:0f4ca02bea9a23221c0182836703cbf8930c5e9454bacce27e767509fa286a30", size = 15097, upload-time = "2024-10-18T15:21:22.646Z" }, - { url = "https://files.pythonhosted.org/packages/c1/80/a61f99dc3a936413c3ee4e1eecac96c0da5ed07ad56fd975f1a9da5bc630/MarkupSafe-3.0.2-cp312-cp312-win_amd64.whl", hash = "sha256:8e06879fc22a25ca47312fbe7c8264eb0b662f6db27cb2d3bbbc74b1df4b9b87", size = 15601, upload-time = "2024-10-18T15:21:23.499Z" }, -] - -[[package]] -name = "matplotlib-inline" -version = "0.1.7" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "traitlets" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/99/5b/a36a337438a14116b16480db471ad061c36c3694df7c2084a0da7ba538b7/matplotlib_inline-0.1.7.tar.gz", hash = "sha256:8423b23ec666be3d16e16b60bdd8ac4e86e840ebd1dd11a30b9f117f2fa0ab90", size = 8159, upload-time = "2024-04-15T13:44:44.803Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/8f/8e/9ad090d3553c280a8060fbf6e24dc1c0c29704ee7d1c372f0c174aa59285/matplotlib_inline-0.1.7-py3-none-any.whl", hash = "sha256:df192d39a4ff8f21b1895d72e6a13f5fcc5099f00fa84384e0ea28c2cc0653ca", size = 9899, upload-time = "2024-04-15T13:44:43.265Z" }, -] - -[[package]] -name = "mdurl" -version = "0.1.2" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/d6/54/cfe61301667036ec958cb99bd3efefba235e65cdeb9c84d24a8293ba1d90/mdurl-0.1.2.tar.gz", hash = "sha256:bb413d29f5eea38f31dd4754dd7377d4465116fb207585f97bf925588687c1ba", size = 8729, upload-time = "2022-08-14T12:40:10.846Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/b3/38/89ba8ad64ae25be8de66a6d463314cf1eb366222074cfda9ee839c56a4b4/mdurl-0.1.2-py3-none-any.whl", hash = "sha256:84008a41e51615a49fc9966191ff91509e3c40b939176e643fd50a5c2196b8f8", size = 9979, upload-time = "2022-08-14T12:40:09.779Z" }, -] - -[[package]] -name = "mistune" -version = "3.1.3" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/c4/79/bda47f7dd7c3c55770478d6d02c9960c430b0cf1773b72366ff89126ea31/mistune-3.1.3.tar.gz", hash = "sha256:a7035c21782b2becb6be62f8f25d3df81ccb4d6fa477a6525b15af06539f02a0", size = 94347, upload-time = "2025-03-19T14:27:24.955Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/01/4d/23c4e4f09da849e127e9f123241946c23c1e30f45a88366879e064211815/mistune-3.1.3-py3-none-any.whl", hash = "sha256:1a32314113cff28aa6432e99e522677c8587fd83e3d51c29b82a52409c842bd9", size = 53410, upload-time = "2025-03-19T14:27:23.451Z" }, -] - -[[package]] -name = "mypy-extensions" -version = "1.1.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/a2/6e/371856a3fb9d31ca8dac321cda606860fa4548858c0cc45d9d1d4ca2628b/mypy_extensions-1.1.0.tar.gz", hash = "sha256:52e68efc3284861e772bbcd66823fde5ae21fd2fdb51c62a211403730b916558", size = 6343, upload-time = "2025-04-22T14:54:24.164Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/79/7b/2c79738432f5c924bef5071f933bcc9efd0473bac3b4aa584a6f7c1c8df8/mypy_extensions-1.1.0-py3-none-any.whl", hash = "sha256:1be4cccdb0f2482337c4743e60421de3a356cd97508abadd57d47403e94f5505", size = 4963, upload-time = "2025-04-22T14:54:22.983Z" }, -] - -[[package]] -name = "nbclient" -version = "0.10.2" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "jupyter-client" }, - { name = "jupyter-core" }, - { name = "nbformat" }, - { name = "traitlets" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/87/66/7ffd18d58eae90d5721f9f39212327695b749e23ad44b3881744eaf4d9e8/nbclient-0.10.2.tar.gz", hash = "sha256:90b7fc6b810630db87a6d0c2250b1f0ab4cf4d3c27a299b0cde78a4ed3fd9193", size = 62424, upload-time = "2024-12-19T10:32:27.164Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/34/6d/e7fa07f03a4a7b221d94b4d586edb754a9b0dc3c9e2c93353e9fa4e0d117/nbclient-0.10.2-py3-none-any.whl", hash = "sha256:4ffee11e788b4a27fabeb7955547e4318a5298f34342a4bfd01f2e1faaeadc3d", size = 25434, upload-time = "2024-12-19T10:32:24.139Z" }, -] - -[[package]] -name = "nbconvert" -version = "7.16.6" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "beautifulsoup4" }, - { name = "bleach", extra = ["css"] }, - { name = "defusedxml" }, - { name = "jinja2" }, - { name = "jupyter-core" }, - { name = "jupyterlab-pygments" }, - { name = "markupsafe" }, - { name = "mistune" }, - { name = "nbclient" }, - { name = "nbformat" }, - { name = "packaging" }, - { name = "pandocfilters" }, - { name = "pygments" }, - { name = "traitlets" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/a3/59/f28e15fc47ffb73af68a8d9b47367a8630d76e97ae85ad18271b9db96fdf/nbconvert-7.16.6.tar.gz", hash = "sha256:576a7e37c6480da7b8465eefa66c17844243816ce1ccc372633c6b71c3c0f582", size = 857715, upload-time = "2025-01-28T09:29:14.724Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/cc/9a/cd673b2f773a12c992f41309ef81b99da1690426bd2f96957a7ade0d3ed7/nbconvert-7.16.6-py3-none-any.whl", hash = "sha256:1375a7b67e0c2883678c48e506dc320febb57685e5ee67faa51b18a90f3a712b", size = 258525, upload-time = "2025-01-28T09:29:12.551Z" }, -] - -[[package]] -name = "nbformat" -version = "5.10.4" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "fastjsonschema" }, - { name = "jsonschema" }, - { name = "jupyter-core" }, - { name = "traitlets" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/6d/fd/91545e604bc3dad7dca9ed03284086039b294c6b3d75c0d2fa45f9e9caf3/nbformat-5.10.4.tar.gz", hash = "sha256:322168b14f937a5d11362988ecac2a4952d3d8e3a2cbeb2319584631226d5b3a", size = 142749, upload-time = "2024-04-04T11:20:37.371Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/a9/82/0340caa499416c78e5d8f5f05947ae4bc3cba53c9f038ab6e9ed964e22f1/nbformat-5.10.4-py3-none-any.whl", hash = "sha256:3b48d6c8fbca4b299bf3982ea7db1af21580e4fec269ad087b9e81588891200b", size = 78454, upload-time = "2024-04-04T11:20:34.895Z" }, -] - -[[package]] -name = "nest-asyncio" -version = "1.6.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/83/f8/51569ac65d696c8ecbee95938f89d4abf00f47d58d48f6fbabfe8f0baefe/nest_asyncio-1.6.0.tar.gz", hash = "sha256:6f172d5449aca15afd6c646851f4e31e02c598d553a667e38cafa997cfec55fe", size = 7418, upload-time = "2024-01-21T14:25:19.227Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/a0/c4/c2971a3ba4c6103a3d10c4b0f24f461ddc027f0f09763220cf35ca1401b3/nest_asyncio-1.6.0-py3-none-any.whl", hash = "sha256:87af6efd6b5e897c81050477ef65c62e2b2f35d51703cae01aff2905b1852e1c", size = 5195, upload-time = "2024-01-21T14:25:17.223Z" }, -] - -[[package]] -name = "nodeenv" -version = "1.9.1" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/43/16/fc88b08840de0e0a72a2f9d8c6bae36be573e475a6326ae854bcc549fc45/nodeenv-1.9.1.tar.gz", hash = "sha256:6ec12890a2dab7946721edbfbcd91f3319c6ccc9aec47be7c7e6b7011ee6645f", size = 47437, upload-time = "2024-06-04T18:44:11.171Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/d2/1d/1b658dbd2b9fa9c4c9f32accbfc0205d532c8c6194dc0f2a4c0428e7128a/nodeenv-1.9.1-py2.py3-none-any.whl", hash = "sha256:ba11c9782d29c27c70ffbdda2d7415098754709be8a7056d79a737cd901155c9", size = 22314, upload-time = "2024-06-04T18:44:08.352Z" }, -] - -[[package]] -name = "notebook" -version = "7.4.1" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "jupyter-server" }, - { name = "jupyterlab" }, - { name = "jupyterlab-server" }, - { name = "notebook-shim" }, - { name = "tornado" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/91/89/1b4636280f01ec948c007e700e24921135b9b76221148a405fd5287c3c17/notebook-7.4.1.tar.gz", hash = "sha256:96894962b230013ea0c0a466e4e642c5aace25ba8c86686175b69990ef628ff9", size = 13881349, upload-time = "2025-04-23T06:40:29.147Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/41/c5/47248ed90d263e4c16f9f6b06f094105ce33f384cf135eab5a6452230d46/notebook-7.4.1-py3-none-any.whl", hash = "sha256:498f12cf567d95b20e780d62d52564ee4310248b3175e996b667b5808028e5d3", size = 14282763, upload-time = "2025-04-23T06:40:25.41Z" }, -] - -[[package]] -name = "notebook-shim" -version = "0.2.4" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "jupyter-server" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/54/d2/92fa3243712b9a3e8bafaf60aac366da1cada3639ca767ff4b5b3654ec28/notebook_shim-0.2.4.tar.gz", hash = "sha256:b4b2cfa1b65d98307ca24361f5b30fe785b53c3fd07b7a47e89acb5e6ac638cb", size = 13167, upload-time = "2024-02-14T23:35:18.353Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/f9/33/bd5b9137445ea4b680023eb0469b2bb969d61303dedb2aac6560ff3d14a1/notebook_shim-0.2.4-py3-none-any.whl", hash = "sha256:411a5be4e9dc882a074ccbcae671eda64cceb068767e9a3419096986560e1cef", size = 13307, upload-time = "2024-02-14T23:35:16.286Z" }, -] - -[[package]] -name = "overrides" -version = "7.7.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/36/86/b585f53236dec60aba864e050778b25045f857e17f6e5ea0ae95fe80edd2/overrides-7.7.0.tar.gz", hash = "sha256:55158fa3d93b98cc75299b1e67078ad9003ca27945c76162c1c0766d6f91820a", size = 22812, upload-time = "2024-01-27T21:01:33.423Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/2c/ab/fc8290c6a4c722e5514d80f62b2dc4c4df1a68a41d1364e625c35990fcf3/overrides-7.7.0-py3-none-any.whl", hash = "sha256:c7ed9d062f78b8e4c1a7b70bd8796b35ead4d9f510227ef9c5dc7626c60d7e49", size = 17832, upload-time = "2024-01-27T21:01:31.393Z" }, -] - -[[package]] -name = "packaging" -version = "24.2" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/d0/63/68dbb6eb2de9cb10ee4c9c14a0148804425e13c4fb20d61cce69f53106da/packaging-24.2.tar.gz", hash = "sha256:c228a6dc5e932d346bc5739379109d49e8853dd8223571c7c5b55260edc0b97f", size = 163950, upload-time = "2024-11-08T09:47:47.202Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/88/ef/eb23f262cca3c0c4eb7ab1933c3b1f03d021f2c48f54763065b6f0e321be/packaging-24.2-py3-none-any.whl", hash = "sha256:09abb1bccd265c01f4a3aa3f7a7db064b36514d2cba19a2f694fe6150451a759", size = 65451, upload-time = "2024-11-08T09:47:44.722Z" }, -] - -[[package]] -name = "pandocfilters" -version = "1.5.1" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/70/6f/3dd4940bbe001c06a65f88e36bad298bc7a0de5036115639926b0c5c0458/pandocfilters-1.5.1.tar.gz", hash = "sha256:002b4a555ee4ebc03f8b66307e287fa492e4a77b4ea14d3f934328297bb4939e", size = 8454, upload-time = "2024-01-18T20:08:13.726Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/ef/af/4fbc8cab944db5d21b7e2a5b8e9211a03a79852b1157e2c102fcc61ac440/pandocfilters-1.5.1-py2.py3-none-any.whl", hash = "sha256:93be382804a9cdb0a7267585f157e5d1731bbe5545a85b268d6f5fe6232de2bc", size = 8663, upload-time = "2024-01-18T20:08:11.28Z" }, -] - -[[package]] -name = "parso" -version = "0.8.4" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/66/94/68e2e17afaa9169cf6412ab0f28623903be73d1b32e208d9e8e541bb086d/parso-0.8.4.tar.gz", hash = "sha256:eb3a7b58240fb99099a345571deecc0f9540ea5f4dd2fe14c2a99d6b281ab92d", size = 400609, upload-time = "2024-04-05T09:43:55.897Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/c6/ac/dac4a63f978e4dcb3c6d3a78c4d8e0192a113d288502a1216950c41b1027/parso-0.8.4-py2.py3-none-any.whl", hash = "sha256:a418670a20291dacd2dddc80c377c5c3791378ee1e8d12bffc35420643d43f18", size = 103650, upload-time = "2024-04-05T09:43:53.299Z" }, -] - -[[package]] -name = "pathspec" -version = "0.12.1" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/ca/bc/f35b8446f4531a7cb215605d100cd88b7ac6f44ab3fc94870c120ab3adbf/pathspec-0.12.1.tar.gz", hash = "sha256:a482d51503a1ab33b1c67a6c3813a26953dbdc71c31dacaef9a838c4e29f5712", size = 51043, upload-time = "2023-12-10T22:30:45Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/cc/20/ff623b09d963f88bfde16306a54e12ee5ea43e9b597108672ff3a408aad6/pathspec-0.12.1-py3-none-any.whl", hash = "sha256:a0d503e138a4c123b27490a4f7beda6a01c6f288df0e4a8b79c7eb0dc7b4cc08", size = 31191, upload-time = "2023-12-10T22:30:43.14Z" }, -] - -[[package]] -name = "pexpect" -version = "4.9.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "ptyprocess" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/42/92/cc564bf6381ff43ce1f4d06852fc19a2f11d180f23dc32d9588bee2f149d/pexpect-4.9.0.tar.gz", hash = "sha256:ee7d41123f3c9911050ea2c2dac107568dc43b2d3b0c7557a33212c398ead30f", size = 166450, upload-time = "2023-11-25T09:07:26.339Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/9e/c3/059298687310d527a58bb01f3b1965787ee3b40dce76752eda8b44e9a2c5/pexpect-4.9.0-py2.py3-none-any.whl", hash = "sha256:7236d1e080e4936be2dc3e326cec0af72acf9212a7e1d060210e70a47e253523", size = 63772, upload-time = "2023-11-25T06:56:14.81Z" }, -] - -[[package]] -name = "platformdirs" -version = "4.3.7" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/b6/2d/7d512a3913d60623e7eb945c6d1b4f0bddf1d0b7ada5225274c87e5b53d1/platformdirs-4.3.7.tar.gz", hash = "sha256:eb437d586b6a0986388f0d6f74aa0cde27b48d0e3d66843640bfb6bdcdb6e351", size = 21291, upload-time = "2025-03-19T20:36:10.989Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/6d/45/59578566b3275b8fd9157885918fcd0c4d74162928a5310926887b856a51/platformdirs-4.3.7-py3-none-any.whl", hash = "sha256:a03875334331946f13c549dbd8f4bac7a13a50a895a0eb1e8c6a8ace80d40a94", size = 18499, upload-time = "2025-03-19T20:36:09.038Z" }, -] - -[[package]] -name = "pluggy" -version = "1.5.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/96/2d/02d4312c973c6050a18b314a5ad0b3210edb65a906f868e31c111dede4a6/pluggy-1.5.0.tar.gz", hash = "sha256:2cffa88e94fdc978c4c574f15f9e59b7f4201d439195c3715ca9e2486f1d0cf1", size = 67955, upload-time = "2024-04-20T21:34:42.531Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/88/5f/e351af9a41f866ac3f1fac4ca0613908d9a41741cfcf2228f4ad853b697d/pluggy-1.5.0-py3-none-any.whl", hash = "sha256:44e1ad92c8ca002de6377e165f3e0f1be63266ab4d554740532335b9d75ea669", size = 20556, upload-time = "2024-04-20T21:34:40.434Z" }, -] - -[[package]] -name = "plum-dispatch" -version = "2.5.7" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "beartype" }, - { name = "rich" }, - { name = "typing-extensions" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/f4/46/ab3928e864b0a88a8ae6987b3da3b7ae32fe0a610264f33272139275dab5/plum_dispatch-2.5.7.tar.gz", hash = "sha256:a7908ad5563b93f387e3817eb0412ad40cfbad04bc61d869cf7a76cd58a3895d", size = 35452, upload-time = "2025-01-17T20:07:31.026Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/2b/31/21609a9be48e877bc33b089a7f495c853215def5aeb9564a31c210d9d769/plum_dispatch-2.5.7-py3-none-any.whl", hash = "sha256:06471782eea0b3798c1e79dca2af2165bafcfa5eb595540b514ddd81053b1ede", size = 42612, upload-time = "2025-01-17T20:07:26.461Z" }, -] - -[[package]] -name = "pnt-functional" -version = "0.1.1" -source = { editable = "packages/pnt-functional" } -dependencies = [ - { name = "beartype" }, - { name = "expression" }, -] - -[package.dev-dependencies] -dev = [ - { name = "hypothesis" }, - { name = "ipython" }, - { name = "pyright" }, - { name = "pytest" }, - { name = "pytest-cov" }, - { name = "ruff" }, - { name = "xdoctest" }, -] -interactive = [ - { name = "ipython" }, -] -lint = [ - { name = "ruff" }, -] -test = [ - { name = "hypothesis" }, - { name = "pytest" }, - { name = "pytest-cov" }, - { name = "xdoctest" }, -] -types = [ - { name = "pyright" }, -] - -[package.metadata] -requires-dist = [ - { name = "beartype", specifier = ">=0.19.0,<0.20.0" }, - { name = "expression", specifier = ">=5.5.0" }, -] - -[package.metadata.requires-dev] -dev = [ - { name = "hypothesis", specifier = ">=6.125.1" }, - { name = "ipython", specifier = ">=8.32.0" }, - { name = "pyright", specifier = ">=1.1.395" }, - { name = "pytest", specifier = ">=8.3.4" }, - { name = "pytest-cov", specifier = ">=6.0.0" }, - { name = "ruff", specifier = ">=0.9.4" }, - { name = "xdoctest", specifier = ">=1.2.0" }, -] -interactive = [{ name = "ipython", specifier = ">=8.32.0" }] -lint = [{ name = "ruff", specifier = ">=0.9.4" }] -test = [ - { name = "hypothesis", specifier = ">=6.125.1" }, - { name = "pytest", specifier = ">=8.3.4" }, - { name = "pytest-cov", specifier = ">=6.0.0" }, - { name = "xdoctest", specifier = ">=1.2.0" }, -] -types = [{ name = "pyright", specifier = ">=1.1.395" }] - -[[package]] -name = "prometheus-client" -version = "0.21.1" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/62/14/7d0f567991f3a9af8d1cd4f619040c93b68f09a02b6d0b6ab1b2d1ded5fe/prometheus_client-0.21.1.tar.gz", hash = "sha256:252505a722ac04b0456be05c05f75f45d760c2911ffc45f2a06bcaed9f3ae3fb", size = 78551, upload-time = "2024-12-03T14:59:12.164Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/ff/c2/ab7d37426c179ceb9aeb109a85cda8948bb269b7561a0be870cc656eefe4/prometheus_client-0.21.1-py3-none-any.whl", hash = "sha256:594b45c410d6f4f8888940fe80b5cc2521b305a1fafe1c58609ef715a001f301", size = 54682, upload-time = "2024-12-03T14:59:10.935Z" }, -] - -[[package]] -name = "prompt-toolkit" -version = "3.0.50" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "wcwidth" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/a1/e1/bd15cb8ffdcfeeb2bdc215de3c3cffca11408d829e4b8416dcfe71ba8854/prompt_toolkit-3.0.50.tar.gz", hash = "sha256:544748f3860a2623ca5cd6d2795e7a14f3d0e1c3c9728359013f79877fc89bab", size = 429087, upload-time = "2025-01-20T15:55:35.072Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/e4/ea/d836f008d33151c7a1f62caf3d8dd782e4d15f6a43897f64480c2b8de2ad/prompt_toolkit-3.0.50-py3-none-any.whl", hash = "sha256:9b6427eb19e479d98acff65196a307c555eb567989e6d88ebbb1b509d9779198", size = 387816, upload-time = "2025-01-20T15:55:29.98Z" }, -] - -[[package]] -name = "psutil" -version = "7.0.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/2a/80/336820c1ad9286a4ded7e845b2eccfcb27851ab8ac6abece774a6ff4d3de/psutil-7.0.0.tar.gz", hash = "sha256:7be9c3eba38beccb6495ea33afd982a44074b78f28c434a1f51cc07fd315c456", size = 497003, upload-time = "2025-02-13T21:54:07.946Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/ed/e6/2d26234410f8b8abdbf891c9da62bee396583f713fb9f3325a4760875d22/psutil-7.0.0-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:101d71dc322e3cffd7cea0650b09b3d08b8e7c4109dd6809fe452dfd00e58b25", size = 238051, upload-time = "2025-02-13T21:54:12.36Z" }, - { url = "https://files.pythonhosted.org/packages/04/8b/30f930733afe425e3cbfc0e1468a30a18942350c1a8816acfade80c005c4/psutil-7.0.0-cp36-abi3-macosx_11_0_arm64.whl", hash = "sha256:39db632f6bb862eeccf56660871433e111b6ea58f2caea825571951d4b6aa3da", size = 239535, upload-time = "2025-02-13T21:54:16.07Z" }, - { url = "https://files.pythonhosted.org/packages/2a/ed/d362e84620dd22876b55389248e522338ed1bf134a5edd3b8231d7207f6d/psutil-7.0.0-cp36-abi3-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1fcee592b4c6f146991ca55919ea3d1f8926497a713ed7faaf8225e174581e91", size = 275004, upload-time = "2025-02-13T21:54:18.662Z" }, - { url = "https://files.pythonhosted.org/packages/bf/b9/b0eb3f3cbcb734d930fdf839431606844a825b23eaf9a6ab371edac8162c/psutil-7.0.0-cp36-abi3-manylinux_2_12_x86_64.manylinux2010_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4b1388a4f6875d7e2aff5c4ca1cc16c545ed41dd8bb596cefea80111db353a34", size = 277986, upload-time = "2025-02-13T21:54:21.811Z" }, - { url = "https://files.pythonhosted.org/packages/eb/a2/709e0fe2f093556c17fbafda93ac032257242cabcc7ff3369e2cb76a97aa/psutil-7.0.0-cp36-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a5f098451abc2828f7dc6b58d44b532b22f2088f4999a937557b603ce72b1993", size = 279544, upload-time = "2025-02-13T21:54:24.68Z" }, - { url = "https://files.pythonhosted.org/packages/50/e6/eecf58810b9d12e6427369784efe814a1eec0f492084ce8eb8f4d89d6d61/psutil-7.0.0-cp37-abi3-win32.whl", hash = "sha256:ba3fcef7523064a6c9da440fc4d6bd07da93ac726b5733c29027d7dc95b39d99", size = 241053, upload-time = "2025-02-13T21:54:34.31Z" }, - { url = "https://files.pythonhosted.org/packages/50/1b/6921afe68c74868b4c9fa424dad3be35b095e16687989ebbb50ce4fceb7c/psutil-7.0.0-cp37-abi3-win_amd64.whl", hash = "sha256:4cf3d4eb1aa9b348dec30105c55cd9b7d4629285735a102beb4441e38db90553", size = 244885, upload-time = "2025-02-13T21:54:37.486Z" }, -] - -[[package]] -name = "ptyprocess" -version = "0.7.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/20/e5/16ff212c1e452235a90aeb09066144d0c5a6a8c0834397e03f5224495c4e/ptyprocess-0.7.0.tar.gz", hash = "sha256:5c5d0a3b48ceee0b48485e0c26037c0acd7d29765ca3fbb5cb3831d347423220", size = 70762, upload-time = "2020-12-28T15:15:30.155Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/22/a6/858897256d0deac81a172289110f31629fc4cee19b6f01283303e18c8db3/ptyprocess-0.7.0-py2.py3-none-any.whl", hash = "sha256:4b41f3967fce3af57cc7e94b888626c18bf37a083e3651ca8feeb66d492fef35", size = 13993, upload-time = "2020-12-28T15:15:28.35Z" }, -] - -[[package]] -name = "pure-eval" -version = "0.2.3" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/cd/05/0a34433a064256a578f1783a10da6df098ceaa4a57bbeaa96a6c0352786b/pure_eval-0.2.3.tar.gz", hash = "sha256:5f4e983f40564c576c7c8635ae88db5956bb2229d7e9237d03b3c0b0190eaf42", size = 19752, upload-time = "2024-07-21T12:58:21.801Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/8e/37/efad0257dc6e593a18957422533ff0f87ede7c9c6ea010a2177d738fb82f/pure_eval-0.2.3-py3-none-any.whl", hash = "sha256:1db8e35b67b3d218d818ae653e27f06c3aa420901fa7b081ca98cbedc874e0d0", size = 11842, upload-time = "2024-07-21T12:58:20.04Z" }, -] - -[[package]] -name = "pycparser" -version = "2.22" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/1d/b2/31537cf4b1ca988837256c910a668b553fceb8f069bedc4b1c826024b52c/pycparser-2.22.tar.gz", hash = "sha256:491c8be9c040f5390f5bf44a5b07752bd07f56edf992381b05c701439eec10f6", size = 172736, upload-time = "2024-03-30T13:22:22.564Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/13/a3/a812df4e2dd5696d1f351d58b8fe16a405b234ad2886a0dab9183fb78109/pycparser-2.22-py3-none-any.whl", hash = "sha256:c3702b6d3dd8c7abc1afa565d7e63d53a1d0bd86cdc24edd75470f4de499cfcc", size = 117552, upload-time = "2024-03-30T13:22:20.476Z" }, -] - -[[package]] -name = "pydantic" -version = "2.11.4" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "annotated-types" }, - { name = "pydantic-core" }, - { name = "typing-extensions" }, - { name = "typing-inspection" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/77/ab/5250d56ad03884ab5efd07f734203943c8a8ab40d551e208af81d0257bf2/pydantic-2.11.4.tar.gz", hash = "sha256:32738d19d63a226a52eed76645a98ee07c1f410ee41d93b4afbfa85ed8111c2d", size = 786540, upload-time = "2025-04-29T20:38:55.02Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/e7/12/46b65f3534d099349e38ef6ec98b1a5a81f42536d17e0ba382c28c67ba67/pydantic-2.11.4-py3-none-any.whl", hash = "sha256:d9615eaa9ac5a063471da949c8fc16376a84afb5024688b3ff885693506764eb", size = 443900, upload-time = "2025-04-29T20:38:52.724Z" }, -] - -[[package]] -name = "pydantic-core" -version = "2.33.2" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "typing-extensions" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/ad/88/5f2260bdfae97aabf98f1778d43f69574390ad787afb646292a638c923d4/pydantic_core-2.33.2.tar.gz", hash = "sha256:7cb8bc3605c29176e1b105350d2e6474142d7c1bd1d9327c4a9bdb46bf827acc", size = 435195, upload-time = "2025-04-23T18:33:52.104Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/3f/8d/71db63483d518cbbf290261a1fc2839d17ff89fce7089e08cad07ccfce67/pydantic_core-2.33.2-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:4c5b0a576fb381edd6d27f0a85915c6daf2f8138dc5c267a57c08a62900758c7", size = 2028584, upload-time = "2025-04-23T18:31:03.106Z" }, - { url = "https://files.pythonhosted.org/packages/24/2f/3cfa7244ae292dd850989f328722d2aef313f74ffc471184dc509e1e4e5a/pydantic_core-2.33.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:e799c050df38a639db758c617ec771fd8fb7a5f8eaaa4b27b101f266b216a246", size = 1855071, upload-time = "2025-04-23T18:31:04.621Z" }, - { url = "https://files.pythonhosted.org/packages/b3/d3/4ae42d33f5e3f50dd467761304be2fa0a9417fbf09735bc2cce003480f2a/pydantic_core-2.33.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:dc46a01bf8d62f227d5ecee74178ffc448ff4e5197c756331f71efcc66dc980f", size = 1897823, upload-time = "2025-04-23T18:31:06.377Z" }, - { url = "https://files.pythonhosted.org/packages/f4/f3/aa5976e8352b7695ff808599794b1fba2a9ae2ee954a3426855935799488/pydantic_core-2.33.2-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:a144d4f717285c6d9234a66778059f33a89096dfb9b39117663fd8413d582dcc", size = 1983792, upload-time = "2025-04-23T18:31:07.93Z" }, - { url = "https://files.pythonhosted.org/packages/d5/7a/cda9b5a23c552037717f2b2a5257e9b2bfe45e687386df9591eff7b46d28/pydantic_core-2.33.2-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:73cf6373c21bc80b2e0dc88444f41ae60b2f070ed02095754eb5a01df12256de", size = 2136338, upload-time = "2025-04-23T18:31:09.283Z" }, - { url = "https://files.pythonhosted.org/packages/2b/9f/b8f9ec8dd1417eb9da784e91e1667d58a2a4a7b7b34cf4af765ef663a7e5/pydantic_core-2.33.2-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3dc625f4aa79713512d1976fe9f0bc99f706a9dee21dfd1810b4bbbf228d0e8a", size = 2730998, upload-time = "2025-04-23T18:31:11.7Z" }, - { url = "https://files.pythonhosted.org/packages/47/bc/cd720e078576bdb8255d5032c5d63ee5c0bf4b7173dd955185a1d658c456/pydantic_core-2.33.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:881b21b5549499972441da4758d662aeea93f1923f953e9cbaff14b8b9565aef", size = 2003200, upload-time = "2025-04-23T18:31:13.536Z" }, - { url = "https://files.pythonhosted.org/packages/ca/22/3602b895ee2cd29d11a2b349372446ae9727c32e78a94b3d588a40fdf187/pydantic_core-2.33.2-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:bdc25f3681f7b78572699569514036afe3c243bc3059d3942624e936ec93450e", size = 2113890, upload-time = "2025-04-23T18:31:15.011Z" }, - { url = "https://files.pythonhosted.org/packages/ff/e6/e3c5908c03cf00d629eb38393a98fccc38ee0ce8ecce32f69fc7d7b558a7/pydantic_core-2.33.2-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:fe5b32187cbc0c862ee201ad66c30cf218e5ed468ec8dc1cf49dec66e160cc4d", size = 2073359, upload-time = "2025-04-23T18:31:16.393Z" }, - { url = "https://files.pythonhosted.org/packages/12/e7/6a36a07c59ebefc8777d1ffdaf5ae71b06b21952582e4b07eba88a421c79/pydantic_core-2.33.2-cp311-cp311-musllinux_1_1_armv7l.whl", hash = "sha256:bc7aee6f634a6f4a95676fcb5d6559a2c2a390330098dba5e5a5f28a2e4ada30", size = 2245883, upload-time = "2025-04-23T18:31:17.892Z" }, - { url = "https://files.pythonhosted.org/packages/16/3f/59b3187aaa6cc0c1e6616e8045b284de2b6a87b027cce2ffcea073adf1d2/pydantic_core-2.33.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:235f45e5dbcccf6bd99f9f472858849f73d11120d76ea8707115415f8e5ebebf", size = 2241074, upload-time = "2025-04-23T18:31:19.205Z" }, - { url = "https://files.pythonhosted.org/packages/e0/ed/55532bb88f674d5d8f67ab121a2a13c385df382de2a1677f30ad385f7438/pydantic_core-2.33.2-cp311-cp311-win32.whl", hash = "sha256:6368900c2d3ef09b69cb0b913f9f8263b03786e5b2a387706c5afb66800efd51", size = 1910538, upload-time = "2025-04-23T18:31:20.541Z" }, - { url = "https://files.pythonhosted.org/packages/fe/1b/25b7cccd4519c0b23c2dd636ad39d381abf113085ce4f7bec2b0dc755eb1/pydantic_core-2.33.2-cp311-cp311-win_amd64.whl", hash = "sha256:1e063337ef9e9820c77acc768546325ebe04ee38b08703244c1309cccc4f1bab", size = 1952909, upload-time = "2025-04-23T18:31:22.371Z" }, - { url = "https://files.pythonhosted.org/packages/49/a9/d809358e49126438055884c4366a1f6227f0f84f635a9014e2deb9b9de54/pydantic_core-2.33.2-cp311-cp311-win_arm64.whl", hash = "sha256:6b99022f1d19bc32a4c2a0d544fc9a76e3be90f0b3f4af413f87d38749300e65", size = 1897786, upload-time = "2025-04-23T18:31:24.161Z" }, - { url = "https://files.pythonhosted.org/packages/18/8a/2b41c97f554ec8c71f2a8a5f85cb56a8b0956addfe8b0efb5b3d77e8bdc3/pydantic_core-2.33.2-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:a7ec89dc587667f22b6a0b6579c249fca9026ce7c333fc142ba42411fa243cdc", size = 2009000, upload-time = "2025-04-23T18:31:25.863Z" }, - { url = "https://files.pythonhosted.org/packages/a1/02/6224312aacb3c8ecbaa959897af57181fb6cf3a3d7917fd44d0f2917e6f2/pydantic_core-2.33.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:3c6db6e52c6d70aa0d00d45cdb9b40f0433b96380071ea80b09277dba021ddf7", size = 1847996, upload-time = "2025-04-23T18:31:27.341Z" }, - { url = "https://files.pythonhosted.org/packages/d6/46/6dcdf084a523dbe0a0be59d054734b86a981726f221f4562aed313dbcb49/pydantic_core-2.33.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4e61206137cbc65e6d5256e1166f88331d3b6238e082d9f74613b9b765fb9025", size = 1880957, upload-time = "2025-04-23T18:31:28.956Z" }, - { url = "https://files.pythonhosted.org/packages/ec/6b/1ec2c03837ac00886ba8160ce041ce4e325b41d06a034adbef11339ae422/pydantic_core-2.33.2-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:eb8c529b2819c37140eb51b914153063d27ed88e3bdc31b71198a198e921e011", size = 1964199, upload-time = "2025-04-23T18:31:31.025Z" }, - { url = "https://files.pythonhosted.org/packages/2d/1d/6bf34d6adb9debd9136bd197ca72642203ce9aaaa85cfcbfcf20f9696e83/pydantic_core-2.33.2-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c52b02ad8b4e2cf14ca7b3d918f3eb0ee91e63b3167c32591e57c4317e134f8f", size = 2120296, upload-time = "2025-04-23T18:31:32.514Z" }, - { url = "https://files.pythonhosted.org/packages/e0/94/2bd0aaf5a591e974b32a9f7123f16637776c304471a0ab33cf263cf5591a/pydantic_core-2.33.2-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:96081f1605125ba0855dfda83f6f3df5ec90c61195421ba72223de35ccfb2f88", size = 2676109, upload-time = "2025-04-23T18:31:33.958Z" }, - { url = "https://files.pythonhosted.org/packages/f9/41/4b043778cf9c4285d59742281a769eac371b9e47e35f98ad321349cc5d61/pydantic_core-2.33.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8f57a69461af2a5fa6e6bbd7a5f60d3b7e6cebb687f55106933188e79ad155c1", size = 2002028, upload-time = "2025-04-23T18:31:39.095Z" }, - { url = "https://files.pythonhosted.org/packages/cb/d5/7bb781bf2748ce3d03af04d5c969fa1308880e1dca35a9bd94e1a96a922e/pydantic_core-2.33.2-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:572c7e6c8bb4774d2ac88929e3d1f12bc45714ae5ee6d9a788a9fb35e60bb04b", size = 2100044, upload-time = "2025-04-23T18:31:41.034Z" }, - { url = "https://files.pythonhosted.org/packages/fe/36/def5e53e1eb0ad896785702a5bbfd25eed546cdcf4087ad285021a90ed53/pydantic_core-2.33.2-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:db4b41f9bd95fbe5acd76d89920336ba96f03e149097365afe1cb092fceb89a1", size = 2058881, upload-time = "2025-04-23T18:31:42.757Z" }, - { url = "https://files.pythonhosted.org/packages/01/6c/57f8d70b2ee57fc3dc8b9610315949837fa8c11d86927b9bb044f8705419/pydantic_core-2.33.2-cp312-cp312-musllinux_1_1_armv7l.whl", hash = "sha256:fa854f5cf7e33842a892e5c73f45327760bc7bc516339fda888c75ae60edaeb6", size = 2227034, upload-time = "2025-04-23T18:31:44.304Z" }, - { url = "https://files.pythonhosted.org/packages/27/b9/9c17f0396a82b3d5cbea4c24d742083422639e7bb1d5bf600e12cb176a13/pydantic_core-2.33.2-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:5f483cfb75ff703095c59e365360cb73e00185e01aaea067cd19acffd2ab20ea", size = 2234187, upload-time = "2025-04-23T18:31:45.891Z" }, - { url = "https://files.pythonhosted.org/packages/b0/6a/adf5734ffd52bf86d865093ad70b2ce543415e0e356f6cacabbc0d9ad910/pydantic_core-2.33.2-cp312-cp312-win32.whl", hash = "sha256:9cb1da0f5a471435a7bc7e439b8a728e8b61e59784b2af70d7c169f8dd8ae290", size = 1892628, upload-time = "2025-04-23T18:31:47.819Z" }, - { url = "https://files.pythonhosted.org/packages/43/e4/5479fecb3606c1368d496a825d8411e126133c41224c1e7238be58b87d7e/pydantic_core-2.33.2-cp312-cp312-win_amd64.whl", hash = "sha256:f941635f2a3d96b2973e867144fde513665c87f13fe0e193c158ac51bfaaa7b2", size = 1955866, upload-time = "2025-04-23T18:31:49.635Z" }, - { url = "https://files.pythonhosted.org/packages/0d/24/8b11e8b3e2be9dd82df4b11408a67c61bb4dc4f8e11b5b0fc888b38118b5/pydantic_core-2.33.2-cp312-cp312-win_arm64.whl", hash = "sha256:cca3868ddfaccfbc4bfb1d608e2ccaaebe0ae628e1416aeb9c4d88c001bb45ab", size = 1888894, upload-time = "2025-04-23T18:31:51.609Z" }, - { url = "https://files.pythonhosted.org/packages/7b/27/d4ae6487d73948d6f20dddcd94be4ea43e74349b56eba82e9bdee2d7494c/pydantic_core-2.33.2-pp311-pypy311_pp73-macosx_10_12_x86_64.whl", hash = "sha256:dd14041875d09cc0f9308e37a6f8b65f5585cf2598a53aa0123df8b129d481f8", size = 2025200, upload-time = "2025-04-23T18:33:14.199Z" }, - { url = "https://files.pythonhosted.org/packages/f1/b8/b3cb95375f05d33801024079b9392a5ab45267a63400bf1866e7ce0f0de4/pydantic_core-2.33.2-pp311-pypy311_pp73-macosx_11_0_arm64.whl", hash = "sha256:d87c561733f66531dced0da6e864f44ebf89a8fba55f31407b00c2f7f9449593", size = 1859123, upload-time = "2025-04-23T18:33:16.555Z" }, - { url = "https://files.pythonhosted.org/packages/05/bc/0d0b5adeda59a261cd30a1235a445bf55c7e46ae44aea28f7bd6ed46e091/pydantic_core-2.33.2-pp311-pypy311_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2f82865531efd18d6e07a04a17331af02cb7a651583c418df8266f17a63c6612", size = 1892852, upload-time = "2025-04-23T18:33:18.513Z" }, - { url = "https://files.pythonhosted.org/packages/3e/11/d37bdebbda2e449cb3f519f6ce950927b56d62f0b84fd9cb9e372a26a3d5/pydantic_core-2.33.2-pp311-pypy311_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2bfb5112df54209d820d7bf9317c7a6c9025ea52e49f46b6a2060104bba37de7", size = 2067484, upload-time = "2025-04-23T18:33:20.475Z" }, - { url = "https://files.pythonhosted.org/packages/8c/55/1f95f0a05ce72ecb02a8a8a1c3be0579bbc29b1d5ab68f1378b7bebc5057/pydantic_core-2.33.2-pp311-pypy311_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:64632ff9d614e5eecfb495796ad51b0ed98c453e447a76bcbeeb69615079fc7e", size = 2108896, upload-time = "2025-04-23T18:33:22.501Z" }, - { url = "https://files.pythonhosted.org/packages/53/89/2b2de6c81fa131f423246a9109d7b2a375e83968ad0800d6e57d0574629b/pydantic_core-2.33.2-pp311-pypy311_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:f889f7a40498cc077332c7ab6b4608d296d852182211787d4f3ee377aaae66e8", size = 2069475, upload-time = "2025-04-23T18:33:24.528Z" }, - { url = "https://files.pythonhosted.org/packages/b8/e9/1f7efbe20d0b2b10f6718944b5d8ece9152390904f29a78e68d4e7961159/pydantic_core-2.33.2-pp311-pypy311_pp73-musllinux_1_1_armv7l.whl", hash = "sha256:de4b83bb311557e439b9e186f733f6c645b9417c84e2eb8203f3f820a4b988bf", size = 2239013, upload-time = "2025-04-23T18:33:26.621Z" }, - { url = "https://files.pythonhosted.org/packages/3c/b2/5309c905a93811524a49b4e031e9851a6b00ff0fb668794472ea7746b448/pydantic_core-2.33.2-pp311-pypy311_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:82f68293f055f51b51ea42fafc74b6aad03e70e191799430b90c13d643059ebb", size = 2238715, upload-time = "2025-04-23T18:33:28.656Z" }, - { url = "https://files.pythonhosted.org/packages/32/56/8a7ca5d2cd2cda1d245d34b1c9a942920a718082ae8e54e5f3e5a58b7add/pydantic_core-2.33.2-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:329467cecfb529c925cf2bbd4d60d2c509bc2fb52a20c1045bf09bb70971a9c1", size = 2066757, upload-time = "2025-04-23T18:33:30.645Z" }, -] - -[[package]] -name = "pygments" -version = "2.19.1" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/7c/2d/c3338d48ea6cc0feb8446d8e6937e1408088a72a39937982cc6111d17f84/pygments-2.19.1.tar.gz", hash = "sha256:61c16d2a8576dc0649d9f39e089b5f02bcd27fba10d8fb4dcc28173f7a45151f", size = 4968581, upload-time = "2025-01-06T17:26:30.443Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/8a/0b/9fcc47d19c48b59121088dd6da2488a49d5f72dacf8262e2790a1d2c7d15/pygments-2.19.1-py3-none-any.whl", hash = "sha256:9ea1544ad55cecf4b8242fab6dd35a93bbce657034b0611ee383099054ab6d8c", size = 1225293, upload-time = "2025-01-06T17:26:25.553Z" }, -] - -[[package]] -name = "pyright" -version = "1.1.396" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "nodeenv" }, - { name = "typing-extensions" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/bd/73/f20cb1dea1bdc1774e7f860fb69dc0718c7d8dea854a345faec845eb086a/pyright-1.1.396.tar.gz", hash = "sha256:142901f5908f5a0895be3d3befcc18bedcdb8cc1798deecaec86ef7233a29b03", size = 3814400, upload-time = "2025-03-02T02:12:16.732Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/80/be/ecb7cfb42d242b7ee764b52e6ff4782beeec00e3b943a3ec832b281f9da6/pyright-1.1.396-py3-none-any.whl", hash = "sha256:c635e473095b9138c471abccca22b9fedbe63858e0b40d4fc4b67da041891844", size = 5689355, upload-time = "2025-03-02T02:12:14.044Z" }, -] - -[[package]] -name = "pytest" -version = "8.3.5" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "colorama", marker = "sys_platform == 'win32'" }, - { name = "iniconfig" }, - { name = "packaging" }, - { name = "pluggy" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/ae/3c/c9d525a414d506893f0cd8a8d0de7706446213181570cdbd766691164e40/pytest-8.3.5.tar.gz", hash = "sha256:f4efe70cc14e511565ac476b57c279e12a855b11f48f212af1080ef2263d3845", size = 1450891, upload-time = "2025-03-02T12:54:54.503Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/30/3d/64ad57c803f1fa1e963a7946b6e0fea4a70df53c1a7fed304586539c2bac/pytest-8.3.5-py3-none-any.whl", hash = "sha256:c69214aa47deac29fad6c2a4f590b9c4a9fdb16a403176fe154b79c0b4d4d820", size = 343634, upload-time = "2025-03-02T12:54:52.069Z" }, -] - -[[package]] -name = "pytest-cov" -version = "6.0.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "coverage", extra = ["toml"] }, - { name = "pytest" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/be/45/9b538de8cef30e17c7b45ef42f538a94889ed6a16f2387a6c89e73220651/pytest-cov-6.0.0.tar.gz", hash = "sha256:fde0b595ca248bb8e2d76f020b465f3b107c9632e6a1d1705f17834c89dcadc0", size = 66945, upload-time = "2024-10-29T20:13:35.363Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/36/3b/48e79f2cd6a61dbbd4807b4ed46cb564b4fd50a76166b1c4ea5c1d9e2371/pytest_cov-6.0.0-py3-none-any.whl", hash = "sha256:eee6f1b9e61008bd34975a4d5bab25801eb31898b032dd55addc93e96fcaaa35", size = 22949, upload-time = "2024-10-29T20:13:33.215Z" }, -] - -[[package]] -name = "python-dateutil" -version = "2.9.0.post0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "six" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/66/c0/0c8b6ad9f17a802ee498c46e004a0eb49bc148f2fd230864601a86dcf6db/python-dateutil-2.9.0.post0.tar.gz", hash = "sha256:37dd54208da7e1cd875388217d5e00ebd4179249f90fb72437e91a35459a0ad3", size = 342432, upload-time = "2024-03-01T18:36:20.211Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/ec/57/56b9bcc3c9c6a792fcbaf139543cee77261f3651ca9da0c93f5c1221264b/python_dateutil-2.9.0.post0-py2.py3-none-any.whl", hash = "sha256:a8b2bc7bffae282281c8140a97d3aa9c14da0b136dfe83f850eea9a5f7470427", size = 229892, upload-time = "2024-03-01T18:36:18.57Z" }, -] - -[[package]] -name = "python-json-logger" -version = "3.3.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/9e/de/d3144a0bceede957f961e975f3752760fbe390d57fbe194baf709d8f1f7b/python_json_logger-3.3.0.tar.gz", hash = "sha256:12b7e74b17775e7d565129296105bbe3910842d9d0eb083fc83a6a617aa8df84", size = 16642, upload-time = "2025-03-07T07:08:27.301Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/08/20/0f2523b9e50a8052bc6a8b732dfc8568abbdc42010aef03a2d750bdab3b2/python_json_logger-3.3.0-py3-none-any.whl", hash = "sha256:dd980fae8cffb24c13caf6e158d3d61c0d6d22342f932cb6e9deedab3d35eec7", size = 15163, upload-time = "2025-03-07T07:08:25.627Z" }, -] - -[[package]] -name = "python-nix-template" -version = "0.1.1" -source = { editable = "packages/python-nix-template" } - -[package.dev-dependencies] -dev = [ - { name = "hypothesis" }, - { name = "ipython" }, - { name = "jupyter" }, - { name = "jupyter-cache" }, - { name = "pyright" }, - { name = "pytest" }, - { name = "pytest-cov" }, - { name = "quartodoc" }, - { name = "ruff" }, - { name = "xdoctest" }, -] -docs = [ - { name = "jupyter" }, - { name = "jupyter-cache" }, - { name = "quartodoc" }, -] -interactive = [ - { name = "ipython" }, -] -lint = [ - { name = "ruff" }, -] -test = [ - { name = "hypothesis" }, - { name = "pytest" }, - { name = "pytest-cov" }, - { name = "xdoctest" }, -] -types = [ - { name = "pyright" }, -] - -[package.metadata] - -[package.metadata.requires-dev] -dev = [ - { name = "hypothesis", specifier = ">=6.125.1" }, - { name = "ipython", specifier = ">=8.32.0" }, - { name = "jupyter", specifier = ">=1.1.1" }, - { name = "jupyter-cache", specifier = ">=1.0.1" }, - { name = "pyright", specifier = ">=1.1.395" }, - { name = "pytest", specifier = ">=8.3.4" }, - { name = "pytest-cov", specifier = ">=6.0.0" }, - { name = "quartodoc", specifier = ">=0.9.1" }, - { name = "ruff", specifier = ">=0.9.4" }, - { name = "xdoctest", specifier = ">=1.2.0" }, -] -docs = [ - { name = "jupyter", specifier = ">=1.1.1" }, - { name = "jupyter-cache", specifier = ">=1.0.1" }, - { name = "quartodoc", specifier = ">=0.9.1" }, -] -interactive = [{ name = "ipython", specifier = ">=8.32.0" }] -lint = [{ name = "ruff", specifier = ">=0.9.4" }] -test = [ - { name = "hypothesis", specifier = ">=6.125.1" }, - { name = "pytest", specifier = ">=8.3.4" }, - { name = "pytest-cov", specifier = ">=6.0.0" }, - { name = "xdoctest", specifier = ">=1.2.0" }, -] -types = [{ name = "pyright", specifier = ">=1.1.395" }] - -[[package]] -name = "pywin32" -version = "310" -source = { registry = "https://pypi.org/simple" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/f7/b1/68aa2986129fb1011dabbe95f0136f44509afaf072b12b8f815905a39f33/pywin32-310-cp311-cp311-win32.whl", hash = "sha256:1e765f9564e83011a63321bb9d27ec456a0ed90d3732c4b2e312b855365ed8bd", size = 8784284, upload-time = "2025-03-17T00:55:53.124Z" }, - { url = "https://files.pythonhosted.org/packages/b3/bd/d1592635992dd8db5bb8ace0551bc3a769de1ac8850200cfa517e72739fb/pywin32-310-cp311-cp311-win_amd64.whl", hash = "sha256:126298077a9d7c95c53823934f000599f66ec9296b09167810eb24875f32689c", size = 9520748, upload-time = "2025-03-17T00:55:55.203Z" }, - { url = "https://files.pythonhosted.org/packages/90/b1/ac8b1ffce6603849eb45a91cf126c0fa5431f186c2e768bf56889c46f51c/pywin32-310-cp311-cp311-win_arm64.whl", hash = "sha256:19ec5fc9b1d51c4350be7bb00760ffce46e6c95eaf2f0b2f1150657b1a43c582", size = 8455941, upload-time = "2025-03-17T00:55:57.048Z" }, - { url = "https://files.pythonhosted.org/packages/6b/ec/4fdbe47932f671d6e348474ea35ed94227fb5df56a7c30cbbb42cd396ed0/pywin32-310-cp312-cp312-win32.whl", hash = "sha256:8a75a5cc3893e83a108c05d82198880704c44bbaee4d06e442e471d3c9ea4f3d", size = 8796239, upload-time = "2025-03-17T00:55:58.807Z" }, - { url = "https://files.pythonhosted.org/packages/e3/e5/b0627f8bb84e06991bea89ad8153a9e50ace40b2e1195d68e9dff6b03d0f/pywin32-310-cp312-cp312-win_amd64.whl", hash = "sha256:bf5c397c9a9a19a6f62f3fb821fbf36cac08f03770056711f765ec1503972060", size = 9503839, upload-time = "2025-03-17T00:56:00.8Z" }, - { url = "https://files.pythonhosted.org/packages/1f/32/9ccf53748df72301a89713936645a664ec001abd35ecc8578beda593d37d/pywin32-310-cp312-cp312-win_arm64.whl", hash = "sha256:2349cc906eae872d0663d4d6290d13b90621eaf78964bb1578632ff20e152966", size = 8459470, upload-time = "2025-03-17T00:56:02.601Z" }, -] - -[[package]] -name = "pywinpty" -version = "2.0.15" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/2d/7c/917f9c4681bb8d34bfbe0b79d36bbcd902651aeab48790df3d30ba0202fb/pywinpty-2.0.15.tar.gz", hash = "sha256:312cf39153a8736c617d45ce8b6ad6cd2107de121df91c455b10ce6bba7a39b2", size = 29017, upload-time = "2025-02-03T21:53:23.265Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/5e/ac/6884dcb7108af66ad53f73ef4dad096e768c9203a6e6ce5e6b0c4a46e238/pywinpty-2.0.15-cp311-cp311-win_amd64.whl", hash = "sha256:9a6bcec2df2707aaa9d08b86071970ee32c5026e10bcc3cc5f6f391d85baf7ca", size = 1405249, upload-time = "2025-02-03T21:55:47.114Z" }, - { url = "https://files.pythonhosted.org/packages/88/e5/9714def18c3a411809771a3fbcec70bffa764b9675afb00048a620fca604/pywinpty-2.0.15-cp312-cp312-win_amd64.whl", hash = "sha256:83a8f20b430bbc5d8957249f875341a60219a4e971580f2ba694fbfb54a45ebc", size = 1405243, upload-time = "2025-02-03T21:56:52.476Z" }, -] - -[[package]] -name = "pyyaml" -version = "6.0.2" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/54/ed/79a089b6be93607fa5cdaedf301d7dfb23af5f25c398d5ead2525b063e17/pyyaml-6.0.2.tar.gz", hash = "sha256:d584d9ec91ad65861cc08d42e834324ef890a082e591037abe114850ff7bbc3e", size = 130631, upload-time = "2024-08-06T20:33:50.674Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/f8/aa/7af4e81f7acba21a4c6be026da38fd2b872ca46226673c89a758ebdc4fd2/PyYAML-6.0.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:cc1c1159b3d456576af7a3e4d1ba7e6924cb39de8f67111c735f6fc832082774", size = 184612, upload-time = "2024-08-06T20:32:03.408Z" }, - { url = "https://files.pythonhosted.org/packages/8b/62/b9faa998fd185f65c1371643678e4d58254add437edb764a08c5a98fb986/PyYAML-6.0.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:1e2120ef853f59c7419231f3bf4e7021f1b936f6ebd222406c3b60212205d2ee", size = 172040, upload-time = "2024-08-06T20:32:04.926Z" }, - { url = "https://files.pythonhosted.org/packages/ad/0c/c804f5f922a9a6563bab712d8dcc70251e8af811fce4524d57c2c0fd49a4/PyYAML-6.0.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5d225db5a45f21e78dd9358e58a98702a0302f2659a3c6cd320564b75b86f47c", size = 736829, upload-time = "2024-08-06T20:32:06.459Z" }, - { url = "https://files.pythonhosted.org/packages/51/16/6af8d6a6b210c8e54f1406a6b9481febf9c64a3109c541567e35a49aa2e7/PyYAML-6.0.2-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5ac9328ec4831237bec75defaf839f7d4564be1e6b25ac710bd1a96321cc8317", size = 764167, upload-time = "2024-08-06T20:32:08.338Z" }, - { url = "https://files.pythonhosted.org/packages/75/e4/2c27590dfc9992f73aabbeb9241ae20220bd9452df27483b6e56d3975cc5/PyYAML-6.0.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3ad2a3decf9aaba3d29c8f537ac4b243e36bef957511b4766cb0057d32b0be85", size = 762952, upload-time = "2024-08-06T20:32:14.124Z" }, - { url = "https://files.pythonhosted.org/packages/9b/97/ecc1abf4a823f5ac61941a9c00fe501b02ac3ab0e373c3857f7d4b83e2b6/PyYAML-6.0.2-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:ff3824dc5261f50c9b0dfb3be22b4567a6f938ccce4587b38952d85fd9e9afe4", size = 735301, upload-time = "2024-08-06T20:32:16.17Z" }, - { url = "https://files.pythonhosted.org/packages/45/73/0f49dacd6e82c9430e46f4a027baa4ca205e8b0a9dce1397f44edc23559d/PyYAML-6.0.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:797b4f722ffa07cc8d62053e4cff1486fa6dc094105d13fea7b1de7d8bf71c9e", size = 756638, upload-time = "2024-08-06T20:32:18.555Z" }, - { url = "https://files.pythonhosted.org/packages/22/5f/956f0f9fc65223a58fbc14459bf34b4cc48dec52e00535c79b8db361aabd/PyYAML-6.0.2-cp311-cp311-win32.whl", hash = "sha256:11d8f3dd2b9c1207dcaf2ee0bbbfd5991f571186ec9cc78427ba5bd32afae4b5", size = 143850, upload-time = "2024-08-06T20:32:19.889Z" }, - { url = "https://files.pythonhosted.org/packages/ed/23/8da0bbe2ab9dcdd11f4f4557ccaf95c10b9811b13ecced089d43ce59c3c8/PyYAML-6.0.2-cp311-cp311-win_amd64.whl", hash = "sha256:e10ce637b18caea04431ce14fabcf5c64a1c61ec9c56b071a4b7ca131ca52d44", size = 161980, upload-time = "2024-08-06T20:32:21.273Z" }, - { url = "https://files.pythonhosted.org/packages/86/0c/c581167fc46d6d6d7ddcfb8c843a4de25bdd27e4466938109ca68492292c/PyYAML-6.0.2-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:c70c95198c015b85feafc136515252a261a84561b7b1d51e3384e0655ddf25ab", size = 183873, upload-time = "2024-08-06T20:32:25.131Z" }, - { url = "https://files.pythonhosted.org/packages/a8/0c/38374f5bb272c051e2a69281d71cba6fdb983413e6758b84482905e29a5d/PyYAML-6.0.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:ce826d6ef20b1bc864f0a68340c8b3287705cae2f8b4b1d932177dcc76721725", size = 173302, upload-time = "2024-08-06T20:32:26.511Z" }, - { url = "https://files.pythonhosted.org/packages/c3/93/9916574aa8c00aa06bbac729972eb1071d002b8e158bd0e83a3b9a20a1f7/PyYAML-6.0.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1f71ea527786de97d1a0cc0eacd1defc0985dcf6b3f17bb77dcfc8c34bec4dc5", size = 739154, upload-time = "2024-08-06T20:32:28.363Z" }, - { url = "https://files.pythonhosted.org/packages/95/0f/b8938f1cbd09739c6da569d172531567dbcc9789e0029aa070856f123984/PyYAML-6.0.2-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:9b22676e8097e9e22e36d6b7bda33190d0d400f345f23d4065d48f4ca7ae0425", size = 766223, upload-time = "2024-08-06T20:32:30.058Z" }, - { url = "https://files.pythonhosted.org/packages/b9/2b/614b4752f2e127db5cc206abc23a8c19678e92b23c3db30fc86ab731d3bd/PyYAML-6.0.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:80bab7bfc629882493af4aa31a4cfa43a4c57c83813253626916b8c7ada83476", size = 767542, upload-time = "2024-08-06T20:32:31.881Z" }, - { url = "https://files.pythonhosted.org/packages/d4/00/dd137d5bcc7efea1836d6264f049359861cf548469d18da90cd8216cf05f/PyYAML-6.0.2-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:0833f8694549e586547b576dcfaba4a6b55b9e96098b36cdc7ebefe667dfed48", size = 731164, upload-time = "2024-08-06T20:32:37.083Z" }, - { url = "https://files.pythonhosted.org/packages/c9/1f/4f998c900485e5c0ef43838363ba4a9723ac0ad73a9dc42068b12aaba4e4/PyYAML-6.0.2-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:8b9c7197f7cb2738065c481a0461e50ad02f18c78cd75775628afb4d7137fb3b", size = 756611, upload-time = "2024-08-06T20:32:38.898Z" }, - { url = "https://files.pythonhosted.org/packages/df/d1/f5a275fdb252768b7a11ec63585bc38d0e87c9e05668a139fea92b80634c/PyYAML-6.0.2-cp312-cp312-win32.whl", hash = "sha256:ef6107725bd54b262d6dedcc2af448a266975032bc85ef0172c5f059da6325b4", size = 140591, upload-time = "2024-08-06T20:32:40.241Z" }, - { url = "https://files.pythonhosted.org/packages/0c/e8/4f648c598b17c3d06e8753d7d13d57542b30d56e6c2dedf9c331ae56312e/PyYAML-6.0.2-cp312-cp312-win_amd64.whl", hash = "sha256:7e7401d0de89a9a855c839bc697c079a4af81cf878373abd7dc625847d25cbd8", size = 156338, upload-time = "2024-08-06T20:32:41.93Z" }, -] - -[[package]] -name = "pyzmq" -version = "26.4.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "cffi", marker = "implementation_name == 'pypy'" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/b1/11/b9213d25230ac18a71b39b3723494e57adebe36e066397b961657b3b41c1/pyzmq-26.4.0.tar.gz", hash = "sha256:4bd13f85f80962f91a651a7356fe0472791a5f7a92f227822b5acf44795c626d", size = 278293, upload-time = "2025-04-04T12:05:44.049Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/32/6d/234e3b0aa82fd0290b1896e9992f56bdddf1f97266110be54d0177a9d2d9/pyzmq-26.4.0-cp311-cp311-macosx_10_15_universal2.whl", hash = "sha256:bfcf82644c9b45ddd7cd2a041f3ff8dce4a0904429b74d73a439e8cab1bd9e54", size = 1339723, upload-time = "2025-04-04T12:03:24.358Z" }, - { url = "https://files.pythonhosted.org/packages/4f/11/6d561efe29ad83f7149a7cd48e498e539ed09019c6cd7ecc73f4cc725028/pyzmq-26.4.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e9bcae3979b2654d5289d3490742378b2f3ce804b0b5fd42036074e2bf35b030", size = 672645, upload-time = "2025-04-04T12:03:25.693Z" }, - { url = "https://files.pythonhosted.org/packages/19/fd/81bfe3e23f418644660bad1a90f0d22f0b3eebe33dd65a79385530bceb3d/pyzmq-26.4.0-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ccdff8ac4246b6fb60dcf3982dfaeeff5dd04f36051fe0632748fc0aa0679c01", size = 910133, upload-time = "2025-04-04T12:03:27.625Z" }, - { url = "https://files.pythonhosted.org/packages/97/68/321b9c775595ea3df832a9516252b653fe32818db66fdc8fa31c9b9fce37/pyzmq-26.4.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4550af385b442dc2d55ab7717837812799d3674cb12f9a3aa897611839c18e9e", size = 867428, upload-time = "2025-04-04T12:03:29.004Z" }, - { url = "https://files.pythonhosted.org/packages/4e/6e/159cbf2055ef36aa2aa297e01b24523176e5b48ead283c23a94179fb2ba2/pyzmq-26.4.0-cp311-cp311-manylinux_2_28_x86_64.whl", hash = "sha256:2f9f7ffe9db1187a253fca95191854b3fda24696f086e8789d1d449308a34b88", size = 862409, upload-time = "2025-04-04T12:03:31.032Z" }, - { url = "https://files.pythonhosted.org/packages/05/1c/45fb8db7be5a7d0cadea1070a9cbded5199a2d578de2208197e592f219bd/pyzmq-26.4.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:3709c9ff7ba61589b7372923fd82b99a81932b592a5c7f1a24147c91da9a68d6", size = 1205007, upload-time = "2025-04-04T12:03:32.687Z" }, - { url = "https://files.pythonhosted.org/packages/f8/fa/658c7f583af6498b463f2fa600f34e298e1b330886f82f1feba0dc2dd6c3/pyzmq-26.4.0-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:f8f3c30fb2d26ae5ce36b59768ba60fb72507ea9efc72f8f69fa088450cff1df", size = 1514599, upload-time = "2025-04-04T12:03:34.084Z" }, - { url = "https://files.pythonhosted.org/packages/4d/d7/44d641522353ce0a2bbd150379cb5ec32f7120944e6bfba4846586945658/pyzmq-26.4.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:382a4a48c8080e273427fc692037e3f7d2851959ffe40864f2db32646eeb3cef", size = 1414546, upload-time = "2025-04-04T12:03:35.478Z" }, - { url = "https://files.pythonhosted.org/packages/72/76/c8ed7263218b3d1e9bce07b9058502024188bd52cc0b0a267a9513b431fc/pyzmq-26.4.0-cp311-cp311-win32.whl", hash = "sha256:d56aad0517d4c09e3b4f15adebba8f6372c5102c27742a5bdbfc74a7dceb8fca", size = 579247, upload-time = "2025-04-04T12:03:36.846Z" }, - { url = "https://files.pythonhosted.org/packages/c3/d0/2d9abfa2571a0b1a67c0ada79a8aa1ba1cce57992d80f771abcdf99bb32c/pyzmq-26.4.0-cp311-cp311-win_amd64.whl", hash = "sha256:963977ac8baed7058c1e126014f3fe58b3773f45c78cce7af5c26c09b6823896", size = 644727, upload-time = "2025-04-04T12:03:38.578Z" }, - { url = "https://files.pythonhosted.org/packages/0d/d1/c8ad82393be6ccedfc3c9f3adb07f8f3976e3c4802640fe3f71441941e70/pyzmq-26.4.0-cp311-cp311-win_arm64.whl", hash = "sha256:c0c8e8cadc81e44cc5088fcd53b9b3b4ce9344815f6c4a03aec653509296fae3", size = 559942, upload-time = "2025-04-04T12:03:40.143Z" }, - { url = "https://files.pythonhosted.org/packages/10/44/a778555ebfdf6c7fc00816aad12d185d10a74d975800341b1bc36bad1187/pyzmq-26.4.0-cp312-cp312-macosx_10_15_universal2.whl", hash = "sha256:5227cb8da4b6f68acfd48d20c588197fd67745c278827d5238c707daf579227b", size = 1341586, upload-time = "2025-04-04T12:03:41.954Z" }, - { url = "https://files.pythonhosted.org/packages/9c/4f/f3a58dc69ac757e5103be3bd41fb78721a5e17da7cc617ddb56d973a365c/pyzmq-26.4.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e1c07a7fa7f7ba86554a2b1bef198c9fed570c08ee062fd2fd6a4dcacd45f905", size = 665880, upload-time = "2025-04-04T12:03:43.45Z" }, - { url = "https://files.pythonhosted.org/packages/fe/45/50230bcfb3ae5cb98bee683b6edeba1919f2565d7cc1851d3c38e2260795/pyzmq-26.4.0-cp312-cp312-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ae775fa83f52f52de73183f7ef5395186f7105d5ed65b1ae65ba27cb1260de2b", size = 902216, upload-time = "2025-04-04T12:03:45.572Z" }, - { url = "https://files.pythonhosted.org/packages/41/59/56bbdc5689be5e13727491ad2ba5efd7cd564365750514f9bc8f212eef82/pyzmq-26.4.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:66c760d0226ebd52f1e6b644a9e839b5db1e107a23f2fcd46ec0569a4fdd4e63", size = 859814, upload-time = "2025-04-04T12:03:47.188Z" }, - { url = "https://files.pythonhosted.org/packages/81/b1/57db58cfc8af592ce94f40649bd1804369c05b2190e4cbc0a2dad572baeb/pyzmq-26.4.0-cp312-cp312-manylinux_2_28_x86_64.whl", hash = "sha256:ef8c6ecc1d520debc147173eaa3765d53f06cd8dbe7bd377064cdbc53ab456f5", size = 855889, upload-time = "2025-04-04T12:03:49.223Z" }, - { url = "https://files.pythonhosted.org/packages/e8/92/47542e629cbac8f221c230a6d0f38dd3d9cff9f6f589ed45fdf572ffd726/pyzmq-26.4.0-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:3150ef4084e163dec29ae667b10d96aad309b668fac6810c9e8c27cf543d6e0b", size = 1197153, upload-time = "2025-04-04T12:03:50.591Z" }, - { url = "https://files.pythonhosted.org/packages/07/e5/b10a979d1d565d54410afc87499b16c96b4a181af46e7645ab4831b1088c/pyzmq-26.4.0-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:4448c9e55bf8329fa1dcedd32f661bf611214fa70c8e02fee4347bc589d39a84", size = 1507352, upload-time = "2025-04-04T12:03:52.473Z" }, - { url = "https://files.pythonhosted.org/packages/ab/58/5a23db84507ab9c01c04b1232a7a763be66e992aa2e66498521bbbc72a71/pyzmq-26.4.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:e07dde3647afb084d985310d067a3efa6efad0621ee10826f2cb2f9a31b89d2f", size = 1406834, upload-time = "2025-04-04T12:03:54Z" }, - { url = "https://files.pythonhosted.org/packages/22/74/aaa837b331580c13b79ac39396601fb361454ee184ca85e8861914769b99/pyzmq-26.4.0-cp312-cp312-win32.whl", hash = "sha256:ba034a32ecf9af72adfa5ee383ad0fd4f4e38cdb62b13624278ef768fe5b5b44", size = 577992, upload-time = "2025-04-04T12:03:55.815Z" }, - { url = "https://files.pythonhosted.org/packages/30/0f/55f8c02c182856743b82dde46b2dc3e314edda7f1098c12a8227eeda0833/pyzmq-26.4.0-cp312-cp312-win_amd64.whl", hash = "sha256:056a97aab4064f526ecb32f4343917a4022a5d9efb6b9df990ff72e1879e40be", size = 640466, upload-time = "2025-04-04T12:03:57.231Z" }, - { url = "https://files.pythonhosted.org/packages/e4/29/073779afc3ef6f830b8de95026ef20b2d1ec22d0324d767748d806e57379/pyzmq-26.4.0-cp312-cp312-win_arm64.whl", hash = "sha256:2f23c750e485ce1eb639dbd576d27d168595908aa2d60b149e2d9e34c9df40e0", size = 556342, upload-time = "2025-04-04T12:03:59.218Z" }, - { url = "https://files.pythonhosted.org/packages/04/52/a70fcd5592715702248306d8e1729c10742c2eac44529984413b05c68658/pyzmq-26.4.0-pp311-pypy311_pp73-macosx_10_15_x86_64.whl", hash = "sha256:4478b14cb54a805088299c25a79f27eaf530564a7a4f72bf432a040042b554eb", size = 834405, upload-time = "2025-04-04T12:05:13.3Z" }, - { url = "https://files.pythonhosted.org/packages/25/f9/1a03f1accff16b3af1a6fa22cbf7ced074776abbf688b2e9cb4629700c62/pyzmq-26.4.0-pp311-pypy311_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8a28ac29c60e4ba84b5f58605ace8ad495414a724fe7aceb7cf06cd0598d04e1", size = 569578, upload-time = "2025-04-04T12:05:15.36Z" }, - { url = "https://files.pythonhosted.org/packages/76/0c/3a633acd762aa6655fcb71fa841907eae0ab1e8582ff494b137266de341d/pyzmq-26.4.0-pp311-pypy311_pp73-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:43b03c1ceea27c6520124f4fb2ba9c647409b9abdf9a62388117148a90419494", size = 798248, upload-time = "2025-04-04T12:05:17.376Z" }, - { url = "https://files.pythonhosted.org/packages/cd/cc/6c99c84aa60ac1cc56747bed6be8ce6305b9b861d7475772e7a25ce019d3/pyzmq-26.4.0-pp311-pypy311_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7731abd23a782851426d4e37deb2057bf9410848a4459b5ede4fe89342e687a9", size = 756757, upload-time = "2025-04-04T12:05:19.19Z" }, - { url = "https://files.pythonhosted.org/packages/13/9c/d8073bd898eb896e94c679abe82e47506e2b750eb261cf6010ced869797c/pyzmq-26.4.0-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:a222ad02fbe80166b0526c038776e8042cd4e5f0dec1489a006a1df47e9040e0", size = 555371, upload-time = "2025-04-04T12:05:20.702Z" }, -] - -[[package]] -name = "quartodoc" -version = "0.9.1" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "black" }, - { name = "click" }, - { name = "griffe" }, - { name = "importlib-metadata" }, - { name = "importlib-resources" }, - { name = "plum-dispatch" }, - { name = "pydantic" }, - { name = "pyyaml" }, - { name = "requests" }, - { name = "sphobjinv" }, - { name = "tabulate" }, - { name = "typing-extensions" }, - { name = "watchdog" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/f4/ad/1bdc6745d0d0527da0a2f30a235850873e98442a2c1afdd67ac7e164e0c4/quartodoc-0.9.1.tar.gz", hash = "sha256:418d9ff0f2d4481a87e926e3a3e5bc31efbe556c7f36912aa0a3f716c0eafa9c", size = 772465, upload-time = "2024-11-08T22:21:36.646Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/0e/47/de4c28e2002653226de3e34c9a3e989619796e5f0fe771284c570a016cec/quartodoc-0.9.1-py3-none-any.whl", hash = "sha256:78345002f75f086be6e1b1ccf3b4e3ada2fa3affb8a8fc0dbdb37890a5da03fa", size = 84275, upload-time = "2024-11-08T22:21:33.794Z" }, -] - -[[package]] -name = "referencing" -version = "0.36.2" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "attrs" }, - { name = "rpds-py" }, - { name = "typing-extensions" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/2f/db/98b5c277be99dd18bfd91dd04e1b759cad18d1a338188c936e92f921c7e2/referencing-0.36.2.tar.gz", hash = "sha256:df2e89862cd09deabbdba16944cc3f10feb6b3e6f18e902f7cc25609a34775aa", size = 74744, upload-time = "2025-01-25T08:48:16.138Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/c1/b1/3baf80dc6d2b7bc27a95a67752d0208e410351e3feb4eb78de5f77454d8d/referencing-0.36.2-py3-none-any.whl", hash = "sha256:e8699adbbf8b5c7de96d8ffa0eb5c158b3beafce084968e2ea8bb08c6794dcd0", size = 26775, upload-time = "2025-01-25T08:48:14.241Z" }, -] - -[[package]] -name = "requests" -version = "2.32.3" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "certifi" }, - { name = "charset-normalizer" }, - { name = "idna" }, - { name = "urllib3" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/63/70/2bf7780ad2d390a8d301ad0b550f1581eadbd9a20f896afe06353c2a2913/requests-2.32.3.tar.gz", hash = "sha256:55365417734eb18255590a9ff9eb97e9e1da868d4ccd6402399eaf68af20a760", size = 131218, upload-time = "2024-05-29T15:37:49.536Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/f9/9b/335f9764261e915ed497fcdeb11df5dfd6f7bf257d4a6a2a686d80da4d54/requests-2.32.3-py3-none-any.whl", hash = "sha256:70761cfe03c773ceb22aa2f671b4757976145175cdfca038c02654d061d6dcc6", size = 64928, upload-time = "2024-05-29T15:37:47.027Z" }, -] - -[[package]] -name = "rfc3339-validator" -version = "0.1.4" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "six" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/28/ea/a9387748e2d111c3c2b275ba970b735e04e15cdb1eb30693b6b5708c4dbd/rfc3339_validator-0.1.4.tar.gz", hash = "sha256:138a2abdf93304ad60530167e51d2dfb9549521a836871b88d7f4695d0022f6b", size = 5513, upload-time = "2021-05-12T16:37:54.178Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/7b/44/4e421b96b67b2daff264473f7465db72fbdf36a07e05494f50300cc7b0c6/rfc3339_validator-0.1.4-py2.py3-none-any.whl", hash = "sha256:24f6ec1eda14ef823da9e36ec7113124b39c04d50a4d3d3a3c2859577e7791fa", size = 3490, upload-time = "2021-05-12T16:37:52.536Z" }, -] - -[[package]] -name = "rfc3986-validator" -version = "0.1.1" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/da/88/f270de456dd7d11dcc808abfa291ecdd3f45ff44e3b549ffa01b126464d0/rfc3986_validator-0.1.1.tar.gz", hash = "sha256:3d44bde7921b3b9ec3ae4e3adca370438eccebc676456449b145d533b240d055", size = 6760, upload-time = "2019-10-28T16:00:19.144Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/9e/51/17023c0f8f1869d8806b979a2bffa3f861f26a3f1a66b094288323fba52f/rfc3986_validator-0.1.1-py2.py3-none-any.whl", hash = "sha256:2f235c432ef459970b4306369336b9d5dbdda31b510ca1e327636e01f528bfa9", size = 4242, upload-time = "2019-10-28T16:00:13.976Z" }, -] - -[[package]] -name = "rich" -version = "14.0.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "markdown-it-py" }, - { name = "pygments" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/a1/53/830aa4c3066a8ab0ae9a9955976fb770fe9c6102117c8ec4ab3ea62d89e8/rich-14.0.0.tar.gz", hash = "sha256:82f1bc23a6a21ebca4ae0c45af9bdbc492ed20231dcb63f297d6d1021a9d5725", size = 224078, upload-time = "2025-03-30T14:15:14.23Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/0d/9b/63f4c7ebc259242c89b3acafdb37b41d1185c07ff0011164674e9076b491/rich-14.0.0-py3-none-any.whl", hash = "sha256:1c9491e1951aac09caffd42f448ee3d04e58923ffe14993f6e83068dc395d7e0", size = 243229, upload-time = "2025-03-30T14:15:12.283Z" }, -] - -[[package]] -name = "rpds-py" -version = "0.24.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/0b/b3/52b213298a0ba7097c7ea96bee95e1947aa84cc816d48cebb539770cdf41/rpds_py-0.24.0.tar.gz", hash = "sha256:772cc1b2cd963e7e17e6cc55fe0371fb9c704d63e44cacec7b9b7f523b78919e", size = 26863, upload-time = "2025-03-26T14:56:01.518Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/80/e6/c1458bbfb257448fdb2528071f1f4e19e26798ed5ef6d47d7aab0cb69661/rpds_py-0.24.0-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:2d3ee4615df36ab8eb16c2507b11e764dcc11fd350bbf4da16d09cda11fcedef", size = 377679, upload-time = "2025-03-26T14:53:06.557Z" }, - { url = "https://files.pythonhosted.org/packages/dd/26/ea4181ef78f58b2c167548c6a833d7dc22408e5b3b181bda9dda440bb92d/rpds_py-0.24.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:e13ae74a8a3a0c2f22f450f773e35f893484fcfacb00bb4344a7e0f4f48e1f97", size = 362571, upload-time = "2025-03-26T14:53:08.439Z" }, - { url = "https://files.pythonhosted.org/packages/56/fa/1ec54dd492c64c280a2249a047fc3369e2789dc474eac20445ebfc72934b/rpds_py-0.24.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cf86f72d705fc2ef776bb7dd9e5fbba79d7e1f3e258bf9377f8204ad0fc1c51e", size = 388012, upload-time = "2025-03-26T14:53:10.314Z" }, - { url = "https://files.pythonhosted.org/packages/3a/be/bad8b0e0f7e58ef4973bb75e91c472a7d51da1977ed43b09989264bf065c/rpds_py-0.24.0-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:c43583ea8517ed2e780a345dd9960896afc1327e8cf3ac8239c167530397440d", size = 394730, upload-time = "2025-03-26T14:53:11.953Z" }, - { url = "https://files.pythonhosted.org/packages/35/56/ab417fc90c21826df048fc16e55316ac40876e4b790104ececcbce813d8f/rpds_py-0.24.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:4cd031e63bc5f05bdcda120646a0d32f6d729486d0067f09d79c8db5368f4586", size = 448264, upload-time = "2025-03-26T14:53:13.42Z" }, - { url = "https://files.pythonhosted.org/packages/b6/75/4c63862d5c05408589196c8440a35a14ea4ae337fa70ded1f03638373f06/rpds_py-0.24.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:34d90ad8c045df9a4259c47d2e16a3f21fdb396665c94520dbfe8766e62187a4", size = 446813, upload-time = "2025-03-26T14:53:15.036Z" }, - { url = "https://files.pythonhosted.org/packages/e7/0c/91cf17dffa9a38835869797a9f041056091ebba6a53963d3641207e3d467/rpds_py-0.24.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e838bf2bb0b91ee67bf2b889a1a841e5ecac06dd7a2b1ef4e6151e2ce155c7ae", size = 389438, upload-time = "2025-03-26T14:53:17.037Z" }, - { url = "https://files.pythonhosted.org/packages/1b/b0/60e6c72727c978276e02851819f3986bc40668f115be72c1bc4d922c950f/rpds_py-0.24.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:04ecf5c1ff4d589987b4d9882872f80ba13da7d42427234fce8f22efb43133bc", size = 420416, upload-time = "2025-03-26T14:53:18.671Z" }, - { url = "https://files.pythonhosted.org/packages/a1/d7/f46f85b9f863fb59fd3c534b5c874c48bee86b19e93423b9da8784605415/rpds_py-0.24.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:630d3d8ea77eabd6cbcd2ea712e1c5cecb5b558d39547ac988351195db433f6c", size = 565236, upload-time = "2025-03-26T14:53:20.357Z" }, - { url = "https://files.pythonhosted.org/packages/2a/d1/1467620ded6dd70afc45ec822cdf8dfe7139537780d1f3905de143deb6fd/rpds_py-0.24.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:ebcb786b9ff30b994d5969213a8430cbb984cdd7ea9fd6df06663194bd3c450c", size = 592016, upload-time = "2025-03-26T14:53:22.216Z" }, - { url = "https://files.pythonhosted.org/packages/5d/13/fb1ded2e6adfaa0c0833106c42feb290973f665300f4facd5bf5d7891d9c/rpds_py-0.24.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:174e46569968ddbbeb8a806d9922f17cd2b524aa753b468f35b97ff9c19cb718", size = 560123, upload-time = "2025-03-26T14:53:23.733Z" }, - { url = "https://files.pythonhosted.org/packages/1e/df/09fc1857ac7cc2eb16465a7199c314cbce7edde53c8ef21d615410d7335b/rpds_py-0.24.0-cp311-cp311-win32.whl", hash = "sha256:5ef877fa3bbfb40b388a5ae1cb00636a624690dcb9a29a65267054c9ea86d88a", size = 222256, upload-time = "2025-03-26T14:53:25.217Z" }, - { url = "https://files.pythonhosted.org/packages/ff/25/939b40bc4d54bf910e5ee60fb5af99262c92458f4948239e8c06b0b750e7/rpds_py-0.24.0-cp311-cp311-win_amd64.whl", hash = "sha256:e274f62cbd274359eff63e5c7e7274c913e8e09620f6a57aae66744b3df046d6", size = 234718, upload-time = "2025-03-26T14:53:26.631Z" }, - { url = "https://files.pythonhosted.org/packages/1a/e0/1c55f4a3be5f1ca1a4fd1f3ff1504a1478c1ed48d84de24574c4fa87e921/rpds_py-0.24.0-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:d8551e733626afec514b5d15befabea0dd70a343a9f23322860c4f16a9430205", size = 366945, upload-time = "2025-03-26T14:53:28.149Z" }, - { url = "https://files.pythonhosted.org/packages/39/1b/a3501574fbf29118164314dbc800d568b8c1c7b3258b505360e8abb3902c/rpds_py-0.24.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:0e374c0ce0ca82e5b67cd61fb964077d40ec177dd2c4eda67dba130de09085c7", size = 351935, upload-time = "2025-03-26T14:53:29.684Z" }, - { url = "https://files.pythonhosted.org/packages/dc/47/77d3d71c55f6a374edde29f1aca0b2e547325ed00a9da820cabbc9497d2b/rpds_py-0.24.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d69d003296df4840bd445a5d15fa5b6ff6ac40496f956a221c4d1f6f7b4bc4d9", size = 390817, upload-time = "2025-03-26T14:53:31.177Z" }, - { url = "https://files.pythonhosted.org/packages/4e/ec/1e336ee27484379e19c7f9cc170f4217c608aee406d3ae3a2e45336bff36/rpds_py-0.24.0-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:8212ff58ac6dfde49946bea57474a386cca3f7706fc72c25b772b9ca4af6b79e", size = 401983, upload-time = "2025-03-26T14:53:33.163Z" }, - { url = "https://files.pythonhosted.org/packages/07/f8/39b65cbc272c635eaea6d393c2ad1ccc81c39eca2db6723a0ca4b2108fce/rpds_py-0.24.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:528927e63a70b4d5f3f5ccc1fa988a35456eb5d15f804d276709c33fc2f19bda", size = 451719, upload-time = "2025-03-26T14:53:34.721Z" }, - { url = "https://files.pythonhosted.org/packages/32/05/05c2b27dd9c30432f31738afed0300659cb9415db0ff7429b05dfb09bbde/rpds_py-0.24.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a824d2c7a703ba6daaca848f9c3d5cb93af0505be505de70e7e66829affd676e", size = 442546, upload-time = "2025-03-26T14:53:36.26Z" }, - { url = "https://files.pythonhosted.org/packages/7d/e0/19383c8b5d509bd741532a47821c3e96acf4543d0832beba41b4434bcc49/rpds_py-0.24.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:44d51febb7a114293ffd56c6cf4736cb31cd68c0fddd6aa303ed09ea5a48e029", size = 393695, upload-time = "2025-03-26T14:53:37.728Z" }, - { url = "https://files.pythonhosted.org/packages/9d/15/39f14e96d94981d0275715ae8ea564772237f3fa89bc3c21e24de934f2c7/rpds_py-0.24.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:3fab5f4a2c64a8fb64fc13b3d139848817a64d467dd6ed60dcdd6b479e7febc9", size = 427218, upload-time = "2025-03-26T14:53:39.326Z" }, - { url = "https://files.pythonhosted.org/packages/22/b9/12da7124905a680f690da7a9de6f11de770b5e359f5649972f7181c8bf51/rpds_py-0.24.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:9be4f99bee42ac107870c61dfdb294d912bf81c3c6d45538aad7aecab468b6b7", size = 568062, upload-time = "2025-03-26T14:53:40.885Z" }, - { url = "https://files.pythonhosted.org/packages/88/17/75229017a2143d915f6f803721a6d721eca24f2659c5718a538afa276b4f/rpds_py-0.24.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:564c96b6076a98215af52f55efa90d8419cc2ef45d99e314fddefe816bc24f91", size = 596262, upload-time = "2025-03-26T14:53:42.544Z" }, - { url = "https://files.pythonhosted.org/packages/aa/64/8e8a1d8bd1b6b638d6acb6d41ab2cec7f2067a5b8b4c9175703875159a7c/rpds_py-0.24.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:75a810b7664c17f24bf2ffd7f92416c00ec84b49bb68e6a0d93e542406336b56", size = 564306, upload-time = "2025-03-26T14:53:44.2Z" }, - { url = "https://files.pythonhosted.org/packages/68/1c/a7eac8d8ed8cb234a9b1064647824c387753343c3fab6ed7c83481ed0be7/rpds_py-0.24.0-cp312-cp312-win32.whl", hash = "sha256:f6016bd950be4dcd047b7475fdf55fb1e1f59fc7403f387be0e8123e4a576d30", size = 224281, upload-time = "2025-03-26T14:53:45.769Z" }, - { url = "https://files.pythonhosted.org/packages/bb/46/b8b5424d1d21f2f2f3f2d468660085318d4f74a8df8289e3dd6ad224d488/rpds_py-0.24.0-cp312-cp312-win_amd64.whl", hash = "sha256:998c01b8e71cf051c28f5d6f1187abbdf5cf45fc0efce5da6c06447cba997034", size = 239719, upload-time = "2025-03-26T14:53:47.187Z" }, - { url = "https://files.pythonhosted.org/packages/65/53/40bcc246a8354530d51a26d2b5b9afd1deacfb0d79e67295cc74df362f52/rpds_py-0.24.0-pp311-pypy311_pp73-macosx_10_12_x86_64.whl", hash = "sha256:f9e0057a509e096e47c87f753136c9b10d7a91842d8042c2ee6866899a717c0d", size = 378386, upload-time = "2025-03-26T14:55:20.381Z" }, - { url = "https://files.pythonhosted.org/packages/80/b0/5ea97dd2f53e3618560aa1f9674e896e63dff95a9b796879a201bc4c1f00/rpds_py-0.24.0-pp311-pypy311_pp73-macosx_11_0_arm64.whl", hash = "sha256:d6e109a454412ab82979c5b1b3aee0604eca4bbf9a02693bb9df027af2bfa91a", size = 363440, upload-time = "2025-03-26T14:55:22.121Z" }, - { url = "https://files.pythonhosted.org/packages/57/9d/259b6eada6f747cdd60c9a5eb3efab15f6704c182547149926c38e5bd0d5/rpds_py-0.24.0-pp311-pypy311_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fc1c892b1ec1f8cbd5da8de287577b455e388d9c328ad592eabbdcb6fc93bee5", size = 388816, upload-time = "2025-03-26T14:55:23.737Z" }, - { url = "https://files.pythonhosted.org/packages/94/c1/faafc7183712f89f4b7620c3c15979ada13df137d35ef3011ae83e93b005/rpds_py-0.24.0-pp311-pypy311_pp73-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:9c39438c55983d48f4bb3487734d040e22dad200dab22c41e331cee145e7a50d", size = 395058, upload-time = "2025-03-26T14:55:25.468Z" }, - { url = "https://files.pythonhosted.org/packages/6c/96/d7fa9d2a7b7604a61da201cc0306a355006254942093779d7121c64700ce/rpds_py-0.24.0-pp311-pypy311_pp73-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9d7e8ce990ae17dda686f7e82fd41a055c668e13ddcf058e7fb5e9da20b57793", size = 448692, upload-time = "2025-03-26T14:55:27.535Z" }, - { url = "https://files.pythonhosted.org/packages/96/37/a3146c6eebc65d6d8c96cc5ffdcdb6af2987412c789004213227fbe52467/rpds_py-0.24.0-pp311-pypy311_pp73-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:9ea7f4174d2e4194289cb0c4e172d83e79a6404297ff95f2875cf9ac9bced8ba", size = 446462, upload-time = "2025-03-26T14:55:29.299Z" }, - { url = "https://files.pythonhosted.org/packages/1f/13/6481dfd9ac7de43acdaaa416e3a7da40bc4bb8f5c6ca85e794100aa54596/rpds_py-0.24.0-pp311-pypy311_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bb2954155bb8f63bb19d56d80e5e5320b61d71084617ed89efedb861a684baea", size = 390460, upload-time = "2025-03-26T14:55:31.017Z" }, - { url = "https://files.pythonhosted.org/packages/61/e1/37e36bce65e109543cc4ff8d23206908649023549604fa2e7fbeba5342f7/rpds_py-0.24.0-pp311-pypy311_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:04f2b712a2206e13800a8136b07aaedc23af3facab84918e7aa89e4be0260032", size = 421609, upload-time = "2025-03-26T14:55:32.84Z" }, - { url = "https://files.pythonhosted.org/packages/20/dd/1f1a923d6cd798b8582176aca8a0784676f1a0449fb6f07fce6ac1cdbfb6/rpds_py-0.24.0-pp311-pypy311_pp73-musllinux_1_2_aarch64.whl", hash = "sha256:eda5c1e2a715a4cbbca2d6d304988460942551e4e5e3b7457b50943cd741626d", size = 565818, upload-time = "2025-03-26T14:55:34.538Z" }, - { url = "https://files.pythonhosted.org/packages/56/ec/d8da6df6a1eb3a418944a17b1cb38dd430b9e5a2e972eafd2b06f10c7c46/rpds_py-0.24.0-pp311-pypy311_pp73-musllinux_1_2_i686.whl", hash = "sha256:9abc80fe8c1f87218db116016de575a7998ab1629078c90840e8d11ab423ee25", size = 592627, upload-time = "2025-03-26T14:55:36.26Z" }, - { url = "https://files.pythonhosted.org/packages/b3/14/c492b9c7d5dd133e13f211ddea6bb9870f99e4f73932f11aa00bc09a9be9/rpds_py-0.24.0-pp311-pypy311_pp73-musllinux_1_2_x86_64.whl", hash = "sha256:6a727fd083009bc83eb83d6950f0c32b3c94c8b80a9b667c87f4bd1274ca30ba", size = 560885, upload-time = "2025-03-26T14:55:38Z" }, -] - -[[package]] -name = "ruff" -version = "0.9.9" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/6f/c3/418441a8170e8d53d05c0b9dad69760dbc7b8a12c10dbe6db1e1205d2377/ruff-0.9.9.tar.gz", hash = "sha256:0062ed13f22173e85f8f7056f9a24016e692efeea8704d1a5e8011b8aa850933", size = 3717448, upload-time = "2025-02-28T10:16:42.209Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/bc/c3/2c4afa9ba467555d074b146d9aed0633a56ccdb900839fb008295d037b89/ruff-0.9.9-py3-none-linux_armv6l.whl", hash = "sha256:628abb5ea10345e53dff55b167595a159d3e174d6720bf19761f5e467e68d367", size = 10027252, upload-time = "2025-02-28T10:15:44.182Z" }, - { url = "https://files.pythonhosted.org/packages/33/d1/439e58487cf9eac26378332e25e7d5ade4b800ce1eec7dc2cfc9b0d7ca96/ruff-0.9.9-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:b6cd1428e834b35d7493354723543b28cc11dc14d1ce19b685f6e68e07c05ec7", size = 10840721, upload-time = "2025-02-28T10:15:49.396Z" }, - { url = "https://files.pythonhosted.org/packages/50/44/fead822c38281ba0122f1b76b460488a175a9bd48b130650a6fb6dbcbcf9/ruff-0.9.9-py3-none-macosx_11_0_arm64.whl", hash = "sha256:5ee162652869120ad260670706f3cd36cd3f32b0c651f02b6da142652c54941d", size = 10161439, upload-time = "2025-02-28T10:15:52.522Z" }, - { url = "https://files.pythonhosted.org/packages/11/ae/d404a2ab8e61ddf6342e09cc6b7f7846cce6b243e45c2007dbe0ca928a5d/ruff-0.9.9-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3aa0f6b75082c9be1ec5a1db78c6d4b02e2375c3068438241dc19c7c306cc61a", size = 10336264, upload-time = "2025-02-28T10:15:56.9Z" }, - { url = "https://files.pythonhosted.org/packages/6a/4e/7c268aa7d84cd709fb6f046b8972313142cffb40dfff1d2515c5e6288d54/ruff-0.9.9-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:584cc66e89fb5f80f84b05133dd677a17cdd86901d6479712c96597a3f28e7fe", size = 9908774, upload-time = "2025-02-28T10:15:59.612Z" }, - { url = "https://files.pythonhosted.org/packages/cc/26/c618a878367ef1b76270fd027ca93692657d3f6122b84ba48911ef5f2edc/ruff-0.9.9-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:abf3369325761a35aba75cd5c55ba1b5eb17d772f12ab168fbfac54be85cf18c", size = 11428127, upload-time = "2025-02-28T10:16:02.94Z" }, - { url = "https://files.pythonhosted.org/packages/d7/9a/c5588a93d9bfed29f565baf193fe802fa676a0c837938137ea6cf0576d8c/ruff-0.9.9-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:3403a53a32a90ce929aa2f758542aca9234befa133e29f4933dcef28a24317be", size = 12133187, upload-time = "2025-02-28T10:16:05.632Z" }, - { url = "https://files.pythonhosted.org/packages/3e/ff/e7980a7704a60905ed7e156a8d73f604c846d9bd87deda9cabfa6cba073a/ruff-0.9.9-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:18454e7fa4e4d72cffe28a37cf6a73cb2594f81ec9f4eca31a0aaa9ccdfb1590", size = 11602937, upload-time = "2025-02-28T10:16:10.489Z" }, - { url = "https://files.pythonhosted.org/packages/24/78/3690444ad9e3cab5c11abe56554c35f005b51d1d118b429765249095269f/ruff-0.9.9-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:0fadfe2c88724c9617339f62319ed40dcdadadf2888d5afb88bf3adee7b35bfb", size = 13771698, upload-time = "2025-02-28T10:16:13.358Z" }, - { url = "https://files.pythonhosted.org/packages/6e/bf/e477c2faf86abe3988e0b5fd22a7f3520e820b2ee335131aca2e16120038/ruff-0.9.9-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6df104d08c442a1aabcfd254279b8cc1e2cbf41a605aa3e26610ba1ec4acf0b0", size = 11249026, upload-time = "2025-02-28T10:16:16.154Z" }, - { url = "https://files.pythonhosted.org/packages/f7/82/cdaffd59e5a8cb5b14c408c73d7a555a577cf6645faaf83e52fe99521715/ruff-0.9.9-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:d7c62939daf5b2a15af48abbd23bea1efdd38c312d6e7c4cedf5a24e03207e17", size = 10220432, upload-time = "2025-02-28T10:16:18.798Z" }, - { url = "https://files.pythonhosted.org/packages/fe/a4/2507d0026225efa5d4412b6e294dfe54725a78652a5c7e29e6bd0fc492f3/ruff-0.9.9-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:9494ba82a37a4b81b6a798076e4a3251c13243fc37967e998efe4cce58c8a8d1", size = 9874602, upload-time = "2025-02-28T10:16:21.903Z" }, - { url = "https://files.pythonhosted.org/packages/d5/be/f3aab1813846b476c4bcffe052d232244979c3cd99d751c17afb530ca8e4/ruff-0.9.9-py3-none-musllinux_1_2_i686.whl", hash = "sha256:4efd7a96ed6d36ef011ae798bf794c5501a514be369296c672dab7921087fa57", size = 10851212, upload-time = "2025-02-28T10:16:24.793Z" }, - { url = "https://files.pythonhosted.org/packages/8b/45/8e5fd559bea0d2f57c4e12bf197a2fade2fac465aa518284f157dfbca92b/ruff-0.9.9-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:ab90a7944c5a1296f3ecb08d1cbf8c2da34c7e68114b1271a431a3ad30cb660e", size = 11327490, upload-time = "2025-02-28T10:16:27.654Z" }, - { url = "https://files.pythonhosted.org/packages/42/55/e6c90f13880aeef327746052907e7e930681f26a164fe130ddac28b08269/ruff-0.9.9-py3-none-win32.whl", hash = "sha256:6b4c376d929c25ecd6d87e182a230fa4377b8e5125a4ff52d506ee8c087153c1", size = 10227912, upload-time = "2025-02-28T10:16:31.55Z" }, - { url = "https://files.pythonhosted.org/packages/35/b2/da925693cb82a1208aa34966c0f36cb222baca94e729dd22a587bc22d0f3/ruff-0.9.9-py3-none-win_amd64.whl", hash = "sha256:837982ea24091d4c1700ddb2f63b7070e5baec508e43b01de013dc7eff974ff1", size = 11355632, upload-time = "2025-02-28T10:16:36.144Z" }, - { url = "https://files.pythonhosted.org/packages/31/d8/de873d1c1b020d668d8ec9855d390764cb90cf8f6486c0983da52be8b7b7/ruff-0.9.9-py3-none-win_arm64.whl", hash = "sha256:3ac78f127517209fe6d96ab00f3ba97cafe38718b23b1db3e96d8b2d39e37ddf", size = 10435860, upload-time = "2025-02-28T10:16:39.481Z" }, -] - -[[package]] -name = "send2trash" -version = "1.8.3" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/fd/3a/aec9b02217bb79b87bbc1a21bc6abc51e3d5dcf65c30487ac96c0908c722/Send2Trash-1.8.3.tar.gz", hash = "sha256:b18e7a3966d99871aefeb00cfbcfdced55ce4871194810fc71f4aa484b953abf", size = 17394, upload-time = "2024-04-07T00:01:09.267Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/40/b0/4562db6223154aa4e22f939003cb92514c79f3d4dccca3444253fd17f902/Send2Trash-1.8.3-py3-none-any.whl", hash = "sha256:0c31227e0bd08961c7665474a3d1ef7193929fedda4233843689baa056be46c9", size = 18072, upload-time = "2024-04-07T00:01:07.438Z" }, -] - -[[package]] -name = "setuptools" -version = "80.3.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/51/6c/a3f892949418b5b9aced7396919c75ffb57e38f08b712b565f5eb10677ee/setuptools-80.3.0.tar.gz", hash = "sha256:ec8308eb180b2312062b1c5523204acf872cd8b0a9e6c2ae76431b22bc4065d7", size = 1314475, upload-time = "2025-05-03T09:17:32.334Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/e6/61/a6239ff35d64e55def020335626894895847cc6659c0f8e1b676c58aad3b/setuptools-80.3.0-py3-none-any.whl", hash = "sha256:a65cffc4fb86167e3020b3ef58e08226baad8b29a3b34ce2c9d07e901bac481d", size = 1200273, upload-time = "2025-05-03T09:17:29.995Z" }, -] - -[[package]] -name = "six" -version = "1.17.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/94/e7/b2c673351809dca68a0e064b6af791aa332cf192da575fd474ed7d6f16a2/six-1.17.0.tar.gz", hash = "sha256:ff70335d468e7eb6ec65b95b99d3a2836546063f63acc5171de367e834932a81", size = 34031, upload-time = "2024-12-04T17:35:28.174Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/b7/ce/149a00dd41f10bc29e5921b496af8b574d8413afcd5e30dfa0ed46c2cc5e/six-1.17.0-py2.py3-none-any.whl", hash = "sha256:4721f391ed90541fddacab5acf947aa0d3dc7d27b2e1e8eda2be8970586c3274", size = 11050, upload-time = "2024-12-04T17:35:26.475Z" }, -] - -[[package]] -name = "sniffio" -version = "1.3.1" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/a2/87/a6771e1546d97e7e041b6ae58d80074f81b7d5121207425c964ddf5cfdbd/sniffio-1.3.1.tar.gz", hash = "sha256:f4324edc670a0f49750a81b895f35c3adb843cca46f0530f79fc1babb23789dc", size = 20372, upload-time = "2024-02-25T23:20:04.057Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl", hash = "sha256:2f6da418d1f1e0fddd844478f41680e794e6051915791a034ff65e5f100525a2", size = 10235, upload-time = "2024-02-25T23:20:01.196Z" }, -] - -[[package]] -name = "sortedcontainers" -version = "2.4.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/e8/c4/ba2f8066cceb6f23394729afe52f3bf7adec04bf9ed2c820b39e19299111/sortedcontainers-2.4.0.tar.gz", hash = "sha256:25caa5a06cc30b6b83d11423433f65d1f9d76c4c6a0c90e3379eaa43b9bfdb88", size = 30594, upload-time = "2021-05-16T22:03:42.897Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/32/46/9cb0e58b2deb7f82b84065f37f3bffeb12413f947f9388e4cac22c4621ce/sortedcontainers-2.4.0-py2.py3-none-any.whl", hash = "sha256:a163dcaede0f1c021485e957a39245190e74249897e2ae4b2aa38595db237ee0", size = 29575, upload-time = "2021-05-16T22:03:41.177Z" }, -] - -[[package]] -name = "soupsieve" -version = "2.7" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/3f/f4/4a80cd6ef364b2e8b65b15816a843c0980f7a5a2b4dc701fc574952aa19f/soupsieve-2.7.tar.gz", hash = "sha256:ad282f9b6926286d2ead4750552c8a6142bc4c783fd66b0293547c8fe6ae126a", size = 103418, upload-time = "2025-04-20T18:50:08.518Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/e7/9c/0e6afc12c269578be5c0c1c9f4b49a8d32770a080260c333ac04cc1c832d/soupsieve-2.7-py3-none-any.whl", hash = "sha256:6e60cc5c1ffaf1cebcc12e8188320b72071e922c2e897f737cadce79ad5d30c4", size = 36677, upload-time = "2025-04-20T18:50:07.196Z" }, -] - -[[package]] -name = "sphobjinv" -version = "2.3.1.2" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "attrs" }, - { name = "certifi" }, - { name = "jsonschema" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/8c/5e/cf2c54fcc6cc999f64d3a34edeee1ca69d6e1f8aee40772c5f3f036296dc/sphobjinv-2.3.1.2.tar.gz", hash = "sha256:1c874a368460851352d45c92afa172b5c42653b47e2e70d78d61dac93308aa9d", size = 268026, upload-time = "2024-12-22T22:34:20.137Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/9c/4d/103e541e2533df159e1070cd4372b447a0b689e08a49d271b7b950e21f92/sphobjinv-2.3.1.2-py3-none-any.whl", hash = "sha256:66478d1787d28ef3ebeeedad57c592fdea04cf10eeed0df56307c85ab4eee789", size = 50820, upload-time = "2024-12-22T22:34:10.572Z" }, -] - -[[package]] -name = "sqlalchemy" -version = "2.0.40" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "greenlet", marker = "platform_machine == 'AMD64' or platform_machine == 'WIN32' or platform_machine == 'aarch64' or platform_machine == 'amd64' or platform_machine == 'ppc64le' or platform_machine == 'win32' or platform_machine == 'x86_64'" }, - { name = "typing-extensions" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/68/c3/3f2bfa5e4dcd9938405fe2fab5b6ab94a9248a4f9536ea2fd497da20525f/sqlalchemy-2.0.40.tar.gz", hash = "sha256:d827099289c64589418ebbcaead0145cd19f4e3e8a93919a0100247af245fa00", size = 9664299, upload-time = "2025-03-27T17:52:31.876Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/77/7e/55044a9ec48c3249bb38d5faae93f09579c35e862bb318ebd1ed7a1994a5/sqlalchemy-2.0.40-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:f6bacab7514de6146a1976bc56e1545bee247242fab030b89e5f70336fc0003e", size = 2114025, upload-time = "2025-03-27T18:49:29.456Z" }, - { url = "https://files.pythonhosted.org/packages/77/0f/dcf7bba95f847aec72f638750747b12d37914f71c8cc7c133cf326ab945c/sqlalchemy-2.0.40-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:5654d1ac34e922b6c5711631f2da497d3a7bffd6f9f87ac23b35feea56098011", size = 2104419, upload-time = "2025-03-27T18:49:30.75Z" }, - { url = "https://files.pythonhosted.org/packages/75/70/c86a5c20715e4fe903dde4c2fd44fc7e7a0d5fb52c1b954d98526f65a3ea/sqlalchemy-2.0.40-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:35904d63412db21088739510216e9349e335f142ce4a04b69e2528020ee19ed4", size = 3222720, upload-time = "2025-03-27T18:44:29.871Z" }, - { url = "https://files.pythonhosted.org/packages/12/cf/b891a8c1d0c27ce9163361664c2128c7a57de3f35000ea5202eb3a2917b7/sqlalchemy-2.0.40-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9c7a80ed86d6aaacb8160a1caef6680d4ddd03c944d985aecee940d168c411d1", size = 3222682, upload-time = "2025-03-27T18:55:20.097Z" }, - { url = "https://files.pythonhosted.org/packages/15/3f/7709d8c8266953d945435a96b7f425ae4172a336963756b58e996fbef7f3/sqlalchemy-2.0.40-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:519624685a51525ddaa7d8ba8265a1540442a2ec71476f0e75241eb8263d6f51", size = 3159542, upload-time = "2025-03-27T18:44:31.333Z" }, - { url = "https://files.pythonhosted.org/packages/85/7e/717eaabaf0f80a0132dc2032ea8f745b7a0914451c984821a7c8737fb75a/sqlalchemy-2.0.40-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:2ee5f9999a5b0e9689bed96e60ee53c3384f1a05c2dd8068cc2e8361b0df5b7a", size = 3179864, upload-time = "2025-03-27T18:55:21.784Z" }, - { url = "https://files.pythonhosted.org/packages/e4/cc/03eb5dfcdb575cbecd2bd82487b9848f250a4b6ecfb4707e834b4ce4ec07/sqlalchemy-2.0.40-cp311-cp311-win32.whl", hash = "sha256:c0cae71e20e3c02c52f6b9e9722bca70e4a90a466d59477822739dc31ac18b4b", size = 2084675, upload-time = "2025-03-27T18:48:55.915Z" }, - { url = "https://files.pythonhosted.org/packages/9a/48/440946bf9dc4dc231f4f31ef0d316f7135bf41d4b86aaba0c0655150d370/sqlalchemy-2.0.40-cp311-cp311-win_amd64.whl", hash = "sha256:574aea2c54d8f1dd1699449f332c7d9b71c339e04ae50163a3eb5ce4c4325ee4", size = 2110099, upload-time = "2025-03-27T18:48:57.45Z" }, - { url = "https://files.pythonhosted.org/packages/92/06/552c1f92e880b57d8b92ce6619bd569b25cead492389b1d84904b55989d8/sqlalchemy-2.0.40-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:9d3b31d0a1c44b74d3ae27a3de422dfccd2b8f0b75e51ecb2faa2bf65ab1ba0d", size = 2112620, upload-time = "2025-03-27T18:40:00.071Z" }, - { url = "https://files.pythonhosted.org/packages/01/72/a5bc6e76c34cebc071f758161dbe1453de8815ae6e662393910d3be6d70d/sqlalchemy-2.0.40-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:37f7a0f506cf78c80450ed1e816978643d3969f99c4ac6b01104a6fe95c5490a", size = 2103004, upload-time = "2025-03-27T18:40:04.204Z" }, - { url = "https://files.pythonhosted.org/packages/bf/fd/0e96c8e6767618ed1a06e4d7a167fe13734c2f8113c4cb704443e6783038/sqlalchemy-2.0.40-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0bb933a650323e476a2e4fbef8997a10d0003d4da996aad3fd7873e962fdde4d", size = 3252440, upload-time = "2025-03-27T18:51:25.624Z" }, - { url = "https://files.pythonhosted.org/packages/cd/6a/eb82e45b15a64266a2917a6833b51a334ea3c1991728fd905bfccbf5cf63/sqlalchemy-2.0.40-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6959738971b4745eea16f818a2cd086fb35081383b078272c35ece2b07012716", size = 3263277, upload-time = "2025-03-27T18:50:28.142Z" }, - { url = "https://files.pythonhosted.org/packages/45/97/ebe41ab4530f50af99e3995ebd4e0204bf1b0dc0930f32250dde19c389fe/sqlalchemy-2.0.40-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:110179728e442dae85dd39591beb74072ae4ad55a44eda2acc6ec98ead80d5f2", size = 3198591, upload-time = "2025-03-27T18:51:27.543Z" }, - { url = "https://files.pythonhosted.org/packages/e6/1c/a569c1b2b2f5ac20ba6846a1321a2bf52e9a4061001f282bf1c5528dcd69/sqlalchemy-2.0.40-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:e8040680eaacdce4d635f12c55c714f3d4c7f57da2bc47a01229d115bd319191", size = 3225199, upload-time = "2025-03-27T18:50:30.069Z" }, - { url = "https://files.pythonhosted.org/packages/8f/91/87cc71a6b10065ca0209d19a4bb575378abda6085e72fa0b61ffb2201b84/sqlalchemy-2.0.40-cp312-cp312-win32.whl", hash = "sha256:650490653b110905c10adac69408380688cefc1f536a137d0d69aca1069dc1d1", size = 2082959, upload-time = "2025-03-27T18:45:57.574Z" }, - { url = "https://files.pythonhosted.org/packages/2a/9f/14c511cda174aa1ad9b0e42b64ff5a71db35d08b0d80dc044dae958921e5/sqlalchemy-2.0.40-cp312-cp312-win_amd64.whl", hash = "sha256:2be94d75ee06548d2fc591a3513422b873490efb124048f50556369a834853b0", size = 2108526, upload-time = "2025-03-27T18:45:58.965Z" }, - { url = "https://files.pythonhosted.org/packages/d1/7c/5fc8e802e7506fe8b55a03a2e1dab156eae205c91bee46305755e086d2e2/sqlalchemy-2.0.40-py3-none-any.whl", hash = "sha256:32587e2e1e359276957e6fe5dad089758bc042a971a8a09ae8ecf7a8fe23d07a", size = 1903894, upload-time = "2025-03-27T18:40:43.796Z" }, -] - -[[package]] -name = "stack-data" -version = "0.6.3" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "asttokens" }, - { name = "executing" }, - { name = "pure-eval" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/28/e3/55dcc2cfbc3ca9c29519eb6884dd1415ecb53b0e934862d3559ddcb7e20b/stack_data-0.6.3.tar.gz", hash = "sha256:836a778de4fec4dcd1dcd89ed8abff8a221f58308462e1c4aa2a3cf30148f0b9", size = 44707, upload-time = "2023-09-30T13:58:05.479Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/f1/7b/ce1eafaf1a76852e2ec9b22edecf1daa58175c090266e9f6c64afcd81d91/stack_data-0.6.3-py3-none-any.whl", hash = "sha256:d5558e0c25a4cb0853cddad3d77da9891a08cb85dd9f9f91b9f8cd66e511e695", size = 24521, upload-time = "2023-09-30T13:58:03.53Z" }, -] - -[[package]] -name = "tabulate" -version = "0.9.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/ec/fe/802052aecb21e3797b8f7902564ab6ea0d60ff8ca23952079064155d1ae1/tabulate-0.9.0.tar.gz", hash = "sha256:0095b12bf5966de529c0feb1fa08671671b3368eec77d7ef7ab114be2c068b3c", size = 81090, upload-time = "2022-10-06T17:21:48.54Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/40/44/4a5f08c96eb108af5cb50b41f76142f0afa346dfa99d5296fe7202a11854/tabulate-0.9.0-py3-none-any.whl", hash = "sha256:024ca478df22e9340661486f85298cff5f6dcdba14f3813e8830015b9ed1948f", size = 35252, upload-time = "2022-10-06T17:21:44.262Z" }, -] - -[[package]] -name = "terminado" -version = "0.18.1" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "ptyprocess", marker = "os_name != 'nt'" }, - { name = "pywinpty", marker = "os_name == 'nt'" }, - { name = "tornado" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/8a/11/965c6fd8e5cc254f1fe142d547387da17a8ebfd75a3455f637c663fb38a0/terminado-0.18.1.tar.gz", hash = "sha256:de09f2c4b85de4765f7714688fff57d3e75bad1f909b589fde880460c753fd2e", size = 32701, upload-time = "2024-03-12T14:34:39.026Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/6a/9e/2064975477fdc887e47ad42157e214526dcad8f317a948dee17e1659a62f/terminado-0.18.1-py3-none-any.whl", hash = "sha256:a4468e1b37bb318f8a86514f65814e1afc977cf29b3992a4500d9dd305dcceb0", size = 14154, upload-time = "2024-03-12T14:34:36.569Z" }, -] - -[[package]] -name = "tinycss2" -version = "1.4.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "webencodings" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/7a/fd/7a5ee21fd08ff70d3d33a5781c255cbe779659bd03278feb98b19ee550f4/tinycss2-1.4.0.tar.gz", hash = "sha256:10c0972f6fc0fbee87c3edb76549357415e94548c1ae10ebccdea16fb404a9b7", size = 87085, upload-time = "2024-10-24T14:58:29.895Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/e6/34/ebdc18bae6aa14fbee1a08b63c015c72b64868ff7dae68808ab500c492e2/tinycss2-1.4.0-py3-none-any.whl", hash = "sha256:3a49cf47b7675da0b15d0c6e1df8df4ebd96e9394bb905a5775adb0d884c5289", size = 26610, upload-time = "2024-10-24T14:58:28.029Z" }, -] - -[[package]] -name = "tomli" -version = "2.2.1" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/18/87/302344fed471e44a87289cf4967697d07e532f2421fdaf868a303cbae4ff/tomli-2.2.1.tar.gz", hash = "sha256:cd45e1dc79c835ce60f7404ec8119f2eb06d38b1deba146f07ced3bbc44505ff", size = 17175, upload-time = "2024-11-27T22:38:36.873Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/43/ca/75707e6efa2b37c77dadb324ae7d9571cb424e61ea73fad7c56c2d14527f/tomli-2.2.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:678e4fa69e4575eb77d103de3df8a895e1591b48e740211bd1067378c69e8249", size = 131077, upload-time = "2024-11-27T22:37:54.956Z" }, - { url = "https://files.pythonhosted.org/packages/c7/16/51ae563a8615d472fdbffc43a3f3d46588c264ac4f024f63f01283becfbb/tomli-2.2.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:023aa114dd824ade0100497eb2318602af309e5a55595f76b626d6d9f3b7b0a6", size = 123429, upload-time = "2024-11-27T22:37:56.698Z" }, - { url = "https://files.pythonhosted.org/packages/f1/dd/4f6cd1e7b160041db83c694abc78e100473c15d54620083dbd5aae7b990e/tomli-2.2.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ece47d672db52ac607a3d9599a9d48dcb2f2f735c6c2d1f34130085bb12b112a", size = 226067, upload-time = "2024-11-27T22:37:57.63Z" }, - { url = "https://files.pythonhosted.org/packages/a9/6b/c54ede5dc70d648cc6361eaf429304b02f2871a345bbdd51e993d6cdf550/tomli-2.2.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6972ca9c9cc9f0acaa56a8ca1ff51e7af152a9f87fb64623e31d5c83700080ee", size = 236030, upload-time = "2024-11-27T22:37:59.344Z" }, - { url = "https://files.pythonhosted.org/packages/1f/47/999514fa49cfaf7a92c805a86c3c43f4215621855d151b61c602abb38091/tomli-2.2.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c954d2250168d28797dd4e3ac5cf812a406cd5a92674ee4c8f123c889786aa8e", size = 240898, upload-time = "2024-11-27T22:38:00.429Z" }, - { url = "https://files.pythonhosted.org/packages/73/41/0a01279a7ae09ee1573b423318e7934674ce06eb33f50936655071d81a24/tomli-2.2.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:8dd28b3e155b80f4d54beb40a441d366adcfe740969820caf156c019fb5c7ec4", size = 229894, upload-time = "2024-11-27T22:38:02.094Z" }, - { url = "https://files.pythonhosted.org/packages/55/18/5d8bc5b0a0362311ce4d18830a5d28943667599a60d20118074ea1b01bb7/tomli-2.2.1-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:e59e304978767a54663af13c07b3d1af22ddee3bb2fb0618ca1593e4f593a106", size = 245319, upload-time = "2024-11-27T22:38:03.206Z" }, - { url = "https://files.pythonhosted.org/packages/92/a3/7ade0576d17f3cdf5ff44d61390d4b3febb8a9fc2b480c75c47ea048c646/tomli-2.2.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:33580bccab0338d00994d7f16f4c4ec25b776af3ffaac1ed74e0b3fc95e885a8", size = 238273, upload-time = "2024-11-27T22:38:04.217Z" }, - { url = "https://files.pythonhosted.org/packages/72/6f/fa64ef058ac1446a1e51110c375339b3ec6be245af9d14c87c4a6412dd32/tomli-2.2.1-cp311-cp311-win32.whl", hash = "sha256:465af0e0875402f1d226519c9904f37254b3045fc5084697cefb9bdde1ff99ff", size = 98310, upload-time = "2024-11-27T22:38:05.908Z" }, - { url = "https://files.pythonhosted.org/packages/6a/1c/4a2dcde4a51b81be3530565e92eda625d94dafb46dbeb15069df4caffc34/tomli-2.2.1-cp311-cp311-win_amd64.whl", hash = "sha256:2d0f2fdd22b02c6d81637a3c95f8cd77f995846af7414c5c4b8d0545afa1bc4b", size = 108309, upload-time = "2024-11-27T22:38:06.812Z" }, - { url = "https://files.pythonhosted.org/packages/52/e1/f8af4c2fcde17500422858155aeb0d7e93477a0d59a98e56cbfe75070fd0/tomli-2.2.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:4a8f6e44de52d5e6c657c9fe83b562f5f4256d8ebbfe4ff922c495620a7f6cea", size = 132762, upload-time = "2024-11-27T22:38:07.731Z" }, - { url = "https://files.pythonhosted.org/packages/03/b8/152c68bb84fc00396b83e7bbddd5ec0bd3dd409db4195e2a9b3e398ad2e3/tomli-2.2.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:8d57ca8095a641b8237d5b079147646153d22552f1c637fd3ba7f4b0b29167a8", size = 123453, upload-time = "2024-11-27T22:38:09.384Z" }, - { url = "https://files.pythonhosted.org/packages/c8/d6/fc9267af9166f79ac528ff7e8c55c8181ded34eb4b0e93daa767b8841573/tomli-2.2.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4e340144ad7ae1533cb897d406382b4b6fede8890a03738ff1683af800d54192", size = 233486, upload-time = "2024-11-27T22:38:10.329Z" }, - { url = "https://files.pythonhosted.org/packages/5c/51/51c3f2884d7bab89af25f678447ea7d297b53b5a3b5730a7cb2ef6069f07/tomli-2.2.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:db2b95f9de79181805df90bedc5a5ab4c165e6ec3fe99f970d0e302f384ad222", size = 242349, upload-time = "2024-11-27T22:38:11.443Z" }, - { url = "https://files.pythonhosted.org/packages/ab/df/bfa89627d13a5cc22402e441e8a931ef2108403db390ff3345c05253935e/tomli-2.2.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:40741994320b232529c802f8bc86da4e1aa9f413db394617b9a256ae0f9a7f77", size = 252159, upload-time = "2024-11-27T22:38:13.099Z" }, - { url = "https://files.pythonhosted.org/packages/9e/6e/fa2b916dced65763a5168c6ccb91066f7639bdc88b48adda990db10c8c0b/tomli-2.2.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:400e720fe168c0f8521520190686ef8ef033fb19fc493da09779e592861b78c6", size = 237243, upload-time = "2024-11-27T22:38:14.766Z" }, - { url = "https://files.pythonhosted.org/packages/b4/04/885d3b1f650e1153cbb93a6a9782c58a972b94ea4483ae4ac5cedd5e4a09/tomli-2.2.1-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:02abe224de6ae62c19f090f68da4e27b10af2b93213d36cf44e6e1c5abd19fdd", size = 259645, upload-time = "2024-11-27T22:38:15.843Z" }, - { url = "https://files.pythonhosted.org/packages/9c/de/6b432d66e986e501586da298e28ebeefd3edc2c780f3ad73d22566034239/tomli-2.2.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:b82ebccc8c8a36f2094e969560a1b836758481f3dc360ce9a3277c65f374285e", size = 244584, upload-time = "2024-11-27T22:38:17.645Z" }, - { url = "https://files.pythonhosted.org/packages/1c/9a/47c0449b98e6e7d1be6cbac02f93dd79003234ddc4aaab6ba07a9a7482e2/tomli-2.2.1-cp312-cp312-win32.whl", hash = "sha256:889f80ef92701b9dbb224e49ec87c645ce5df3fa2cc548664eb8a25e03127a98", size = 98875, upload-time = "2024-11-27T22:38:19.159Z" }, - { url = "https://files.pythonhosted.org/packages/ef/60/9b9638f081c6f1261e2688bd487625cd1e660d0a85bd469e91d8db969734/tomli-2.2.1-cp312-cp312-win_amd64.whl", hash = "sha256:7fc04e92e1d624a4a63c76474610238576942d6b8950a2d7f908a340494e67e4", size = 109418, upload-time = "2024-11-27T22:38:20.064Z" }, - { url = "https://files.pythonhosted.org/packages/6e/c2/61d3e0f47e2b74ef40a68b9e6ad5984f6241a942f7cd3bbfbdbd03861ea9/tomli-2.2.1-py3-none-any.whl", hash = "sha256:cb55c73c5f4408779d0cf3eef9f762b9c9f147a77de7b258bef0a5628adc85cc", size = 14257, upload-time = "2024-11-27T22:38:35.385Z" }, -] - -[[package]] -name = "tornado" -version = "6.4.2" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/59/45/a0daf161f7d6f36c3ea5fc0c2de619746cc3dd4c76402e9db545bd920f63/tornado-6.4.2.tar.gz", hash = "sha256:92bad5b4746e9879fd7bf1eb21dce4e3fc5128d71601f80005afa39237ad620b", size = 501135, upload-time = "2024-11-22T03:06:38.036Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/26/7e/71f604d8cea1b58f82ba3590290b66da1e72d840aeb37e0d5f7291bd30db/tornado-6.4.2-cp38-abi3-macosx_10_9_universal2.whl", hash = "sha256:e828cce1123e9e44ae2a50a9de3055497ab1d0aeb440c5ac23064d9e44880da1", size = 436299, upload-time = "2024-11-22T03:06:20.162Z" }, - { url = "https://files.pythonhosted.org/packages/96/44/87543a3b99016d0bf54fdaab30d24bf0af2e848f1d13d34a3a5380aabe16/tornado-6.4.2-cp38-abi3-macosx_10_9_x86_64.whl", hash = "sha256:072ce12ada169c5b00b7d92a99ba089447ccc993ea2143c9ede887e0937aa803", size = 434253, upload-time = "2024-11-22T03:06:22.39Z" }, - { url = "https://files.pythonhosted.org/packages/cb/fb/fdf679b4ce51bcb7210801ef4f11fdac96e9885daa402861751353beea6e/tornado-6.4.2-cp38-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1a017d239bd1bb0919f72af256a970624241f070496635784d9bf0db640d3fec", size = 437602, upload-time = "2024-11-22T03:06:24.214Z" }, - { url = "https://files.pythonhosted.org/packages/4f/3b/e31aeffffc22b475a64dbeb273026a21b5b566f74dee48742817626c47dc/tornado-6.4.2-cp38-abi3-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c36e62ce8f63409301537222faffcef7dfc5284f27eec227389f2ad11b09d946", size = 436972, upload-time = "2024-11-22T03:06:25.559Z" }, - { url = "https://files.pythonhosted.org/packages/22/55/b78a464de78051a30599ceb6983b01d8f732e6f69bf37b4ed07f642ac0fc/tornado-6.4.2-cp38-abi3-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bca9eb02196e789c9cb5c3c7c0f04fb447dc2adffd95265b2c7223a8a615ccbf", size = 437173, upload-time = "2024-11-22T03:06:27.584Z" }, - { url = "https://files.pythonhosted.org/packages/79/5e/be4fb0d1684eb822c9a62fb18a3e44a06188f78aa466b2ad991d2ee31104/tornado-6.4.2-cp38-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:304463bd0772442ff4d0f5149c6f1c2135a1fae045adf070821c6cdc76980634", size = 437892, upload-time = "2024-11-22T03:06:28.933Z" }, - { url = "https://files.pythonhosted.org/packages/f5/33/4f91fdd94ea36e1d796147003b490fe60a0215ac5737b6f9c65e160d4fe0/tornado-6.4.2-cp38-abi3-musllinux_1_2_i686.whl", hash = "sha256:c82c46813ba483a385ab2a99caeaedf92585a1f90defb5693351fa7e4ea0bf73", size = 437334, upload-time = "2024-11-22T03:06:30.428Z" }, - { url = "https://files.pythonhosted.org/packages/2b/ae/c1b22d4524b0e10da2f29a176fb2890386f7bd1f63aacf186444873a88a0/tornado-6.4.2-cp38-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:932d195ca9015956fa502c6b56af9eb06106140d844a335590c1ec7f5277d10c", size = 437261, upload-time = "2024-11-22T03:06:32.458Z" }, - { url = "https://files.pythonhosted.org/packages/b5/25/36dbd49ab6d179bcfc4c6c093a51795a4f3bed380543a8242ac3517a1751/tornado-6.4.2-cp38-abi3-win32.whl", hash = "sha256:2876cef82e6c5978fde1e0d5b1f919d756968d5b4282418f3146b79b58556482", size = 438463, upload-time = "2024-11-22T03:06:34.71Z" }, - { url = "https://files.pythonhosted.org/packages/61/cc/58b1adeb1bb46228442081e746fcdbc4540905c87e8add7c277540934edb/tornado-6.4.2-cp38-abi3-win_amd64.whl", hash = "sha256:908b71bf3ff37d81073356a5fadcc660eb10c1476ee6e2725588626ce7e5ca38", size = 438907, upload-time = "2024-11-22T03:06:36.71Z" }, -] - -[[package]] -name = "traitlets" -version = "5.14.3" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/eb/79/72064e6a701c2183016abbbfedaba506d81e30e232a68c9f0d6f6fcd1574/traitlets-5.14.3.tar.gz", hash = "sha256:9ed0579d3502c94b4b3732ac120375cda96f923114522847de4b3bb98b96b6b7", size = 161621, upload-time = "2024-04-19T11:11:49.746Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/00/c0/8f5d070730d7836adc9c9b6408dec68c6ced86b304a9b26a14df072a6e8c/traitlets-5.14.3-py3-none-any.whl", hash = "sha256:b74e89e397b1ed28cc831db7aea759ba6640cb3de13090ca145426688ff1ac4f", size = 85359, upload-time = "2024-04-19T11:11:46.763Z" }, -] - -[[package]] -name = "types-python-dateutil" -version = "2.9.0.20241206" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/a9/60/47d92293d9bc521cd2301e423a358abfac0ad409b3a1606d8fbae1321961/types_python_dateutil-2.9.0.20241206.tar.gz", hash = "sha256:18f493414c26ffba692a72369fea7a154c502646301ebfe3d56a04b3767284cb", size = 13802, upload-time = "2024-12-06T02:56:41.019Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/0f/b3/ca41df24db5eb99b00d97f89d7674a90cb6b3134c52fb8121b6d8d30f15c/types_python_dateutil-2.9.0.20241206-py3-none-any.whl", hash = "sha256:e248a4bc70a486d3e3ec84d0dc30eec3a5f979d6e7ee4123ae043eedbb987f53", size = 14384, upload-time = "2024-12-06T02:56:39.412Z" }, -] - -[[package]] -name = "typing-extensions" -version = "4.12.2" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/df/db/f35a00659bc03fec321ba8bce9420de607a1d37f8342eee1863174c69557/typing_extensions-4.12.2.tar.gz", hash = "sha256:1a7ead55c7e559dd4dee8856e3a88b41225abfe1ce8df57b7c13915fe121ffb8", size = 85321, upload-time = "2024-06-07T18:52:15.995Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/26/9f/ad63fc0248c5379346306f8668cda6e2e2e9c95e01216d2b8ffd9ff037d0/typing_extensions-4.12.2-py3-none-any.whl", hash = "sha256:04e5ca0351e0f3f85c6853954072df659d0d13fac324d0072316b67d7794700d", size = 37438, upload-time = "2024-06-07T18:52:13.582Z" }, -] - -[[package]] -name = "typing-inspection" -version = "0.4.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "typing-extensions" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/82/5c/e6082df02e215b846b4b8c0b887a64d7d08ffaba30605502639d44c06b82/typing_inspection-0.4.0.tar.gz", hash = "sha256:9765c87de36671694a67904bf2c96e395be9c6439bb6c87b5142569dcdd65122", size = 76222, upload-time = "2025-02-25T17:27:59.638Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/31/08/aa4fdfb71f7de5176385bd9e90852eaf6b5d622735020ad600f2bab54385/typing_inspection-0.4.0-py3-none-any.whl", hash = "sha256:50e72559fcd2a6367a19f7a7e610e6afcb9fac940c650290eed893d61386832f", size = 14125, upload-time = "2025-02-25T17:27:57.754Z" }, -] - -[[package]] -name = "uri-template" -version = "1.3.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/31/c7/0336f2bd0bcbada6ccef7aaa25e443c118a704f828a0620c6fa0207c1b64/uri-template-1.3.0.tar.gz", hash = "sha256:0e00f8eb65e18c7de20d595a14336e9f337ead580c70934141624b6d1ffdacc7", size = 21678, upload-time = "2023-06-21T01:49:05.374Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/e7/00/3fca040d7cf8a32776d3d81a00c8ee7457e00f80c649f1e4a863c8321ae9/uri_template-1.3.0-py3-none-any.whl", hash = "sha256:a44a133ea12d44a0c0f06d7d42a52d71282e77e2f937d8abd5655b8d56fc1363", size = 11140, upload-time = "2023-06-21T01:49:03.467Z" }, -] - -[[package]] -name = "urllib3" -version = "2.4.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/8a/78/16493d9c386d8e60e442a35feac5e00f0913c0f4b7c217c11e8ec2ff53e0/urllib3-2.4.0.tar.gz", hash = "sha256:414bc6535b787febd7567804cc015fee39daab8ad86268f1310a9250697de466", size = 390672, upload-time = "2025-04-10T15:23:39.232Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/6b/11/cc635220681e93a0183390e26485430ca2c7b5f9d33b15c74c2861cb8091/urllib3-2.4.0-py3-none-any.whl", hash = "sha256:4e16665048960a0900c702d4a66415956a584919c03361cac9f1df5c5dd7e813", size = 128680, upload-time = "2025-04-10T15:23:37.377Z" }, -] - -[[package]] -name = "watchdog" -version = "6.0.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/db/7d/7f3d619e951c88ed75c6037b246ddcf2d322812ee8ea189be89511721d54/watchdog-6.0.0.tar.gz", hash = "sha256:9ddf7c82fda3ae8e24decda1338ede66e1c99883db93711d8fb941eaa2d8c282", size = 131220, upload-time = "2024-11-01T14:07:13.037Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/e0/24/d9be5cd6642a6aa68352ded4b4b10fb0d7889cb7f45814fb92cecd35f101/watchdog-6.0.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:6eb11feb5a0d452ee41f824e271ca311a09e250441c262ca2fd7ebcf2461a06c", size = 96393, upload-time = "2024-11-01T14:06:31.756Z" }, - { url = "https://files.pythonhosted.org/packages/63/7a/6013b0d8dbc56adca7fdd4f0beed381c59f6752341b12fa0886fa7afc78b/watchdog-6.0.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:ef810fbf7b781a5a593894e4f439773830bdecb885e6880d957d5b9382a960d2", size = 88392, upload-time = "2024-11-01T14:06:32.99Z" }, - { url = "https://files.pythonhosted.org/packages/d1/40/b75381494851556de56281e053700e46bff5b37bf4c7267e858640af5a7f/watchdog-6.0.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:afd0fe1b2270917c5e23c2a65ce50c2a4abb63daafb0d419fde368e272a76b7c", size = 89019, upload-time = "2024-11-01T14:06:34.963Z" }, - { url = "https://files.pythonhosted.org/packages/39/ea/3930d07dafc9e286ed356a679aa02d777c06e9bfd1164fa7c19c288a5483/watchdog-6.0.0-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:bdd4e6f14b8b18c334febb9c4425a878a2ac20efd1e0b231978e7b150f92a948", size = 96471, upload-time = "2024-11-01T14:06:37.745Z" }, - { url = "https://files.pythonhosted.org/packages/12/87/48361531f70b1f87928b045df868a9fd4e253d9ae087fa4cf3f7113be363/watchdog-6.0.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:c7c15dda13c4eb00d6fb6fc508b3c0ed88b9d5d374056b239c4ad1611125c860", size = 88449, upload-time = "2024-11-01T14:06:39.748Z" }, - { url = "https://files.pythonhosted.org/packages/5b/7e/8f322f5e600812e6f9a31b75d242631068ca8f4ef0582dd3ae6e72daecc8/watchdog-6.0.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:6f10cb2d5902447c7d0da897e2c6768bca89174d0c6e1e30abec5421af97a5b0", size = 89054, upload-time = "2024-11-01T14:06:41.009Z" }, - { url = "https://files.pythonhosted.org/packages/a9/c7/ca4bf3e518cb57a686b2feb4f55a1892fd9a3dd13f470fca14e00f80ea36/watchdog-6.0.0-py3-none-manylinux2014_aarch64.whl", hash = "sha256:7607498efa04a3542ae3e05e64da8202e58159aa1fa4acddf7678d34a35d4f13", size = 79079, upload-time = "2024-11-01T14:06:59.472Z" }, - { url = "https://files.pythonhosted.org/packages/5c/51/d46dc9332f9a647593c947b4b88e2381c8dfc0942d15b8edc0310fa4abb1/watchdog-6.0.0-py3-none-manylinux2014_armv7l.whl", hash = "sha256:9041567ee8953024c83343288ccc458fd0a2d811d6a0fd68c4c22609e3490379", size = 79078, upload-time = "2024-11-01T14:07:01.431Z" }, - { url = "https://files.pythonhosted.org/packages/d4/57/04edbf5e169cd318d5f07b4766fee38e825d64b6913ca157ca32d1a42267/watchdog-6.0.0-py3-none-manylinux2014_i686.whl", hash = "sha256:82dc3e3143c7e38ec49d61af98d6558288c415eac98486a5c581726e0737c00e", size = 79076, upload-time = "2024-11-01T14:07:02.568Z" }, - { url = "https://files.pythonhosted.org/packages/ab/cc/da8422b300e13cb187d2203f20b9253e91058aaf7db65b74142013478e66/watchdog-6.0.0-py3-none-manylinux2014_ppc64.whl", hash = "sha256:212ac9b8bf1161dc91bd09c048048a95ca3a4c4f5e5d4a7d1b1a7d5752a7f96f", size = 79077, upload-time = "2024-11-01T14:07:03.893Z" }, - { url = "https://files.pythonhosted.org/packages/2c/3b/b8964e04ae1a025c44ba8e4291f86e97fac443bca31de8bd98d3263d2fcf/watchdog-6.0.0-py3-none-manylinux2014_ppc64le.whl", hash = "sha256:e3df4cbb9a450c6d49318f6d14f4bbc80d763fa587ba46ec86f99f9e6876bb26", size = 79078, upload-time = "2024-11-01T14:07:05.189Z" }, - { url = "https://files.pythonhosted.org/packages/62/ae/a696eb424bedff7407801c257d4b1afda455fe40821a2be430e173660e81/watchdog-6.0.0-py3-none-manylinux2014_s390x.whl", hash = "sha256:2cce7cfc2008eb51feb6aab51251fd79b85d9894e98ba847408f662b3395ca3c", size = 79077, upload-time = "2024-11-01T14:07:06.376Z" }, - { url = "https://files.pythonhosted.org/packages/b5/e8/dbf020b4d98251a9860752a094d09a65e1b436ad181faf929983f697048f/watchdog-6.0.0-py3-none-manylinux2014_x86_64.whl", hash = "sha256:20ffe5b202af80ab4266dcd3e91aae72bf2da48c0d33bdb15c66658e685e94e2", size = 79078, upload-time = "2024-11-01T14:07:07.547Z" }, - { url = "https://files.pythonhosted.org/packages/07/f6/d0e5b343768e8bcb4cda79f0f2f55051bf26177ecd5651f84c07567461cf/watchdog-6.0.0-py3-none-win32.whl", hash = "sha256:07df1fdd701c5d4c8e55ef6cf55b8f0120fe1aef7ef39a1c6fc6bc2e606d517a", size = 79065, upload-time = "2024-11-01T14:07:09.525Z" }, - { url = "https://files.pythonhosted.org/packages/db/d9/c495884c6e548fce18a8f40568ff120bc3a4b7b99813081c8ac0c936fa64/watchdog-6.0.0-py3-none-win_amd64.whl", hash = "sha256:cbafb470cf848d93b5d013e2ecb245d4aa1c8fd0504e863ccefa32445359d680", size = 79070, upload-time = "2024-11-01T14:07:10.686Z" }, - { url = "https://files.pythonhosted.org/packages/33/e8/e40370e6d74ddba47f002a32919d91310d6074130fe4e17dabcafc15cbf1/watchdog-6.0.0-py3-none-win_ia64.whl", hash = "sha256:a1914259fa9e1454315171103c6a30961236f508b9b623eae470268bbcc6a22f", size = 79067, upload-time = "2024-11-01T14:07:11.845Z" }, -] - -[[package]] -name = "wcwidth" -version = "0.2.13" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/6c/63/53559446a878410fc5a5974feb13d31d78d752eb18aeba59c7fef1af7598/wcwidth-0.2.13.tar.gz", hash = "sha256:72ea0c06399eb286d978fdedb6923a9eb47e1c486ce63e9b4e64fc18303972b5", size = 101301, upload-time = "2024-01-06T02:10:57.829Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/fd/84/fd2ba7aafacbad3c4201d395674fc6348826569da3c0937e75505ead3528/wcwidth-0.2.13-py2.py3-none-any.whl", hash = "sha256:3da69048e4540d84af32131829ff948f1e022c1c6bdb8d6102117aac784f6859", size = 34166, upload-time = "2024-01-06T02:10:55.763Z" }, -] - -[[package]] -name = "webcolors" -version = "24.11.1" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/7b/29/061ec845fb58521848f3739e466efd8250b4b7b98c1b6c5bf4d40b419b7e/webcolors-24.11.1.tar.gz", hash = "sha256:ecb3d768f32202af770477b8b65f318fa4f566c22948673a977b00d589dd80f6", size = 45064, upload-time = "2024-11-11T07:43:24.224Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/60/e8/c0e05e4684d13459f93d312077a9a2efbe04d59c393bc2b8802248c908d4/webcolors-24.11.1-py3-none-any.whl", hash = "sha256:515291393b4cdf0eb19c155749a096f779f7d909f7cceea072791cb9095b92e9", size = 14934, upload-time = "2024-11-11T07:43:22.529Z" }, -] - -[[package]] -name = "webencodings" -version = "0.5.1" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/0b/02/ae6ceac1baeda530866a85075641cec12989bd8d31af6d5ab4a3e8c92f47/webencodings-0.5.1.tar.gz", hash = "sha256:b36a1c245f2d304965eb4e0a82848379241dc04b865afcc4aab16748587e1923", size = 9721, upload-time = "2017-04-05T20:21:34.189Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/f4/24/2a3e3df732393fed8b3ebf2ec078f05546de641fe1b667ee316ec1dcf3b7/webencodings-0.5.1-py2.py3-none-any.whl", hash = "sha256:a0af1213f3c2226497a97e2b3aa01a7e4bee4f403f95be16fc9acd2947514a78", size = 11774, upload-time = "2017-04-05T20:21:32.581Z" }, -] - -[[package]] -name = "websocket-client" -version = "1.8.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/e6/30/fba0d96b4b5fbf5948ed3f4681f7da2f9f64512e1d303f94b4cc174c24a5/websocket_client-1.8.0.tar.gz", hash = "sha256:3239df9f44da632f96012472805d40a23281a991027ce11d2f45a6f24ac4c3da", size = 54648, upload-time = "2024-04-23T22:16:16.976Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/5a/84/44687a29792a70e111c5c477230a72c4b957d88d16141199bf9acb7537a3/websocket_client-1.8.0-py3-none-any.whl", hash = "sha256:17b44cc997f5c498e809b22cdf2d9c7a9e71c02c8cc2b6c56e7c2d1239bfa526", size = 58826, upload-time = "2024-04-23T22:16:14.422Z" }, -] - -[[package]] -name = "widgetsnbextension" -version = "4.0.14" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/41/53/2e0253c5efd69c9656b1843892052a31c36d37ad42812b5da45c62191f7e/widgetsnbextension-4.0.14.tar.gz", hash = "sha256:a3629b04e3edb893212df862038c7232f62973373869db5084aed739b437b5af", size = 1097428, upload-time = "2025-04-10T13:01:25.628Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/ca/51/5447876806d1088a0f8f71e16542bf350918128d0a69437df26047c8e46f/widgetsnbextension-4.0.14-py3-none-any.whl", hash = "sha256:4875a9eaf72fbf5079dc372a51a9f268fc38d46f767cbf85c43a36da5cb9b575", size = 2196503, upload-time = "2025-04-10T13:01:23.086Z" }, -] - -[[package]] -name = "xdoctest" -version = "1.2.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/e9/a5/7f6dfdaf3a221e16ff79281d2a3c3e4b58989c92de8964a317feb1e6cbb5/xdoctest-1.2.0.tar.gz", hash = "sha256:d8cfca6d8991e488d33f756e600d35b9fdf5efd5c3a249d644efcbbbd2ed5863", size = 204804, upload-time = "2024-08-20T13:48:21.076Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/58/b8/e4722f5e5f592a665cc8e55a334ea721c359f09574e6b987dc551a1e1f4c/xdoctest-1.2.0-py3-none-any.whl", hash = "sha256:0f1ecf5939a687bd1fc8deefbff1743c65419cce26dff908f8b84c93fbe486bc", size = 151194, upload-time = "2024-08-20T13:48:18.674Z" }, -] - -[[package]] -name = "zipp" -version = "3.21.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/3f/50/bad581df71744867e9468ebd0bcd6505de3b275e06f202c2cb016e3ff56f/zipp-3.21.0.tar.gz", hash = "sha256:2c9958f6430a2040341a52eb608ed6dd93ef4392e02ffe219417c1b28b5dd1f4", size = 24545, upload-time = "2024-11-10T15:05:20.202Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/b7/1a/7e4798e9339adc931158c9d69ecc34f5e6791489d469f5e50ec15e35f458/zipp-3.21.0-py3-none-any.whl", hash = "sha256:ac1bbe05fd2991f160ebce24ffbac5f6d11d83dc90891255885223d42b3cd931", size = 9630, upload-time = "2024-11-10T15:05:19.275Z" }, -] From 4d8090387957420285ba38c1e0eb5d1b7547a53f Mon Sep 17 00:00:00 2001 From: Cameron Smith Date: Mon, 2 Feb 2026 14:37:50 -0500 Subject: [PATCH 011/134] build(pnt-functional): add independent uv lock file --- packages/pnt-functional/uv.lock | 482 ++++++++++++++++++++++++++++++++ 1 file changed, 482 insertions(+) create mode 100644 packages/pnt-functional/uv.lock diff --git a/packages/pnt-functional/uv.lock b/packages/pnt-functional/uv.lock new file mode 100644 index 0000000..c20657b --- /dev/null +++ b/packages/pnt-functional/uv.lock @@ -0,0 +1,482 @@ +version = 1 +revision = 3 +requires-python = ">=3.11, <3.13" + +[[package]] +name = "asttokens" +version = "3.0.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/be/a5/8e3f9b6771b0b408517c82d97aed8f2036509bc247d46114925e32fe33f0/asttokens-3.0.1.tar.gz", hash = "sha256:71a4ee5de0bde6a31d64f6b13f2293ac190344478f081c3d1bccfcf5eacb0cb7", size = 62308, upload-time = "2025-11-15T16:43:48.578Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/d2/39/e7eaf1799466a4aef85b6a4fe7bd175ad2b1c6345066aa33f1f58d4b18d0/asttokens-3.0.1-py3-none-any.whl", hash = "sha256:15a3ebc0f43c2d0a50eeafea25e19046c68398e487b9f1f5b517f7c0f40f976a", size = 27047, upload-time = "2025-11-15T16:43:16.109Z" }, +] + +[[package]] +name = "beartype" +version = "0.19.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/6f/e1/00515b97afa3993b4a314e4bc168fbde0917fd5845435cb6f16a19770746/beartype-0.19.0.tar.gz", hash = "sha256:de42dfc1ba5c3710fde6c3002e3bd2cad236ed4d2aabe876345ab0b4234a6573", size = 1294480, upload-time = "2024-09-26T07:06:17.308Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/64/69/f6db6e4cb2fe2f887dead40b76caa91af4844cb647dd2c7223bb010aa416/beartype-0.19.0-py3-none-any.whl", hash = "sha256:33b2694eda0daf052eb2aff623ed9a8a586703bbf0a90bbc475a83bbf427f699", size = 1039760, upload-time = "2024-09-26T07:06:13.546Z" }, +] + +[[package]] +name = "colorama" +version = "0.4.6" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/d8/53/6f443c9a4a8358a93a6792e2acffb9d9d5cb0a5cfd8802644b7b1c9a02e4/colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44", size = 27697, upload-time = "2022-10-25T02:36:22.414Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/d1/d6/3965ed04c63042e047cb6a3e6ed1a63a35087b6a609aa3a15ed8ac56c221/colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6", size = 25335, upload-time = "2022-10-25T02:36:20.889Z" }, +] + +[[package]] +name = "coverage" +version = "7.13.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/ad/49/349848445b0e53660e258acbcc9b0d014895b6739237920886672240f84b/coverage-7.13.2.tar.gz", hash = "sha256:044c6951ec37146b72a50cc81ef02217d27d4c3640efd2640311393cbbf143d3", size = 826523, upload-time = "2026-01-25T13:00:04.889Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/6c/01/abca50583a8975bb6e1c59eff67ed8e48bb127c07dad5c28d9e96ccc09ec/coverage-7.13.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:060ebf6f2c51aff5ba38e1f43a2095e087389b1c69d559fde6049a4b0001320e", size = 218971, upload-time = "2026-01-25T12:57:36.953Z" }, + { url = "https://files.pythonhosted.org/packages/eb/0e/b6489f344d99cd1e5b4d5e1be52dfd3f8a3dc5112aa6c33948da8cabad4e/coverage-7.13.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:c1ea8ca9db5e7469cd364552985e15911548ea5b69c48a17291f0cac70484b2e", size = 219473, upload-time = "2026-01-25T12:57:38.934Z" }, + { url = "https://files.pythonhosted.org/packages/17/11/db2f414915a8e4ec53f60b17956c27f21fb68fcf20f8a455ce7c2ccec638/coverage-7.13.2-cp311-cp311-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:b780090d15fd58f07cf2011943e25a5f0c1c894384b13a216b6c86c8a8a7c508", size = 249896, upload-time = "2026-01-25T12:57:40.365Z" }, + { url = "https://files.pythonhosted.org/packages/80/06/0823fe93913663c017e508e8810c998c8ebd3ec2a5a85d2c3754297bdede/coverage-7.13.2-cp311-cp311-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:88a800258d83acb803c38175b4495d293656d5fac48659c953c18e5f539a274b", size = 251810, upload-time = "2026-01-25T12:57:42.045Z" }, + { url = "https://files.pythonhosted.org/packages/61/dc/b151c3cc41b28cdf7f0166c5fa1271cbc305a8ec0124cce4b04f74791a18/coverage-7.13.2-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6326e18e9a553e674d948536a04a80d850a5eeefe2aae2e6d7cf05d54046c01b", size = 253920, upload-time = "2026-01-25T12:57:44.026Z" }, + { url = "https://files.pythonhosted.org/packages/2d/35/e83de0556e54a4729a2b94ea816f74ce08732e81945024adee46851c2264/coverage-7.13.2-cp311-cp311-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:59562de3f797979e1ff07c587e2ac36ba60ca59d16c211eceaa579c266c5022f", size = 250025, upload-time = "2026-01-25T12:57:45.624Z" }, + { url = "https://files.pythonhosted.org/packages/39/67/af2eb9c3926ce3ea0d58a0d2516fcbdacf7a9fc9559fe63076beaf3f2596/coverage-7.13.2-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:27ba1ed6f66b0e2d61bfa78874dffd4f8c3a12f8e2b5410e515ab345ba7bc9c3", size = 251612, upload-time = "2026-01-25T12:57:47.713Z" }, + { url = "https://files.pythonhosted.org/packages/26/62/5be2e25f3d6c711d23b71296f8b44c978d4c8b4e5b26871abfc164297502/coverage-7.13.2-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:8be48da4d47cc68754ce643ea50b3234557cbefe47c2f120495e7bd0a2756f2b", size = 249670, upload-time = "2026-01-25T12:57:49.378Z" }, + { url = "https://files.pythonhosted.org/packages/b3/51/400d1b09a8344199f9b6a6fc1868005d766b7ea95e7882e494fa862ca69c/coverage-7.13.2-cp311-cp311-musllinux_1_2_riscv64.whl", hash = "sha256:2a47a4223d3361b91176aedd9d4e05844ca67d7188456227b6bf5e436630c9a1", size = 249395, upload-time = "2026-01-25T12:57:50.86Z" }, + { url = "https://files.pythonhosted.org/packages/e0/36/f02234bc6e5230e2f0a63fd125d0a2093c73ef20fdf681c7af62a140e4e7/coverage-7.13.2-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:c6f141b468740197d6bd38f2b26ade124363228cc3f9858bd9924ab059e00059", size = 250298, upload-time = "2026-01-25T12:57:52.287Z" }, + { url = "https://files.pythonhosted.org/packages/b0/06/713110d3dd3151b93611c9cbfc65c15b4156b44f927fced49ac0b20b32a4/coverage-7.13.2-cp311-cp311-win32.whl", hash = "sha256:89567798404af067604246e01a49ef907d112edf2b75ef814b1364d5ce267031", size = 221485, upload-time = "2026-01-25T12:57:53.876Z" }, + { url = "https://files.pythonhosted.org/packages/16/0c/3ae6255fa1ebcb7dec19c9a59e85ef5f34566d1265c70af5b2fc981da834/coverage-7.13.2-cp311-cp311-win_amd64.whl", hash = "sha256:21dd57941804ae2ac7e921771a5e21bbf9aabec317a041d164853ad0a96ce31e", size = 222421, upload-time = "2026-01-25T12:57:55.433Z" }, + { url = "https://files.pythonhosted.org/packages/b5/37/fabc3179af4d61d89ea47bd04333fec735cd5e8b59baad44fed9fc4170d7/coverage-7.13.2-cp311-cp311-win_arm64.whl", hash = "sha256:10758e0586c134a0bafa28f2d37dd2cdb5e4a90de25c0fc0c77dabbad46eca28", size = 221088, upload-time = "2026-01-25T12:57:57.41Z" }, + { url = "https://files.pythonhosted.org/packages/46/39/e92a35f7800222d3f7b2cbb7bbc3b65672ae8d501cb31801b2d2bd7acdf1/coverage-7.13.2-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:f106b2af193f965d0d3234f3f83fc35278c7fb935dfbde56ae2da3dd2c03b84d", size = 219142, upload-time = "2026-01-25T12:58:00.448Z" }, + { url = "https://files.pythonhosted.org/packages/45/7a/8bf9e9309c4c996e65c52a7c5a112707ecdd9fbaf49e10b5a705a402bbb4/coverage-7.13.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:78f45d21dc4d5d6bd29323f0320089ef7eae16e4bef712dff79d184fa7330af3", size = 219503, upload-time = "2026-01-25T12:58:02.451Z" }, + { url = "https://files.pythonhosted.org/packages/87/93/17661e06b7b37580923f3f12406ac91d78aeed293fb6da0b69cc7957582f/coverage-7.13.2-cp312-cp312-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:fae91dfecd816444c74531a9c3d6ded17a504767e97aa674d44f638107265b99", size = 251006, upload-time = "2026-01-25T12:58:04.059Z" }, + { url = "https://files.pythonhosted.org/packages/12/f0/f9e59fb8c310171497f379e25db060abef9fa605e09d63157eebec102676/coverage-7.13.2-cp312-cp312-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:264657171406c114787b441484de620e03d8f7202f113d62fcd3d9688baa3e6f", size = 253750, upload-time = "2026-01-25T12:58:05.574Z" }, + { url = "https://files.pythonhosted.org/packages/e5/b1/1935e31add2232663cf7edd8269548b122a7d100047ff93475dbaaae673e/coverage-7.13.2-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ae47d8dcd3ded0155afbb59c62bd8ab07ea0fd4902e1c40567439e6db9dcaf2f", size = 254862, upload-time = "2026-01-25T12:58:07.647Z" }, + { url = "https://files.pythonhosted.org/packages/af/59/b5e97071ec13df5f45da2b3391b6cdbec78ba20757bc92580a5b3d5fa53c/coverage-7.13.2-cp312-cp312-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:8a0b33e9fd838220b007ce8f299114d406c1e8edb21336af4c97a26ecfd185aa", size = 251420, upload-time = "2026-01-25T12:58:09.309Z" }, + { url = "https://files.pythonhosted.org/packages/3f/75/9495932f87469d013dc515fb0ce1aac5fa97766f38f6b1a1deb1ee7b7f3a/coverage-7.13.2-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:b3becbea7f3ce9a2d4d430f223ec15888e4deb31395840a79e916368d6004cce", size = 252786, upload-time = "2026-01-25T12:58:10.909Z" }, + { url = "https://files.pythonhosted.org/packages/6a/59/af550721f0eb62f46f7b8cb7e6f1860592189267b1c411a4e3a057caacee/coverage-7.13.2-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:f819c727a6e6eeb8711e4ce63d78c620f69630a2e9d53bc95ca5379f57b6ba94", size = 250928, upload-time = "2026-01-25T12:58:12.449Z" }, + { url = "https://files.pythonhosted.org/packages/9b/b1/21b4445709aae500be4ab43bbcfb4e53dc0811c3396dcb11bf9f23fd0226/coverage-7.13.2-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:4f7b71757a3ab19f7ba286e04c181004c1d61be921795ee8ba6970fd0ec91da5", size = 250496, upload-time = "2026-01-25T12:58:14.047Z" }, + { url = "https://files.pythonhosted.org/packages/ba/b1/0f5d89dfe0392990e4f3980adbde3eb34885bc1effb2dc369e0bf385e389/coverage-7.13.2-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:b7fc50d2afd2e6b4f6f2f403b70103d280a8e0cb35320cbbe6debcda02a1030b", size = 252373, upload-time = "2026-01-25T12:58:15.976Z" }, + { url = "https://files.pythonhosted.org/packages/01/c9/0cf1a6a57a9968cc049a6b896693faa523c638a5314b1fc374eb2b2ac904/coverage-7.13.2-cp312-cp312-win32.whl", hash = "sha256:292250282cf9bcf206b543d7608bda17ca6fc151f4cbae949fc7e115112fbd41", size = 221696, upload-time = "2026-01-25T12:58:17.517Z" }, + { url = "https://files.pythonhosted.org/packages/4d/05/d7540bf983f09d32803911afed135524570f8c47bb394bf6206c1dc3a786/coverage-7.13.2-cp312-cp312-win_amd64.whl", hash = "sha256:eeea10169fac01549a7921d27a3e517194ae254b542102267bef7a93ed38c40e", size = 222504, upload-time = "2026-01-25T12:58:19.115Z" }, + { url = "https://files.pythonhosted.org/packages/15/8b/1a9f037a736ced0a12aacf6330cdaad5008081142a7070bc58b0f7930cbc/coverage-7.13.2-cp312-cp312-win_arm64.whl", hash = "sha256:2a5b567f0b635b592c917f96b9a9cb3dbd4c320d03f4bf94e9084e494f2e8894", size = 221120, upload-time = "2026-01-25T12:58:21.334Z" }, + { url = "https://files.pythonhosted.org/packages/d2/db/d291e30fdf7ea617a335531e72294e0c723356d7fdde8fba00610a76bda9/coverage-7.13.2-py3-none-any.whl", hash = "sha256:40ce1ea1e25125556d8e76bd0b61500839a07944cc287ac21d5626f3e620cad5", size = 210943, upload-time = "2026-01-25T13:00:02.388Z" }, +] + +[package.optional-dependencies] +toml = [ + { name = "tomli", marker = "python_full_version <= '3.11'" }, +] + +[[package]] +name = "decorator" +version = "5.2.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/43/fa/6d96a0978d19e17b68d634497769987b16c8f4cd0a7a05048bec693caa6b/decorator-5.2.1.tar.gz", hash = "sha256:65f266143752f734b0a7cc83c46f4618af75b8c5911b00ccb61d0ac9b6da0360", size = 56711, upload-time = "2025-02-24T04:41:34.073Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/4e/8c/f3147f5c4b73e7550fe5f9352eaa956ae838d5c51eb58e7a25b9f3e2643b/decorator-5.2.1-py3-none-any.whl", hash = "sha256:d316bb415a2d9e2d2b3abcc4084c6502fc09240e292cd76a76afc106a1c8e04a", size = 9190, upload-time = "2025-02-24T04:41:32.565Z" }, +] + +[[package]] +name = "executing" +version = "2.2.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/cc/28/c14e053b6762b1044f34a13aab6859bbf40456d37d23aa286ac24cfd9a5d/executing-2.2.1.tar.gz", hash = "sha256:3632cc370565f6648cc328b32435bd120a1e4ebb20c77e3fdde9a13cd1e533c4", size = 1129488, upload-time = "2025-09-01T09:48:10.866Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/c1/ea/53f2148663b321f21b5a606bd5f191517cf40b7072c0497d3c92c4a13b1e/executing-2.2.1-py2.py3-none-any.whl", hash = "sha256:760643d3452b4d777d295bb167ccc74c64a81df23fb5e08eff250c425a4b2017", size = 28317, upload-time = "2025-09-01T09:48:08.5Z" }, +] + +[[package]] +name = "expression" +version = "5.6.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "typing-extensions" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/43/c7/bb061623b5815566bda69f5e9d156e38a97ebb383b8db3d2dedb26415466/expression-5.6.0.tar.gz", hash = "sha256:454f6fe138347194a43c7f878d958efe9b84b9cc770e462010c7a52e18058065", size = 59147, upload-time = "2025-02-19T09:37:37.432Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/6b/a2/656b8bebe495117342a8676ccabf52b3885ce11a856c8dfe1fbbdc250d2d/expression-5.6.0-py3-none-any.whl", hash = "sha256:f5c62e38186c9287e088dee9cf3939b0bbde21cb4c59571872154a53d33dd7c0", size = 69673, upload-time = "2025-02-19T09:37:35.476Z" }, +] + +[[package]] +name = "hypothesis" +version = "6.151.4" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "sortedcontainers" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/47/03/9fd03d5db09029250e69745c1600edab16fe90947636f77a12ba92d79939/hypothesis-6.151.4.tar.gz", hash = "sha256:658a62da1c3ccb36746ac2f7dc4bb1a6e76bd314e0dc54c4e1aaba2503d5545c", size = 475706, upload-time = "2026-01-29T01:30:14.985Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/9b/6d/01ad1b6c3b8cb2bb47eeaa9765dabc27cbe68e3b59f6cff83d5668f57780/hypothesis-6.151.4-py3-none-any.whl", hash = "sha256:a1cf7e0fdaa296d697a68ff3c0b3912c0050f07aa37e7d2ff33a966749d1d9b4", size = 543146, upload-time = "2026-01-29T01:30:12.805Z" }, +] + +[[package]] +name = "iniconfig" +version = "2.3.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/72/34/14ca021ce8e5dfedc35312d08ba8bf51fdd999c576889fc2c24cb97f4f10/iniconfig-2.3.0.tar.gz", hash = "sha256:c76315c77db068650d49c5b56314774a7804df16fee4402c1f19d6d15d8c4730", size = 20503, upload-time = "2025-10-18T21:55:43.219Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl", hash = "sha256:f631c04d2c48c52b84d0d0549c99ff3859c98df65b3101406327ecc7d53fbf12", size = 7484, upload-time = "2025-10-18T21:55:41.639Z" }, +] + +[[package]] +name = "ipython" +version = "9.10.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "colorama", marker = "sys_platform == 'win32'" }, + { name = "decorator" }, + { name = "ipython-pygments-lexers" }, + { name = "jedi" }, + { name = "matplotlib-inline" }, + { name = "pexpect", marker = "sys_platform != 'emscripten' and sys_platform != 'win32'" }, + { name = "prompt-toolkit" }, + { name = "pygments" }, + { name = "stack-data" }, + { name = "traitlets" }, + { name = "typing-extensions", marker = "python_full_version < '3.12'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/a6/60/2111715ea11f39b1535bed6024b7dec7918b71e5e5d30855a5b503056b50/ipython-9.10.0.tar.gz", hash = "sha256:cd9e656be97618a0676d058134cd44e6dc7012c0e5cb36a9ce96a8c904adaf77", size = 4426526, upload-time = "2026-02-02T10:00:33.594Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/3d/aa/898dec789a05731cd5a9f50605b7b44a72bd198fd0d4528e11fc610177cc/ipython-9.10.0-py3-none-any.whl", hash = "sha256:c6ab68cc23bba8c7e18e9b932797014cc61ea7fd6f19de180ab9ba73e65ee58d", size = 622774, upload-time = "2026-02-02T10:00:31.503Z" }, +] + +[[package]] +name = "ipython-pygments-lexers" +version = "1.1.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "pygments" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/ef/4c/5dd1d8af08107f88c7f741ead7a40854b8ac24ddf9ae850afbcf698aa552/ipython_pygments_lexers-1.1.1.tar.gz", hash = "sha256:09c0138009e56b6854f9535736f4171d855c8c08a563a0dcd8022f78355c7e81", size = 8393, upload-time = "2025-01-17T11:24:34.505Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/d9/33/1f075bf72b0b747cb3288d011319aaf64083cf2efef8354174e3ed4540e2/ipython_pygments_lexers-1.1.1-py3-none-any.whl", hash = "sha256:a9462224a505ade19a605f71f8fa63c2048833ce50abc86768a0d81d876dc81c", size = 8074, upload-time = "2025-01-17T11:24:33.271Z" }, +] + +[[package]] +name = "jedi" +version = "0.19.2" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "parso" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/72/3a/79a912fbd4d8dd6fbb02bf69afd3bb72cf0c729bb3063c6f4498603db17a/jedi-0.19.2.tar.gz", hash = "sha256:4770dc3de41bde3966b02eb84fbcf557fb33cce26ad23da12c742fb50ecb11f0", size = 1231287, upload-time = "2024-11-11T01:41:42.873Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/c0/5a/9cac0c82afec3d09ccd97c8b6502d48f165f9124db81b4bcb90b4af974ee/jedi-0.19.2-py2.py3-none-any.whl", hash = "sha256:a8ef22bde8490f57fe5c7681a3c83cb58874daf72b4784de3cce5b6ef6edb5b9", size = 1572278, upload-time = "2024-11-11T01:41:40.175Z" }, +] + +[[package]] +name = "matplotlib-inline" +version = "0.2.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "traitlets" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/c7/74/97e72a36efd4ae2bccb3463284300f8953f199b5ffbc04cbbb0ec78f74b1/matplotlib_inline-0.2.1.tar.gz", hash = "sha256:e1ee949c340d771fc39e241ea75683deb94762c8fa5f2927ec57c83c4dffa9fe", size = 8110, upload-time = "2025-10-23T09:00:22.126Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/af/33/ee4519fa02ed11a94aef9559552f3b17bb863f2ecfe1a35dc7f548cde231/matplotlib_inline-0.2.1-py3-none-any.whl", hash = "sha256:d56ce5156ba6085e00a9d54fead6ed29a9c47e215cd1bba2e976ef39f5710a76", size = 9516, upload-time = "2025-10-23T09:00:20.675Z" }, +] + +[[package]] +name = "nodeenv" +version = "1.10.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/24/bf/d1bda4f6168e0b2e9e5958945e01910052158313224ada5ce1fb2e1113b8/nodeenv-1.10.0.tar.gz", hash = "sha256:996c191ad80897d076bdfba80a41994c2b47c68e224c542b48feba42ba00f8bb", size = 55611, upload-time = "2025-12-20T14:08:54.006Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/88/b2/d0896bdcdc8d28a7fc5717c305f1a861c26e18c05047949fb371034d98bd/nodeenv-1.10.0-py2.py3-none-any.whl", hash = "sha256:5bb13e3eed2923615535339b3c620e76779af4cb4c6a90deccc9e36b274d3827", size = 23438, upload-time = "2025-12-20T14:08:52.782Z" }, +] + +[[package]] +name = "packaging" +version = "26.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/65/ee/299d360cdc32edc7d2cf530f3accf79c4fca01e96ffc950d8a52213bd8e4/packaging-26.0.tar.gz", hash = "sha256:00243ae351a257117b6a241061796684b084ed1c516a08c48a3f7e147a9d80b4", size = 143416, upload-time = "2026-01-21T20:50:39.064Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/b7/b9/c538f279a4e237a006a2c98387d081e9eb060d203d8ed34467cc0f0b9b53/packaging-26.0-py3-none-any.whl", hash = "sha256:b36f1fef9334a5588b4166f8bcd26a14e521f2b55e6b9de3aaa80d3ff7a37529", size = 74366, upload-time = "2026-01-21T20:50:37.788Z" }, +] + +[[package]] +name = "parso" +version = "0.8.5" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/d4/de/53e0bcf53d13e005bd8c92e7855142494f41171b34c2536b86187474184d/parso-0.8.5.tar.gz", hash = "sha256:034d7354a9a018bdce352f48b2a8a450f05e9d6ee85db84764e9b6bd96dafe5a", size = 401205, upload-time = "2025-08-23T15:15:28.028Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/16/32/f8e3c85d1d5250232a5d3477a2a28cc291968ff175caeadaf3cc19ce0e4a/parso-0.8.5-py2.py3-none-any.whl", hash = "sha256:646204b5ee239c396d040b90f9e272e9a8017c630092bf59980beb62fd033887", size = 106668, upload-time = "2025-08-23T15:15:25.663Z" }, +] + +[[package]] +name = "pexpect" +version = "4.9.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "ptyprocess" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/42/92/cc564bf6381ff43ce1f4d06852fc19a2f11d180f23dc32d9588bee2f149d/pexpect-4.9.0.tar.gz", hash = "sha256:ee7d41123f3c9911050ea2c2dac107568dc43b2d3b0c7557a33212c398ead30f", size = 166450, upload-time = "2023-11-25T09:07:26.339Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/9e/c3/059298687310d527a58bb01f3b1965787ee3b40dce76752eda8b44e9a2c5/pexpect-4.9.0-py2.py3-none-any.whl", hash = "sha256:7236d1e080e4936be2dc3e326cec0af72acf9212a7e1d060210e70a47e253523", size = 63772, upload-time = "2023-11-25T06:56:14.81Z" }, +] + +[[package]] +name = "pluggy" +version = "1.6.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/f9/e2/3e91f31a7d2b083fe6ef3fa267035b518369d9511ffab804f839851d2779/pluggy-1.6.0.tar.gz", hash = "sha256:7dcc130b76258d33b90f61b658791dede3486c3e6bfb003ee5c9bfb396dd22f3", size = 69412, upload-time = "2025-05-15T12:30:07.975Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl", hash = "sha256:e920276dd6813095e9377c0bc5566d94c932c33b27a3e3945d8389c374dd4746", size = 20538, upload-time = "2025-05-15T12:30:06.134Z" }, +] + +[[package]] +name = "pnt-functional" +version = "0.1.1" +source = { editable = "." } +dependencies = [ + { name = "beartype" }, + { name = "expression" }, +] + +[package.dev-dependencies] +dev = [ + { name = "hypothesis" }, + { name = "ipython" }, + { name = "pyright" }, + { name = "pytest" }, + { name = "pytest-cov" }, + { name = "ruff" }, + { name = "xdoctest" }, +] +interactive = [ + { name = "ipython" }, +] +lint = [ + { name = "ruff" }, +] +test = [ + { name = "hypothesis" }, + { name = "pytest" }, + { name = "pytest-cov" }, + { name = "xdoctest" }, +] +types = [ + { name = "pyright" }, +] + +[package.metadata] +requires-dist = [ + { name = "beartype", specifier = ">=0.19.0,<0.20.0" }, + { name = "expression", specifier = ">=5.5.0" }, +] + +[package.metadata.requires-dev] +dev = [ + { name = "hypothesis", specifier = ">=6.125.1" }, + { name = "ipython", specifier = ">=8.32.0" }, + { name = "pyright", specifier = ">=1.1.395" }, + { name = "pytest", specifier = ">=8.3.4" }, + { name = "pytest-cov", specifier = ">=6.0.0" }, + { name = "ruff", specifier = ">=0.9.4" }, + { name = "xdoctest", specifier = ">=1.2.0" }, +] +interactive = [{ name = "ipython", specifier = ">=8.32.0" }] +lint = [{ name = "ruff", specifier = ">=0.9.4" }] +test = [ + { name = "hypothesis", specifier = ">=6.125.1" }, + { name = "pytest", specifier = ">=8.3.4" }, + { name = "pytest-cov", specifier = ">=6.0.0" }, + { name = "xdoctest", specifier = ">=1.2.0" }, +] +types = [{ name = "pyright", specifier = ">=1.1.395" }] + +[[package]] +name = "prompt-toolkit" +version = "3.0.52" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "wcwidth" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/a1/96/06e01a7b38dce6fe1db213e061a4602dd6032a8a97ef6c1a862537732421/prompt_toolkit-3.0.52.tar.gz", hash = "sha256:28cde192929c8e7321de85de1ddbe736f1375148b02f2e17edd840042b1be855", size = 434198, upload-time = "2025-08-27T15:24:02.057Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/84/03/0d3ce49e2505ae70cf43bc5bb3033955d2fc9f932163e84dc0779cc47f48/prompt_toolkit-3.0.52-py3-none-any.whl", hash = "sha256:9aac639a3bbd33284347de5ad8d68ecc044b91a762dc39b7c21095fcd6a19955", size = 391431, upload-time = "2025-08-27T15:23:59.498Z" }, +] + +[[package]] +name = "ptyprocess" +version = "0.7.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/20/e5/16ff212c1e452235a90aeb09066144d0c5a6a8c0834397e03f5224495c4e/ptyprocess-0.7.0.tar.gz", hash = "sha256:5c5d0a3b48ceee0b48485e0c26037c0acd7d29765ca3fbb5cb3831d347423220", size = 70762, upload-time = "2020-12-28T15:15:30.155Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/22/a6/858897256d0deac81a172289110f31629fc4cee19b6f01283303e18c8db3/ptyprocess-0.7.0-py2.py3-none-any.whl", hash = "sha256:4b41f3967fce3af57cc7e94b888626c18bf37a083e3651ca8feeb66d492fef35", size = 13993, upload-time = "2020-12-28T15:15:28.35Z" }, +] + +[[package]] +name = "pure-eval" +version = "0.2.3" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/cd/05/0a34433a064256a578f1783a10da6df098ceaa4a57bbeaa96a6c0352786b/pure_eval-0.2.3.tar.gz", hash = "sha256:5f4e983f40564c576c7c8635ae88db5956bb2229d7e9237d03b3c0b0190eaf42", size = 19752, upload-time = "2024-07-21T12:58:21.801Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/8e/37/efad0257dc6e593a18957422533ff0f87ede7c9c6ea010a2177d738fb82f/pure_eval-0.2.3-py3-none-any.whl", hash = "sha256:1db8e35b67b3d218d818ae653e27f06c3aa420901fa7b081ca98cbedc874e0d0", size = 11842, upload-time = "2024-07-21T12:58:20.04Z" }, +] + +[[package]] +name = "pygments" +version = "2.19.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/b0/77/a5b8c569bf593b0140bde72ea885a803b82086995367bf2037de0159d924/pygments-2.19.2.tar.gz", hash = "sha256:636cb2477cec7f8952536970bc533bc43743542f70392ae026374600add5b887", size = 4968631, upload-time = "2025-06-21T13:39:12.283Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/c7/21/705964c7812476f378728bdf590ca4b771ec72385c533964653c68e86bdc/pygments-2.19.2-py3-none-any.whl", hash = "sha256:86540386c03d588bb81d44bc3928634ff26449851e99741617ecb9037ee5ec0b", size = 1225217, upload-time = "2025-06-21T13:39:07.939Z" }, +] + +[[package]] +name = "pyright" +version = "1.1.408" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "nodeenv" }, + { name = "typing-extensions" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/74/b2/5db700e52554b8f025faa9c3c624c59f1f6c8841ba81ab97641b54322f16/pyright-1.1.408.tar.gz", hash = "sha256:f28f2321f96852fa50b5829ea492f6adb0e6954568d1caa3f3af3a5f555eb684", size = 4400578, upload-time = "2026-01-08T08:07:38.795Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/0c/82/a2c93e32800940d9573fb28c346772a14778b84ba7524e691b324620ab89/pyright-1.1.408-py3-none-any.whl", hash = "sha256:090b32865f4fdb1e0e6cd82bf5618480d48eecd2eb2e70f960982a3d9a4c17c1", size = 6399144, upload-time = "2026-01-08T08:07:37.082Z" }, +] + +[[package]] +name = "pytest" +version = "9.0.2" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "colorama", marker = "sys_platform == 'win32'" }, + { name = "iniconfig" }, + { name = "packaging" }, + { name = "pluggy" }, + { name = "pygments" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/d1/db/7ef3487e0fb0049ddb5ce41d3a49c235bf9ad299b6a25d5780a89f19230f/pytest-9.0.2.tar.gz", hash = "sha256:75186651a92bd89611d1d9fc20f0b4345fd827c41ccd5c299a868a05d70edf11", size = 1568901, upload-time = "2025-12-06T21:30:51.014Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/3b/ab/b3226f0bd7cdcf710fbede2b3548584366da3b19b5021e74f5bde2a8fa3f/pytest-9.0.2-py3-none-any.whl", hash = "sha256:711ffd45bf766d5264d487b917733b453d917afd2b0ad65223959f59089f875b", size = 374801, upload-time = "2025-12-06T21:30:49.154Z" }, +] + +[[package]] +name = "pytest-cov" +version = "7.0.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "coverage", extra = ["toml"] }, + { name = "pluggy" }, + { name = "pytest" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/5e/f7/c933acc76f5208b3b00089573cf6a2bc26dc80a8aece8f52bb7d6b1855ca/pytest_cov-7.0.0.tar.gz", hash = "sha256:33c97eda2e049a0c5298e91f519302a1334c26ac65c1a483d6206fd458361af1", size = 54328, upload-time = "2025-09-09T10:57:02.113Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/ee/49/1377b49de7d0c1ce41292161ea0f721913fa8722c19fb9c1e3aa0367eecb/pytest_cov-7.0.0-py3-none-any.whl", hash = "sha256:3b8e9558b16cc1479da72058bdecf8073661c7f57f7d3c5f22a1c23507f2d861", size = 22424, upload-time = "2025-09-09T10:57:00.695Z" }, +] + +[[package]] +name = "ruff" +version = "0.14.14" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/2e/06/f71e3a86b2df0dfa2d2f72195941cd09b44f87711cb7fa5193732cb9a5fc/ruff-0.14.14.tar.gz", hash = "sha256:2d0f819c9a90205f3a867dbbd0be083bee9912e170fd7d9704cc8ae45824896b", size = 4515732, upload-time = "2026-01-22T22:30:17.527Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/d2/89/20a12e97bc6b9f9f68343952da08a8099c57237aef953a56b82711d55edd/ruff-0.14.14-py3-none-linux_armv6l.whl", hash = "sha256:7cfe36b56e8489dee8fbc777c61959f60ec0f1f11817e8f2415f429552846aed", size = 10467650, upload-time = "2026-01-22T22:30:08.578Z" }, + { url = "https://files.pythonhosted.org/packages/a3/b1/c5de3fd2d5a831fcae21beda5e3589c0ba67eec8202e992388e4b17a6040/ruff-0.14.14-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:6006a0082336e7920b9573ef8a7f52eec837add1265cc74e04ea8a4368cd704c", size = 10883245, upload-time = "2026-01-22T22:30:04.155Z" }, + { url = "https://files.pythonhosted.org/packages/b8/7c/3c1db59a10e7490f8f6f8559d1db8636cbb13dccebf18686f4e3c9d7c772/ruff-0.14.14-py3-none-macosx_11_0_arm64.whl", hash = "sha256:026c1d25996818f0bf498636686199d9bd0d9d6341c9c2c3b62e2a0198b758de", size = 10231273, upload-time = "2026-01-22T22:30:34.642Z" }, + { url = "https://files.pythonhosted.org/packages/a1/6e/5e0e0d9674be0f8581d1f5e0f0a04761203affce3232c1a1189d0e3b4dad/ruff-0.14.14-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f666445819d31210b71e0a6d1c01e24447a20b85458eea25a25fe8142210ae0e", size = 10585753, upload-time = "2026-01-22T22:30:31.781Z" }, + { url = "https://files.pythonhosted.org/packages/23/09/754ab09f46ff1884d422dc26d59ba18b4e5d355be147721bb2518aa2a014/ruff-0.14.14-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:3c0f18b922c6d2ff9a5e6c3ee16259adc513ca775bcf82c67ebab7cbd9da5bc8", size = 10286052, upload-time = "2026-01-22T22:30:24.827Z" }, + { url = "https://files.pythonhosted.org/packages/c8/cc/e71f88dd2a12afb5f50733851729d6b571a7c3a35bfdb16c3035132675a0/ruff-0.14.14-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1629e67489c2dea43e8658c3dba659edbfd87361624b4040d1df04c9740ae906", size = 11043637, upload-time = "2026-01-22T22:30:13.239Z" }, + { url = "https://files.pythonhosted.org/packages/67/b2/397245026352494497dac935d7f00f1468c03a23a0c5db6ad8fc49ca3fb2/ruff-0.14.14-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:27493a2131ea0f899057d49d303e4292b2cae2bb57253c1ed1f256fbcd1da480", size = 12194761, upload-time = "2026-01-22T22:30:22.542Z" }, + { url = "https://files.pythonhosted.org/packages/5b/06/06ef271459f778323112c51b7587ce85230785cd64e91772034ddb88f200/ruff-0.14.14-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:01ff589aab3f5b539e35db38425da31a57521efd1e4ad1ae08fc34dbe30bd7df", size = 12005701, upload-time = "2026-01-22T22:30:20.499Z" }, + { url = "https://files.pythonhosted.org/packages/41/d6/99364514541cf811ccc5ac44362f88df66373e9fec1b9d1c4cc830593fe7/ruff-0.14.14-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:1cc12d74eef0f29f51775f5b755913eb523546b88e2d733e1d701fe65144e89b", size = 11282455, upload-time = "2026-01-22T22:29:59.679Z" }, + { url = "https://files.pythonhosted.org/packages/ca/71/37daa46f89475f8582b7762ecd2722492df26421714a33e72ccc9a84d7a5/ruff-0.14.14-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bb8481604b7a9e75eff53772496201690ce2687067e038b3cc31aaf16aa0b974", size = 11215882, upload-time = "2026-01-22T22:29:57.032Z" }, + { url = "https://files.pythonhosted.org/packages/2c/10/a31f86169ec91c0705e618443ee74ede0bdd94da0a57b28e72db68b2dbac/ruff-0.14.14-py3-none-manylinux_2_31_riscv64.whl", hash = "sha256:14649acb1cf7b5d2d283ebd2f58d56b75836ed8c6f329664fa91cdea19e76e66", size = 11180549, upload-time = "2026-01-22T22:30:27.175Z" }, + { url = "https://files.pythonhosted.org/packages/fd/1e/c723f20536b5163adf79bdd10c5f093414293cdf567eed9bdb7b83940f3f/ruff-0.14.14-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:e8058d2145566510790eab4e2fad186002e288dec5e0d343a92fe7b0bc1b3e13", size = 10543416, upload-time = "2026-01-22T22:30:01.964Z" }, + { url = "https://files.pythonhosted.org/packages/3e/34/8a84cea7e42c2d94ba5bde1d7a4fae164d6318f13f933d92da6d7c2041ff/ruff-0.14.14-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:e651e977a79e4c758eb807f0481d673a67ffe53cfa92209781dfa3a996cf8412", size = 10285491, upload-time = "2026-01-22T22:30:29.51Z" }, + { url = "https://files.pythonhosted.org/packages/55/ef/b7c5ea0be82518906c978e365e56a77f8de7678c8bb6651ccfbdc178c29f/ruff-0.14.14-py3-none-musllinux_1_2_i686.whl", hash = "sha256:cc8b22da8d9d6fdd844a68ae937e2a0adf9b16514e9a97cc60355e2d4b219fc3", size = 10733525, upload-time = "2026-01-22T22:30:06.499Z" }, + { url = "https://files.pythonhosted.org/packages/6a/5b/aaf1dfbcc53a2811f6cc0a1759de24e4b03e02ba8762daabd9b6bd8c59e3/ruff-0.14.14-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:16bc890fb4cc9781bb05beb5ab4cd51be9e7cb376bf1dd3580512b24eb3fda2b", size = 11315626, upload-time = "2026-01-22T22:30:36.848Z" }, + { url = "https://files.pythonhosted.org/packages/2c/aa/9f89c719c467dfaf8ad799b9bae0df494513fb21d31a6059cb5870e57e74/ruff-0.14.14-py3-none-win32.whl", hash = "sha256:b530c191970b143375b6a68e6f743800b2b786bbcf03a7965b06c4bf04568167", size = 10502442, upload-time = "2026-01-22T22:30:38.93Z" }, + { url = "https://files.pythonhosted.org/packages/87/44/90fa543014c45560cae1fffc63ea059fb3575ee6e1cb654562197e5d16fb/ruff-0.14.14-py3-none-win_amd64.whl", hash = "sha256:3dde1435e6b6fe5b66506c1dff67a421d0b7f6488d466f651c07f4cab3bf20fd", size = 11630486, upload-time = "2026-01-22T22:30:10.852Z" }, + { url = "https://files.pythonhosted.org/packages/9e/6a/40fee331a52339926a92e17ae748827270b288a35ef4a15c9c8f2ec54715/ruff-0.14.14-py3-none-win_arm64.whl", hash = "sha256:56e6981a98b13a32236a72a8da421d7839221fa308b223b9283312312e5ac76c", size = 10920448, upload-time = "2026-01-22T22:30:15.417Z" }, +] + +[[package]] +name = "sortedcontainers" +version = "2.4.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/e8/c4/ba2f8066cceb6f23394729afe52f3bf7adec04bf9ed2c820b39e19299111/sortedcontainers-2.4.0.tar.gz", hash = "sha256:25caa5a06cc30b6b83d11423433f65d1f9d76c4c6a0c90e3379eaa43b9bfdb88", size = 30594, upload-time = "2021-05-16T22:03:42.897Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/32/46/9cb0e58b2deb7f82b84065f37f3bffeb12413f947f9388e4cac22c4621ce/sortedcontainers-2.4.0-py2.py3-none-any.whl", hash = "sha256:a163dcaede0f1c021485e957a39245190e74249897e2ae4b2aa38595db237ee0", size = 29575, upload-time = "2021-05-16T22:03:41.177Z" }, +] + +[[package]] +name = "stack-data" +version = "0.6.3" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "asttokens" }, + { name = "executing" }, + { name = "pure-eval" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/28/e3/55dcc2cfbc3ca9c29519eb6884dd1415ecb53b0e934862d3559ddcb7e20b/stack_data-0.6.3.tar.gz", hash = "sha256:836a778de4fec4dcd1dcd89ed8abff8a221f58308462e1c4aa2a3cf30148f0b9", size = 44707, upload-time = "2023-09-30T13:58:05.479Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/f1/7b/ce1eafaf1a76852e2ec9b22edecf1daa58175c090266e9f6c64afcd81d91/stack_data-0.6.3-py3-none-any.whl", hash = "sha256:d5558e0c25a4cb0853cddad3d77da9891a08cb85dd9f9f91b9f8cd66e511e695", size = 24521, upload-time = "2023-09-30T13:58:03.53Z" }, +] + +[[package]] +name = "tomli" +version = "2.4.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/82/30/31573e9457673ab10aa432461bee537ce6cef177667deca369efb79df071/tomli-2.4.0.tar.gz", hash = "sha256:aa89c3f6c277dd275d8e243ad24f3b5e701491a860d5121f2cdd399fbb31fc9c", size = 17477, upload-time = "2026-01-11T11:22:38.165Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/3c/d9/3dc2289e1f3b32eb19b9785b6a006b28ee99acb37d1d47f78d4c10e28bf8/tomli-2.4.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:b5ef256a3fd497d4973c11bf142e9ed78b150d36f5773f1ca6088c230ffc5867", size = 153663, upload-time = "2026-01-11T11:21:45.27Z" }, + { url = "https://files.pythonhosted.org/packages/51/32/ef9f6845e6b9ca392cd3f64f9ec185cc6f09f0a2df3db08cbe8809d1d435/tomli-2.4.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:5572e41282d5268eb09a697c89a7bee84fae66511f87533a6f88bd2f7b652da9", size = 148469, upload-time = "2026-01-11T11:21:46.873Z" }, + { url = "https://files.pythonhosted.org/packages/d6/c2/506e44cce89a8b1b1e047d64bd495c22c9f71f21e05f380f1a950dd9c217/tomli-2.4.0-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:551e321c6ba03b55676970b47cb1b73f14a0a4dce6a3e1a9458fd6d921d72e95", size = 236039, upload-time = "2026-01-11T11:21:48.503Z" }, + { url = "https://files.pythonhosted.org/packages/b3/40/e1b65986dbc861b7e986e8ec394598187fa8aee85b1650b01dd925ca0be8/tomli-2.4.0-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:5e3f639a7a8f10069d0e15408c0b96a2a828cfdec6fca05296ebcdcc28ca7c76", size = 243007, upload-time = "2026-01-11T11:21:49.456Z" }, + { url = "https://files.pythonhosted.org/packages/9c/6f/6e39ce66b58a5b7ae572a0f4352ff40c71e8573633deda43f6a379d56b3e/tomli-2.4.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:1b168f2731796b045128c45982d3a4874057626da0e2ef1fdd722848b741361d", size = 240875, upload-time = "2026-01-11T11:21:50.755Z" }, + { url = "https://files.pythonhosted.org/packages/aa/ad/cb089cb190487caa80204d503c7fd0f4d443f90b95cf4ef5cf5aa0f439b0/tomli-2.4.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:133e93646ec4300d651839d382d63edff11d8978be23da4cc106f5a18b7d0576", size = 246271, upload-time = "2026-01-11T11:21:51.81Z" }, + { url = "https://files.pythonhosted.org/packages/0b/63/69125220e47fd7a3a27fd0de0c6398c89432fec41bc739823bcc66506af6/tomli-2.4.0-cp311-cp311-win32.whl", hash = "sha256:b6c78bdf37764092d369722d9946cb65b8767bfa4110f902a1b2542d8d173c8a", size = 96770, upload-time = "2026-01-11T11:21:52.647Z" }, + { url = "https://files.pythonhosted.org/packages/1e/0d/a22bb6c83f83386b0008425a6cd1fa1c14b5f3dd4bad05e98cf3dbbf4a64/tomli-2.4.0-cp311-cp311-win_amd64.whl", hash = "sha256:d3d1654e11d724760cdb37a3d7691f0be9db5fbdaef59c9f532aabf87006dbaa", size = 107626, upload-time = "2026-01-11T11:21:53.459Z" }, + { url = "https://files.pythonhosted.org/packages/2f/6d/77be674a3485e75cacbf2ddba2b146911477bd887dda9d8c9dfb2f15e871/tomli-2.4.0-cp311-cp311-win_arm64.whl", hash = "sha256:cae9c19ed12d4e8f3ebf46d1a75090e4c0dc16271c5bce1c833ac168f08fb614", size = 94842, upload-time = "2026-01-11T11:21:54.831Z" }, + { url = "https://files.pythonhosted.org/packages/3c/43/7389a1869f2f26dba52404e1ef13b4784b6b37dac93bac53457e3ff24ca3/tomli-2.4.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:920b1de295e72887bafa3ad9f7a792f811847d57ea6b1215154030cf131f16b1", size = 154894, upload-time = "2026-01-11T11:21:56.07Z" }, + { url = "https://files.pythonhosted.org/packages/e9/05/2f9bf110b5294132b2edf13fe6ca6ae456204f3d749f623307cbb7a946f2/tomli-2.4.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:7d6d9a4aee98fac3eab4952ad1d73aee87359452d1c086b5ceb43ed02ddb16b8", size = 149053, upload-time = "2026-01-11T11:21:57.467Z" }, + { url = "https://files.pythonhosted.org/packages/e8/41/1eda3ca1abc6f6154a8db4d714a4d35c4ad90adc0bcf700657291593fbf3/tomli-2.4.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:36b9d05b51e65b254ea6c2585b59d2c4cb91c8a3d91d0ed0f17591a29aaea54a", size = 243481, upload-time = "2026-01-11T11:21:58.661Z" }, + { url = "https://files.pythonhosted.org/packages/d2/6d/02ff5ab6c8868b41e7d4b987ce2b5f6a51d3335a70aa144edd999e055a01/tomli-2.4.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:1c8a885b370751837c029ef9bc014f27d80840e48bac415f3412e6593bbc18c1", size = 251720, upload-time = "2026-01-11T11:22:00.178Z" }, + { url = "https://files.pythonhosted.org/packages/7b/57/0405c59a909c45d5b6f146107c6d997825aa87568b042042f7a9c0afed34/tomli-2.4.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:8768715ffc41f0008abe25d808c20c3d990f42b6e2e58305d5da280ae7d1fa3b", size = 247014, upload-time = "2026-01-11T11:22:01.238Z" }, + { url = "https://files.pythonhosted.org/packages/2c/0e/2e37568edd944b4165735687cbaf2fe3648129e440c26d02223672ee0630/tomli-2.4.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:7b438885858efd5be02a9a133caf5812b8776ee0c969fea02c45e8e3f296ba51", size = 251820, upload-time = "2026-01-11T11:22:02.727Z" }, + { url = "https://files.pythonhosted.org/packages/5a/1c/ee3b707fdac82aeeb92d1a113f803cf6d0f37bdca0849cb489553e1f417a/tomli-2.4.0-cp312-cp312-win32.whl", hash = "sha256:0408e3de5ec77cc7f81960c362543cbbd91ef883e3138e81b729fc3eea5b9729", size = 97712, upload-time = "2026-01-11T11:22:03.777Z" }, + { url = "https://files.pythonhosted.org/packages/69/13/c07a9177d0b3bab7913299b9278845fc6eaaca14a02667c6be0b0a2270c8/tomli-2.4.0-cp312-cp312-win_amd64.whl", hash = "sha256:685306e2cc7da35be4ee914fd34ab801a6acacb061b6a7abca922aaf9ad368da", size = 108296, upload-time = "2026-01-11T11:22:04.86Z" }, + { url = "https://files.pythonhosted.org/packages/18/27/e267a60bbeeee343bcc279bb9e8fbed0cbe224bc7b2a3dc2975f22809a09/tomli-2.4.0-cp312-cp312-win_arm64.whl", hash = "sha256:5aa48d7c2356055feef06a43611fc401a07337d5b006be13a30f6c58f869e3c3", size = 94553, upload-time = "2026-01-11T11:22:05.854Z" }, + { url = "https://files.pythonhosted.org/packages/23/d1/136eb2cb77520a31e1f64cbae9d33ec6df0d78bdf4160398e86eec8a8754/tomli-2.4.0-py3-none-any.whl", hash = "sha256:1f776e7d669ebceb01dee46484485f43a4048746235e683bcdffacdf1fb4785a", size = 14477, upload-time = "2026-01-11T11:22:37.446Z" }, +] + +[[package]] +name = "traitlets" +version = "5.14.3" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/eb/79/72064e6a701c2183016abbbfedaba506d81e30e232a68c9f0d6f6fcd1574/traitlets-5.14.3.tar.gz", hash = "sha256:9ed0579d3502c94b4b3732ac120375cda96f923114522847de4b3bb98b96b6b7", size = 161621, upload-time = "2024-04-19T11:11:49.746Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/00/c0/8f5d070730d7836adc9c9b6408dec68c6ced86b304a9b26a14df072a6e8c/traitlets-5.14.3-py3-none-any.whl", hash = "sha256:b74e89e397b1ed28cc831db7aea759ba6640cb3de13090ca145426688ff1ac4f", size = 85359, upload-time = "2024-04-19T11:11:46.763Z" }, +] + +[[package]] +name = "typing-extensions" +version = "4.15.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/72/94/1a15dd82efb362ac84269196e94cf00f187f7ed21c242792a923cdb1c61f/typing_extensions-4.15.0.tar.gz", hash = "sha256:0cea48d173cc12fa28ecabc3b837ea3cf6f38c6d1136f85cbaaf598984861466", size = 109391, upload-time = "2025-08-25T13:49:26.313Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/18/67/36e9267722cc04a6b9f15c7f3441c2363321a3ea07da7ae0c0707beb2a9c/typing_extensions-4.15.0-py3-none-any.whl", hash = "sha256:f0fa19c6845758ab08074a0cfa8b7aecb71c999ca73d62883bc25cc018c4e548", size = 44614, upload-time = "2025-08-25T13:49:24.86Z" }, +] + +[[package]] +name = "wcwidth" +version = "0.5.3" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/c2/62/a7c072fbfefb2980a00f99ca994279cb9ecf310cb2e6b2a4d2a28fe192b3/wcwidth-0.5.3.tar.gz", hash = "sha256:53123b7af053c74e9fe2e92ac810301f6139e64379031f7124574212fb3b4091", size = 157587, upload-time = "2026-01-31T03:52:10.92Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/3c/c1/d73f12f8cdb1891334a2ccf7389eed244d3941e74d80dd220badb937f3fb/wcwidth-0.5.3-py3-none-any.whl", hash = "sha256:d584eff31cd4753e1e5ff6c12e1edfdb324c995713f75d26c29807bb84bf649e", size = 92981, upload-time = "2026-01-31T03:52:09.14Z" }, +] + +[[package]] +name = "xdoctest" +version = "1.3.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/92/3a/425e9555e23409559fa01d3431b7e1ffbc4ad6fa3b808e9f7bac9e3afbb6/xdoctest-1.3.0.tar.gz", hash = "sha256:f92cb99a3be6011c57bb94613a26b09a268e0095e926b4559132d135d8f6c9d4", size = 207394, upload-time = "2025-09-08T15:02:46.256Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/a7/75/35c17f21153190386af9fb36aab5f76d9f865c69d2f13afdfeb0b3109481/xdoctest-1.3.0-py3-none-any.whl", hash = "sha256:b546accaecae2fd0a14e8d8e125550832f3f11981629324519d057e218dd348f", size = 152543, upload-time = "2025-09-08T15:02:43.245Z" }, +] From 593f820d54c3cefd0cd8892f137b5512d1851851 Mon Sep 17 00:00:00 2001 From: Cameron Smith Date: Mon, 2 Feb 2026 14:37:51 -0500 Subject: [PATCH 012/134] build(python-nix-template): add independent uv lock file --- packages/python-nix-template/uv.lock | 2060 ++++++++++++++++++++++++++ 1 file changed, 2060 insertions(+) create mode 100644 packages/python-nix-template/uv.lock diff --git a/packages/python-nix-template/uv.lock b/packages/python-nix-template/uv.lock new file mode 100644 index 0000000..faaceb6 --- /dev/null +++ b/packages/python-nix-template/uv.lock @@ -0,0 +1,2060 @@ +version = 1 +revision = 3 +requires-python = ">=3.11, <3.13" + +[[package]] +name = "annotated-types" +version = "0.7.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/ee/67/531ea369ba64dcff5ec9c3402f9f51bf748cec26dde048a2f973a4eea7f5/annotated_types-0.7.0.tar.gz", hash = "sha256:aff07c09a53a08bc8cfccb9c85b05f1aa9a2a6f23728d790723543408344ce89", size = 16081, upload-time = "2024-05-20T21:33:25.928Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/78/b6/6307fbef88d9b5ee7421e68d78a9f162e0da4900bc5f5793f6d3d0e34fb8/annotated_types-0.7.0-py3-none-any.whl", hash = "sha256:1f02e8b43a8fbbc3f3e0d4f0f4bfc8131bcb4eebe8849b8e5c773f3a1c582a53", size = 13643, upload-time = "2024-05-20T21:33:24.1Z" }, +] + +[[package]] +name = "anyio" +version = "4.12.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "idna" }, + { name = "typing-extensions" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/96/f0/5eb65b2bb0d09ac6776f2eb54adee6abe8228ea05b20a5ad0e4945de8aac/anyio-4.12.1.tar.gz", hash = "sha256:41cfcc3a4c85d3f05c932da7c26d0201ac36f72abd4435ba90d0464a3ffed703", size = 228685, upload-time = "2026-01-06T11:45:21.246Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/38/0e/27be9fdef66e72d64c0cdc3cc2823101b80585f8119b5c112c2e8f5f7dab/anyio-4.12.1-py3-none-any.whl", hash = "sha256:d405828884fc140aa80a3c667b8beed277f1dfedec42ba031bd6ac3db606ab6c", size = 113592, upload-time = "2026-01-06T11:45:19.497Z" }, +] + +[[package]] +name = "appnope" +version = "0.1.4" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/35/5d/752690df9ef5b76e169e68d6a129fa6d08a7100ca7f754c89495db3c6019/appnope-0.1.4.tar.gz", hash = "sha256:1de3860566df9caf38f01f86f65e0e13e379af54f9e4bee1e66b48f2efffd1ee", size = 4170, upload-time = "2024-02-06T09:43:11.258Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/81/29/5ecc3a15d5a33e31b26c11426c45c501e439cb865d0bff96315d86443b78/appnope-0.1.4-py2.py3-none-any.whl", hash = "sha256:502575ee11cd7a28c0205f379b525beefebab9d161b7c964670864014ed7213c", size = 4321, upload-time = "2024-02-06T09:43:09.663Z" }, +] + +[[package]] +name = "argon2-cffi" +version = "25.1.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "argon2-cffi-bindings" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/0e/89/ce5af8a7d472a67cc819d5d998aa8c82c5d860608c4db9f46f1162d7dab9/argon2_cffi-25.1.0.tar.gz", hash = "sha256:694ae5cc8a42f4c4e2bf2ca0e64e51e23a040c6a517a85074683d3959e1346c1", size = 45706, upload-time = "2025-06-03T06:55:32.073Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/4f/d3/a8b22fa575b297cd6e3e3b0155c7e25db170edf1c74783d6a31a2490b8d9/argon2_cffi-25.1.0-py3-none-any.whl", hash = "sha256:fdc8b074db390fccb6eb4a3604ae7231f219aa669a2652e0f20e16ba513d5741", size = 14657, upload-time = "2025-06-03T06:55:30.804Z" }, +] + +[[package]] +name = "argon2-cffi-bindings" +version = "25.1.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "cffi" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/5c/2d/db8af0df73c1cf454f71b2bbe5e356b8c1f8041c979f505b3d3186e520a9/argon2_cffi_bindings-25.1.0.tar.gz", hash = "sha256:b957f3e6ea4d55d820e40ff76f450952807013d361a65d7f28acc0acbf29229d", size = 1783441, upload-time = "2025-07-30T10:02:05.147Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/1d/57/96b8b9f93166147826da5f90376e784a10582dd39a393c99bb62cfcf52f0/argon2_cffi_bindings-25.1.0-cp39-abi3-macosx_10_9_universal2.whl", hash = "sha256:aecba1723ae35330a008418a91ea6cfcedf6d31e5fbaa056a166462ff066d500", size = 54121, upload-time = "2025-07-30T10:01:50.815Z" }, + { url = "https://files.pythonhosted.org/packages/0a/08/a9bebdb2e0e602dde230bdde8021b29f71f7841bd54801bcfd514acb5dcf/argon2_cffi_bindings-25.1.0-cp39-abi3-macosx_10_9_x86_64.whl", hash = "sha256:2630b6240b495dfab90aebe159ff784d08ea999aa4b0d17efa734055a07d2f44", size = 29177, upload-time = "2025-07-30T10:01:51.681Z" }, + { url = "https://files.pythonhosted.org/packages/b6/02/d297943bcacf05e4f2a94ab6f462831dc20158614e5d067c35d4e63b9acb/argon2_cffi_bindings-25.1.0-cp39-abi3-macosx_11_0_arm64.whl", hash = "sha256:7aef0c91e2c0fbca6fc68e7555aa60ef7008a739cbe045541e438373bc54d2b0", size = 31090, upload-time = "2025-07-30T10:01:53.184Z" }, + { url = "https://files.pythonhosted.org/packages/c1/93/44365f3d75053e53893ec6d733e4a5e3147502663554b4d864587c7828a7/argon2_cffi_bindings-25.1.0-cp39-abi3-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:1e021e87faa76ae0d413b619fe2b65ab9a037f24c60a1e6cc43457ae20de6dc6", size = 81246, upload-time = "2025-07-30T10:01:54.145Z" }, + { url = "https://files.pythonhosted.org/packages/09/52/94108adfdd6e2ddf58be64f959a0b9c7d4ef2fa71086c38356d22dc501ea/argon2_cffi_bindings-25.1.0-cp39-abi3-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:d3e924cfc503018a714f94a49a149fdc0b644eaead5d1f089330399134fa028a", size = 87126, upload-time = "2025-07-30T10:01:55.074Z" }, + { url = "https://files.pythonhosted.org/packages/72/70/7a2993a12b0ffa2a9271259b79cc616e2389ed1a4d93842fac5a1f923ffd/argon2_cffi_bindings-25.1.0-cp39-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:c87b72589133f0346a1cb8d5ecca4b933e3c9b64656c9d175270a000e73b288d", size = 80343, upload-time = "2025-07-30T10:01:56.007Z" }, + { url = "https://files.pythonhosted.org/packages/78/9a/4e5157d893ffc712b74dbd868c7f62365618266982b64accab26bab01edc/argon2_cffi_bindings-25.1.0-cp39-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:1db89609c06afa1a214a69a462ea741cf735b29a57530478c06eb81dd403de99", size = 86777, upload-time = "2025-07-30T10:01:56.943Z" }, + { url = "https://files.pythonhosted.org/packages/74/cd/15777dfde1c29d96de7f18edf4cc94c385646852e7c7b0320aa91ccca583/argon2_cffi_bindings-25.1.0-cp39-abi3-win32.whl", hash = "sha256:473bcb5f82924b1becbb637b63303ec8d10e84c8d241119419897a26116515d2", size = 27180, upload-time = "2025-07-30T10:01:57.759Z" }, + { url = "https://files.pythonhosted.org/packages/e2/c6/a759ece8f1829d1f162261226fbfd2c6832b3ff7657384045286d2afa384/argon2_cffi_bindings-25.1.0-cp39-abi3-win_amd64.whl", hash = "sha256:a98cd7d17e9f7ce244c0803cad3c23a7d379c301ba618a5fa76a67d116618b98", size = 31715, upload-time = "2025-07-30T10:01:58.56Z" }, + { url = "https://files.pythonhosted.org/packages/42/b9/f8d6fa329ab25128b7e98fd83a3cb34d9db5b059a9847eddb840a0af45dd/argon2_cffi_bindings-25.1.0-cp39-abi3-win_arm64.whl", hash = "sha256:b0fdbcf513833809c882823f98dc2f931cf659d9a1429616ac3adebb49f5db94", size = 27149, upload-time = "2025-07-30T10:01:59.329Z" }, +] + +[[package]] +name = "arrow" +version = "1.4.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "python-dateutil" }, + { name = "tzdata" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/b9/33/032cdc44182491aa708d06a68b62434140d8c50820a087fac7af37703357/arrow-1.4.0.tar.gz", hash = "sha256:ed0cc050e98001b8779e84d461b0098c4ac597e88704a655582b21d116e526d7", size = 152931, upload-time = "2025-10-18T17:46:46.761Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/ed/c9/d7977eaacb9df673210491da99e6a247e93df98c715fc43fd136ce1d3d33/arrow-1.4.0-py3-none-any.whl", hash = "sha256:749f0769958ebdc79c173ff0b0670d59051a535fa26e8eba02953dc19eb43205", size = 68797, upload-time = "2025-10-18T17:46:45.663Z" }, +] + +[[package]] +name = "asttokens" +version = "3.0.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/be/a5/8e3f9b6771b0b408517c82d97aed8f2036509bc247d46114925e32fe33f0/asttokens-3.0.1.tar.gz", hash = "sha256:71a4ee5de0bde6a31d64f6b13f2293ac190344478f081c3d1bccfcf5eacb0cb7", size = 62308, upload-time = "2025-11-15T16:43:48.578Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/d2/39/e7eaf1799466a4aef85b6a4fe7bd175ad2b1c6345066aa33f1f58d4b18d0/asttokens-3.0.1-py3-none-any.whl", hash = "sha256:15a3ebc0f43c2d0a50eeafea25e19046c68398e487b9f1f5b517f7c0f40f976a", size = 27047, upload-time = "2025-11-15T16:43:16.109Z" }, +] + +[[package]] +name = "async-lru" +version = "2.1.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/ef/c3/bbf34f15ea88dfb649ab2c40f9d75081784a50573a9ea431563cab64adb8/async_lru-2.1.0.tar.gz", hash = "sha256:9eeb2fecd3fe42cc8a787fc32ead53a3a7158cc43d039c3c55ab3e4e5b2a80ed", size = 12041, upload-time = "2026-01-17T22:52:18.931Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/2e/e9/eb6a5db5ac505d5d45715388e92bced7a5bb556facc4d0865d192823f2d2/async_lru-2.1.0-py3-none-any.whl", hash = "sha256:fa12dcf99a42ac1280bc16c634bbaf06883809790f6304d85cdab3f666f33a7e", size = 6933, upload-time = "2026-01-17T22:52:17.389Z" }, +] + +[[package]] +name = "attrs" +version = "25.4.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/6b/5c/685e6633917e101e5dcb62b9dd76946cbb57c26e133bae9e0cd36033c0a9/attrs-25.4.0.tar.gz", hash = "sha256:16d5969b87f0859ef33a48b35d55ac1be6e42ae49d5e853b597db70c35c57e11", size = 934251, upload-time = "2025-10-06T13:54:44.725Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/3a/2a/7cc015f5b9f5db42b7d48157e23356022889fc354a2813c15934b7cb5c0e/attrs-25.4.0-py3-none-any.whl", hash = "sha256:adcf7e2a1fb3b36ac48d97835bb6d8ade15b8dcce26aba8bf1d14847b57a3373", size = 67615, upload-time = "2025-10-06T13:54:43.17Z" }, +] + +[[package]] +name = "babel" +version = "2.18.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/7d/b2/51899539b6ceeeb420d40ed3cd4b7a40519404f9baf3d4ac99dc413a834b/babel-2.18.0.tar.gz", hash = "sha256:b80b99a14bd085fcacfa15c9165f651fbb3406e66cc603abf11c5750937c992d", size = 9959554, upload-time = "2026-02-01T12:30:56.078Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/77/f5/21d2de20e8b8b0408f0681956ca2c69f1320a3848ac50e6e7f39c6159675/babel-2.18.0-py3-none-any.whl", hash = "sha256:e2b422b277c2b9a9630c1d7903c2a00d0830c409c59ac8cae9081c92f1aeba35", size = 10196845, upload-time = "2026-02-01T12:30:53.445Z" }, +] + +[[package]] +name = "beartype" +version = "0.22.9" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/c7/94/1009e248bbfbab11397abca7193bea6626806be9a327d399810d523a07cb/beartype-0.22.9.tar.gz", hash = "sha256:8f82b54aa723a2848a56008d18875f91c1db02c32ef6a62319a002e3e25a975f", size = 1608866, upload-time = "2025-12-13T06:50:30.72Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/71/cc/18245721fa7747065ab478316c7fea7c74777d07f37ae60db2e84f8172e8/beartype-0.22.9-py3-none-any.whl", hash = "sha256:d16c9bbc61ea14637596c5f6fbff2ee99cbe3573e46a716401734ef50c3060c2", size = 1333658, upload-time = "2025-12-13T06:50:28.266Z" }, +] + +[[package]] +name = "beautifulsoup4" +version = "4.14.3" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "soupsieve" }, + { name = "typing-extensions" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/c3/b0/1c6a16426d389813b48d95e26898aff79abbde42ad353958ad95cc8c9b21/beautifulsoup4-4.14.3.tar.gz", hash = "sha256:6292b1c5186d356bba669ef9f7f051757099565ad9ada5dd630bd9de5fa7fb86", size = 627737, upload-time = "2025-11-30T15:08:26.084Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/1a/39/47f9197bdd44df24d67ac8893641e16f386c984a0619ef2ee4c51fbbc019/beautifulsoup4-4.14.3-py3-none-any.whl", hash = "sha256:0918bfe44902e6ad8d57732ba310582e98da931428d231a5ecb9e7c703a735bb", size = 107721, upload-time = "2025-11-30T15:08:24.087Z" }, +] + +[[package]] +name = "black" +version = "26.1.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "click" }, + { name = "mypy-extensions" }, + { name = "packaging" }, + { name = "pathspec" }, + { name = "platformdirs" }, + { name = "pytokens" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/13/88/560b11e521c522440af991d46848a2bde64b5f7202ec14e1f46f9509d328/black-26.1.0.tar.gz", hash = "sha256:d294ac3340eef9c9eb5d29288e96dc719ff269a88e27b396340459dd85da4c58", size = 658785, upload-time = "2026-01-18T04:50:11.993Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/30/83/f05f22ff13756e1a8ce7891db517dbc06200796a16326258268f4658a745/black-26.1.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:3cee1487a9e4c640dc7467aaa543d6c0097c391dc8ac74eb313f2fbf9d7a7cb5", size = 1831956, upload-time = "2026-01-18T04:59:21.38Z" }, + { url = "https://files.pythonhosted.org/packages/7d/f2/b2c570550e39bedc157715e43927360312d6dd677eed2cc149a802577491/black-26.1.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:d62d14ca31c92adf561ebb2e5f2741bf8dea28aef6deb400d49cca011d186c68", size = 1672499, upload-time = "2026-01-18T04:59:23.257Z" }, + { url = "https://files.pythonhosted.org/packages/7a/d7/990d6a94dc9e169f61374b1c3d4f4dd3037e93c2cc12b6f3b12bc663aa7b/black-26.1.0-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:fb1dafbbaa3b1ee8b4550a84425aac8874e5f390200f5502cf3aee4a2acb2f14", size = 1735431, upload-time = "2026-01-18T04:59:24.729Z" }, + { url = "https://files.pythonhosted.org/packages/36/1c/cbd7bae7dd3cb315dfe6eeca802bb56662cc92b89af272e014d98c1f2286/black-26.1.0-cp311-cp311-win_amd64.whl", hash = "sha256:101540cb2a77c680f4f80e628ae98bd2bd8812fb9d72ade4f8995c5ff019e82c", size = 1400468, upload-time = "2026-01-18T04:59:27.381Z" }, + { url = "https://files.pythonhosted.org/packages/59/b1/9fe6132bb2d0d1f7094613320b56297a108ae19ecf3041d9678aec381b37/black-26.1.0-cp311-cp311-win_arm64.whl", hash = "sha256:6f3977a16e347f1b115662be07daa93137259c711e526402aa444d7a88fdc9d4", size = 1207332, upload-time = "2026-01-18T04:59:28.711Z" }, + { url = "https://files.pythonhosted.org/packages/f5/13/710298938a61f0f54cdb4d1c0baeb672c01ff0358712eddaf29f76d32a0b/black-26.1.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:6eeca41e70b5f5c84f2f913af857cf2ce17410847e1d54642e658e078da6544f", size = 1878189, upload-time = "2026-01-18T04:59:30.682Z" }, + { url = "https://files.pythonhosted.org/packages/79/a6/5179beaa57e5dbd2ec9f1c64016214057b4265647c62125aa6aeffb05392/black-26.1.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:dd39eef053e58e60204f2cdf059e2442e2eb08f15989eefe259870f89614c8b6", size = 1700178, upload-time = "2026-01-18T04:59:32.387Z" }, + { url = "https://files.pythonhosted.org/packages/8c/04/c96f79d7b93e8f09d9298b333ca0d31cd9b2ee6c46c274fd0f531de9dc61/black-26.1.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:9459ad0d6cd483eacad4c6566b0f8e42af5e8b583cee917d90ffaa3778420a0a", size = 1777029, upload-time = "2026-01-18T04:59:33.767Z" }, + { url = "https://files.pythonhosted.org/packages/49/f9/71c161c4c7aa18bdda3776b66ac2dc07aed62053c7c0ff8bbda8c2624fe2/black-26.1.0-cp312-cp312-win_amd64.whl", hash = "sha256:a19915ec61f3a8746e8b10adbac4a577c6ba9851fa4a9e9fbfbcf319887a5791", size = 1406466, upload-time = "2026-01-18T04:59:35.177Z" }, + { url = "https://files.pythonhosted.org/packages/4a/8b/a7b0f974e473b159d0ac1b6bcefffeb6bec465898a516ee5cc989503cbc7/black-26.1.0-cp312-cp312-win_arm64.whl", hash = "sha256:643d27fb5facc167c0b1b59d0315f2674a6e950341aed0fc05cf307d22bf4954", size = 1216393, upload-time = "2026-01-18T04:59:37.18Z" }, + { url = "https://files.pythonhosted.org/packages/e4/3d/51bdb3ecbfadfaf825ec0c75e1de6077422b4afa2091c6c9ba34fbfc0c2d/black-26.1.0-py3-none-any.whl", hash = "sha256:1054e8e47ebd686e078c0bb0eaf31e6ce69c966058d122f2c0c950311f9f3ede", size = 204010, upload-time = "2026-01-18T04:50:09.978Z" }, +] + +[[package]] +name = "bleach" +version = "6.3.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "webencodings" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/07/18/3c8523962314be6bf4c8989c79ad9531c825210dd13a8669f6b84336e8bd/bleach-6.3.0.tar.gz", hash = "sha256:6f3b91b1c0a02bb9a78b5a454c92506aa0fdf197e1d5e114d2e00c6f64306d22", size = 203533, upload-time = "2025-10-27T17:57:39.211Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/cd/3a/577b549de0cc09d95f11087ee63c739bba856cd3952697eec4c4bb91350a/bleach-6.3.0-py3-none-any.whl", hash = "sha256:fe10ec77c93ddf3d13a73b035abaac7a9f5e436513864ccdad516693213c65d6", size = 164437, upload-time = "2025-10-27T17:57:37.538Z" }, +] + +[package.optional-dependencies] +css = [ + { name = "tinycss2" }, +] + +[[package]] +name = "certifi" +version = "2026.1.4" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/e0/2d/a891ca51311197f6ad14a7ef42e2399f36cf2f9bd44752b3dc4eab60fdc5/certifi-2026.1.4.tar.gz", hash = "sha256:ac726dd470482006e014ad384921ed6438c457018f4b3d204aea4281258b2120", size = 154268, upload-time = "2026-01-04T02:42:41.825Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/e6/ad/3cc14f097111b4de0040c83a525973216457bbeeb63739ef1ed275c1c021/certifi-2026.1.4-py3-none-any.whl", hash = "sha256:9943707519e4add1115f44c2bc244f782c0249876bf51b6599fee1ffbedd685c", size = 152900, upload-time = "2026-01-04T02:42:40.15Z" }, +] + +[[package]] +name = "cffi" +version = "2.0.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "pycparser", marker = "implementation_name != 'PyPy'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/eb/56/b1ba7935a17738ae8453301356628e8147c79dbb825bcbc73dc7401f9846/cffi-2.0.0.tar.gz", hash = "sha256:44d1b5909021139fe36001ae048dbdde8214afa20200eda0f64c068cac5d5529", size = 523588, upload-time = "2025-09-08T23:24:04.541Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/12/4a/3dfd5f7850cbf0d06dc84ba9aa00db766b52ca38d8b86e3a38314d52498c/cffi-2.0.0-cp311-cp311-macosx_10_13_x86_64.whl", hash = "sha256:b4c854ef3adc177950a8dfc81a86f5115d2abd545751a304c5bcf2c2c7283cfe", size = 184344, upload-time = "2025-09-08T23:22:26.456Z" }, + { url = "https://files.pythonhosted.org/packages/4f/8b/f0e4c441227ba756aafbe78f117485b25bb26b1c059d01f137fa6d14896b/cffi-2.0.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:2de9a304e27f7596cd03d16f1b7c72219bd944e99cc52b84d0145aefb07cbd3c", size = 180560, upload-time = "2025-09-08T23:22:28.197Z" }, + { url = "https://files.pythonhosted.org/packages/b1/b7/1200d354378ef52ec227395d95c2576330fd22a869f7a70e88e1447eb234/cffi-2.0.0-cp311-cp311-manylinux1_i686.manylinux2014_i686.manylinux_2_17_i686.manylinux_2_5_i686.whl", hash = "sha256:baf5215e0ab74c16e2dd324e8ec067ef59e41125d3eade2b863d294fd5035c92", size = 209613, upload-time = "2025-09-08T23:22:29.475Z" }, + { url = "https://files.pythonhosted.org/packages/b8/56/6033f5e86e8cc9bb629f0077ba71679508bdf54a9a5e112a3c0b91870332/cffi-2.0.0-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:730cacb21e1bdff3ce90babf007d0a0917cc3e6492f336c2f0134101e0944f93", size = 216476, upload-time = "2025-09-08T23:22:31.063Z" }, + { url = "https://files.pythonhosted.org/packages/dc/7f/55fecd70f7ece178db2f26128ec41430d8720f2d12ca97bf8f0a628207d5/cffi-2.0.0-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:6824f87845e3396029f3820c206e459ccc91760e8fa24422f8b0c3d1731cbec5", size = 203374, upload-time = "2025-09-08T23:22:32.507Z" }, + { url = "https://files.pythonhosted.org/packages/84/ef/a7b77c8bdc0f77adc3b46888f1ad54be8f3b7821697a7b89126e829e676a/cffi-2.0.0-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:9de40a7b0323d889cf8d23d1ef214f565ab154443c42737dfe52ff82cf857664", size = 202597, upload-time = "2025-09-08T23:22:34.132Z" }, + { url = "https://files.pythonhosted.org/packages/d7/91/500d892b2bf36529a75b77958edfcd5ad8e2ce4064ce2ecfeab2125d72d1/cffi-2.0.0-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:8941aaadaf67246224cee8c3803777eed332a19d909b47e29c9842ef1e79ac26", size = 215574, upload-time = "2025-09-08T23:22:35.443Z" }, + { url = "https://files.pythonhosted.org/packages/44/64/58f6255b62b101093d5df22dcb752596066c7e89dd725e0afaed242a61be/cffi-2.0.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:a05d0c237b3349096d3981b727493e22147f934b20f6f125a3eba8f994bec4a9", size = 218971, upload-time = "2025-09-08T23:22:36.805Z" }, + { url = "https://files.pythonhosted.org/packages/ab/49/fa72cebe2fd8a55fbe14956f9970fe8eb1ac59e5df042f603ef7c8ba0adc/cffi-2.0.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:94698a9c5f91f9d138526b48fe26a199609544591f859c870d477351dc7b2414", size = 211972, upload-time = "2025-09-08T23:22:38.436Z" }, + { url = "https://files.pythonhosted.org/packages/0b/28/dd0967a76aab36731b6ebfe64dec4e981aff7e0608f60c2d46b46982607d/cffi-2.0.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:5fed36fccc0612a53f1d4d9a816b50a36702c28a2aa880cb8a122b3466638743", size = 217078, upload-time = "2025-09-08T23:22:39.776Z" }, + { url = "https://files.pythonhosted.org/packages/2b/c0/015b25184413d7ab0a410775fdb4a50fca20f5589b5dab1dbbfa3baad8ce/cffi-2.0.0-cp311-cp311-win32.whl", hash = "sha256:c649e3a33450ec82378822b3dad03cc228b8f5963c0c12fc3b1e0ab940f768a5", size = 172076, upload-time = "2025-09-08T23:22:40.95Z" }, + { url = "https://files.pythonhosted.org/packages/ae/8f/dc5531155e7070361eb1b7e4c1a9d896d0cb21c49f807a6c03fd63fc877e/cffi-2.0.0-cp311-cp311-win_amd64.whl", hash = "sha256:66f011380d0e49ed280c789fbd08ff0d40968ee7b665575489afa95c98196ab5", size = 182820, upload-time = "2025-09-08T23:22:42.463Z" }, + { url = "https://files.pythonhosted.org/packages/95/5c/1b493356429f9aecfd56bc171285a4c4ac8697f76e9bbbbb105e537853a1/cffi-2.0.0-cp311-cp311-win_arm64.whl", hash = "sha256:c6638687455baf640e37344fe26d37c404db8b80d037c3d29f58fe8d1c3b194d", size = 177635, upload-time = "2025-09-08T23:22:43.623Z" }, + { url = "https://files.pythonhosted.org/packages/ea/47/4f61023ea636104d4f16ab488e268b93008c3d0bb76893b1b31db1f96802/cffi-2.0.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:6d02d6655b0e54f54c4ef0b94eb6be0607b70853c45ce98bd278dc7de718be5d", size = 185271, upload-time = "2025-09-08T23:22:44.795Z" }, + { url = "https://files.pythonhosted.org/packages/df/a2/781b623f57358e360d62cdd7a8c681f074a71d445418a776eef0aadb4ab4/cffi-2.0.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:8eca2a813c1cb7ad4fb74d368c2ffbbb4789d377ee5bb8df98373c2cc0dee76c", size = 181048, upload-time = "2025-09-08T23:22:45.938Z" }, + { url = "https://files.pythonhosted.org/packages/ff/df/a4f0fbd47331ceeba3d37c2e51e9dfc9722498becbeec2bd8bc856c9538a/cffi-2.0.0-cp312-cp312-manylinux1_i686.manylinux2014_i686.manylinux_2_17_i686.manylinux_2_5_i686.whl", hash = "sha256:21d1152871b019407d8ac3985f6775c079416c282e431a4da6afe7aefd2bccbe", size = 212529, upload-time = "2025-09-08T23:22:47.349Z" }, + { url = "https://files.pythonhosted.org/packages/d5/72/12b5f8d3865bf0f87cf1404d8c374e7487dcf097a1c91c436e72e6badd83/cffi-2.0.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:b21e08af67b8a103c71a250401c78d5e0893beff75e28c53c98f4de42f774062", size = 220097, upload-time = "2025-09-08T23:22:48.677Z" }, + { url = "https://files.pythonhosted.org/packages/c2/95/7a135d52a50dfa7c882ab0ac17e8dc11cec9d55d2c18dda414c051c5e69e/cffi-2.0.0-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:1e3a615586f05fc4065a8b22b8152f0c1b00cdbc60596d187c2a74f9e3036e4e", size = 207983, upload-time = "2025-09-08T23:22:50.06Z" }, + { url = "https://files.pythonhosted.org/packages/3a/c8/15cb9ada8895957ea171c62dc78ff3e99159ee7adb13c0123c001a2546c1/cffi-2.0.0-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:81afed14892743bbe14dacb9e36d9e0e504cd204e0b165062c488942b9718037", size = 206519, upload-time = "2025-09-08T23:22:51.364Z" }, + { url = "https://files.pythonhosted.org/packages/78/2d/7fa73dfa841b5ac06c7b8855cfc18622132e365f5b81d02230333ff26e9e/cffi-2.0.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:3e17ed538242334bf70832644a32a7aae3d83b57567f9fd60a26257e992b79ba", size = 219572, upload-time = "2025-09-08T23:22:52.902Z" }, + { url = "https://files.pythonhosted.org/packages/07/e0/267e57e387b4ca276b90f0434ff88b2c2241ad72b16d31836adddfd6031b/cffi-2.0.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:3925dd22fa2b7699ed2617149842d2e6adde22b262fcbfada50e3d195e4b3a94", size = 222963, upload-time = "2025-09-08T23:22:54.518Z" }, + { url = "https://files.pythonhosted.org/packages/b6/75/1f2747525e06f53efbd878f4d03bac5b859cbc11c633d0fb81432d98a795/cffi-2.0.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:2c8f814d84194c9ea681642fd164267891702542f028a15fc97d4674b6206187", size = 221361, upload-time = "2025-09-08T23:22:55.867Z" }, + { url = "https://files.pythonhosted.org/packages/7b/2b/2b6435f76bfeb6bbf055596976da087377ede68df465419d192acf00c437/cffi-2.0.0-cp312-cp312-win32.whl", hash = "sha256:da902562c3e9c550df360bfa53c035b2f241fed6d9aef119048073680ace4a18", size = 172932, upload-time = "2025-09-08T23:22:57.188Z" }, + { url = "https://files.pythonhosted.org/packages/f8/ed/13bd4418627013bec4ed6e54283b1959cf6db888048c7cf4b4c3b5b36002/cffi-2.0.0-cp312-cp312-win_amd64.whl", hash = "sha256:da68248800ad6320861f129cd9c1bf96ca849a2771a59e0344e88681905916f5", size = 183557, upload-time = "2025-09-08T23:22:58.351Z" }, + { url = "https://files.pythonhosted.org/packages/95/31/9f7f93ad2f8eff1dbc1c3656d7ca5bfd8fb52c9d786b4dcf19b2d02217fa/cffi-2.0.0-cp312-cp312-win_arm64.whl", hash = "sha256:4671d9dd5ec934cb9a73e7ee9676f9362aba54f7f34910956b84d727b0d73fb6", size = 177762, upload-time = "2025-09-08T23:22:59.668Z" }, +] + +[[package]] +name = "charset-normalizer" +version = "3.4.4" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/13/69/33ddede1939fdd074bce5434295f38fae7136463422fe4fd3e0e89b98062/charset_normalizer-3.4.4.tar.gz", hash = "sha256:94537985111c35f28720e43603b8e7b43a6ecfb2ce1d3058bbe955b73404e21a", size = 129418, upload-time = "2025-10-14T04:42:32.879Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/ed/27/c6491ff4954e58a10f69ad90aca8a1b6fe9c5d3c6f380907af3c37435b59/charset_normalizer-3.4.4-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:6e1fcf0720908f200cd21aa4e6750a48ff6ce4afe7ff5a79a90d5ed8a08296f8", size = 206988, upload-time = "2025-10-14T04:40:33.79Z" }, + { url = "https://files.pythonhosted.org/packages/94/59/2e87300fe67ab820b5428580a53cad894272dbb97f38a7a814a2a1ac1011/charset_normalizer-3.4.4-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:5f819d5fe9234f9f82d75bdfa9aef3a3d72c4d24a6e57aeaebba32a704553aa0", size = 147324, upload-time = "2025-10-14T04:40:34.961Z" }, + { url = "https://files.pythonhosted.org/packages/07/fb/0cf61dc84b2b088391830f6274cb57c82e4da8bbc2efeac8c025edb88772/charset_normalizer-3.4.4-cp311-cp311-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:a59cb51917aa591b1c4e6a43c132f0cdc3c76dbad6155df4e28ee626cc77a0a3", size = 142742, upload-time = "2025-10-14T04:40:36.105Z" }, + { url = "https://files.pythonhosted.org/packages/62/8b/171935adf2312cd745d290ed93cf16cf0dfe320863ab7cbeeae1dcd6535f/charset_normalizer-3.4.4-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:8ef3c867360f88ac904fd3f5e1f902f13307af9052646963ee08ff4f131adafc", size = 160863, upload-time = "2025-10-14T04:40:37.188Z" }, + { url = "https://files.pythonhosted.org/packages/09/73/ad875b192bda14f2173bfc1bc9a55e009808484a4b256748d931b6948442/charset_normalizer-3.4.4-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:d9e45d7faa48ee908174d8fe84854479ef838fc6a705c9315372eacbc2f02897", size = 157837, upload-time = "2025-10-14T04:40:38.435Z" }, + { url = "https://files.pythonhosted.org/packages/6d/fc/de9cce525b2c5b94b47c70a4b4fb19f871b24995c728e957ee68ab1671ea/charset_normalizer-3.4.4-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:840c25fb618a231545cbab0564a799f101b63b9901f2569faecd6b222ac72381", size = 151550, upload-time = "2025-10-14T04:40:40.053Z" }, + { url = "https://files.pythonhosted.org/packages/55/c2/43edd615fdfba8c6f2dfbd459b25a6b3b551f24ea21981e23fb768503ce1/charset_normalizer-3.4.4-cp311-cp311-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:ca5862d5b3928c4940729dacc329aa9102900382fea192fc5e52eb69d6093815", size = 149162, upload-time = "2025-10-14T04:40:41.163Z" }, + { url = "https://files.pythonhosted.org/packages/03/86/bde4ad8b4d0e9429a4e82c1e8f5c659993a9a863ad62c7df05cf7b678d75/charset_normalizer-3.4.4-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:d9c7f57c3d666a53421049053eaacdd14bbd0a528e2186fcb2e672effd053bb0", size = 150019, upload-time = "2025-10-14T04:40:42.276Z" }, + { url = "https://files.pythonhosted.org/packages/1f/86/a151eb2af293a7e7bac3a739b81072585ce36ccfb4493039f49f1d3cae8c/charset_normalizer-3.4.4-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:277e970e750505ed74c832b4bf75dac7476262ee2a013f5574dd49075879e161", size = 143310, upload-time = "2025-10-14T04:40:43.439Z" }, + { url = "https://files.pythonhosted.org/packages/b5/fe/43dae6144a7e07b87478fdfc4dbe9efd5defb0e7ec29f5f58a55aeef7bf7/charset_normalizer-3.4.4-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:31fd66405eaf47bb62e8cd575dc621c56c668f27d46a61d975a249930dd5e2a4", size = 162022, upload-time = "2025-10-14T04:40:44.547Z" }, + { url = "https://files.pythonhosted.org/packages/80/e6/7aab83774f5d2bca81f42ac58d04caf44f0cc2b65fc6db2b3b2e8a05f3b3/charset_normalizer-3.4.4-cp311-cp311-musllinux_1_2_riscv64.whl", hash = "sha256:0d3d8f15c07f86e9ff82319b3d9ef6f4bf907608f53fe9d92b28ea9ae3d1fd89", size = 149383, upload-time = "2025-10-14T04:40:46.018Z" }, + { url = "https://files.pythonhosted.org/packages/4f/e8/b289173b4edae05c0dde07f69f8db476a0b511eac556dfe0d6bda3c43384/charset_normalizer-3.4.4-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:9f7fcd74d410a36883701fafa2482a6af2ff5ba96b9a620e9e0721e28ead5569", size = 159098, upload-time = "2025-10-14T04:40:47.081Z" }, + { url = "https://files.pythonhosted.org/packages/d8/df/fe699727754cae3f8478493c7f45f777b17c3ef0600e28abfec8619eb49c/charset_normalizer-3.4.4-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:ebf3e58c7ec8a8bed6d66a75d7fb37b55e5015b03ceae72a8e7c74495551e224", size = 152991, upload-time = "2025-10-14T04:40:48.246Z" }, + { url = "https://files.pythonhosted.org/packages/1a/86/584869fe4ddb6ffa3bd9f491b87a01568797fb9bd8933f557dba9771beaf/charset_normalizer-3.4.4-cp311-cp311-win32.whl", hash = "sha256:eecbc200c7fd5ddb9a7f16c7decb07b566c29fa2161a16cf67b8d068bd21690a", size = 99456, upload-time = "2025-10-14T04:40:49.376Z" }, + { url = "https://files.pythonhosted.org/packages/65/f6/62fdd5feb60530f50f7e38b4f6a1d5203f4d16ff4f9f0952962c044e919a/charset_normalizer-3.4.4-cp311-cp311-win_amd64.whl", hash = "sha256:5ae497466c7901d54b639cf42d5b8c1b6a4fead55215500d2f486d34db48d016", size = 106978, upload-time = "2025-10-14T04:40:50.844Z" }, + { url = "https://files.pythonhosted.org/packages/7a/9d/0710916e6c82948b3be62d9d398cb4fcf4e97b56d6a6aeccd66c4b2f2bd5/charset_normalizer-3.4.4-cp311-cp311-win_arm64.whl", hash = "sha256:65e2befcd84bc6f37095f5961e68a6f077bf44946771354a28ad434c2cce0ae1", size = 99969, upload-time = "2025-10-14T04:40:52.272Z" }, + { url = "https://files.pythonhosted.org/packages/f3/85/1637cd4af66fa687396e757dec650f28025f2a2f5a5531a3208dc0ec43f2/charset_normalizer-3.4.4-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:0a98e6759f854bd25a58a73fa88833fba3b7c491169f86ce1180c948ab3fd394", size = 208425, upload-time = "2025-10-14T04:40:53.353Z" }, + { url = "https://files.pythonhosted.org/packages/9d/6a/04130023fef2a0d9c62d0bae2649b69f7b7d8d24ea5536feef50551029df/charset_normalizer-3.4.4-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:b5b290ccc2a263e8d185130284f8501e3e36c5e02750fc6b6bdeb2e9e96f1e25", size = 148162, upload-time = "2025-10-14T04:40:54.558Z" }, + { url = "https://files.pythonhosted.org/packages/78/29/62328d79aa60da22c9e0b9a66539feae06ca0f5a4171ac4f7dc285b83688/charset_normalizer-3.4.4-cp312-cp312-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:74bb723680f9f7a6234dcf67aea57e708ec1fbdf5699fb91dfd6f511b0a320ef", size = 144558, upload-time = "2025-10-14T04:40:55.677Z" }, + { url = "https://files.pythonhosted.org/packages/86/bb/b32194a4bf15b88403537c2e120b817c61cd4ecffa9b6876e941c3ee38fe/charset_normalizer-3.4.4-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:f1e34719c6ed0b92f418c7c780480b26b5d9c50349e9a9af7d76bf757530350d", size = 161497, upload-time = "2025-10-14T04:40:57.217Z" }, + { url = "https://files.pythonhosted.org/packages/19/89/a54c82b253d5b9b111dc74aca196ba5ccfcca8242d0fb64146d4d3183ff1/charset_normalizer-3.4.4-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:2437418e20515acec67d86e12bf70056a33abdacb5cb1655042f6538d6b085a8", size = 159240, upload-time = "2025-10-14T04:40:58.358Z" }, + { url = "https://files.pythonhosted.org/packages/c0/10/d20b513afe03acc89ec33948320a5544d31f21b05368436d580dec4e234d/charset_normalizer-3.4.4-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:11d694519d7f29d6cd09f6ac70028dba10f92f6cdd059096db198c283794ac86", size = 153471, upload-time = "2025-10-14T04:40:59.468Z" }, + { url = "https://files.pythonhosted.org/packages/61/fa/fbf177b55bdd727010f9c0a3c49eefa1d10f960e5f09d1d887bf93c2e698/charset_normalizer-3.4.4-cp312-cp312-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:ac1c4a689edcc530fc9d9aa11f5774b9e2f33f9a0c6a57864e90908f5208d30a", size = 150864, upload-time = "2025-10-14T04:41:00.623Z" }, + { url = "https://files.pythonhosted.org/packages/05/12/9fbc6a4d39c0198adeebbde20b619790e9236557ca59fc40e0e3cebe6f40/charset_normalizer-3.4.4-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:21d142cc6c0ec30d2efee5068ca36c128a30b0f2c53c1c07bd78cb6bc1d3be5f", size = 150647, upload-time = "2025-10-14T04:41:01.754Z" }, + { url = "https://files.pythonhosted.org/packages/ad/1f/6a9a593d52e3e8c5d2b167daf8c6b968808efb57ef4c210acb907c365bc4/charset_normalizer-3.4.4-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:5dbe56a36425d26d6cfb40ce79c314a2e4dd6211d51d6d2191c00bed34f354cc", size = 145110, upload-time = "2025-10-14T04:41:03.231Z" }, + { url = "https://files.pythonhosted.org/packages/30/42/9a52c609e72471b0fc54386dc63c3781a387bb4fe61c20231a4ebcd58bdd/charset_normalizer-3.4.4-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:5bfbb1b9acf3334612667b61bd3002196fe2a1eb4dd74d247e0f2a4d50ec9bbf", size = 162839, upload-time = "2025-10-14T04:41:04.715Z" }, + { url = "https://files.pythonhosted.org/packages/c4/5b/c0682bbf9f11597073052628ddd38344a3d673fda35a36773f7d19344b23/charset_normalizer-3.4.4-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:d055ec1e26e441f6187acf818b73564e6e6282709e9bcb5b63f5b23068356a15", size = 150667, upload-time = "2025-10-14T04:41:05.827Z" }, + { url = "https://files.pythonhosted.org/packages/e4/24/a41afeab6f990cf2daf6cb8c67419b63b48cf518e4f56022230840c9bfb2/charset_normalizer-3.4.4-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:af2d8c67d8e573d6de5bc30cdb27e9b95e49115cd9baad5ddbd1a6207aaa82a9", size = 160535, upload-time = "2025-10-14T04:41:06.938Z" }, + { url = "https://files.pythonhosted.org/packages/2a/e5/6a4ce77ed243c4a50a1fecca6aaaab419628c818a49434be428fe24c9957/charset_normalizer-3.4.4-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:780236ac706e66881f3b7f2f32dfe90507a09e67d1d454c762cf642e6e1586e0", size = 154816, upload-time = "2025-10-14T04:41:08.101Z" }, + { url = "https://files.pythonhosted.org/packages/a8/ef/89297262b8092b312d29cdb2517cb1237e51db8ecef2e9af5edbe7b683b1/charset_normalizer-3.4.4-cp312-cp312-win32.whl", hash = "sha256:5833d2c39d8896e4e19b689ffc198f08ea58116bee26dea51e362ecc7cd3ed26", size = 99694, upload-time = "2025-10-14T04:41:09.23Z" }, + { url = "https://files.pythonhosted.org/packages/3d/2d/1e5ed9dd3b3803994c155cd9aacb60c82c331bad84daf75bcb9c91b3295e/charset_normalizer-3.4.4-cp312-cp312-win_amd64.whl", hash = "sha256:a79cfe37875f822425b89a82333404539ae63dbdddf97f84dcbc3d339aae9525", size = 107131, upload-time = "2025-10-14T04:41:10.467Z" }, + { url = "https://files.pythonhosted.org/packages/d0/d9/0ed4c7098a861482a7b6a95603edce4c0d9db2311af23da1fb2b75ec26fc/charset_normalizer-3.4.4-cp312-cp312-win_arm64.whl", hash = "sha256:376bec83a63b8021bb5c8ea75e21c4ccb86e7e45ca4eb81146091b56599b80c3", size = 100390, upload-time = "2025-10-14T04:41:11.915Z" }, + { url = "https://files.pythonhosted.org/packages/0a/4c/925909008ed5a988ccbb72dcc897407e5d6d3bd72410d69e051fc0c14647/charset_normalizer-3.4.4-py3-none-any.whl", hash = "sha256:7a32c560861a02ff789ad905a2fe94e3f840803362c84fecf1851cb4cf3dc37f", size = 53402, upload-time = "2025-10-14T04:42:31.76Z" }, +] + +[[package]] +name = "click" +version = "8.3.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "colorama", marker = "sys_platform == 'win32'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/3d/fa/656b739db8587d7b5dfa22e22ed02566950fbfbcdc20311993483657a5c0/click-8.3.1.tar.gz", hash = "sha256:12ff4785d337a1bb490bb7e9c2b1ee5da3112e94a8622f26a6c77f5d2fc6842a", size = 295065, upload-time = "2025-11-15T20:45:42.706Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/98/78/01c019cdb5d6498122777c1a43056ebb3ebfeef2076d9d026bfe15583b2b/click-8.3.1-py3-none-any.whl", hash = "sha256:981153a64e25f12d547d3426c367a4857371575ee7ad18df2a6183ab0545b2a6", size = 108274, upload-time = "2025-11-15T20:45:41.139Z" }, +] + +[[package]] +name = "colorama" +version = "0.4.6" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/d8/53/6f443c9a4a8358a93a6792e2acffb9d9d5cb0a5cfd8802644b7b1c9a02e4/colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44", size = 27697, upload-time = "2022-10-25T02:36:22.414Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/d1/d6/3965ed04c63042e047cb6a3e6ed1a63a35087b6a609aa3a15ed8ac56c221/colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6", size = 25335, upload-time = "2022-10-25T02:36:20.889Z" }, +] + +[[package]] +name = "comm" +version = "0.2.3" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/4c/13/7d740c5849255756bc17888787313b61fd38a0a8304fc4f073dfc46122aa/comm-0.2.3.tar.gz", hash = "sha256:2dc8048c10962d55d7ad693be1e7045d891b7ce8d999c97963a5e3e99c055971", size = 6319, upload-time = "2025-07-25T14:02:04.452Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/60/97/891a0971e1e4a8c5d2b20bbe0e524dc04548d2307fee33cdeba148fd4fc7/comm-0.2.3-py3-none-any.whl", hash = "sha256:c615d91d75f7f04f095b30d1c1711babd43bdc6419c1be9886a85f2f4e489417", size = 7294, upload-time = "2025-07-25T14:02:02.896Z" }, +] + +[[package]] +name = "coverage" +version = "7.13.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/ad/49/349848445b0e53660e258acbcc9b0d014895b6739237920886672240f84b/coverage-7.13.2.tar.gz", hash = "sha256:044c6951ec37146b72a50cc81ef02217d27d4c3640efd2640311393cbbf143d3", size = 826523, upload-time = "2026-01-25T13:00:04.889Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/6c/01/abca50583a8975bb6e1c59eff67ed8e48bb127c07dad5c28d9e96ccc09ec/coverage-7.13.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:060ebf6f2c51aff5ba38e1f43a2095e087389b1c69d559fde6049a4b0001320e", size = 218971, upload-time = "2026-01-25T12:57:36.953Z" }, + { url = "https://files.pythonhosted.org/packages/eb/0e/b6489f344d99cd1e5b4d5e1be52dfd3f8a3dc5112aa6c33948da8cabad4e/coverage-7.13.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:c1ea8ca9db5e7469cd364552985e15911548ea5b69c48a17291f0cac70484b2e", size = 219473, upload-time = "2026-01-25T12:57:38.934Z" }, + { url = "https://files.pythonhosted.org/packages/17/11/db2f414915a8e4ec53f60b17956c27f21fb68fcf20f8a455ce7c2ccec638/coverage-7.13.2-cp311-cp311-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:b780090d15fd58f07cf2011943e25a5f0c1c894384b13a216b6c86c8a8a7c508", size = 249896, upload-time = "2026-01-25T12:57:40.365Z" }, + { url = "https://files.pythonhosted.org/packages/80/06/0823fe93913663c017e508e8810c998c8ebd3ec2a5a85d2c3754297bdede/coverage-7.13.2-cp311-cp311-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:88a800258d83acb803c38175b4495d293656d5fac48659c953c18e5f539a274b", size = 251810, upload-time = "2026-01-25T12:57:42.045Z" }, + { url = "https://files.pythonhosted.org/packages/61/dc/b151c3cc41b28cdf7f0166c5fa1271cbc305a8ec0124cce4b04f74791a18/coverage-7.13.2-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6326e18e9a553e674d948536a04a80d850a5eeefe2aae2e6d7cf05d54046c01b", size = 253920, upload-time = "2026-01-25T12:57:44.026Z" }, + { url = "https://files.pythonhosted.org/packages/2d/35/e83de0556e54a4729a2b94ea816f74ce08732e81945024adee46851c2264/coverage-7.13.2-cp311-cp311-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:59562de3f797979e1ff07c587e2ac36ba60ca59d16c211eceaa579c266c5022f", size = 250025, upload-time = "2026-01-25T12:57:45.624Z" }, + { url = "https://files.pythonhosted.org/packages/39/67/af2eb9c3926ce3ea0d58a0d2516fcbdacf7a9fc9559fe63076beaf3f2596/coverage-7.13.2-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:27ba1ed6f66b0e2d61bfa78874dffd4f8c3a12f8e2b5410e515ab345ba7bc9c3", size = 251612, upload-time = "2026-01-25T12:57:47.713Z" }, + { url = "https://files.pythonhosted.org/packages/26/62/5be2e25f3d6c711d23b71296f8b44c978d4c8b4e5b26871abfc164297502/coverage-7.13.2-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:8be48da4d47cc68754ce643ea50b3234557cbefe47c2f120495e7bd0a2756f2b", size = 249670, upload-time = "2026-01-25T12:57:49.378Z" }, + { url = "https://files.pythonhosted.org/packages/b3/51/400d1b09a8344199f9b6a6fc1868005d766b7ea95e7882e494fa862ca69c/coverage-7.13.2-cp311-cp311-musllinux_1_2_riscv64.whl", hash = "sha256:2a47a4223d3361b91176aedd9d4e05844ca67d7188456227b6bf5e436630c9a1", size = 249395, upload-time = "2026-01-25T12:57:50.86Z" }, + { url = "https://files.pythonhosted.org/packages/e0/36/f02234bc6e5230e2f0a63fd125d0a2093c73ef20fdf681c7af62a140e4e7/coverage-7.13.2-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:c6f141b468740197d6bd38f2b26ade124363228cc3f9858bd9924ab059e00059", size = 250298, upload-time = "2026-01-25T12:57:52.287Z" }, + { url = "https://files.pythonhosted.org/packages/b0/06/713110d3dd3151b93611c9cbfc65c15b4156b44f927fced49ac0b20b32a4/coverage-7.13.2-cp311-cp311-win32.whl", hash = "sha256:89567798404af067604246e01a49ef907d112edf2b75ef814b1364d5ce267031", size = 221485, upload-time = "2026-01-25T12:57:53.876Z" }, + { url = "https://files.pythonhosted.org/packages/16/0c/3ae6255fa1ebcb7dec19c9a59e85ef5f34566d1265c70af5b2fc981da834/coverage-7.13.2-cp311-cp311-win_amd64.whl", hash = "sha256:21dd57941804ae2ac7e921771a5e21bbf9aabec317a041d164853ad0a96ce31e", size = 222421, upload-time = "2026-01-25T12:57:55.433Z" }, + { url = "https://files.pythonhosted.org/packages/b5/37/fabc3179af4d61d89ea47bd04333fec735cd5e8b59baad44fed9fc4170d7/coverage-7.13.2-cp311-cp311-win_arm64.whl", hash = "sha256:10758e0586c134a0bafa28f2d37dd2cdb5e4a90de25c0fc0c77dabbad46eca28", size = 221088, upload-time = "2026-01-25T12:57:57.41Z" }, + { url = "https://files.pythonhosted.org/packages/46/39/e92a35f7800222d3f7b2cbb7bbc3b65672ae8d501cb31801b2d2bd7acdf1/coverage-7.13.2-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:f106b2af193f965d0d3234f3f83fc35278c7fb935dfbde56ae2da3dd2c03b84d", size = 219142, upload-time = "2026-01-25T12:58:00.448Z" }, + { url = "https://files.pythonhosted.org/packages/45/7a/8bf9e9309c4c996e65c52a7c5a112707ecdd9fbaf49e10b5a705a402bbb4/coverage-7.13.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:78f45d21dc4d5d6bd29323f0320089ef7eae16e4bef712dff79d184fa7330af3", size = 219503, upload-time = "2026-01-25T12:58:02.451Z" }, + { url = "https://files.pythonhosted.org/packages/87/93/17661e06b7b37580923f3f12406ac91d78aeed293fb6da0b69cc7957582f/coverage-7.13.2-cp312-cp312-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:fae91dfecd816444c74531a9c3d6ded17a504767e97aa674d44f638107265b99", size = 251006, upload-time = "2026-01-25T12:58:04.059Z" }, + { url = "https://files.pythonhosted.org/packages/12/f0/f9e59fb8c310171497f379e25db060abef9fa605e09d63157eebec102676/coverage-7.13.2-cp312-cp312-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:264657171406c114787b441484de620e03d8f7202f113d62fcd3d9688baa3e6f", size = 253750, upload-time = "2026-01-25T12:58:05.574Z" }, + { url = "https://files.pythonhosted.org/packages/e5/b1/1935e31add2232663cf7edd8269548b122a7d100047ff93475dbaaae673e/coverage-7.13.2-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ae47d8dcd3ded0155afbb59c62bd8ab07ea0fd4902e1c40567439e6db9dcaf2f", size = 254862, upload-time = "2026-01-25T12:58:07.647Z" }, + { url = "https://files.pythonhosted.org/packages/af/59/b5e97071ec13df5f45da2b3391b6cdbec78ba20757bc92580a5b3d5fa53c/coverage-7.13.2-cp312-cp312-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:8a0b33e9fd838220b007ce8f299114d406c1e8edb21336af4c97a26ecfd185aa", size = 251420, upload-time = "2026-01-25T12:58:09.309Z" }, + { url = "https://files.pythonhosted.org/packages/3f/75/9495932f87469d013dc515fb0ce1aac5fa97766f38f6b1a1deb1ee7b7f3a/coverage-7.13.2-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:b3becbea7f3ce9a2d4d430f223ec15888e4deb31395840a79e916368d6004cce", size = 252786, upload-time = "2026-01-25T12:58:10.909Z" }, + { url = "https://files.pythonhosted.org/packages/6a/59/af550721f0eb62f46f7b8cb7e6f1860592189267b1c411a4e3a057caacee/coverage-7.13.2-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:f819c727a6e6eeb8711e4ce63d78c620f69630a2e9d53bc95ca5379f57b6ba94", size = 250928, upload-time = "2026-01-25T12:58:12.449Z" }, + { url = "https://files.pythonhosted.org/packages/9b/b1/21b4445709aae500be4ab43bbcfb4e53dc0811c3396dcb11bf9f23fd0226/coverage-7.13.2-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:4f7b71757a3ab19f7ba286e04c181004c1d61be921795ee8ba6970fd0ec91da5", size = 250496, upload-time = "2026-01-25T12:58:14.047Z" }, + { url = "https://files.pythonhosted.org/packages/ba/b1/0f5d89dfe0392990e4f3980adbde3eb34885bc1effb2dc369e0bf385e389/coverage-7.13.2-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:b7fc50d2afd2e6b4f6f2f403b70103d280a8e0cb35320cbbe6debcda02a1030b", size = 252373, upload-time = "2026-01-25T12:58:15.976Z" }, + { url = "https://files.pythonhosted.org/packages/01/c9/0cf1a6a57a9968cc049a6b896693faa523c638a5314b1fc374eb2b2ac904/coverage-7.13.2-cp312-cp312-win32.whl", hash = "sha256:292250282cf9bcf206b543d7608bda17ca6fc151f4cbae949fc7e115112fbd41", size = 221696, upload-time = "2026-01-25T12:58:17.517Z" }, + { url = "https://files.pythonhosted.org/packages/4d/05/d7540bf983f09d32803911afed135524570f8c47bb394bf6206c1dc3a786/coverage-7.13.2-cp312-cp312-win_amd64.whl", hash = "sha256:eeea10169fac01549a7921d27a3e517194ae254b542102267bef7a93ed38c40e", size = 222504, upload-time = "2026-01-25T12:58:19.115Z" }, + { url = "https://files.pythonhosted.org/packages/15/8b/1a9f037a736ced0a12aacf6330cdaad5008081142a7070bc58b0f7930cbc/coverage-7.13.2-cp312-cp312-win_arm64.whl", hash = "sha256:2a5b567f0b635b592c917f96b9a9cb3dbd4c320d03f4bf94e9084e494f2e8894", size = 221120, upload-time = "2026-01-25T12:58:21.334Z" }, + { url = "https://files.pythonhosted.org/packages/d2/db/d291e30fdf7ea617a335531e72294e0c723356d7fdde8fba00610a76bda9/coverage-7.13.2-py3-none-any.whl", hash = "sha256:40ce1ea1e25125556d8e76bd0b61500839a07944cc287ac21d5626f3e620cad5", size = 210943, upload-time = "2026-01-25T13:00:02.388Z" }, +] + +[package.optional-dependencies] +toml = [ + { name = "tomli", marker = "python_full_version <= '3.11'" }, +] + +[[package]] +name = "debugpy" +version = "1.8.20" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/e0/b7/cd8080344452e4874aae67c40d8940e2b4d47b01601a8fd9f44786c757c7/debugpy-1.8.20.tar.gz", hash = "sha256:55bc8701714969f1ab89a6d5f2f3d40c36f91b2cbe2f65d98bf8196f6a6a2c33", size = 1645207, upload-time = "2026-01-29T23:03:28.199Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/51/56/c3baf5cbe4dd77427fd9aef99fcdade259ad128feeb8a786c246adb838e5/debugpy-1.8.20-cp311-cp311-macosx_15_0_universal2.whl", hash = "sha256:eada6042ad88fa1571b74bd5402ee8b86eded7a8f7b827849761700aff171f1b", size = 2208318, upload-time = "2026-01-29T23:03:36.481Z" }, + { url = "https://files.pythonhosted.org/packages/9a/7d/4fa79a57a8e69fe0d9763e98d1110320f9ecd7f1f362572e3aafd7417c9d/debugpy-1.8.20-cp311-cp311-manylinux_2_34_x86_64.whl", hash = "sha256:7de0b7dfeedc504421032afba845ae2a7bcc32ddfb07dae2c3ca5442f821c344", size = 3171493, upload-time = "2026-01-29T23:03:37.775Z" }, + { url = "https://files.pythonhosted.org/packages/7d/f2/1e8f8affe51e12a26f3a8a8a4277d6e60aa89d0a66512f63b1e799d424a4/debugpy-1.8.20-cp311-cp311-win32.whl", hash = "sha256:773e839380cf459caf73cc533ea45ec2737a5cc184cf1b3b796cd4fd98504fec", size = 5209240, upload-time = "2026-01-29T23:03:39.109Z" }, + { url = "https://files.pythonhosted.org/packages/d5/92/1cb532e88560cbee973396254b21bece8c5d7c2ece958a67afa08c9f10dc/debugpy-1.8.20-cp311-cp311-win_amd64.whl", hash = "sha256:1f7650546e0eded1902d0f6af28f787fa1f1dbdbc97ddabaf1cd963a405930cb", size = 5233481, upload-time = "2026-01-29T23:03:40.659Z" }, + { url = "https://files.pythonhosted.org/packages/14/57/7f34f4736bfb6e00f2e4c96351b07805d83c9a7b33d28580ae01374430f7/debugpy-1.8.20-cp312-cp312-macosx_15_0_universal2.whl", hash = "sha256:4ae3135e2089905a916909ef31922b2d733d756f66d87345b3e5e52b7a55f13d", size = 2550686, upload-time = "2026-01-29T23:03:42.023Z" }, + { url = "https://files.pythonhosted.org/packages/ab/78/b193a3975ca34458f6f0e24aaf5c3e3da72f5401f6054c0dfd004b41726f/debugpy-1.8.20-cp312-cp312-manylinux_2_34_x86_64.whl", hash = "sha256:88f47850a4284b88bd2bfee1f26132147d5d504e4e86c22485dfa44b97e19b4b", size = 4310588, upload-time = "2026-01-29T23:03:43.314Z" }, + { url = "https://files.pythonhosted.org/packages/c1/55/f14deb95eaf4f30f07ef4b90a8590fc05d9e04df85ee379712f6fb6736d7/debugpy-1.8.20-cp312-cp312-win32.whl", hash = "sha256:4057ac68f892064e5f98209ab582abfee3b543fb55d2e87610ddc133a954d390", size = 5331372, upload-time = "2026-01-29T23:03:45.526Z" }, + { url = "https://files.pythonhosted.org/packages/a1/39/2bef246368bd42f9bd7cba99844542b74b84dacbdbea0833e610f384fee8/debugpy-1.8.20-cp312-cp312-win_amd64.whl", hash = "sha256:a1a8f851e7cf171330679ef6997e9c579ef6dd33c9098458bd9986a0f4ca52e3", size = 5372835, upload-time = "2026-01-29T23:03:47.245Z" }, + { url = "https://files.pythonhosted.org/packages/e0/c3/7f67dea8ccf8fdcb9c99033bbe3e90b9e7395415843accb81428c441be2d/debugpy-1.8.20-py2.py3-none-any.whl", hash = "sha256:5be9bed9ae3be00665a06acaa48f8329d2b9632f15fd09f6a9a8c8d9907e54d7", size = 5337658, upload-time = "2026-01-29T23:04:17.404Z" }, +] + +[[package]] +name = "decorator" +version = "5.2.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/43/fa/6d96a0978d19e17b68d634497769987b16c8f4cd0a7a05048bec693caa6b/decorator-5.2.1.tar.gz", hash = "sha256:65f266143752f734b0a7cc83c46f4618af75b8c5911b00ccb61d0ac9b6da0360", size = 56711, upload-time = "2025-02-24T04:41:34.073Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/4e/8c/f3147f5c4b73e7550fe5f9352eaa956ae838d5c51eb58e7a25b9f3e2643b/decorator-5.2.1-py3-none-any.whl", hash = "sha256:d316bb415a2d9e2d2b3abcc4084c6502fc09240e292cd76a76afc106a1c8e04a", size = 9190, upload-time = "2025-02-24T04:41:32.565Z" }, +] + +[[package]] +name = "defusedxml" +version = "0.7.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/0f/d5/c66da9b79e5bdb124974bfe172b4daf3c984ebd9c2a06e2b8a4dc7331c72/defusedxml-0.7.1.tar.gz", hash = "sha256:1bb3032db185915b62d7c6209c5a8792be6a32ab2fedacc84e01b52c51aa3e69", size = 75520, upload-time = "2021-03-08T10:59:26.269Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/07/6c/aa3f2f849e01cb6a001cd8554a88d4c77c5c1a31c95bdf1cf9301e6d9ef4/defusedxml-0.7.1-py2.py3-none-any.whl", hash = "sha256:a352e7e428770286cc899e2542b6cdaedb2b4953ff269a210103ec58f6198a61", size = 25604, upload-time = "2021-03-08T10:59:24.45Z" }, +] + +[[package]] +name = "executing" +version = "2.2.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/cc/28/c14e053b6762b1044f34a13aab6859bbf40456d37d23aa286ac24cfd9a5d/executing-2.2.1.tar.gz", hash = "sha256:3632cc370565f6648cc328b32435bd120a1e4ebb20c77e3fdde9a13cd1e533c4", size = 1129488, upload-time = "2025-09-01T09:48:10.866Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/c1/ea/53f2148663b321f21b5a606bd5f191517cf40b7072c0497d3c92c4a13b1e/executing-2.2.1-py2.py3-none-any.whl", hash = "sha256:760643d3452b4d777d295bb167ccc74c64a81df23fb5e08eff250c425a4b2017", size = 28317, upload-time = "2025-09-01T09:48:08.5Z" }, +] + +[[package]] +name = "fastjsonschema" +version = "2.21.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/20/b5/23b216d9d985a956623b6bd12d4086b60f0059b27799f23016af04a74ea1/fastjsonschema-2.21.2.tar.gz", hash = "sha256:b1eb43748041c880796cd077f1a07c3d94e93ae84bba5ed36800a33554ae05de", size = 374130, upload-time = "2025-08-14T18:49:36.666Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/cb/a8/20d0723294217e47de6d9e2e40fd4a9d2f7c4b6ef974babd482a59743694/fastjsonschema-2.21.2-py3-none-any.whl", hash = "sha256:1c797122d0a86c5cace2e54bf4e819c36223b552017172f32c5c024a6b77e463", size = 24024, upload-time = "2025-08-14T18:49:34.776Z" }, +] + +[[package]] +name = "fqdn" +version = "1.5.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/30/3e/a80a8c077fd798951169626cde3e239adeba7dab75deb3555716415bd9b0/fqdn-1.5.1.tar.gz", hash = "sha256:105ed3677e767fb5ca086a0c1f4bb66ebc3c100be518f0e0d755d9eae164d89f", size = 6015, upload-time = "2021-03-11T07:16:29.08Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/cf/58/8acf1b3e91c58313ce5cb67df61001fc9dcd21be4fadb76c1a2d540e09ed/fqdn-1.5.1-py3-none-any.whl", hash = "sha256:3a179af3761e4df6eb2e026ff9e1a3033d3587bf980a0b1b2e1e5d08d7358014", size = 9121, upload-time = "2021-03-11T07:16:28.351Z" }, +] + +[[package]] +name = "greenlet" +version = "3.3.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/8a/99/1cd3411c56a410994669062bd73dd58270c00cc074cac15f385a1fd91f8a/greenlet-3.3.1.tar.gz", hash = "sha256:41848f3230b58c08bb43dee542e74a2a2e34d3c59dc3076cec9151aeeedcae98", size = 184690, upload-time = "2026-01-23T15:31:02.076Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/ec/e8/2e1462c8fdbe0f210feb5ac7ad2d9029af8be3bf45bd9fa39765f821642f/greenlet-3.3.1-cp311-cp311-macosx_11_0_universal2.whl", hash = "sha256:5fd23b9bc6d37b563211c6abbb1b3cab27db385a4449af5c32e932f93017080c", size = 274974, upload-time = "2026-01-23T15:31:02.891Z" }, + { url = "https://files.pythonhosted.org/packages/7e/a8/530a401419a6b302af59f67aaf0b9ba1015855ea7e56c036b5928793c5bd/greenlet-3.3.1-cp311-cp311-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:09f51496a0bfbaa9d74d36a52d2580d1ef5ed4fdfcff0a73730abfbbbe1403dd", size = 577175, upload-time = "2026-01-23T16:00:56.213Z" }, + { url = "https://files.pythonhosted.org/packages/8e/89/7e812bb9c05e1aaef9b597ac1d0962b9021d2c6269354966451e885c4e6b/greenlet-3.3.1-cp311-cp311-manylinux_2_24_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:cb0feb07fe6e6a74615ee62a880007d976cf739b6669cce95daa7373d4fc69c5", size = 590401, upload-time = "2026-01-23T16:05:26.365Z" }, + { url = "https://files.pythonhosted.org/packages/70/ae/e2d5f0e59b94a2269b68a629173263fa40b63da32f5c231307c349315871/greenlet-3.3.1-cp311-cp311-manylinux_2_24_s390x.manylinux_2_28_s390x.whl", hash = "sha256:67ea3fc73c8cd92f42467a72b75e8f05ed51a0e9b1d15398c913416f2dafd49f", size = 601161, upload-time = "2026-01-23T16:15:53.456Z" }, + { url = "https://files.pythonhosted.org/packages/5c/ae/8d472e1f5ac5efe55c563f3eabb38c98a44b832602e12910750a7c025802/greenlet-3.3.1-cp311-cp311-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:39eda9ba259cc9801da05351eaa8576e9aa83eb9411e8f0c299e05d712a210f2", size = 590272, upload-time = "2026-01-23T15:32:49.411Z" }, + { url = "https://files.pythonhosted.org/packages/a8/51/0fde34bebfcadc833550717eade64e35ec8738e6b097d5d248274a01258b/greenlet-3.3.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:e2e7e882f83149f0a71ac822ebf156d902e7a5d22c9045e3e0d1daf59cee2cc9", size = 1550729, upload-time = "2026-01-23T16:04:20.867Z" }, + { url = "https://files.pythonhosted.org/packages/16/c9/2fb47bee83b25b119d5a35d580807bb8b92480a54b68fef009a02945629f/greenlet-3.3.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:80aa4d79eb5564f2e0a6144fcc744b5a37c56c4a92d60920720e99210d88db0f", size = 1615552, upload-time = "2026-01-23T15:33:45.743Z" }, + { url = "https://files.pythonhosted.org/packages/1f/54/dcf9f737b96606f82f8dd05becfb8d238db0633dd7397d542a296fe9cad3/greenlet-3.3.1-cp311-cp311-win_amd64.whl", hash = "sha256:32e4ca9777c5addcbf42ff3915d99030d8e00173a56f80001fb3875998fe410b", size = 226462, upload-time = "2026-01-23T15:36:50.422Z" }, + { url = "https://files.pythonhosted.org/packages/91/37/61e1015cf944ddd2337447d8e97fb423ac9bc21f9963fb5f206b53d65649/greenlet-3.3.1-cp311-cp311-win_arm64.whl", hash = "sha256:da19609432f353fed186cc1b85e9440db93d489f198b4bdf42ae19cc9d9ac9b4", size = 225715, upload-time = "2026-01-23T15:33:17.298Z" }, + { url = "https://files.pythonhosted.org/packages/f9/c8/9d76a66421d1ae24340dfae7e79c313957f6e3195c144d2c73333b5bfe34/greenlet-3.3.1-cp312-cp312-macosx_11_0_universal2.whl", hash = "sha256:7e806ca53acf6d15a888405880766ec84721aa4181261cd11a457dfe9a7a4975", size = 276443, upload-time = "2026-01-23T15:30:10.066Z" }, + { url = "https://files.pythonhosted.org/packages/81/99/401ff34bb3c032d1f10477d199724f5e5f6fbfb59816ad1455c79c1eb8e7/greenlet-3.3.1-cp312-cp312-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:d842c94b9155f1c9b3058036c24ffb8ff78b428414a19792b2380be9cecf4f36", size = 597359, upload-time = "2026-01-23T16:00:57.394Z" }, + { url = "https://files.pythonhosted.org/packages/2b/bc/4dcc0871ed557792d304f50be0f7487a14e017952ec689effe2180a6ff35/greenlet-3.3.1-cp312-cp312-manylinux_2_24_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:20fedaadd422fa02695f82093f9a98bad3dab5fcda793c658b945fcde2ab27ba", size = 607805, upload-time = "2026-01-23T16:05:28.068Z" }, + { url = "https://files.pythonhosted.org/packages/3b/cd/7a7ca57588dac3389e97f7c9521cb6641fd8b6602faf1eaa4188384757df/greenlet-3.3.1-cp312-cp312-manylinux_2_24_s390x.manylinux_2_28_s390x.whl", hash = "sha256:c620051669fd04ac6b60ebc70478210119c56e2d5d5df848baec4312e260e4ca", size = 622363, upload-time = "2026-01-23T16:15:54.754Z" }, + { url = "https://files.pythonhosted.org/packages/cf/05/821587cf19e2ce1f2b24945d890b164401e5085f9d09cbd969b0c193cd20/greenlet-3.3.1-cp312-cp312-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:14194f5f4305800ff329cbf02c5fcc88f01886cadd29941b807668a45f0d2336", size = 609947, upload-time = "2026-01-23T15:32:51.004Z" }, + { url = "https://files.pythonhosted.org/packages/a4/52/ee8c46ed9f8babaa93a19e577f26e3d28a519feac6350ed6f25f1afee7e9/greenlet-3.3.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:7b2fe4150a0cf59f847a67db8c155ac36aed89080a6a639e9f16df5d6c6096f1", size = 1567487, upload-time = "2026-01-23T16:04:22.125Z" }, + { url = "https://files.pythonhosted.org/packages/8f/7c/456a74f07029597626f3a6db71b273a3632aecb9afafeeca452cfa633197/greenlet-3.3.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:49f4ad195d45f4a66a0eb9c1ba4832bb380570d361912fa3554746830d332149", size = 1636087, upload-time = "2026-01-23T15:33:47.486Z" }, + { url = "https://files.pythonhosted.org/packages/34/2f/5e0e41f33c69655300a5e54aeb637cf8ff57f1786a3aba374eacc0228c1d/greenlet-3.3.1-cp312-cp312-win_amd64.whl", hash = "sha256:cc98b9c4e4870fa983436afa999d4eb16b12872fab7071423d5262fa7120d57a", size = 227156, upload-time = "2026-01-23T15:34:34.808Z" }, + { url = "https://files.pythonhosted.org/packages/c8/ab/717c58343cf02c5265b531384b248787e04d8160b8afe53d9eec053d7b44/greenlet-3.3.1-cp312-cp312-win_arm64.whl", hash = "sha256:bfb2d1763d777de5ee495c85309460f6fd8146e50ec9d0ae0183dbf6f0a829d1", size = 226403, upload-time = "2026-01-23T15:31:39.372Z" }, +] + +[[package]] +name = "griffe" +version = "1.15.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "colorama" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/0d/0c/3a471b6e31951dce2360477420d0a8d1e00dea6cf33b70f3e8c3ab6e28e1/griffe-1.15.0.tar.gz", hash = "sha256:7726e3afd6f298fbc3696e67958803e7ac843c1cfe59734b6251a40cdbfb5eea", size = 424112, upload-time = "2025-11-10T15:03:15.52Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/9c/83/3b1d03d36f224edded98e9affd0467630fc09d766c0e56fb1498cbb04a9b/griffe-1.15.0-py3-none-any.whl", hash = "sha256:6f6762661949411031f5fcda9593f586e6ce8340f0ba88921a0f2ef7a81eb9a3", size = 150705, upload-time = "2025-11-10T15:03:13.549Z" }, +] + +[[package]] +name = "h11" +version = "0.16.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/01/ee/02a2c011bdab74c6fb3c75474d40b3052059d95df7e73351460c8588d963/h11-0.16.0.tar.gz", hash = "sha256:4e35b956cf45792e4caa5885e69fba00bdbc6ffafbfa020300e549b208ee5ff1", size = 101250, upload-time = "2025-04-24T03:35:25.427Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl", hash = "sha256:63cf8bbe7522de3bf65932fda1d9c2772064ffb3dae62d55932da54b31cb6c86", size = 37515, upload-time = "2025-04-24T03:35:24.344Z" }, +] + +[[package]] +name = "httpcore" +version = "1.0.9" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "certifi" }, + { name = "h11" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/06/94/82699a10bca87a5556c9c59b5963f2d039dbd239f25bc2a63907a05a14cb/httpcore-1.0.9.tar.gz", hash = "sha256:6e34463af53fd2ab5d807f399a9b45ea31c3dfa2276f15a2c3f00afff6e176e8", size = 85484, upload-time = "2025-04-24T22:06:22.219Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl", hash = "sha256:2d400746a40668fc9dec9810239072b40b4484b640a8c38fd654a024c7a1bf55", size = 78784, upload-time = "2025-04-24T22:06:20.566Z" }, +] + +[[package]] +name = "httpx" +version = "0.28.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "anyio" }, + { name = "certifi" }, + { name = "httpcore" }, + { name = "idna" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/b1/df/48c586a5fe32a0f01324ee087459e112ebb7224f646c0b5023f5e79e9956/httpx-0.28.1.tar.gz", hash = "sha256:75e98c5f16b0f35b567856f597f06ff2270a374470a5c2392242528e3e3e42fc", size = 141406, upload-time = "2024-12-06T15:37:23.222Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl", hash = "sha256:d909fcccc110f8c7faf814ca82a9a4d816bc5a6dbfea25d6591d6985b8ba59ad", size = 73517, upload-time = "2024-12-06T15:37:21.509Z" }, +] + +[[package]] +name = "hypothesis" +version = "6.151.4" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "sortedcontainers" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/47/03/9fd03d5db09029250e69745c1600edab16fe90947636f77a12ba92d79939/hypothesis-6.151.4.tar.gz", hash = "sha256:658a62da1c3ccb36746ac2f7dc4bb1a6e76bd314e0dc54c4e1aaba2503d5545c", size = 475706, upload-time = "2026-01-29T01:30:14.985Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/9b/6d/01ad1b6c3b8cb2bb47eeaa9765dabc27cbe68e3b59f6cff83d5668f57780/hypothesis-6.151.4-py3-none-any.whl", hash = "sha256:a1cf7e0fdaa296d697a68ff3c0b3912c0050f07aa37e7d2ff33a966749d1d9b4", size = 543146, upload-time = "2026-01-29T01:30:12.805Z" }, +] + +[[package]] +name = "idna" +version = "3.11" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/6f/6d/0703ccc57f3a7233505399edb88de3cbd678da106337b9fcde432b65ed60/idna-3.11.tar.gz", hash = "sha256:795dafcc9c04ed0c1fb032c2aa73654d8e8c5023a7df64a53f39190ada629902", size = 194582, upload-time = "2025-10-12T14:55:20.501Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/0e/61/66938bbb5fc52dbdf84594873d5b51fb1f7c7794e9c0f5bd885f30bc507b/idna-3.11-py3-none-any.whl", hash = "sha256:771a87f49d9defaf64091e6e6fe9c18d4833f140bd19464795bc32d966ca37ea", size = 71008, upload-time = "2025-10-12T14:55:18.883Z" }, +] + +[[package]] +name = "importlib-metadata" +version = "8.7.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "zipp" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/f3/49/3b30cad09e7771a4982d9975a8cbf64f00d4a1ececb53297f1d9a7be1b10/importlib_metadata-8.7.1.tar.gz", hash = "sha256:49fef1ae6440c182052f407c8d34a68f72efc36db9ca90dc0113398f2fdde8bb", size = 57107, upload-time = "2025-12-21T10:00:19.278Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/fa/5e/f8e9a1d23b9c20a551a8a02ea3637b4642e22c2626e3a13a9a29cdea99eb/importlib_metadata-8.7.1-py3-none-any.whl", hash = "sha256:5a1f80bf1daa489495071efbb095d75a634cf28a8bc299581244063b53176151", size = 27865, upload-time = "2025-12-21T10:00:18.329Z" }, +] + +[[package]] +name = "importlib-resources" +version = "6.5.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/cf/8c/f834fbf984f691b4f7ff60f50b514cc3de5cc08abfc3295564dd89c5e2e7/importlib_resources-6.5.2.tar.gz", hash = "sha256:185f87adef5bcc288449d98fb4fba07cea78bc036455dd44c5fc4a2fe78fed2c", size = 44693, upload-time = "2025-01-03T18:51:56.698Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/a4/ed/1f1afb2e9e7f38a545d628f864d562a5ae64fe6f7a10e28ffb9b185b4e89/importlib_resources-6.5.2-py3-none-any.whl", hash = "sha256:789cfdc3ed28c78b67a06acb8126751ced69a3d5f79c095a98298cd8a760ccec", size = 37461, upload-time = "2025-01-03T18:51:54.306Z" }, +] + +[[package]] +name = "iniconfig" +version = "2.3.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/72/34/14ca021ce8e5dfedc35312d08ba8bf51fdd999c576889fc2c24cb97f4f10/iniconfig-2.3.0.tar.gz", hash = "sha256:c76315c77db068650d49c5b56314774a7804df16fee4402c1f19d6d15d8c4730", size = 20503, upload-time = "2025-10-18T21:55:43.219Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl", hash = "sha256:f631c04d2c48c52b84d0d0549c99ff3859c98df65b3101406327ecc7d53fbf12", size = 7484, upload-time = "2025-10-18T21:55:41.639Z" }, +] + +[[package]] +name = "ipykernel" +version = "7.1.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "appnope", marker = "sys_platform == 'darwin'" }, + { name = "comm" }, + { name = "debugpy" }, + { name = "ipython" }, + { name = "jupyter-client" }, + { name = "jupyter-core" }, + { name = "matplotlib-inline" }, + { name = "nest-asyncio" }, + { name = "packaging" }, + { name = "psutil" }, + { name = "pyzmq" }, + { name = "tornado" }, + { name = "traitlets" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/b9/a4/4948be6eb88628505b83a1f2f40d90254cab66abf2043b3c40fa07dfce0f/ipykernel-7.1.0.tar.gz", hash = "sha256:58a3fc88533d5930c3546dc7eac66c6d288acde4f801e2001e65edc5dc9cf0db", size = 174579, upload-time = "2025-10-27T09:46:39.471Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/a3/17/20c2552266728ceba271967b87919664ecc0e33efca29c3efc6baf88c5f9/ipykernel-7.1.0-py3-none-any.whl", hash = "sha256:763b5ec6c5b7776f6a8d7ce09b267693b4e5ce75cb50ae696aaefb3c85e1ea4c", size = 117968, upload-time = "2025-10-27T09:46:37.805Z" }, +] + +[[package]] +name = "ipython" +version = "9.10.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "colorama", marker = "sys_platform == 'win32'" }, + { name = "decorator" }, + { name = "ipython-pygments-lexers" }, + { name = "jedi" }, + { name = "matplotlib-inline" }, + { name = "pexpect", marker = "sys_platform != 'emscripten' and sys_platform != 'win32'" }, + { name = "prompt-toolkit" }, + { name = "pygments" }, + { name = "stack-data" }, + { name = "traitlets" }, + { name = "typing-extensions", marker = "python_full_version < '3.12'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/a6/60/2111715ea11f39b1535bed6024b7dec7918b71e5e5d30855a5b503056b50/ipython-9.10.0.tar.gz", hash = "sha256:cd9e656be97618a0676d058134cd44e6dc7012c0e5cb36a9ce96a8c904adaf77", size = 4426526, upload-time = "2026-02-02T10:00:33.594Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/3d/aa/898dec789a05731cd5a9f50605b7b44a72bd198fd0d4528e11fc610177cc/ipython-9.10.0-py3-none-any.whl", hash = "sha256:c6ab68cc23bba8c7e18e9b932797014cc61ea7fd6f19de180ab9ba73e65ee58d", size = 622774, upload-time = "2026-02-02T10:00:31.503Z" }, +] + +[[package]] +name = "ipython-pygments-lexers" +version = "1.1.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "pygments" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/ef/4c/5dd1d8af08107f88c7f741ead7a40854b8ac24ddf9ae850afbcf698aa552/ipython_pygments_lexers-1.1.1.tar.gz", hash = "sha256:09c0138009e56b6854f9535736f4171d855c8c08a563a0dcd8022f78355c7e81", size = 8393, upload-time = "2025-01-17T11:24:34.505Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/d9/33/1f075bf72b0b747cb3288d011319aaf64083cf2efef8354174e3ed4540e2/ipython_pygments_lexers-1.1.1-py3-none-any.whl", hash = "sha256:a9462224a505ade19a605f71f8fa63c2048833ce50abc86768a0d81d876dc81c", size = 8074, upload-time = "2025-01-17T11:24:33.271Z" }, +] + +[[package]] +name = "ipywidgets" +version = "8.1.8" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "comm" }, + { name = "ipython" }, + { name = "jupyterlab-widgets" }, + { name = "traitlets" }, + { name = "widgetsnbextension" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/4c/ae/c5ce1edc1afe042eadb445e95b0671b03cee61895264357956e61c0d2ac0/ipywidgets-8.1.8.tar.gz", hash = "sha256:61f969306b95f85fba6b6986b7fe45d73124d1d9e3023a8068710d47a22ea668", size = 116739, upload-time = "2025-11-01T21:18:12.393Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/56/6d/0d9848617b9f753b87f214f1c682592f7ca42de085f564352f10f0843026/ipywidgets-8.1.8-py3-none-any.whl", hash = "sha256:ecaca67aed704a338f88f67b1181b58f821ab5dc89c1f0f5ef99db43c1c2921e", size = 139808, upload-time = "2025-11-01T21:18:10.956Z" }, +] + +[[package]] +name = "isoduration" +version = "20.11.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "arrow" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/7c/1a/3c8edc664e06e6bd06cce40c6b22da5f1429aa4224d0c590f3be21c91ead/isoduration-20.11.0.tar.gz", hash = "sha256:ac2f9015137935279eac671f94f89eb00584f940f5dc49462a0c4ee692ba1bd9", size = 11649, upload-time = "2020-11-01T11:00:00.312Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/7b/55/e5326141505c5d5e34c5e0935d2908a74e4561eca44108fbfb9c13d2911a/isoduration-20.11.0-py3-none-any.whl", hash = "sha256:b2904c2a4228c3d44f409c8ae8e2370eb21a26f7ac2ec5446df141dde3452042", size = 11321, upload-time = "2020-11-01T10:59:58.02Z" }, +] + +[[package]] +name = "jedi" +version = "0.19.2" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "parso" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/72/3a/79a912fbd4d8dd6fbb02bf69afd3bb72cf0c729bb3063c6f4498603db17a/jedi-0.19.2.tar.gz", hash = "sha256:4770dc3de41bde3966b02eb84fbcf557fb33cce26ad23da12c742fb50ecb11f0", size = 1231287, upload-time = "2024-11-11T01:41:42.873Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/c0/5a/9cac0c82afec3d09ccd97c8b6502d48f165f9124db81b4bcb90b4af974ee/jedi-0.19.2-py2.py3-none-any.whl", hash = "sha256:a8ef22bde8490f57fe5c7681a3c83cb58874daf72b4784de3cce5b6ef6edb5b9", size = 1572278, upload-time = "2024-11-11T01:41:40.175Z" }, +] + +[[package]] +name = "jinja2" +version = "3.1.6" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "markupsafe" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/df/bf/f7da0350254c0ed7c72f3e33cef02e048281fec7ecec5f032d4aac52226b/jinja2-3.1.6.tar.gz", hash = "sha256:0137fb05990d35f1275a587e9aee6d56da821fc83491a0fb838183be43f66d6d", size = 245115, upload-time = "2025-03-05T20:05:02.478Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/62/a1/3d680cbfd5f4b8f15abc1d571870c5fc3e594bb582bc3b64ea099db13e56/jinja2-3.1.6-py3-none-any.whl", hash = "sha256:85ece4451f492d0c13c5dd7c13a64681a86afae63a5f347908daf103ce6d2f67", size = 134899, upload-time = "2025-03-05T20:05:00.369Z" }, +] + +[[package]] +name = "json5" +version = "0.13.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/77/e8/a3f261a66e4663f22700bc8a17c08cb83e91fbf086726e7a228398968981/json5-0.13.0.tar.gz", hash = "sha256:b1edf8d487721c0bf64d83c28e91280781f6e21f4a797d3261c7c828d4c165bf", size = 52441, upload-time = "2026-01-01T19:42:14.99Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/d7/9e/038522f50ceb7e74f1f991bf1b699f24b0c2bbe7c390dd36ad69f4582258/json5-0.13.0-py3-none-any.whl", hash = "sha256:9a08e1dd65f6a4d4c6fa82d216cf2477349ec2346a38fd70cc11d2557499fbcc", size = 36163, upload-time = "2026-01-01T19:42:13.962Z" }, +] + +[[package]] +name = "jsonpointer" +version = "3.0.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/6a/0a/eebeb1fa92507ea94016a2a790b93c2ae41a7e18778f85471dc54475ed25/jsonpointer-3.0.0.tar.gz", hash = "sha256:2b2d729f2091522d61c3b31f82e11870f60b68f43fbc705cb76bf4b832af59ef", size = 9114, upload-time = "2024-06-10T19:24:42.462Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/71/92/5e77f98553e9e75130c78900d000368476aed74276eb8ae8796f65f00918/jsonpointer-3.0.0-py2.py3-none-any.whl", hash = "sha256:13e088adc14fca8b6aa8177c044e12701e6ad4b28ff10e65f2267a90109c9942", size = 7595, upload-time = "2024-06-10T19:24:40.698Z" }, +] + +[[package]] +name = "jsonschema" +version = "4.26.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "attrs" }, + { name = "jsonschema-specifications" }, + { name = "referencing" }, + { name = "rpds-py" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/b3/fc/e067678238fa451312d4c62bf6e6cf5ec56375422aee02f9cb5f909b3047/jsonschema-4.26.0.tar.gz", hash = "sha256:0c26707e2efad8aa1bfc5b7ce170f3fccc2e4918ff85989ba9ffa9facb2be326", size = 366583, upload-time = "2026-01-07T13:41:07.246Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/69/90/f63fb5873511e014207a475e2bb4e8b2e570d655b00ac19a9a0ca0a385ee/jsonschema-4.26.0-py3-none-any.whl", hash = "sha256:d489f15263b8d200f8387e64b4c3a75f06629559fb73deb8fdfb525f2dab50ce", size = 90630, upload-time = "2026-01-07T13:41:05.306Z" }, +] + +[package.optional-dependencies] +format-nongpl = [ + { name = "fqdn" }, + { name = "idna" }, + { name = "isoduration" }, + { name = "jsonpointer" }, + { name = "rfc3339-validator" }, + { name = "rfc3986-validator" }, + { name = "rfc3987-syntax" }, + { name = "uri-template" }, + { name = "webcolors" }, +] + +[[package]] +name = "jsonschema-specifications" +version = "2025.9.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "referencing" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/19/74/a633ee74eb36c44aa6d1095e7cc5569bebf04342ee146178e2d36600708b/jsonschema_specifications-2025.9.1.tar.gz", hash = "sha256:b540987f239e745613c7a9176f3edb72b832a4ac465cf02712288397832b5e8d", size = 32855, upload-time = "2025-09-08T01:34:59.186Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/41/45/1a4ed80516f02155c51f51e8cedb3c1902296743db0bbc66608a0db2814f/jsonschema_specifications-2025.9.1-py3-none-any.whl", hash = "sha256:98802fee3a11ee76ecaca44429fda8a41bff98b00a0f2838151b113f210cc6fe", size = 18437, upload-time = "2025-09-08T01:34:57.871Z" }, +] + +[[package]] +name = "jupyter" +version = "1.1.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "ipykernel" }, + { name = "ipywidgets" }, + { name = "jupyter-console" }, + { name = "jupyterlab" }, + { name = "nbconvert" }, + { name = "notebook" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/58/f3/af28ea964ab8bc1e472dba2e82627d36d470c51f5cd38c37502eeffaa25e/jupyter-1.1.1.tar.gz", hash = "sha256:d55467bceabdea49d7e3624af7e33d59c37fff53ed3a350e1ac957bed731de7a", size = 5714959, upload-time = "2024-08-30T07:15:48.299Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/38/64/285f20a31679bf547b75602702f7800e74dbabae36ef324f716c02804753/jupyter-1.1.1-py2.py3-none-any.whl", hash = "sha256:7a59533c22af65439b24bbe60373a4e95af8f16ac65a6c00820ad378e3f7cc83", size = 2657, upload-time = "2024-08-30T07:15:47.045Z" }, +] + +[[package]] +name = "jupyter-cache" +version = "1.0.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "attrs" }, + { name = "click" }, + { name = "importlib-metadata" }, + { name = "nbclient" }, + { name = "nbformat" }, + { name = "pyyaml" }, + { name = "sqlalchemy" }, + { name = "tabulate" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/bb/f7/3627358075f183956e8c4974603232b03afd4ddc7baf72c2bc9fff522291/jupyter_cache-1.0.1.tar.gz", hash = "sha256:16e808eb19e3fb67a223db906e131ea6e01f03aa27f49a7214ce6a5fec186fb9", size = 32048, upload-time = "2024-11-15T16:03:55.322Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/64/6b/67b87da9d36bff9df7d0efbd1a325fa372a43be7158effaf43ed7b22341d/jupyter_cache-1.0.1-py3-none-any.whl", hash = "sha256:9c3cafd825ba7da8b5830485343091143dff903e4d8c69db9349b728b140abf6", size = 33907, upload-time = "2024-11-15T16:03:54.021Z" }, +] + +[[package]] +name = "jupyter-client" +version = "8.8.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "jupyter-core" }, + { name = "python-dateutil" }, + { name = "pyzmq" }, + { name = "tornado" }, + { name = "traitlets" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/05/e4/ba649102a3bc3fbca54e7239fb924fd434c766f855693d86de0b1f2bec81/jupyter_client-8.8.0.tar.gz", hash = "sha256:d556811419a4f2d96c869af34e854e3f059b7cc2d6d01a9cd9c85c267691be3e", size = 348020, upload-time = "2026-01-08T13:55:47.938Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/2d/0b/ceb7694d864abc0a047649aec263878acb9f792e1fec3e676f22dc9015e3/jupyter_client-8.8.0-py3-none-any.whl", hash = "sha256:f93a5b99c5e23a507b773d3a1136bd6e16c67883ccdbd9a829b0bbdb98cd7d7a", size = 107371, upload-time = "2026-01-08T13:55:45.562Z" }, +] + +[[package]] +name = "jupyter-console" +version = "6.6.3" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "ipykernel" }, + { name = "ipython" }, + { name = "jupyter-client" }, + { name = "jupyter-core" }, + { name = "prompt-toolkit" }, + { name = "pygments" }, + { name = "pyzmq" }, + { name = "traitlets" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/bd/2d/e2fd31e2fc41c14e2bcb6c976ab732597e907523f6b2420305f9fc7fdbdb/jupyter_console-6.6.3.tar.gz", hash = "sha256:566a4bf31c87adbfadf22cdf846e3069b59a71ed5da71d6ba4d8aaad14a53539", size = 34363, upload-time = "2023-03-06T14:13:31.02Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/ca/77/71d78d58f15c22db16328a476426f7ac4a60d3a5a7ba3b9627ee2f7903d4/jupyter_console-6.6.3-py3-none-any.whl", hash = "sha256:309d33409fcc92ffdad25f0bcdf9a4a9daa61b6f341177570fdac03de5352485", size = 24510, upload-time = "2023-03-06T14:13:28.229Z" }, +] + +[[package]] +name = "jupyter-core" +version = "5.9.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "platformdirs" }, + { name = "traitlets" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/02/49/9d1284d0dc65e2c757b74c6687b6d319b02f822ad039e5c512df9194d9dd/jupyter_core-5.9.1.tar.gz", hash = "sha256:4d09aaff303b9566c3ce657f580bd089ff5c91f5f89cf7d8846c3cdf465b5508", size = 89814, upload-time = "2025-10-16T19:19:18.444Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/e7/e7/80988e32bf6f73919a113473a604f5a8f09094de312b9d52b79c2df7612b/jupyter_core-5.9.1-py3-none-any.whl", hash = "sha256:ebf87fdc6073d142e114c72c9e29a9d7ca03fad818c5d300ce2adc1fb0743407", size = 29032, upload-time = "2025-10-16T19:19:16.783Z" }, +] + +[[package]] +name = "jupyter-events" +version = "0.12.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "jsonschema", extra = ["format-nongpl"] }, + { name = "packaging" }, + { name = "python-json-logger" }, + { name = "pyyaml" }, + { name = "referencing" }, + { name = "rfc3339-validator" }, + { name = "rfc3986-validator" }, + { name = "traitlets" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/9d/c3/306d090461e4cf3cd91eceaff84bede12a8e52cd821c2d20c9a4fd728385/jupyter_events-0.12.0.tar.gz", hash = "sha256:fc3fce98865f6784c9cd0a56a20644fc6098f21c8c33834a8d9fe383c17e554b", size = 62196, upload-time = "2025-02-03T17:23:41.485Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/e2/48/577993f1f99c552f18a0428731a755e06171f9902fa118c379eb7c04ea22/jupyter_events-0.12.0-py3-none-any.whl", hash = "sha256:6464b2fa5ad10451c3d35fabc75eab39556ae1e2853ad0c0cc31b656731a97fb", size = 19430, upload-time = "2025-02-03T17:23:38.643Z" }, +] + +[[package]] +name = "jupyter-lsp" +version = "2.3.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "jupyter-server" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/eb/5a/9066c9f8e94ee517133cd98dba393459a16cd48bba71a82f16a65415206c/jupyter_lsp-2.3.0.tar.gz", hash = "sha256:458aa59339dc868fb784d73364f17dbce8836e906cd75fd471a325cba02e0245", size = 54823, upload-time = "2025-08-27T17:47:34.671Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/1a/60/1f6cee0c46263de1173894f0fafcb3475ded276c472c14d25e0280c18d6d/jupyter_lsp-2.3.0-py3-none-any.whl", hash = "sha256:e914a3cb2addf48b1c7710914771aaf1819d46b2e5a79b0f917b5478ec93f34f", size = 76687, upload-time = "2025-08-27T17:47:33.15Z" }, +] + +[[package]] +name = "jupyter-server" +version = "2.17.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "anyio" }, + { name = "argon2-cffi" }, + { name = "jinja2" }, + { name = "jupyter-client" }, + { name = "jupyter-core" }, + { name = "jupyter-events" }, + { name = "jupyter-server-terminals" }, + { name = "nbconvert" }, + { name = "nbformat" }, + { name = "overrides", marker = "python_full_version < '3.12'" }, + { name = "packaging" }, + { name = "prometheus-client" }, + { name = "pywinpty", marker = "os_name == 'nt'" }, + { name = "pyzmq" }, + { name = "send2trash" }, + { name = "terminado" }, + { name = "tornado" }, + { name = "traitlets" }, + { name = "websocket-client" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/5b/ac/e040ec363d7b6b1f11304cc9f209dac4517ece5d5e01821366b924a64a50/jupyter_server-2.17.0.tar.gz", hash = "sha256:c38ea898566964c888b4772ae1ed58eca84592e88251d2cfc4d171f81f7e99d5", size = 731949, upload-time = "2025-08-21T14:42:54.042Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/92/80/a24767e6ca280f5a49525d987bf3e4d7552bf67c8be07e8ccf20271f8568/jupyter_server-2.17.0-py3-none-any.whl", hash = "sha256:e8cb9c7db4251f51ed307e329b81b72ccf2056ff82d50524debde1ee1870e13f", size = 388221, upload-time = "2025-08-21T14:42:52.034Z" }, +] + +[[package]] +name = "jupyter-server-terminals" +version = "0.5.4" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "pywinpty", marker = "os_name == 'nt'" }, + { name = "terminado" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/f4/a7/bcd0a9b0cbba88986fe944aaaf91bfda603e5a50bda8ed15123f381a3b2f/jupyter_server_terminals-0.5.4.tar.gz", hash = "sha256:bbda128ed41d0be9020349f9f1f2a4ab9952a73ed5f5ac9f1419794761fb87f5", size = 31770, upload-time = "2026-01-14T16:53:20.213Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/d1/2d/6674563f71c6320841fc300911a55143925112a72a883e2ca71fba4c618d/jupyter_server_terminals-0.5.4-py3-none-any.whl", hash = "sha256:55be353fc74a80bc7f3b20e6be50a55a61cd525626f578dcb66a5708e2007d14", size = 13704, upload-time = "2026-01-14T16:53:18.738Z" }, +] + +[[package]] +name = "jupyterlab" +version = "4.5.3" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "async-lru" }, + { name = "httpx" }, + { name = "ipykernel" }, + { name = "jinja2" }, + { name = "jupyter-core" }, + { name = "jupyter-lsp" }, + { name = "jupyter-server" }, + { name = "jupyterlab-server" }, + { name = "notebook-shim" }, + { name = "packaging" }, + { name = "setuptools" }, + { name = "tornado" }, + { name = "traitlets" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/3e/76/393eae3349f9a39bf21f8f5406e5244d36e2bfc932049b6070c271f92764/jupyterlab-4.5.3.tar.gz", hash = "sha256:4a159f71067cb38e4a82e86a42de8e7e926f384d7f2291964f282282096d27e8", size = 23939231, upload-time = "2026-01-23T15:04:25.768Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/9e/9a/0bf9a7a45f0006d7ff4fdc4fc313de4255acab02bf4db1887c65f0472c01/jupyterlab-4.5.3-py3-none-any.whl", hash = "sha256:63c9f3a48de72ba00df766ad6eed416394f5bb883829f11eeff0872302520ba7", size = 12391761, upload-time = "2026-01-23T15:04:21.214Z" }, +] + +[[package]] +name = "jupyterlab-pygments" +version = "0.3.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/90/51/9187be60d989df97f5f0aba133fa54e7300f17616e065d1ada7d7646b6d6/jupyterlab_pygments-0.3.0.tar.gz", hash = "sha256:721aca4d9029252b11cfa9d185e5b5af4d54772bb8072f9b7036f4170054d35d", size = 512900, upload-time = "2023-11-23T09:26:37.44Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/b1/dd/ead9d8ea85bf202d90cc513b533f9c363121c7792674f78e0d8a854b63b4/jupyterlab_pygments-0.3.0-py3-none-any.whl", hash = "sha256:841a89020971da1d8693f1a99997aefc5dc424bb1b251fd6322462a1b8842780", size = 15884, upload-time = "2023-11-23T09:26:34.325Z" }, +] + +[[package]] +name = "jupyterlab-server" +version = "2.28.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "babel" }, + { name = "jinja2" }, + { name = "json5" }, + { name = "jsonschema" }, + { name = "jupyter-server" }, + { name = "packaging" }, + { name = "requests" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/d6/2c/90153f189e421e93c4bb4f9e3f59802a1f01abd2ac5cf40b152d7f735232/jupyterlab_server-2.28.0.tar.gz", hash = "sha256:35baa81898b15f93573e2deca50d11ac0ae407ebb688299d3a5213265033712c", size = 76996, upload-time = "2025-10-22T13:59:18.37Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/e0/07/a000fe835f76b7e1143242ab1122e6362ef1c03f23f83a045c38859c2ae0/jupyterlab_server-2.28.0-py3-none-any.whl", hash = "sha256:e4355b148fdcf34d312bbbc80f22467d6d20460e8b8736bf235577dd18506968", size = 59830, upload-time = "2025-10-22T13:59:16.767Z" }, +] + +[[package]] +name = "jupyterlab-widgets" +version = "3.0.16" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/26/2d/ef58fed122b268c69c0aa099da20bc67657cdfb2e222688d5731bd5b971d/jupyterlab_widgets-3.0.16.tar.gz", hash = "sha256:423da05071d55cf27a9e602216d35a3a65a3e41cdf9c5d3b643b814ce38c19e0", size = 897423, upload-time = "2025-11-01T21:11:29.724Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/ab/b5/36c712098e6191d1b4e349304ef73a8d06aed77e56ceaac8c0a306c7bda1/jupyterlab_widgets-3.0.16-py3-none-any.whl", hash = "sha256:45fa36d9c6422cf2559198e4db481aa243c7a32d9926b500781c830c80f7ecf8", size = 914926, upload-time = "2025-11-01T21:11:28.008Z" }, +] + +[[package]] +name = "lark" +version = "1.3.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/da/34/28fff3ab31ccff1fd4f6c7c7b0ceb2b6968d8ea4950663eadcb5720591a0/lark-1.3.1.tar.gz", hash = "sha256:b426a7a6d6d53189d318f2b6236ab5d6429eaf09259f1ca33eb716eed10d2905", size = 382732, upload-time = "2025-10-27T18:25:56.653Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/82/3d/14ce75ef66813643812f3093ab17e46d3a206942ce7376d31ec2d36229e7/lark-1.3.1-py3-none-any.whl", hash = "sha256:c629b661023a014c37da873b4ff58a817398d12635d3bbb2c5a03be7fe5d1e12", size = 113151, upload-time = "2025-10-27T18:25:54.882Z" }, +] + +[[package]] +name = "markdown-it-py" +version = "4.0.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "mdurl" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/5b/f5/4ec618ed16cc4f8fb3b701563655a69816155e79e24a17b651541804721d/markdown_it_py-4.0.0.tar.gz", hash = "sha256:cb0a2b4aa34f932c007117b194e945bd74e0ec24133ceb5bac59009cda1cb9f3", size = 73070, upload-time = "2025-08-11T12:57:52.854Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/94/54/e7d793b573f298e1c9013b8c4dade17d481164aa517d1d7148619c2cedbf/markdown_it_py-4.0.0-py3-none-any.whl", hash = "sha256:87327c59b172c5011896038353a81343b6754500a08cd7a4973bb48c6d578147", size = 87321, upload-time = "2025-08-11T12:57:51.923Z" }, +] + +[[package]] +name = "markupsafe" +version = "3.0.3" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/7e/99/7690b6d4034fffd95959cbe0c02de8deb3098cc577c67bb6a24fe5d7caa7/markupsafe-3.0.3.tar.gz", hash = "sha256:722695808f4b6457b320fdc131280796bdceb04ab50fe1795cd540799ebe1698", size = 80313, upload-time = "2025-09-27T18:37:40.426Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/08/db/fefacb2136439fc8dd20e797950e749aa1f4997ed584c62cfb8ef7c2be0e/markupsafe-3.0.3-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:1cc7ea17a6824959616c525620e387f6dd30fec8cb44f649e31712db02123dad", size = 11631, upload-time = "2025-09-27T18:36:18.185Z" }, + { url = "https://files.pythonhosted.org/packages/e1/2e/5898933336b61975ce9dc04decbc0a7f2fee78c30353c5efba7f2d6ff27a/markupsafe-3.0.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:4bd4cd07944443f5a265608cc6aab442e4f74dff8088b0dfc8238647b8f6ae9a", size = 12058, upload-time = "2025-09-27T18:36:19.444Z" }, + { url = "https://files.pythonhosted.org/packages/1d/09/adf2df3699d87d1d8184038df46a9c80d78c0148492323f4693df54e17bb/markupsafe-3.0.3-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6b5420a1d9450023228968e7e6a9ce57f65d148ab56d2313fcd589eee96a7a50", size = 24287, upload-time = "2025-09-27T18:36:20.768Z" }, + { url = "https://files.pythonhosted.org/packages/30/ac/0273f6fcb5f42e314c6d8cd99effae6a5354604d461b8d392b5ec9530a54/markupsafe-3.0.3-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:0bf2a864d67e76e5c9a34dc26ec616a66b9888e25e7b9460e1c76d3293bd9dbf", size = 22940, upload-time = "2025-09-27T18:36:22.249Z" }, + { url = "https://files.pythonhosted.org/packages/19/ae/31c1be199ef767124c042c6c3e904da327a2f7f0cd63a0337e1eca2967a8/markupsafe-3.0.3-cp311-cp311-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:bc51efed119bc9cfdf792cdeaa4d67e8f6fcccab66ed4bfdd6bde3e59bfcbb2f", size = 21887, upload-time = "2025-09-27T18:36:23.535Z" }, + { url = "https://files.pythonhosted.org/packages/b2/76/7edcab99d5349a4532a459e1fe64f0b0467a3365056ae550d3bcf3f79e1e/markupsafe-3.0.3-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:068f375c472b3e7acbe2d5318dea141359e6900156b5b2ba06a30b169086b91a", size = 23692, upload-time = "2025-09-27T18:36:24.823Z" }, + { url = "https://files.pythonhosted.org/packages/a4/28/6e74cdd26d7514849143d69f0bf2399f929c37dc2b31e6829fd2045b2765/markupsafe-3.0.3-cp311-cp311-musllinux_1_2_riscv64.whl", hash = "sha256:7be7b61bb172e1ed687f1754f8e7484f1c8019780f6f6b0786e76bb01c2ae115", size = 21471, upload-time = "2025-09-27T18:36:25.95Z" }, + { url = "https://files.pythonhosted.org/packages/62/7e/a145f36a5c2945673e590850a6f8014318d5577ed7e5920a4b3448e0865d/markupsafe-3.0.3-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:f9e130248f4462aaa8e2552d547f36ddadbeaa573879158d721bbd33dfe4743a", size = 22923, upload-time = "2025-09-27T18:36:27.109Z" }, + { url = "https://files.pythonhosted.org/packages/0f/62/d9c46a7f5c9adbeeeda52f5b8d802e1094e9717705a645efc71b0913a0a8/markupsafe-3.0.3-cp311-cp311-win32.whl", hash = "sha256:0db14f5dafddbb6d9208827849fad01f1a2609380add406671a26386cdf15a19", size = 14572, upload-time = "2025-09-27T18:36:28.045Z" }, + { url = "https://files.pythonhosted.org/packages/83/8a/4414c03d3f891739326e1783338e48fb49781cc915b2e0ee052aa490d586/markupsafe-3.0.3-cp311-cp311-win_amd64.whl", hash = "sha256:de8a88e63464af587c950061a5e6a67d3632e36df62b986892331d4620a35c01", size = 15077, upload-time = "2025-09-27T18:36:29.025Z" }, + { url = "https://files.pythonhosted.org/packages/35/73/893072b42e6862f319b5207adc9ae06070f095b358655f077f69a35601f0/markupsafe-3.0.3-cp311-cp311-win_arm64.whl", hash = "sha256:3b562dd9e9ea93f13d53989d23a7e775fdfd1066c33494ff43f5418bc8c58a5c", size = 13876, upload-time = "2025-09-27T18:36:29.954Z" }, + { url = "https://files.pythonhosted.org/packages/5a/72/147da192e38635ada20e0a2e1a51cf8823d2119ce8883f7053879c2199b5/markupsafe-3.0.3-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:d53197da72cc091b024dd97249dfc7794d6a56530370992a5e1a08983ad9230e", size = 11615, upload-time = "2025-09-27T18:36:30.854Z" }, + { url = "https://files.pythonhosted.org/packages/9a/81/7e4e08678a1f98521201c3079f77db69fb552acd56067661f8c2f534a718/markupsafe-3.0.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:1872df69a4de6aead3491198eaf13810b565bdbeec3ae2dc8780f14458ec73ce", size = 12020, upload-time = "2025-09-27T18:36:31.971Z" }, + { url = "https://files.pythonhosted.org/packages/1e/2c/799f4742efc39633a1b54a92eec4082e4f815314869865d876824c257c1e/markupsafe-3.0.3-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:3a7e8ae81ae39e62a41ec302f972ba6ae23a5c5396c8e60113e9066ef893da0d", size = 24332, upload-time = "2025-09-27T18:36:32.813Z" }, + { url = "https://files.pythonhosted.org/packages/3c/2e/8d0c2ab90a8c1d9a24f0399058ab8519a3279d1bd4289511d74e909f060e/markupsafe-3.0.3-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:d6dd0be5b5b189d31db7cda48b91d7e0a9795f31430b7f271219ab30f1d3ac9d", size = 22947, upload-time = "2025-09-27T18:36:33.86Z" }, + { url = "https://files.pythonhosted.org/packages/2c/54/887f3092a85238093a0b2154bd629c89444f395618842e8b0c41783898ea/markupsafe-3.0.3-cp312-cp312-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:94c6f0bb423f739146aec64595853541634bde58b2135f27f61c1ffd1cd4d16a", size = 21962, upload-time = "2025-09-27T18:36:35.099Z" }, + { url = "https://files.pythonhosted.org/packages/c9/2f/336b8c7b6f4a4d95e91119dc8521402461b74a485558d8f238a68312f11c/markupsafe-3.0.3-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:be8813b57049a7dc738189df53d69395eba14fb99345e0a5994914a3864c8a4b", size = 23760, upload-time = "2025-09-27T18:36:36.001Z" }, + { url = "https://files.pythonhosted.org/packages/32/43/67935f2b7e4982ffb50a4d169b724d74b62a3964bc1a9a527f5ac4f1ee2b/markupsafe-3.0.3-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:83891d0e9fb81a825d9a6d61e3f07550ca70a076484292a70fde82c4b807286f", size = 21529, upload-time = "2025-09-27T18:36:36.906Z" }, + { url = "https://files.pythonhosted.org/packages/89/e0/4486f11e51bbba8b0c041098859e869e304d1c261e59244baa3d295d47b7/markupsafe-3.0.3-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:77f0643abe7495da77fb436f50f8dab76dbc6e5fd25d39589a0f1fe6548bfa2b", size = 23015, upload-time = "2025-09-27T18:36:37.868Z" }, + { url = "https://files.pythonhosted.org/packages/2f/e1/78ee7a023dac597a5825441ebd17170785a9dab23de95d2c7508ade94e0e/markupsafe-3.0.3-cp312-cp312-win32.whl", hash = "sha256:d88b440e37a16e651bda4c7c2b930eb586fd15ca7406cb39e211fcff3bf3017d", size = 14540, upload-time = "2025-09-27T18:36:38.761Z" }, + { url = "https://files.pythonhosted.org/packages/aa/5b/bec5aa9bbbb2c946ca2733ef9c4ca91c91b6a24580193e891b5f7dbe8e1e/markupsafe-3.0.3-cp312-cp312-win_amd64.whl", hash = "sha256:26a5784ded40c9e318cfc2bdb30fe164bdb8665ded9cd64d500a34fb42067b1c", size = 15105, upload-time = "2025-09-27T18:36:39.701Z" }, + { url = "https://files.pythonhosted.org/packages/e5/f1/216fc1bbfd74011693a4fd837e7026152e89c4bcf3e77b6692fba9923123/markupsafe-3.0.3-cp312-cp312-win_arm64.whl", hash = "sha256:35add3b638a5d900e807944a078b51922212fb3dedb01633a8defc4b01a3c85f", size = 13906, upload-time = "2025-09-27T18:36:40.689Z" }, +] + +[[package]] +name = "matplotlib-inline" +version = "0.2.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "traitlets" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/c7/74/97e72a36efd4ae2bccb3463284300f8953f199b5ffbc04cbbb0ec78f74b1/matplotlib_inline-0.2.1.tar.gz", hash = "sha256:e1ee949c340d771fc39e241ea75683deb94762c8fa5f2927ec57c83c4dffa9fe", size = 8110, upload-time = "2025-10-23T09:00:22.126Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/af/33/ee4519fa02ed11a94aef9559552f3b17bb863f2ecfe1a35dc7f548cde231/matplotlib_inline-0.2.1-py3-none-any.whl", hash = "sha256:d56ce5156ba6085e00a9d54fead6ed29a9c47e215cd1bba2e976ef39f5710a76", size = 9516, upload-time = "2025-10-23T09:00:20.675Z" }, +] + +[[package]] +name = "mdurl" +version = "0.1.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/d6/54/cfe61301667036ec958cb99bd3efefba235e65cdeb9c84d24a8293ba1d90/mdurl-0.1.2.tar.gz", hash = "sha256:bb413d29f5eea38f31dd4754dd7377d4465116fb207585f97bf925588687c1ba", size = 8729, upload-time = "2022-08-14T12:40:10.846Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/b3/38/89ba8ad64ae25be8de66a6d463314cf1eb366222074cfda9ee839c56a4b4/mdurl-0.1.2-py3-none-any.whl", hash = "sha256:84008a41e51615a49fc9966191ff91509e3c40b939176e643fd50a5c2196b8f8", size = 9979, upload-time = "2022-08-14T12:40:09.779Z" }, +] + +[[package]] +name = "mistune" +version = "3.2.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/9d/55/d01f0c4b45ade6536c51170b9043db8b2ec6ddf4a35c7ea3f5f559ac935b/mistune-3.2.0.tar.gz", hash = "sha256:708487c8a8cdd99c9d90eb3ed4c3ed961246ff78ac82f03418f5183ab70e398a", size = 95467, upload-time = "2025-12-23T11:36:34.994Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/9b/f7/4a5e785ec9fbd65146a27b6b70b6cdc161a66f2024e4b04ac06a67f5578b/mistune-3.2.0-py3-none-any.whl", hash = "sha256:febdc629a3c78616b94393c6580551e0e34cc289987ec6c35ed3f4be42d0eee1", size = 53598, upload-time = "2025-12-23T11:36:33.211Z" }, +] + +[[package]] +name = "mypy-extensions" +version = "1.1.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/a2/6e/371856a3fb9d31ca8dac321cda606860fa4548858c0cc45d9d1d4ca2628b/mypy_extensions-1.1.0.tar.gz", hash = "sha256:52e68efc3284861e772bbcd66823fde5ae21fd2fdb51c62a211403730b916558", size = 6343, upload-time = "2025-04-22T14:54:24.164Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/79/7b/2c79738432f5c924bef5071f933bcc9efd0473bac3b4aa584a6f7c1c8df8/mypy_extensions-1.1.0-py3-none-any.whl", hash = "sha256:1be4cccdb0f2482337c4743e60421de3a356cd97508abadd57d47403e94f5505", size = 4963, upload-time = "2025-04-22T14:54:22.983Z" }, +] + +[[package]] +name = "nbclient" +version = "0.10.4" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "jupyter-client" }, + { name = "jupyter-core" }, + { name = "nbformat" }, + { name = "traitlets" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/56/91/1c1d5a4b9a9ebba2b4e32b8c852c2975c872aec1fe42ab5e516b2cecd193/nbclient-0.10.4.tar.gz", hash = "sha256:1e54091b16e6da39e297b0ece3e10f6f29f4ac4e8ee515d29f8a7099bd6553c9", size = 62554, upload-time = "2025-12-23T07:45:46.369Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/83/a0/5b0c2f11142ed1dddec842457d3f65eaf71a0080894eb6f018755b319c3a/nbclient-0.10.4-py3-none-any.whl", hash = "sha256:9162df5a7373d70d606527300a95a975a47c137776cd942e52d9c7e29ff83440", size = 25465, upload-time = "2025-12-23T07:45:44.51Z" }, +] + +[[package]] +name = "nbconvert" +version = "7.17.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "beautifulsoup4" }, + { name = "bleach", extra = ["css"] }, + { name = "defusedxml" }, + { name = "jinja2" }, + { name = "jupyter-core" }, + { name = "jupyterlab-pygments" }, + { name = "markupsafe" }, + { name = "mistune" }, + { name = "nbclient" }, + { name = "nbformat" }, + { name = "packaging" }, + { name = "pandocfilters" }, + { name = "pygments" }, + { name = "traitlets" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/38/47/81f886b699450d0569f7bc551df2b1673d18df7ff25cc0c21ca36ed8a5ff/nbconvert-7.17.0.tar.gz", hash = "sha256:1b2696f1b5be12309f6c7d707c24af604b87dfaf6d950794c7b07acab96dda78", size = 862855, upload-time = "2026-01-29T16:37:48.478Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/0d/4b/8d5f796a792f8a25f6925a96032f098789f448571eb92011df1ae59e8ea8/nbconvert-7.17.0-py3-none-any.whl", hash = "sha256:4f99a63b337b9a23504347afdab24a11faa7d86b405e5c8f9881cd313336d518", size = 261510, upload-time = "2026-01-29T16:37:46.322Z" }, +] + +[[package]] +name = "nbformat" +version = "5.10.4" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "fastjsonschema" }, + { name = "jsonschema" }, + { name = "jupyter-core" }, + { name = "traitlets" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/6d/fd/91545e604bc3dad7dca9ed03284086039b294c6b3d75c0d2fa45f9e9caf3/nbformat-5.10.4.tar.gz", hash = "sha256:322168b14f937a5d11362988ecac2a4952d3d8e3a2cbeb2319584631226d5b3a", size = 142749, upload-time = "2024-04-04T11:20:37.371Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/a9/82/0340caa499416c78e5d8f5f05947ae4bc3cba53c9f038ab6e9ed964e22f1/nbformat-5.10.4-py3-none-any.whl", hash = "sha256:3b48d6c8fbca4b299bf3982ea7db1af21580e4fec269ad087b9e81588891200b", size = 78454, upload-time = "2024-04-04T11:20:34.895Z" }, +] + +[[package]] +name = "nest-asyncio" +version = "1.6.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/83/f8/51569ac65d696c8ecbee95938f89d4abf00f47d58d48f6fbabfe8f0baefe/nest_asyncio-1.6.0.tar.gz", hash = "sha256:6f172d5449aca15afd6c646851f4e31e02c598d553a667e38cafa997cfec55fe", size = 7418, upload-time = "2024-01-21T14:25:19.227Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/a0/c4/c2971a3ba4c6103a3d10c4b0f24f461ddc027f0f09763220cf35ca1401b3/nest_asyncio-1.6.0-py3-none-any.whl", hash = "sha256:87af6efd6b5e897c81050477ef65c62e2b2f35d51703cae01aff2905b1852e1c", size = 5195, upload-time = "2024-01-21T14:25:17.223Z" }, +] + +[[package]] +name = "nodeenv" +version = "1.10.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/24/bf/d1bda4f6168e0b2e9e5958945e01910052158313224ada5ce1fb2e1113b8/nodeenv-1.10.0.tar.gz", hash = "sha256:996c191ad80897d076bdfba80a41994c2b47c68e224c542b48feba42ba00f8bb", size = 55611, upload-time = "2025-12-20T14:08:54.006Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/88/b2/d0896bdcdc8d28a7fc5717c305f1a861c26e18c05047949fb371034d98bd/nodeenv-1.10.0-py2.py3-none-any.whl", hash = "sha256:5bb13e3eed2923615535339b3c620e76779af4cb4c6a90deccc9e36b274d3827", size = 23438, upload-time = "2025-12-20T14:08:52.782Z" }, +] + +[[package]] +name = "notebook" +version = "7.5.3" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "jupyter-server" }, + { name = "jupyterlab" }, + { name = "jupyterlab-server" }, + { name = "notebook-shim" }, + { name = "tornado" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/b8/cb/cc7f4df5cee315dd126a47eb60890690a0438d5e0dd40c32d60ce16de377/notebook-7.5.3.tar.gz", hash = "sha256:393ceb269cf9fdb02a3be607a57d7bd5c2c14604f1818a17dbeb38e04f98cbfa", size = 14073140, upload-time = "2026-01-26T07:28:36.605Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/96/98/9286e7f35e5584ebb79f997f2fb0cb66745c86f6c5fccf15ba32aac5e908/notebook-7.5.3-py3-none-any.whl", hash = "sha256:c997bfa1a2a9eb58c9bbb7e77d50428befb1033dd6f02c482922e96851d67354", size = 14481744, upload-time = "2026-01-26T07:28:31.867Z" }, +] + +[[package]] +name = "notebook-shim" +version = "0.2.4" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "jupyter-server" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/54/d2/92fa3243712b9a3e8bafaf60aac366da1cada3639ca767ff4b5b3654ec28/notebook_shim-0.2.4.tar.gz", hash = "sha256:b4b2cfa1b65d98307ca24361f5b30fe785b53c3fd07b7a47e89acb5e6ac638cb", size = 13167, upload-time = "2024-02-14T23:35:18.353Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/f9/33/bd5b9137445ea4b680023eb0469b2bb969d61303dedb2aac6560ff3d14a1/notebook_shim-0.2.4-py3-none-any.whl", hash = "sha256:411a5be4e9dc882a074ccbcae671eda64cceb068767e9a3419096986560e1cef", size = 13307, upload-time = "2024-02-14T23:35:16.286Z" }, +] + +[[package]] +name = "overrides" +version = "7.7.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/36/86/b585f53236dec60aba864e050778b25045f857e17f6e5ea0ae95fe80edd2/overrides-7.7.0.tar.gz", hash = "sha256:55158fa3d93b98cc75299b1e67078ad9003ca27945c76162c1c0766d6f91820a", size = 22812, upload-time = "2024-01-27T21:01:33.423Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/2c/ab/fc8290c6a4c722e5514d80f62b2dc4c4df1a68a41d1364e625c35990fcf3/overrides-7.7.0-py3-none-any.whl", hash = "sha256:c7ed9d062f78b8e4c1a7b70bd8796b35ead4d9f510227ef9c5dc7626c60d7e49", size = 17832, upload-time = "2024-01-27T21:01:31.393Z" }, +] + +[[package]] +name = "packaging" +version = "26.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/65/ee/299d360cdc32edc7d2cf530f3accf79c4fca01e96ffc950d8a52213bd8e4/packaging-26.0.tar.gz", hash = "sha256:00243ae351a257117b6a241061796684b084ed1c516a08c48a3f7e147a9d80b4", size = 143416, upload-time = "2026-01-21T20:50:39.064Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/b7/b9/c538f279a4e237a006a2c98387d081e9eb060d203d8ed34467cc0f0b9b53/packaging-26.0-py3-none-any.whl", hash = "sha256:b36f1fef9334a5588b4166f8bcd26a14e521f2b55e6b9de3aaa80d3ff7a37529", size = 74366, upload-time = "2026-01-21T20:50:37.788Z" }, +] + +[[package]] +name = "pandocfilters" +version = "1.5.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/70/6f/3dd4940bbe001c06a65f88e36bad298bc7a0de5036115639926b0c5c0458/pandocfilters-1.5.1.tar.gz", hash = "sha256:002b4a555ee4ebc03f8b66307e287fa492e4a77b4ea14d3f934328297bb4939e", size = 8454, upload-time = "2024-01-18T20:08:13.726Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/ef/af/4fbc8cab944db5d21b7e2a5b8e9211a03a79852b1157e2c102fcc61ac440/pandocfilters-1.5.1-py2.py3-none-any.whl", hash = "sha256:93be382804a9cdb0a7267585f157e5d1731bbe5545a85b268d6f5fe6232de2bc", size = 8663, upload-time = "2024-01-18T20:08:11.28Z" }, +] + +[[package]] +name = "parso" +version = "0.8.5" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/d4/de/53e0bcf53d13e005bd8c92e7855142494f41171b34c2536b86187474184d/parso-0.8.5.tar.gz", hash = "sha256:034d7354a9a018bdce352f48b2a8a450f05e9d6ee85db84764e9b6bd96dafe5a", size = 401205, upload-time = "2025-08-23T15:15:28.028Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/16/32/f8e3c85d1d5250232a5d3477a2a28cc291968ff175caeadaf3cc19ce0e4a/parso-0.8.5-py2.py3-none-any.whl", hash = "sha256:646204b5ee239c396d040b90f9e272e9a8017c630092bf59980beb62fd033887", size = 106668, upload-time = "2025-08-23T15:15:25.663Z" }, +] + +[[package]] +name = "pathspec" +version = "1.0.4" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/fa/36/e27608899f9b8d4dff0617b2d9ab17ca5608956ca44461ac14ac48b44015/pathspec-1.0.4.tar.gz", hash = "sha256:0210e2ae8a21a9137c0d470578cb0e595af87edaa6ebf12ff176f14a02e0e645", size = 131200, upload-time = "2026-01-27T03:59:46.938Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/ef/3c/2c197d226f9ea224a9ab8d197933f9da0ae0aac5b6e0f884e2b8d9c8e9f7/pathspec-1.0.4-py3-none-any.whl", hash = "sha256:fb6ae2fd4e7c921a165808a552060e722767cfa526f99ca5156ed2ce45a5c723", size = 55206, upload-time = "2026-01-27T03:59:45.137Z" }, +] + +[[package]] +name = "pexpect" +version = "4.9.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "ptyprocess" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/42/92/cc564bf6381ff43ce1f4d06852fc19a2f11d180f23dc32d9588bee2f149d/pexpect-4.9.0.tar.gz", hash = "sha256:ee7d41123f3c9911050ea2c2dac107568dc43b2d3b0c7557a33212c398ead30f", size = 166450, upload-time = "2023-11-25T09:07:26.339Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/9e/c3/059298687310d527a58bb01f3b1965787ee3b40dce76752eda8b44e9a2c5/pexpect-4.9.0-py2.py3-none-any.whl", hash = "sha256:7236d1e080e4936be2dc3e326cec0af72acf9212a7e1d060210e70a47e253523", size = 63772, upload-time = "2023-11-25T06:56:14.81Z" }, +] + +[[package]] +name = "platformdirs" +version = "4.5.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/cf/86/0248f086a84f01b37aaec0fa567b397df1a119f73c16f6c7a9aac73ea309/platformdirs-4.5.1.tar.gz", hash = "sha256:61d5cdcc6065745cdd94f0f878977f8de9437be93de97c1c12f853c9c0cdcbda", size = 21715, upload-time = "2025-12-05T13:52:58.638Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/cb/28/3bfe2fa5a7b9c46fe7e13c97bda14c895fb10fa2ebf1d0abb90e0cea7ee1/platformdirs-4.5.1-py3-none-any.whl", hash = "sha256:d03afa3963c806a9bed9d5125c8f4cb2fdaf74a55ab60e5d59b3fde758104d31", size = 18731, upload-time = "2025-12-05T13:52:56.823Z" }, +] + +[[package]] +name = "pluggy" +version = "1.6.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/f9/e2/3e91f31a7d2b083fe6ef3fa267035b518369d9511ffab804f839851d2779/pluggy-1.6.0.tar.gz", hash = "sha256:7dcc130b76258d33b90f61b658791dede3486c3e6bfb003ee5c9bfb396dd22f3", size = 69412, upload-time = "2025-05-15T12:30:07.975Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl", hash = "sha256:e920276dd6813095e9377c0bc5566d94c932c33b27a3e3945d8389c374dd4746", size = 20538, upload-time = "2025-05-15T12:30:06.134Z" }, +] + +[[package]] +name = "plum-dispatch" +version = "2.6.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "beartype" }, + { name = "rich" }, + { name = "typing-extensions" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/a8/df/36f6677eff00a853c6a7d365316920ea411aa8015cf218612871082e25e7/plum_dispatch-2.6.1.tar.gz", hash = "sha256:05d14f31bf2ac8550d7742426d5c5a3fa532d8ed7cc12ffd695c4b452cffbdfa", size = 34952, upload-time = "2025-12-18T11:56:54.862Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/42/88/71fa06eb487ed9d4fab0ad173300b7a58706385f98fb66b1ccdc3ec3d4dd/plum_dispatch-2.6.1-py3-none-any.whl", hash = "sha256:49cd83027498e35eac32c7a93ecd6a99970d72d90f4141cc93be760c7ba831c4", size = 41456, upload-time = "2025-12-18T11:56:53.599Z" }, +] + +[[package]] +name = "prometheus-client" +version = "0.24.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/f0/58/a794d23feb6b00fc0c72787d7e87d872a6730dd9ed7c7b3e954637d8f280/prometheus_client-0.24.1.tar.gz", hash = "sha256:7e0ced7fbbd40f7b84962d5d2ab6f17ef88a72504dcf7c0b40737b43b2a461f9", size = 85616, upload-time = "2026-01-14T15:26:26.965Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/74/c3/24a2f845e3917201628ecaba4f18bab4d18a337834c1df2a159ee9d22a42/prometheus_client-0.24.1-py3-none-any.whl", hash = "sha256:150db128af71a5c2482b36e588fc8a6b95e498750da4b17065947c16070f4055", size = 64057, upload-time = "2026-01-14T15:26:24.42Z" }, +] + +[[package]] +name = "prompt-toolkit" +version = "3.0.52" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "wcwidth" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/a1/96/06e01a7b38dce6fe1db213e061a4602dd6032a8a97ef6c1a862537732421/prompt_toolkit-3.0.52.tar.gz", hash = "sha256:28cde192929c8e7321de85de1ddbe736f1375148b02f2e17edd840042b1be855", size = 434198, upload-time = "2025-08-27T15:24:02.057Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/84/03/0d3ce49e2505ae70cf43bc5bb3033955d2fc9f932163e84dc0779cc47f48/prompt_toolkit-3.0.52-py3-none-any.whl", hash = "sha256:9aac639a3bbd33284347de5ad8d68ecc044b91a762dc39b7c21095fcd6a19955", size = 391431, upload-time = "2025-08-27T15:23:59.498Z" }, +] + +[[package]] +name = "psutil" +version = "7.2.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/aa/c6/d1ddf4abb55e93cebc4f2ed8b5d6dbad109ecb8d63748dd2b20ab5e57ebe/psutil-7.2.2.tar.gz", hash = "sha256:0746f5f8d406af344fd547f1c8daa5f5c33dbc293bb8d6a16d80b4bb88f59372", size = 493740, upload-time = "2026-01-28T18:14:54.428Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/e7/36/5ee6e05c9bd427237b11b3937ad82bb8ad2752d72c6969314590dd0c2f6e/psutil-7.2.2-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:ed0cace939114f62738d808fdcecd4c869222507e266e574799e9c0faa17d486", size = 129090, upload-time = "2026-01-28T18:15:22.168Z" }, + { url = "https://files.pythonhosted.org/packages/80/c4/f5af4c1ca8c1eeb2e92ccca14ce8effdeec651d5ab6053c589b074eda6e1/psutil-7.2.2-cp36-abi3-macosx_11_0_arm64.whl", hash = "sha256:1a7b04c10f32cc88ab39cbf606e117fd74721c831c98a27dc04578deb0c16979", size = 129859, upload-time = "2026-01-28T18:15:23.795Z" }, + { url = "https://files.pythonhosted.org/packages/b5/70/5d8df3b09e25bce090399cf48e452d25c935ab72dad19406c77f4e828045/psutil-7.2.2-cp36-abi3-manylinux2010_x86_64.manylinux_2_12_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:076a2d2f923fd4821644f5ba89f059523da90dc9014e85f8e45a5774ca5bc6f9", size = 155560, upload-time = "2026-01-28T18:15:25.976Z" }, + { url = "https://files.pythonhosted.org/packages/63/65/37648c0c158dc222aba51c089eb3bdfa238e621674dc42d48706e639204f/psutil-7.2.2-cp36-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:b0726cecd84f9474419d67252add4ac0cd9811b04d61123054b9fb6f57df6e9e", size = 156997, upload-time = "2026-01-28T18:15:27.794Z" }, + { url = "https://files.pythonhosted.org/packages/8e/13/125093eadae863ce03c6ffdbae9929430d116a246ef69866dad94da3bfbc/psutil-7.2.2-cp36-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:fd04ef36b4a6d599bbdb225dd1d3f51e00105f6d48a28f006da7f9822f2606d8", size = 148972, upload-time = "2026-01-28T18:15:29.342Z" }, + { url = "https://files.pythonhosted.org/packages/04/78/0acd37ca84ce3ddffaa92ef0f571e073faa6d8ff1f0559ab1272188ea2be/psutil-7.2.2-cp36-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:b58fabe35e80b264a4e3bb23e6b96f9e45a3df7fb7eed419ac0e5947c61e47cc", size = 148266, upload-time = "2026-01-28T18:15:31.597Z" }, + { url = "https://files.pythonhosted.org/packages/b4/90/e2159492b5426be0c1fef7acba807a03511f97c5f86b3caeda6ad92351a7/psutil-7.2.2-cp37-abi3-win_amd64.whl", hash = "sha256:eb7e81434c8d223ec4a219b5fc1c47d0417b12be7ea866e24fb5ad6e84b3d988", size = 137737, upload-time = "2026-01-28T18:15:33.849Z" }, + { url = "https://files.pythonhosted.org/packages/8c/c7/7bb2e321574b10df20cbde462a94e2b71d05f9bbda251ef27d104668306a/psutil-7.2.2-cp37-abi3-win_arm64.whl", hash = "sha256:8c233660f575a5a89e6d4cb65d9f938126312bca76d8fe087b947b3a1aaac9ee", size = 134617, upload-time = "2026-01-28T18:15:36.514Z" }, +] + +[[package]] +name = "ptyprocess" +version = "0.7.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/20/e5/16ff212c1e452235a90aeb09066144d0c5a6a8c0834397e03f5224495c4e/ptyprocess-0.7.0.tar.gz", hash = "sha256:5c5d0a3b48ceee0b48485e0c26037c0acd7d29765ca3fbb5cb3831d347423220", size = 70762, upload-time = "2020-12-28T15:15:30.155Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/22/a6/858897256d0deac81a172289110f31629fc4cee19b6f01283303e18c8db3/ptyprocess-0.7.0-py2.py3-none-any.whl", hash = "sha256:4b41f3967fce3af57cc7e94b888626c18bf37a083e3651ca8feeb66d492fef35", size = 13993, upload-time = "2020-12-28T15:15:28.35Z" }, +] + +[[package]] +name = "pure-eval" +version = "0.2.3" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/cd/05/0a34433a064256a578f1783a10da6df098ceaa4a57bbeaa96a6c0352786b/pure_eval-0.2.3.tar.gz", hash = "sha256:5f4e983f40564c576c7c8635ae88db5956bb2229d7e9237d03b3c0b0190eaf42", size = 19752, upload-time = "2024-07-21T12:58:21.801Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/8e/37/efad0257dc6e593a18957422533ff0f87ede7c9c6ea010a2177d738fb82f/pure_eval-0.2.3-py3-none-any.whl", hash = "sha256:1db8e35b67b3d218d818ae653e27f06c3aa420901fa7b081ca98cbedc874e0d0", size = 11842, upload-time = "2024-07-21T12:58:20.04Z" }, +] + +[[package]] +name = "pycparser" +version = "3.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/1b/7d/92392ff7815c21062bea51aa7b87d45576f649f16458d78b7cf94b9ab2e6/pycparser-3.0.tar.gz", hash = "sha256:600f49d217304a5902ac3c37e1281c9fe94e4d0489de643a9504c5cdfdfc6b29", size = 103492, upload-time = "2026-01-21T14:26:51.89Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/0c/c3/44f3fbbfa403ea2a7c779186dc20772604442dde72947e7d01069cbe98e3/pycparser-3.0-py3-none-any.whl", hash = "sha256:b727414169a36b7d524c1c3e31839a521725078d7b2ff038656844266160a992", size = 48172, upload-time = "2026-01-21T14:26:50.693Z" }, +] + +[[package]] +name = "pydantic" +version = "2.12.5" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "annotated-types" }, + { name = "pydantic-core" }, + { name = "typing-extensions" }, + { name = "typing-inspection" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/69/44/36f1a6e523abc58ae5f928898e4aca2e0ea509b5aa6f6f392a5d882be928/pydantic-2.12.5.tar.gz", hash = "sha256:4d351024c75c0f085a9febbb665ce8c0c6ec5d30e903bdb6394b7ede26aebb49", size = 821591, upload-time = "2025-11-26T15:11:46.471Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/5a/87/b70ad306ebb6f9b585f114d0ac2137d792b48be34d732d60e597c2f8465a/pydantic-2.12.5-py3-none-any.whl", hash = "sha256:e561593fccf61e8a20fc46dfc2dfe075b8be7d0188df33f221ad1f0139180f9d", size = 463580, upload-time = "2025-11-26T15:11:44.605Z" }, +] + +[[package]] +name = "pydantic-core" +version = "2.41.5" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "typing-extensions" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/71/70/23b021c950c2addd24ec408e9ab05d59b035b39d97cdc1130e1bce647bb6/pydantic_core-2.41.5.tar.gz", hash = "sha256:08daa51ea16ad373ffd5e7606252cc32f07bc72b28284b6bc9c6df804816476e", size = 460952, upload-time = "2025-11-04T13:43:49.098Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/e8/72/74a989dd9f2084b3d9530b0915fdda64ac48831c30dbf7c72a41a5232db8/pydantic_core-2.41.5-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:a3a52f6156e73e7ccb0f8cced536adccb7042be67cb45f9562e12b319c119da6", size = 2105873, upload-time = "2025-11-04T13:39:31.373Z" }, + { url = "https://files.pythonhosted.org/packages/12/44/37e403fd9455708b3b942949e1d7febc02167662bf1a7da5b78ee1ea2842/pydantic_core-2.41.5-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:7f3bf998340c6d4b0c9a2f02d6a400e51f123b59565d74dc60d252ce888c260b", size = 1899826, upload-time = "2025-11-04T13:39:32.897Z" }, + { url = "https://files.pythonhosted.org/packages/33/7f/1d5cab3ccf44c1935a359d51a8a2a9e1a654b744b5e7f80d41b88d501eec/pydantic_core-2.41.5-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:378bec5c66998815d224c9ca994f1e14c0c21cb95d2f52b6021cc0b2a58f2a5a", size = 1917869, upload-time = "2025-11-04T13:39:34.469Z" }, + { url = "https://files.pythonhosted.org/packages/6e/6a/30d94a9674a7fe4f4744052ed6c5e083424510be1e93da5bc47569d11810/pydantic_core-2.41.5-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:e7b576130c69225432866fe2f4a469a85a54ade141d96fd396dffcf607b558f8", size = 2063890, upload-time = "2025-11-04T13:39:36.053Z" }, + { url = "https://files.pythonhosted.org/packages/50/be/76e5d46203fcb2750e542f32e6c371ffa9b8ad17364cf94bb0818dbfb50c/pydantic_core-2.41.5-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:6cb58b9c66f7e4179a2d5e0f849c48eff5c1fca560994d6eb6543abf955a149e", size = 2229740, upload-time = "2025-11-04T13:39:37.753Z" }, + { url = "https://files.pythonhosted.org/packages/d3/ee/fed784df0144793489f87db310a6bbf8118d7b630ed07aa180d6067e653a/pydantic_core-2.41.5-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:88942d3a3dff3afc8288c21e565e476fc278902ae4d6d134f1eeda118cc830b1", size = 2350021, upload-time = "2025-11-04T13:39:40.94Z" }, + { url = "https://files.pythonhosted.org/packages/c8/be/8fed28dd0a180dca19e72c233cbf58efa36df055e5b9d90d64fd1740b828/pydantic_core-2.41.5-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f31d95a179f8d64d90f6831d71fa93290893a33148d890ba15de25642c5d075b", size = 2066378, upload-time = "2025-11-04T13:39:42.523Z" }, + { url = "https://files.pythonhosted.org/packages/b0/3b/698cf8ae1d536a010e05121b4958b1257f0b5522085e335360e53a6b1c8b/pydantic_core-2.41.5-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:c1df3d34aced70add6f867a8cf413e299177e0c22660cc767218373d0779487b", size = 2175761, upload-time = "2025-11-04T13:39:44.553Z" }, + { url = "https://files.pythonhosted.org/packages/b8/ba/15d537423939553116dea94ce02f9c31be0fa9d0b806d427e0308ec17145/pydantic_core-2.41.5-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:4009935984bd36bd2c774e13f9a09563ce8de4abaa7226f5108262fa3e637284", size = 2146303, upload-time = "2025-11-04T13:39:46.238Z" }, + { url = "https://files.pythonhosted.org/packages/58/7f/0de669bf37d206723795f9c90c82966726a2ab06c336deba4735b55af431/pydantic_core-2.41.5-cp311-cp311-musllinux_1_1_armv7l.whl", hash = "sha256:34a64bc3441dc1213096a20fe27e8e128bd3ff89921706e83c0b1ac971276594", size = 2340355, upload-time = "2025-11-04T13:39:48.002Z" }, + { url = "https://files.pythonhosted.org/packages/e5/de/e7482c435b83d7e3c3ee5ee4451f6e8973cff0eb6007d2872ce6383f6398/pydantic_core-2.41.5-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:c9e19dd6e28fdcaa5a1de679aec4141f691023916427ef9bae8584f9c2fb3b0e", size = 2319875, upload-time = "2025-11-04T13:39:49.705Z" }, + { url = "https://files.pythonhosted.org/packages/fe/e6/8c9e81bb6dd7560e33b9053351c29f30c8194b72f2d6932888581f503482/pydantic_core-2.41.5-cp311-cp311-win32.whl", hash = "sha256:2c010c6ded393148374c0f6f0bf89d206bf3217f201faa0635dcd56bd1520f6b", size = 1987549, upload-time = "2025-11-04T13:39:51.842Z" }, + { url = "https://files.pythonhosted.org/packages/11/66/f14d1d978ea94d1bc21fc98fcf570f9542fe55bfcc40269d4e1a21c19bf7/pydantic_core-2.41.5-cp311-cp311-win_amd64.whl", hash = "sha256:76ee27c6e9c7f16f47db7a94157112a2f3a00e958bc626e2f4ee8bec5c328fbe", size = 2011305, upload-time = "2025-11-04T13:39:53.485Z" }, + { url = "https://files.pythonhosted.org/packages/56/d8/0e271434e8efd03186c5386671328154ee349ff0354d83c74f5caaf096ed/pydantic_core-2.41.5-cp311-cp311-win_arm64.whl", hash = "sha256:4bc36bbc0b7584de96561184ad7f012478987882ebf9f9c389b23f432ea3d90f", size = 1972902, upload-time = "2025-11-04T13:39:56.488Z" }, + { url = "https://files.pythonhosted.org/packages/5f/5d/5f6c63eebb5afee93bcaae4ce9a898f3373ca23df3ccaef086d0233a35a7/pydantic_core-2.41.5-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:f41a7489d32336dbf2199c8c0a215390a751c5b014c2c1c5366e817202e9cdf7", size = 2110990, upload-time = "2025-11-04T13:39:58.079Z" }, + { url = "https://files.pythonhosted.org/packages/aa/32/9c2e8ccb57c01111e0fd091f236c7b371c1bccea0fa85247ac55b1e2b6b6/pydantic_core-2.41.5-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:070259a8818988b9a84a449a2a7337c7f430a22acc0859c6b110aa7212a6d9c0", size = 1896003, upload-time = "2025-11-04T13:39:59.956Z" }, + { url = "https://files.pythonhosted.org/packages/68/b8/a01b53cb0e59139fbc9e4fda3e9724ede8de279097179be4ff31f1abb65a/pydantic_core-2.41.5-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e96cea19e34778f8d59fe40775a7a574d95816eb150850a85a7a4c8f4b94ac69", size = 1919200, upload-time = "2025-11-04T13:40:02.241Z" }, + { url = "https://files.pythonhosted.org/packages/38/de/8c36b5198a29bdaade07b5985e80a233a5ac27137846f3bc2d3b40a47360/pydantic_core-2.41.5-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:ed2e99c456e3fadd05c991f8f437ef902e00eedf34320ba2b0842bd1c3ca3a75", size = 2052578, upload-time = "2025-11-04T13:40:04.401Z" }, + { url = "https://files.pythonhosted.org/packages/00/b5/0e8e4b5b081eac6cb3dbb7e60a65907549a1ce035a724368c330112adfdd/pydantic_core-2.41.5-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:65840751b72fbfd82c3c640cff9284545342a4f1eb1586ad0636955b261b0b05", size = 2208504, upload-time = "2025-11-04T13:40:06.072Z" }, + { url = "https://files.pythonhosted.org/packages/77/56/87a61aad59c7c5b9dc8caad5a41a5545cba3810c3e828708b3d7404f6cef/pydantic_core-2.41.5-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e536c98a7626a98feb2d3eaf75944ef6f3dbee447e1f841eae16f2f0a72d8ddc", size = 2335816, upload-time = "2025-11-04T13:40:07.835Z" }, + { url = "https://files.pythonhosted.org/packages/0d/76/941cc9f73529988688a665a5c0ecff1112b3d95ab48f81db5f7606f522d3/pydantic_core-2.41.5-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:eceb81a8d74f9267ef4081e246ffd6d129da5d87e37a77c9bde550cb04870c1c", size = 2075366, upload-time = "2025-11-04T13:40:09.804Z" }, + { url = "https://files.pythonhosted.org/packages/d3/43/ebef01f69baa07a482844faaa0a591bad1ef129253ffd0cdaa9d8a7f72d3/pydantic_core-2.41.5-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:d38548150c39b74aeeb0ce8ee1d8e82696f4a4e16ddc6de7b1d8823f7de4b9b5", size = 2171698, upload-time = "2025-11-04T13:40:12.004Z" }, + { url = "https://files.pythonhosted.org/packages/b1/87/41f3202e4193e3bacfc2c065fab7706ebe81af46a83d3e27605029c1f5a6/pydantic_core-2.41.5-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:c23e27686783f60290e36827f9c626e63154b82b116d7fe9adba1fda36da706c", size = 2132603, upload-time = "2025-11-04T13:40:13.868Z" }, + { url = "https://files.pythonhosted.org/packages/49/7d/4c00df99cb12070b6bccdef4a195255e6020a550d572768d92cc54dba91a/pydantic_core-2.41.5-cp312-cp312-musllinux_1_1_armv7l.whl", hash = "sha256:482c982f814460eabe1d3bb0adfdc583387bd4691ef00b90575ca0d2b6fe2294", size = 2329591, upload-time = "2025-11-04T13:40:15.672Z" }, + { url = "https://files.pythonhosted.org/packages/cc/6a/ebf4b1d65d458f3cda6a7335d141305dfa19bdc61140a884d165a8a1bbc7/pydantic_core-2.41.5-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:bfea2a5f0b4d8d43adf9d7b8bf019fb46fdd10a2e5cde477fbcb9d1fa08c68e1", size = 2319068, upload-time = "2025-11-04T13:40:17.532Z" }, + { url = "https://files.pythonhosted.org/packages/49/3b/774f2b5cd4192d5ab75870ce4381fd89cf218af999515baf07e7206753f0/pydantic_core-2.41.5-cp312-cp312-win32.whl", hash = "sha256:b74557b16e390ec12dca509bce9264c3bbd128f8a2c376eaa68003d7f327276d", size = 1985908, upload-time = "2025-11-04T13:40:19.309Z" }, + { url = "https://files.pythonhosted.org/packages/86/45/00173a033c801cacf67c190fef088789394feaf88a98a7035b0e40d53dc9/pydantic_core-2.41.5-cp312-cp312-win_amd64.whl", hash = "sha256:1962293292865bca8e54702b08a4f26da73adc83dd1fcf26fbc875b35d81c815", size = 2020145, upload-time = "2025-11-04T13:40:21.548Z" }, + { url = "https://files.pythonhosted.org/packages/f9/22/91fbc821fa6d261b376a3f73809f907cec5ca6025642c463d3488aad22fb/pydantic_core-2.41.5-cp312-cp312-win_arm64.whl", hash = "sha256:1746d4a3d9a794cacae06a5eaaccb4b8643a131d45fbc9af23e353dc0a5ba5c3", size = 1976179, upload-time = "2025-11-04T13:40:23.393Z" }, + { url = "https://files.pythonhosted.org/packages/11/72/90fda5ee3b97e51c494938a4a44c3a35a9c96c19bba12372fb9c634d6f57/pydantic_core-2.41.5-graalpy311-graalpy242_311_native-macosx_10_12_x86_64.whl", hash = "sha256:b96d5f26b05d03cc60f11a7761a5ded1741da411e7fe0909e27a5e6a0cb7b034", size = 2115441, upload-time = "2025-11-04T13:42:39.557Z" }, + { url = "https://files.pythonhosted.org/packages/1f/53/8942f884fa33f50794f119012dc6a1a02ac43a56407adaac20463df8e98f/pydantic_core-2.41.5-graalpy311-graalpy242_311_native-macosx_11_0_arm64.whl", hash = "sha256:634e8609e89ceecea15e2d61bc9ac3718caaaa71963717bf3c8f38bfde64242c", size = 1930291, upload-time = "2025-11-04T13:42:42.169Z" }, + { url = "https://files.pythonhosted.org/packages/79/c8/ecb9ed9cd942bce09fc888ee960b52654fbdbede4ba6c2d6e0d3b1d8b49c/pydantic_core-2.41.5-graalpy311-graalpy242_311_native-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:93e8740d7503eb008aa2df04d3b9735f845d43ae845e6dcd2be0b55a2da43cd2", size = 1948632, upload-time = "2025-11-04T13:42:44.564Z" }, + { url = "https://files.pythonhosted.org/packages/2e/1b/687711069de7efa6af934e74f601e2a4307365e8fdc404703afc453eab26/pydantic_core-2.41.5-graalpy311-graalpy242_311_native-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f15489ba13d61f670dcc96772e733aad1a6f9c429cc27574c6cdaed82d0146ad", size = 2138905, upload-time = "2025-11-04T13:42:47.156Z" }, + { url = "https://files.pythonhosted.org/packages/09/32/59b0c7e63e277fa7911c2fc70ccfb45ce4b98991e7ef37110663437005af/pydantic_core-2.41.5-graalpy312-graalpy250_312_native-macosx_10_12_x86_64.whl", hash = "sha256:7da7087d756b19037bc2c06edc6c170eeef3c3bafcb8f532ff17d64dc427adfd", size = 2110495, upload-time = "2025-11-04T13:42:49.689Z" }, + { url = "https://files.pythonhosted.org/packages/aa/81/05e400037eaf55ad400bcd318c05bb345b57e708887f07ddb2d20e3f0e98/pydantic_core-2.41.5-graalpy312-graalpy250_312_native-macosx_11_0_arm64.whl", hash = "sha256:aabf5777b5c8ca26f7824cb4a120a740c9588ed58df9b2d196ce92fba42ff8dc", size = 1915388, upload-time = "2025-11-04T13:42:52.215Z" }, + { url = "https://files.pythonhosted.org/packages/6e/0d/e3549b2399f71d56476b77dbf3cf8937cec5cd70536bdc0e374a421d0599/pydantic_core-2.41.5-graalpy312-graalpy250_312_native-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c007fe8a43d43b3969e8469004e9845944f1a80e6acd47c150856bb87f230c56", size = 1942879, upload-time = "2025-11-04T13:42:56.483Z" }, + { url = "https://files.pythonhosted.org/packages/f7/07/34573da085946b6a313d7c42f82f16e8920bfd730665de2d11c0c37a74b5/pydantic_core-2.41.5-graalpy312-graalpy250_312_native-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:76d0819de158cd855d1cbb8fcafdf6f5cf1eb8e470abe056d5d161106e38062b", size = 2139017, upload-time = "2025-11-04T13:42:59.471Z" }, + { url = "https://files.pythonhosted.org/packages/5f/9b/1b3f0e9f9305839d7e84912f9e8bfbd191ed1b1ef48083609f0dabde978c/pydantic_core-2.41.5-pp311-pypy311_pp73-macosx_10_12_x86_64.whl", hash = "sha256:b2379fa7ed44ddecb5bfe4e48577d752db9fc10be00a6b7446e9663ba143de26", size = 2101980, upload-time = "2025-11-04T13:43:25.97Z" }, + { url = "https://files.pythonhosted.org/packages/a4/ed/d71fefcb4263df0da6a85b5d8a7508360f2f2e9b3bf5814be9c8bccdccc1/pydantic_core-2.41.5-pp311-pypy311_pp73-macosx_11_0_arm64.whl", hash = "sha256:266fb4cbf5e3cbd0b53669a6d1b039c45e3ce651fd5442eff4d07c2cc8d66808", size = 1923865, upload-time = "2025-11-04T13:43:28.763Z" }, + { url = "https://files.pythonhosted.org/packages/ce/3a/626b38db460d675f873e4444b4bb030453bbe7b4ba55df821d026a0493c4/pydantic_core-2.41.5-pp311-pypy311_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:58133647260ea01e4d0500089a8c4f07bd7aa6ce109682b1426394988d8aaacc", size = 2134256, upload-time = "2025-11-04T13:43:31.71Z" }, + { url = "https://files.pythonhosted.org/packages/83/d9/8412d7f06f616bbc053d30cb4e5f76786af3221462ad5eee1f202021eb4e/pydantic_core-2.41.5-pp311-pypy311_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:287dad91cfb551c363dc62899a80e9e14da1f0e2b6ebde82c806612ca2a13ef1", size = 2174762, upload-time = "2025-11-04T13:43:34.744Z" }, + { url = "https://files.pythonhosted.org/packages/55/4c/162d906b8e3ba3a99354e20faa1b49a85206c47de97a639510a0e673f5da/pydantic_core-2.41.5-pp311-pypy311_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:03b77d184b9eb40240ae9fd676ca364ce1085f203e1b1256f8ab9984dca80a84", size = 2143141, upload-time = "2025-11-04T13:43:37.701Z" }, + { url = "https://files.pythonhosted.org/packages/1f/f2/f11dd73284122713f5f89fc940f370d035fa8e1e078d446b3313955157fe/pydantic_core-2.41.5-pp311-pypy311_pp73-musllinux_1_1_armv7l.whl", hash = "sha256:a668ce24de96165bb239160b3d854943128f4334822900534f2fe947930e5770", size = 2330317, upload-time = "2025-11-04T13:43:40.406Z" }, + { url = "https://files.pythonhosted.org/packages/88/9d/b06ca6acfe4abb296110fb1273a4d848a0bfb2ff65f3ee92127b3244e16b/pydantic_core-2.41.5-pp311-pypy311_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:f14f8f046c14563f8eb3f45f499cc658ab8d10072961e07225e507adb700e93f", size = 2316992, upload-time = "2025-11-04T13:43:43.602Z" }, + { url = "https://files.pythonhosted.org/packages/36/c7/cfc8e811f061c841d7990b0201912c3556bfeb99cdcb7ed24adc8d6f8704/pydantic_core-2.41.5-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:56121965f7a4dc965bff783d70b907ddf3d57f6eba29b6d2e5dabfaf07799c51", size = 2145302, upload-time = "2025-11-04T13:43:46.64Z" }, +] + +[[package]] +name = "pygments" +version = "2.19.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/b0/77/a5b8c569bf593b0140bde72ea885a803b82086995367bf2037de0159d924/pygments-2.19.2.tar.gz", hash = "sha256:636cb2477cec7f8952536970bc533bc43743542f70392ae026374600add5b887", size = 4968631, upload-time = "2025-06-21T13:39:12.283Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/c7/21/705964c7812476f378728bdf590ca4b771ec72385c533964653c68e86bdc/pygments-2.19.2-py3-none-any.whl", hash = "sha256:86540386c03d588bb81d44bc3928634ff26449851e99741617ecb9037ee5ec0b", size = 1225217, upload-time = "2025-06-21T13:39:07.939Z" }, +] + +[[package]] +name = "pyright" +version = "1.1.408" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "nodeenv" }, + { name = "typing-extensions" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/74/b2/5db700e52554b8f025faa9c3c624c59f1f6c8841ba81ab97641b54322f16/pyright-1.1.408.tar.gz", hash = "sha256:f28f2321f96852fa50b5829ea492f6adb0e6954568d1caa3f3af3a5f555eb684", size = 4400578, upload-time = "2026-01-08T08:07:38.795Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/0c/82/a2c93e32800940d9573fb28c346772a14778b84ba7524e691b324620ab89/pyright-1.1.408-py3-none-any.whl", hash = "sha256:090b32865f4fdb1e0e6cd82bf5618480d48eecd2eb2e70f960982a3d9a4c17c1", size = 6399144, upload-time = "2026-01-08T08:07:37.082Z" }, +] + +[[package]] +name = "pytest" +version = "9.0.2" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "colorama", marker = "sys_platform == 'win32'" }, + { name = "iniconfig" }, + { name = "packaging" }, + { name = "pluggy" }, + { name = "pygments" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/d1/db/7ef3487e0fb0049ddb5ce41d3a49c235bf9ad299b6a25d5780a89f19230f/pytest-9.0.2.tar.gz", hash = "sha256:75186651a92bd89611d1d9fc20f0b4345fd827c41ccd5c299a868a05d70edf11", size = 1568901, upload-time = "2025-12-06T21:30:51.014Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/3b/ab/b3226f0bd7cdcf710fbede2b3548584366da3b19b5021e74f5bde2a8fa3f/pytest-9.0.2-py3-none-any.whl", hash = "sha256:711ffd45bf766d5264d487b917733b453d917afd2b0ad65223959f59089f875b", size = 374801, upload-time = "2025-12-06T21:30:49.154Z" }, +] + +[[package]] +name = "pytest-cov" +version = "7.0.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "coverage", extra = ["toml"] }, + { name = "pluggy" }, + { name = "pytest" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/5e/f7/c933acc76f5208b3b00089573cf6a2bc26dc80a8aece8f52bb7d6b1855ca/pytest_cov-7.0.0.tar.gz", hash = "sha256:33c97eda2e049a0c5298e91f519302a1334c26ac65c1a483d6206fd458361af1", size = 54328, upload-time = "2025-09-09T10:57:02.113Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/ee/49/1377b49de7d0c1ce41292161ea0f721913fa8722c19fb9c1e3aa0367eecb/pytest_cov-7.0.0-py3-none-any.whl", hash = "sha256:3b8e9558b16cc1479da72058bdecf8073661c7f57f7d3c5f22a1c23507f2d861", size = 22424, upload-time = "2025-09-09T10:57:00.695Z" }, +] + +[[package]] +name = "python-dateutil" +version = "2.9.0.post0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "six" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/66/c0/0c8b6ad9f17a802ee498c46e004a0eb49bc148f2fd230864601a86dcf6db/python-dateutil-2.9.0.post0.tar.gz", hash = "sha256:37dd54208da7e1cd875388217d5e00ebd4179249f90fb72437e91a35459a0ad3", size = 342432, upload-time = "2024-03-01T18:36:20.211Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/ec/57/56b9bcc3c9c6a792fcbaf139543cee77261f3651ca9da0c93f5c1221264b/python_dateutil-2.9.0.post0-py2.py3-none-any.whl", hash = "sha256:a8b2bc7bffae282281c8140a97d3aa9c14da0b136dfe83f850eea9a5f7470427", size = 229892, upload-time = "2024-03-01T18:36:18.57Z" }, +] + +[[package]] +name = "python-json-logger" +version = "4.0.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/29/bf/eca6a3d43db1dae7070f70e160ab20b807627ba953663ba07928cdd3dc58/python_json_logger-4.0.0.tar.gz", hash = "sha256:f58e68eb46e1faed27e0f574a55a0455eecd7b8a5b88b85a784519ba3cff047f", size = 17683, upload-time = "2025-10-06T04:15:18.984Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/51/e5/fecf13f06e5e5f67e8837d777d1bc43fac0ed2b77a676804df5c34744727/python_json_logger-4.0.0-py3-none-any.whl", hash = "sha256:af09c9daf6a813aa4cc7180395f50f2a9e5fa056034c9953aec92e381c5ba1e2", size = 15548, upload-time = "2025-10-06T04:15:17.553Z" }, +] + +[[package]] +name = "python-nix-template" +version = "0.1.1" +source = { editable = "." } + +[package.dev-dependencies] +dev = [ + { name = "hypothesis" }, + { name = "ipython" }, + { name = "jupyter" }, + { name = "jupyter-cache" }, + { name = "pyright" }, + { name = "pytest" }, + { name = "pytest-cov" }, + { name = "quartodoc" }, + { name = "ruff" }, + { name = "xdoctest" }, +] +docs = [ + { name = "jupyter" }, + { name = "jupyter-cache" }, + { name = "quartodoc" }, +] +interactive = [ + { name = "ipython" }, +] +lint = [ + { name = "ruff" }, +] +test = [ + { name = "hypothesis" }, + { name = "pytest" }, + { name = "pytest-cov" }, + { name = "xdoctest" }, +] +types = [ + { name = "pyright" }, +] + +[package.metadata] + +[package.metadata.requires-dev] +dev = [ + { name = "hypothesis", specifier = ">=6.125.1" }, + { name = "ipython", specifier = ">=8.32.0" }, + { name = "jupyter", specifier = ">=1.1.1" }, + { name = "jupyter-cache", specifier = ">=1.0.1" }, + { name = "pyright", specifier = ">=1.1.395" }, + { name = "pytest", specifier = ">=8.3.4" }, + { name = "pytest-cov", specifier = ">=6.0.0" }, + { name = "quartodoc", specifier = ">=0.9.1" }, + { name = "ruff", specifier = ">=0.9.4" }, + { name = "xdoctest", specifier = ">=1.2.0" }, +] +docs = [ + { name = "jupyter", specifier = ">=1.1.1" }, + { name = "jupyter-cache", specifier = ">=1.0.1" }, + { name = "quartodoc", specifier = ">=0.9.1" }, +] +interactive = [{ name = "ipython", specifier = ">=8.32.0" }] +lint = [{ name = "ruff", specifier = ">=0.9.4" }] +test = [ + { name = "hypothesis", specifier = ">=6.125.1" }, + { name = "pytest", specifier = ">=8.3.4" }, + { name = "pytest-cov", specifier = ">=6.0.0" }, + { name = "xdoctest", specifier = ">=1.2.0" }, +] +types = [{ name = "pyright", specifier = ">=1.1.395" }] + +[[package]] +name = "pytokens" +version = "0.4.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/b6/34/b4e015b99031667a7b960f888889c5bd34ef585c85e1cb56a594b92836ac/pytokens-0.4.1.tar.gz", hash = "sha256:292052fe80923aae2260c073f822ceba21f3872ced9a68bb7953b348e561179a", size = 23015, upload-time = "2026-01-30T01:03:45.924Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/3d/92/790ebe03f07b57e53b10884c329b9a1a308648fc083a6d4a39a10a28c8fc/pytokens-0.4.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:d70e77c55ae8380c91c0c18dea05951482e263982911fc7410b1ffd1dadd3440", size = 160864, upload-time = "2026-01-30T01:02:57.882Z" }, + { url = "https://files.pythonhosted.org/packages/13/25/a4f555281d975bfdd1eba731450e2fe3a95870274da73fb12c40aeae7625/pytokens-0.4.1-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:4a58d057208cb9075c144950d789511220b07636dd2e4708d5645d24de666bdc", size = 248565, upload-time = "2026-01-30T01:02:59.912Z" }, + { url = "https://files.pythonhosted.org/packages/17/50/bc0394b4ad5b1601be22fa43652173d47e4c9efbf0044c62e9a59b747c56/pytokens-0.4.1-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:b49750419d300e2b5a3813cf229d4e5a4c728dae470bcc89867a9ad6f25a722d", size = 260824, upload-time = "2026-01-30T01:03:01.471Z" }, + { url = "https://files.pythonhosted.org/packages/4e/54/3e04f9d92a4be4fc6c80016bc396b923d2a6933ae94b5f557c939c460ee0/pytokens-0.4.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:d9907d61f15bf7261d7e775bd5d7ee4d2930e04424bab1972591918497623a16", size = 264075, upload-time = "2026-01-30T01:03:04.143Z" }, + { url = "https://files.pythonhosted.org/packages/d1/1b/44b0326cb5470a4375f37988aea5d61b5cc52407143303015ebee94abfd6/pytokens-0.4.1-cp311-cp311-win_amd64.whl", hash = "sha256:ee44d0f85b803321710f9239f335aafe16553b39106384cef8e6de40cb4ef2f6", size = 103323, upload-time = "2026-01-30T01:03:05.412Z" }, + { url = "https://files.pythonhosted.org/packages/41/5d/e44573011401fb82e9d51e97f1290ceb377800fb4eed650b96f4753b499c/pytokens-0.4.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:140709331e846b728475786df8aeb27d24f48cbcf7bcd449f8de75cae7a45083", size = 160663, upload-time = "2026-01-30T01:03:06.473Z" }, + { url = "https://files.pythonhosted.org/packages/f0/e6/5bbc3019f8e6f21d09c41f8b8654536117e5e211a85d89212d59cbdab381/pytokens-0.4.1-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6d6c4268598f762bc8e91f5dbf2ab2f61f7b95bdc07953b602db879b3c8c18e1", size = 255626, upload-time = "2026-01-30T01:03:08.177Z" }, + { url = "https://files.pythonhosted.org/packages/bf/3c/2d5297d82286f6f3d92770289fd439956b201c0a4fc7e72efb9b2293758e/pytokens-0.4.1-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:24afde1f53d95348b5a0eb19488661147285ca4dd7ed752bbc3e1c6242a304d1", size = 269779, upload-time = "2026-01-30T01:03:09.756Z" }, + { url = "https://files.pythonhosted.org/packages/20/01/7436e9ad693cebda0551203e0bf28f7669976c60ad07d6402098208476de/pytokens-0.4.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:5ad948d085ed6c16413eb5fec6b3e02fa00dc29a2534f088d3302c47eb59adf9", size = 268076, upload-time = "2026-01-30T01:03:10.957Z" }, + { url = "https://files.pythonhosted.org/packages/2e/df/533c82a3c752ba13ae7ef238b7f8cdd272cf1475f03c63ac6cf3fcfb00b6/pytokens-0.4.1-cp312-cp312-win_amd64.whl", hash = "sha256:3f901fe783e06e48e8cbdc82d631fca8f118333798193e026a50ce1b3757ea68", size = 103552, upload-time = "2026-01-30T01:03:12.066Z" }, + { url = "https://files.pythonhosted.org/packages/c6/78/397db326746f0a342855b81216ae1f0a32965deccfd7c830a2dbc66d2483/pytokens-0.4.1-py3-none-any.whl", hash = "sha256:26cef14744a8385f35d0e095dc8b3a7583f6c953c2e3d269c7f82484bf5ad2de", size = 13729, upload-time = "2026-01-30T01:03:45.029Z" }, +] + +[[package]] +name = "pywinpty" +version = "3.0.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/f3/bb/a7cc2967c5c4eceb6cc49cfe39447d4bfc56e6c865e7c2249b6eb978935f/pywinpty-3.0.2.tar.gz", hash = "sha256:1505cc4cb248af42cb6285a65c9c2086ee9e7e574078ee60933d5d7fa86fb004", size = 30669, upload-time = "2025-10-03T21:16:29.205Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/a6/a1/409c1651c9f874d598c10f51ff586c416625601df4bca315d08baec4c3e3/pywinpty-3.0.2-cp311-cp311-win_amd64.whl", hash = "sha256:327790d70e4c841ebd9d0f295a780177149aeb405bca44c7115a3de5c2054b23", size = 2050304, upload-time = "2025-10-03T21:19:29.466Z" }, + { url = "https://files.pythonhosted.org/packages/02/4e/1098484e042c9485f56f16eb2b69b43b874bd526044ee401512234cf9e04/pywinpty-3.0.2-cp312-cp312-win_amd64.whl", hash = "sha256:99fdd9b455f0ad6419aba6731a7a0d2f88ced83c3c94a80ff9533d95fa8d8a9e", size = 2050391, upload-time = "2025-10-03T21:19:01.642Z" }, +] + +[[package]] +name = "pyyaml" +version = "6.0.3" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/05/8e/961c0007c59b8dd7729d542c61a4d537767a59645b82a0b521206e1e25c2/pyyaml-6.0.3.tar.gz", hash = "sha256:d76623373421df22fb4cf8817020cbb7ef15c725b9d5e45f17e189bfc384190f", size = 130960, upload-time = "2025-09-25T21:33:16.546Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/6d/16/a95b6757765b7b031c9374925bb718d55e0a9ba8a1b6a12d25962ea44347/pyyaml-6.0.3-cp311-cp311-macosx_10_13_x86_64.whl", hash = "sha256:44edc647873928551a01e7a563d7452ccdebee747728c1080d881d68af7b997e", size = 185826, upload-time = "2025-09-25T21:31:58.655Z" }, + { url = "https://files.pythonhosted.org/packages/16/19/13de8e4377ed53079ee996e1ab0a9c33ec2faf808a4647b7b4c0d46dd239/pyyaml-6.0.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:652cb6edd41e718550aad172851962662ff2681490a8a711af6a4d288dd96824", size = 175577, upload-time = "2025-09-25T21:32:00.088Z" }, + { url = "https://files.pythonhosted.org/packages/0c/62/d2eb46264d4b157dae1275b573017abec435397aa59cbcdab6fc978a8af4/pyyaml-6.0.3-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:10892704fc220243f5305762e276552a0395f7beb4dbf9b14ec8fd43b57f126c", size = 775556, upload-time = "2025-09-25T21:32:01.31Z" }, + { url = "https://files.pythonhosted.org/packages/10/cb/16c3f2cf3266edd25aaa00d6c4350381c8b012ed6f5276675b9eba8d9ff4/pyyaml-6.0.3-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:850774a7879607d3a6f50d36d04f00ee69e7fc816450e5f7e58d7f17f1ae5c00", size = 882114, upload-time = "2025-09-25T21:32:03.376Z" }, + { url = "https://files.pythonhosted.org/packages/71/60/917329f640924b18ff085ab889a11c763e0b573da888e8404ff486657602/pyyaml-6.0.3-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:b8bb0864c5a28024fac8a632c443c87c5aa6f215c0b126c449ae1a150412f31d", size = 806638, upload-time = "2025-09-25T21:32:04.553Z" }, + { url = "https://files.pythonhosted.org/packages/dd/6f/529b0f316a9fd167281a6c3826b5583e6192dba792dd55e3203d3f8e655a/pyyaml-6.0.3-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:1d37d57ad971609cf3c53ba6a7e365e40660e3be0e5175fa9f2365a379d6095a", size = 767463, upload-time = "2025-09-25T21:32:06.152Z" }, + { url = "https://files.pythonhosted.org/packages/f2/6a/b627b4e0c1dd03718543519ffb2f1deea4a1e6d42fbab8021936a4d22589/pyyaml-6.0.3-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:37503bfbfc9d2c40b344d06b2199cf0e96e97957ab1c1b546fd4f87e53e5d3e4", size = 794986, upload-time = "2025-09-25T21:32:07.367Z" }, + { url = "https://files.pythonhosted.org/packages/45/91/47a6e1c42d9ee337c4839208f30d9f09caa9f720ec7582917b264defc875/pyyaml-6.0.3-cp311-cp311-win32.whl", hash = "sha256:8098f252adfa6c80ab48096053f512f2321f0b998f98150cea9bd23d83e1467b", size = 142543, upload-time = "2025-09-25T21:32:08.95Z" }, + { url = "https://files.pythonhosted.org/packages/da/e3/ea007450a105ae919a72393cb06f122f288ef60bba2dc64b26e2646fa315/pyyaml-6.0.3-cp311-cp311-win_amd64.whl", hash = "sha256:9f3bfb4965eb874431221a3ff3fdcddc7e74e3b07799e0e84ca4a0f867d449bf", size = 158763, upload-time = "2025-09-25T21:32:09.96Z" }, + { url = "https://files.pythonhosted.org/packages/d1/33/422b98d2195232ca1826284a76852ad5a86fe23e31b009c9886b2d0fb8b2/pyyaml-6.0.3-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:7f047e29dcae44602496db43be01ad42fc6f1cc0d8cd6c83d342306c32270196", size = 182063, upload-time = "2025-09-25T21:32:11.445Z" }, + { url = "https://files.pythonhosted.org/packages/89/a0/6cf41a19a1f2f3feab0e9c0b74134aa2ce6849093d5517a0c550fe37a648/pyyaml-6.0.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:fc09d0aa354569bc501d4e787133afc08552722d3ab34836a80547331bb5d4a0", size = 173973, upload-time = "2025-09-25T21:32:12.492Z" }, + { url = "https://files.pythonhosted.org/packages/ed/23/7a778b6bd0b9a8039df8b1b1d80e2e2ad78aa04171592c8a5c43a56a6af4/pyyaml-6.0.3-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:9149cad251584d5fb4981be1ecde53a1ca46c891a79788c0df828d2f166bda28", size = 775116, upload-time = "2025-09-25T21:32:13.652Z" }, + { url = "https://files.pythonhosted.org/packages/65/30/d7353c338e12baef4ecc1b09e877c1970bd3382789c159b4f89d6a70dc09/pyyaml-6.0.3-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:5fdec68f91a0c6739b380c83b951e2c72ac0197ace422360e6d5a959d8d97b2c", size = 844011, upload-time = "2025-09-25T21:32:15.21Z" }, + { url = "https://files.pythonhosted.org/packages/8b/9d/b3589d3877982d4f2329302ef98a8026e7f4443c765c46cfecc8858c6b4b/pyyaml-6.0.3-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:ba1cc08a7ccde2d2ec775841541641e4548226580ab850948cbfda66a1befcdc", size = 807870, upload-time = "2025-09-25T21:32:16.431Z" }, + { url = "https://files.pythonhosted.org/packages/05/c0/b3be26a015601b822b97d9149ff8cb5ead58c66f981e04fedf4e762f4bd4/pyyaml-6.0.3-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:8dc52c23056b9ddd46818a57b78404882310fb473d63f17b07d5c40421e47f8e", size = 761089, upload-time = "2025-09-25T21:32:17.56Z" }, + { url = "https://files.pythonhosted.org/packages/be/8e/98435a21d1d4b46590d5459a22d88128103f8da4c2d4cb8f14f2a96504e1/pyyaml-6.0.3-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:41715c910c881bc081f1e8872880d3c650acf13dfa8214bad49ed4cede7c34ea", size = 790181, upload-time = "2025-09-25T21:32:18.834Z" }, + { url = "https://files.pythonhosted.org/packages/74/93/7baea19427dcfbe1e5a372d81473250b379f04b1bd3c4c5ff825e2327202/pyyaml-6.0.3-cp312-cp312-win32.whl", hash = "sha256:96b533f0e99f6579b3d4d4995707cf36df9100d67e0c8303a0c55b27b5f99bc5", size = 137658, upload-time = "2025-09-25T21:32:20.209Z" }, + { url = "https://files.pythonhosted.org/packages/86/bf/899e81e4cce32febab4fb42bb97dcdf66bc135272882d1987881a4b519e9/pyyaml-6.0.3-cp312-cp312-win_amd64.whl", hash = "sha256:5fcd34e47f6e0b794d17de1b4ff496c00986e1c83f7ab2fb8fcfe9616ff7477b", size = 154003, upload-time = "2025-09-25T21:32:21.167Z" }, + { url = "https://files.pythonhosted.org/packages/1a/08/67bd04656199bbb51dbed1439b7f27601dfb576fb864099c7ef0c3e55531/pyyaml-6.0.3-cp312-cp312-win_arm64.whl", hash = "sha256:64386e5e707d03a7e172c0701abfb7e10f0fb753ee1d773128192742712a98fd", size = 140344, upload-time = "2025-09-25T21:32:22.617Z" }, +] + +[[package]] +name = "pyzmq" +version = "27.1.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "cffi", marker = "implementation_name == 'pypy'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/04/0b/3c9baedbdf613ecaa7aa07027780b8867f57b6293b6ee50de316c9f3222b/pyzmq-27.1.0.tar.gz", hash = "sha256:ac0765e3d44455adb6ddbf4417dcce460fc40a05978c08efdf2948072f6db540", size = 281750, upload-time = "2025-09-08T23:10:18.157Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/06/5d/305323ba86b284e6fcb0d842d6adaa2999035f70f8c38a9b6d21ad28c3d4/pyzmq-27.1.0-cp311-cp311-macosx_10_15_universal2.whl", hash = "sha256:226b091818d461a3bef763805e75685e478ac17e9008f49fce2d3e52b3d58b86", size = 1333328, upload-time = "2025-09-08T23:07:45.946Z" }, + { url = "https://files.pythonhosted.org/packages/bd/a0/fc7e78a23748ad5443ac3275943457e8452da67fda347e05260261108cbc/pyzmq-27.1.0-cp311-cp311-manylinux2014_i686.manylinux_2_17_i686.whl", hash = "sha256:0790a0161c281ca9723f804871b4027f2e8b5a528d357c8952d08cd1a9c15581", size = 908803, upload-time = "2025-09-08T23:07:47.551Z" }, + { url = "https://files.pythonhosted.org/packages/7e/22/37d15eb05f3bdfa4abea6f6d96eb3bb58585fbd3e4e0ded4e743bc650c97/pyzmq-27.1.0-cp311-cp311-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:c895a6f35476b0c3a54e3eb6ccf41bf3018de937016e6e18748317f25d4e925f", size = 668836, upload-time = "2025-09-08T23:07:49.436Z" }, + { url = "https://files.pythonhosted.org/packages/b1/c4/2a6fe5111a01005fc7af3878259ce17684fabb8852815eda6225620f3c59/pyzmq-27.1.0-cp311-cp311-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:5bbf8d3630bf96550b3be8e1fc0fea5cbdc8d5466c1192887bd94869da17a63e", size = 857038, upload-time = "2025-09-08T23:07:51.234Z" }, + { url = "https://files.pythonhosted.org/packages/cb/eb/bfdcb41d0db9cd233d6fb22dc131583774135505ada800ebf14dfb0a7c40/pyzmq-27.1.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:15c8bd0fe0dabf808e2d7a681398c4e5ded70a551ab47482067a572c054c8e2e", size = 1657531, upload-time = "2025-09-08T23:07:52.795Z" }, + { url = "https://files.pythonhosted.org/packages/ab/21/e3180ca269ed4a0de5c34417dfe71a8ae80421198be83ee619a8a485b0c7/pyzmq-27.1.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:bafcb3dd171b4ae9f19ee6380dfc71ce0390fefaf26b504c0e5f628d7c8c54f2", size = 2034786, upload-time = "2025-09-08T23:07:55.047Z" }, + { url = "https://files.pythonhosted.org/packages/3b/b1/5e21d0b517434b7f33588ff76c177c5a167858cc38ef740608898cd329f2/pyzmq-27.1.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:e829529fcaa09937189178115c49c504e69289abd39967cd8a4c215761373394", size = 1894220, upload-time = "2025-09-08T23:07:57.172Z" }, + { url = "https://files.pythonhosted.org/packages/03/f2/44913a6ff6941905efc24a1acf3d3cb6146b636c546c7406c38c49c403d4/pyzmq-27.1.0-cp311-cp311-win32.whl", hash = "sha256:6df079c47d5902af6db298ec92151db82ecb557af663098b92f2508c398bb54f", size = 567155, upload-time = "2025-09-08T23:07:59.05Z" }, + { url = "https://files.pythonhosted.org/packages/23/6d/d8d92a0eb270a925c9b4dd039c0b4dc10abc2fcbc48331788824ef113935/pyzmq-27.1.0-cp311-cp311-win_amd64.whl", hash = "sha256:190cbf120fbc0fc4957b56866830def56628934a9d112aec0e2507aa6a032b97", size = 633428, upload-time = "2025-09-08T23:08:00.663Z" }, + { url = "https://files.pythonhosted.org/packages/ae/14/01afebc96c5abbbd713ecfc7469cfb1bc801c819a74ed5c9fad9a48801cb/pyzmq-27.1.0-cp311-cp311-win_arm64.whl", hash = "sha256:eca6b47df11a132d1745eb3b5b5e557a7dae2c303277aa0e69c6ba91b8736e07", size = 559497, upload-time = "2025-09-08T23:08:02.15Z" }, + { url = "https://files.pythonhosted.org/packages/92/e7/038aab64a946d535901103da16b953c8c9cc9c961dadcbf3609ed6428d23/pyzmq-27.1.0-cp312-abi3-macosx_10_15_universal2.whl", hash = "sha256:452631b640340c928fa343801b0d07eb0c3789a5ffa843f6e1a9cee0ba4eb4fc", size = 1306279, upload-time = "2025-09-08T23:08:03.807Z" }, + { url = "https://files.pythonhosted.org/packages/e8/5e/c3c49fdd0f535ef45eefcc16934648e9e59dace4a37ee88fc53f6cd8e641/pyzmq-27.1.0-cp312-abi3-manylinux2014_i686.manylinux_2_17_i686.whl", hash = "sha256:1c179799b118e554b66da67d88ed66cd37a169f1f23b5d9f0a231b4e8d44a113", size = 895645, upload-time = "2025-09-08T23:08:05.301Z" }, + { url = "https://files.pythonhosted.org/packages/f8/e5/b0b2504cb4e903a74dcf1ebae157f9e20ebb6ea76095f6cfffea28c42ecd/pyzmq-27.1.0-cp312-abi3-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:3837439b7f99e60312f0c926a6ad437b067356dc2bc2ec96eb395fd0fe804233", size = 652574, upload-time = "2025-09-08T23:08:06.828Z" }, + { url = "https://files.pythonhosted.org/packages/f8/9b/c108cdb55560eaf253f0cbdb61b29971e9fb34d9c3499b0e96e4e60ed8a5/pyzmq-27.1.0-cp312-abi3-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:43ad9a73e3da1fab5b0e7e13402f0b2fb934ae1c876c51d0afff0e7c052eca31", size = 840995, upload-time = "2025-09-08T23:08:08.396Z" }, + { url = "https://files.pythonhosted.org/packages/c2/bb/b79798ca177b9eb0825b4c9998c6af8cd2a7f15a6a1a4272c1d1a21d382f/pyzmq-27.1.0-cp312-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:0de3028d69d4cdc475bfe47a6128eb38d8bc0e8f4d69646adfbcd840facbac28", size = 1642070, upload-time = "2025-09-08T23:08:09.989Z" }, + { url = "https://files.pythonhosted.org/packages/9c/80/2df2e7977c4ede24c79ae39dcef3899bfc5f34d1ca7a5b24f182c9b7a9ca/pyzmq-27.1.0-cp312-abi3-musllinux_1_2_i686.whl", hash = "sha256:cf44a7763aea9298c0aa7dbf859f87ed7012de8bda0f3977b6fb1d96745df856", size = 2021121, upload-time = "2025-09-08T23:08:11.907Z" }, + { url = "https://files.pythonhosted.org/packages/46/bd/2d45ad24f5f5ae7e8d01525eb76786fa7557136555cac7d929880519e33a/pyzmq-27.1.0-cp312-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:f30f395a9e6fbca195400ce833c731e7b64c3919aa481af4d88c3759e0cb7496", size = 1878550, upload-time = "2025-09-08T23:08:13.513Z" }, + { url = "https://files.pythonhosted.org/packages/e6/2f/104c0a3c778d7c2ab8190e9db4f62f0b6957b53c9d87db77c284b69f33ea/pyzmq-27.1.0-cp312-abi3-win32.whl", hash = "sha256:250e5436a4ba13885494412b3da5d518cd0d3a278a1ae640e113c073a5f88edd", size = 559184, upload-time = "2025-09-08T23:08:15.163Z" }, + { url = "https://files.pythonhosted.org/packages/fc/7f/a21b20d577e4100c6a41795842028235998a643b1ad406a6d4163ea8f53e/pyzmq-27.1.0-cp312-abi3-win_amd64.whl", hash = "sha256:9ce490cf1d2ca2ad84733aa1d69ce6855372cb5ce9223802450c9b2a7cba0ccf", size = 619480, upload-time = "2025-09-08T23:08:17.192Z" }, + { url = "https://files.pythonhosted.org/packages/78/c2/c012beae5f76b72f007a9e91ee9401cb88c51d0f83c6257a03e785c81cc2/pyzmq-27.1.0-cp312-abi3-win_arm64.whl", hash = "sha256:75a2f36223f0d535a0c919e23615fc85a1e23b71f40c7eb43d7b1dedb4d8f15f", size = 552993, upload-time = "2025-09-08T23:08:18.926Z" }, + { url = "https://files.pythonhosted.org/packages/4c/c6/c4dcdecdbaa70969ee1fdced6d7b8f60cfabe64d25361f27ac4665a70620/pyzmq-27.1.0-pp311-pypy311_pp73-macosx_10_15_x86_64.whl", hash = "sha256:18770c8d3563715387139060d37859c02ce40718d1faf299abddcdcc6a649066", size = 836265, upload-time = "2025-09-08T23:09:49.376Z" }, + { url = "https://files.pythonhosted.org/packages/3e/79/f38c92eeaeb03a2ccc2ba9866f0439593bb08c5e3b714ac1d553e5c96e25/pyzmq-27.1.0-pp311-pypy311_pp73-manylinux2014_i686.manylinux_2_17_i686.whl", hash = "sha256:ac25465d42f92e990f8d8b0546b01c391ad431c3bf447683fdc40565941d0604", size = 800208, upload-time = "2025-09-08T23:09:51.073Z" }, + { url = "https://files.pythonhosted.org/packages/49/0e/3f0d0d335c6b3abb9b7b723776d0b21fa7f3a6c819a0db6097059aada160/pyzmq-27.1.0-pp311-pypy311_pp73-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:53b40f8ae006f2734ee7608d59ed661419f087521edbfc2149c3932e9c14808c", size = 567747, upload-time = "2025-09-08T23:09:52.698Z" }, + { url = "https://files.pythonhosted.org/packages/a1/cf/f2b3784d536250ffd4be70e049f3b60981235d70c6e8ce7e3ef21e1adb25/pyzmq-27.1.0-pp311-pypy311_pp73-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:f605d884e7c8be8fe1aa94e0a783bf3f591b84c24e4bc4f3e7564c82ac25e271", size = 747371, upload-time = "2025-09-08T23:09:54.563Z" }, + { url = "https://files.pythonhosted.org/packages/01/1b/5dbe84eefc86f48473947e2f41711aded97eecef1231f4558f1f02713c12/pyzmq-27.1.0-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:c9f7f6e13dff2e44a6afeaf2cf54cee5929ad64afaf4d40b50f93c58fc687355", size = 544862, upload-time = "2025-09-08T23:09:56.509Z" }, +] + +[[package]] +name = "quartodoc" +version = "0.11.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "black" }, + { name = "click" }, + { name = "griffe" }, + { name = "importlib-metadata" }, + { name = "importlib-resources" }, + { name = "plum-dispatch" }, + { name = "pydantic" }, + { name = "pyyaml" }, + { name = "requests" }, + { name = "sphobjinv" }, + { name = "tabulate" }, + { name = "typing-extensions" }, + { name = "watchdog" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/ff/b9/0bb44cc62a5d63728d04fd6b1e14bcb64945fabad4aa8c03b9d70315fb06/quartodoc-0.11.1.tar.gz", hash = "sha256:c121626e1a36392d168631f33c4d3e7fd48d185de178859f8eafbda14fbfe92f", size = 778611, upload-time = "2025-06-10T14:50:08.185Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/75/d9/0b48d4184f9ca6a996c4fac46897a968698c9d1e0f0e43a6906746201323/quartodoc-0.11.1-py3-none-any.whl", hash = "sha256:0776eb8e53d89385e2c9a8ae0ec08e8c307c1410dd1bd78bb28e8b1823dbb6ad", size = 88053, upload-time = "2025-06-10T14:50:06.443Z" }, +] + +[[package]] +name = "referencing" +version = "0.37.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "attrs" }, + { name = "rpds-py" }, + { name = "typing-extensions" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/22/f5/df4e9027acead3ecc63e50fe1e36aca1523e1719559c499951bb4b53188f/referencing-0.37.0.tar.gz", hash = "sha256:44aefc3142c5b842538163acb373e24cce6632bd54bdb01b21ad5863489f50d8", size = 78036, upload-time = "2025-10-13T15:30:48.871Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/2c/58/ca301544e1fa93ed4f80d724bf5b194f6e4b945841c5bfd555878eea9fcb/referencing-0.37.0-py3-none-any.whl", hash = "sha256:381329a9f99628c9069361716891d34ad94af76e461dcb0335825aecc7692231", size = 26766, upload-time = "2025-10-13T15:30:47.625Z" }, +] + +[[package]] +name = "requests" +version = "2.32.5" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "certifi" }, + { name = "charset-normalizer" }, + { name = "idna" }, + { name = "urllib3" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/c9/74/b3ff8e6c8446842c3f5c837e9c3dfcfe2018ea6ecef224c710c85ef728f4/requests-2.32.5.tar.gz", hash = "sha256:dbba0bac56e100853db0ea71b82b4dfd5fe2bf6d3754a8893c3af500cec7d7cf", size = 134517, upload-time = "2025-08-18T20:46:02.573Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/1e/db/4254e3eabe8020b458f1a747140d32277ec7a271daf1d235b70dc0b4e6e3/requests-2.32.5-py3-none-any.whl", hash = "sha256:2462f94637a34fd532264295e186976db0f5d453d1cdd31473c85a6a161affb6", size = 64738, upload-time = "2025-08-18T20:46:00.542Z" }, +] + +[[package]] +name = "rfc3339-validator" +version = "0.1.4" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "six" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/28/ea/a9387748e2d111c3c2b275ba970b735e04e15cdb1eb30693b6b5708c4dbd/rfc3339_validator-0.1.4.tar.gz", hash = "sha256:138a2abdf93304ad60530167e51d2dfb9549521a836871b88d7f4695d0022f6b", size = 5513, upload-time = "2021-05-12T16:37:54.178Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/7b/44/4e421b96b67b2daff264473f7465db72fbdf36a07e05494f50300cc7b0c6/rfc3339_validator-0.1.4-py2.py3-none-any.whl", hash = "sha256:24f6ec1eda14ef823da9e36ec7113124b39c04d50a4d3d3a3c2859577e7791fa", size = 3490, upload-time = "2021-05-12T16:37:52.536Z" }, +] + +[[package]] +name = "rfc3986-validator" +version = "0.1.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/da/88/f270de456dd7d11dcc808abfa291ecdd3f45ff44e3b549ffa01b126464d0/rfc3986_validator-0.1.1.tar.gz", hash = "sha256:3d44bde7921b3b9ec3ae4e3adca370438eccebc676456449b145d533b240d055", size = 6760, upload-time = "2019-10-28T16:00:19.144Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/9e/51/17023c0f8f1869d8806b979a2bffa3f861f26a3f1a66b094288323fba52f/rfc3986_validator-0.1.1-py2.py3-none-any.whl", hash = "sha256:2f235c432ef459970b4306369336b9d5dbdda31b510ca1e327636e01f528bfa9", size = 4242, upload-time = "2019-10-28T16:00:13.976Z" }, +] + +[[package]] +name = "rfc3987-syntax" +version = "1.1.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "lark" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/2c/06/37c1a5557acf449e8e406a830a05bf885ac47d33270aec454ef78675008d/rfc3987_syntax-1.1.0.tar.gz", hash = "sha256:717a62cbf33cffdd16dfa3a497d81ce48a660ea691b1ddd7be710c22f00b4a0d", size = 14239, upload-time = "2025-07-18T01:05:05.015Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/7e/71/44ce230e1b7fadd372515a97e32a83011f906ddded8d03e3c6aafbdedbb7/rfc3987_syntax-1.1.0-py3-none-any.whl", hash = "sha256:6c3d97604e4c5ce9f714898e05401a0445a641cfa276432b0a648c80856f6a3f", size = 8046, upload-time = "2025-07-18T01:05:03.843Z" }, +] + +[[package]] +name = "rich" +version = "14.3.2" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "markdown-it-py" }, + { name = "pygments" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/74/99/a4cab2acbb884f80e558b0771e97e21e939c5dfb460f488d19df485e8298/rich-14.3.2.tar.gz", hash = "sha256:e712f11c1a562a11843306f5ed999475f09ac31ffb64281f73ab29ffdda8b3b8", size = 230143, upload-time = "2026-02-01T16:20:47.908Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/ef/45/615f5babd880b4bd7d405cc0dc348234c5ffb6ed1ea33e152ede08b2072d/rich-14.3.2-py3-none-any.whl", hash = "sha256:08e67c3e90884651da3239ea668222d19bea7b589149d8014a21c633420dbb69", size = 309963, upload-time = "2026-02-01T16:20:46.078Z" }, +] + +[[package]] +name = "rpds-py" +version = "0.30.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/20/af/3f2f423103f1113b36230496629986e0ef7e199d2aa8392452b484b38ced/rpds_py-0.30.0.tar.gz", hash = "sha256:dd8ff7cf90014af0c0f787eea34794ebf6415242ee1d6fa91eaba725cc441e84", size = 69469, upload-time = "2025-11-30T20:24:38.837Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/4d/6e/f964e88b3d2abee2a82c1ac8366da848fce1c6d834dc2132c3fda3970290/rpds_py-0.30.0-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:a2bffea6a4ca9f01b3f8e548302470306689684e61602aa3d141e34da06cf425", size = 370157, upload-time = "2025-11-30T20:21:53.789Z" }, + { url = "https://files.pythonhosted.org/packages/94/ba/24e5ebb7c1c82e74c4e4f33b2112a5573ddc703915b13a073737b59b86e0/rpds_py-0.30.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:dc4f992dfe1e2bc3ebc7444f6c7051b4bc13cd8e33e43511e8ffd13bf407010d", size = 359676, upload-time = "2025-11-30T20:21:55.475Z" }, + { url = "https://files.pythonhosted.org/packages/84/86/04dbba1b087227747d64d80c3b74df946b986c57af0a9f0c98726d4d7a3b/rpds_py-0.30.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:422c3cb9856d80b09d30d2eb255d0754b23e090034e1deb4083f8004bd0761e4", size = 389938, upload-time = "2025-11-30T20:21:57.079Z" }, + { url = "https://files.pythonhosted.org/packages/42/bb/1463f0b1722b7f45431bdd468301991d1328b16cffe0b1c2918eba2c4eee/rpds_py-0.30.0-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:07ae8a593e1c3c6b82ca3292efbe73c30b61332fd612e05abee07c79359f292f", size = 402932, upload-time = "2025-11-30T20:21:58.47Z" }, + { url = "https://files.pythonhosted.org/packages/99/ee/2520700a5c1f2d76631f948b0736cdf9b0acb25abd0ca8e889b5c62ac2e3/rpds_py-0.30.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:12f90dd7557b6bd57f40abe7747e81e0c0b119bef015ea7726e69fe550e394a4", size = 525830, upload-time = "2025-11-30T20:21:59.699Z" }, + { url = "https://files.pythonhosted.org/packages/e0/ad/bd0331f740f5705cc555a5e17fdf334671262160270962e69a2bdef3bf76/rpds_py-0.30.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:99b47d6ad9a6da00bec6aabe5a6279ecd3c06a329d4aa4771034a21e335c3a97", size = 412033, upload-time = "2025-11-30T20:22:00.991Z" }, + { url = "https://files.pythonhosted.org/packages/f8/1e/372195d326549bb51f0ba0f2ecb9874579906b97e08880e7a65c3bef1a99/rpds_py-0.30.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:33f559f3104504506a44bb666b93a33f5d33133765b0c216a5bf2f1e1503af89", size = 390828, upload-time = "2025-11-30T20:22:02.723Z" }, + { url = "https://files.pythonhosted.org/packages/ab/2b/d88bb33294e3e0c76bc8f351a3721212713629ffca1700fa94979cb3eae8/rpds_py-0.30.0-cp311-cp311-manylinux_2_31_riscv64.whl", hash = "sha256:946fe926af6e44f3697abbc305ea168c2c31d3e3ef1058cf68f379bf0335a78d", size = 404683, upload-time = "2025-11-30T20:22:04.367Z" }, + { url = "https://files.pythonhosted.org/packages/50/32/c759a8d42bcb5289c1fac697cd92f6fe01a018dd937e62ae77e0e7f15702/rpds_py-0.30.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:495aeca4b93d465efde585977365187149e75383ad2684f81519f504f5c13038", size = 421583, upload-time = "2025-11-30T20:22:05.814Z" }, + { url = "https://files.pythonhosted.org/packages/2b/81/e729761dbd55ddf5d84ec4ff1f47857f4374b0f19bdabfcf929164da3e24/rpds_py-0.30.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:d9a0ca5da0386dee0655b4ccdf46119df60e0f10da268d04fe7cc87886872ba7", size = 572496, upload-time = "2025-11-30T20:22:07.713Z" }, + { url = "https://files.pythonhosted.org/packages/14/f6/69066a924c3557c9c30baa6ec3a0aa07526305684c6f86c696b08860726c/rpds_py-0.30.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:8d6d1cc13664ec13c1b84241204ff3b12f9bb82464b8ad6e7a5d3486975c2eed", size = 598669, upload-time = "2025-11-30T20:22:09.312Z" }, + { url = "https://files.pythonhosted.org/packages/5f/48/905896b1eb8a05630d20333d1d8ffd162394127b74ce0b0784ae04498d32/rpds_py-0.30.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:3896fa1be39912cf0757753826bc8bdc8ca331a28a7c4ae46b7a21280b06bb85", size = 561011, upload-time = "2025-11-30T20:22:11.309Z" }, + { url = "https://files.pythonhosted.org/packages/22/16/cd3027c7e279d22e5eb431dd3c0fbc677bed58797fe7581e148f3f68818b/rpds_py-0.30.0-cp311-cp311-win32.whl", hash = "sha256:55f66022632205940f1827effeff17c4fa7ae1953d2b74a8581baaefb7d16f8c", size = 221406, upload-time = "2025-11-30T20:22:13.101Z" }, + { url = "https://files.pythonhosted.org/packages/fa/5b/e7b7aa136f28462b344e652ee010d4de26ee9fd16f1bfd5811f5153ccf89/rpds_py-0.30.0-cp311-cp311-win_amd64.whl", hash = "sha256:a51033ff701fca756439d641c0ad09a41d9242fa69121c7d8769604a0a629825", size = 236024, upload-time = "2025-11-30T20:22:14.853Z" }, + { url = "https://files.pythonhosted.org/packages/14/a6/364bba985e4c13658edb156640608f2c9e1d3ea3c81b27aa9d889fff0e31/rpds_py-0.30.0-cp311-cp311-win_arm64.whl", hash = "sha256:47b0ef6231c58f506ef0b74d44e330405caa8428e770fec25329ed2cb971a229", size = 229069, upload-time = "2025-11-30T20:22:16.577Z" }, + { url = "https://files.pythonhosted.org/packages/03/e7/98a2f4ac921d82f33e03f3835f5bf3a4a40aa1bfdc57975e74a97b2b4bdd/rpds_py-0.30.0-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:a161f20d9a43006833cd7068375a94d035714d73a172b681d8881820600abfad", size = 375086, upload-time = "2025-11-30T20:22:17.93Z" }, + { url = "https://files.pythonhosted.org/packages/4d/a1/bca7fd3d452b272e13335db8d6b0b3ecde0f90ad6f16f3328c6fb150c889/rpds_py-0.30.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:6abc8880d9d036ecaafe709079969f56e876fcf107f7a8e9920ba6d5a3878d05", size = 359053, upload-time = "2025-11-30T20:22:19.297Z" }, + { url = "https://files.pythonhosted.org/packages/65/1c/ae157e83a6357eceff62ba7e52113e3ec4834a84cfe07fa4b0757a7d105f/rpds_py-0.30.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ca28829ae5f5d569bb62a79512c842a03a12576375d5ece7d2cadf8abe96ec28", size = 390763, upload-time = "2025-11-30T20:22:21.661Z" }, + { url = "https://files.pythonhosted.org/packages/d4/36/eb2eb8515e2ad24c0bd43c3ee9cd74c33f7ca6430755ccdb240fd3144c44/rpds_py-0.30.0-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:a1010ed9524c73b94d15919ca4d41d8780980e1765babf85f9a2f90d247153dd", size = 408951, upload-time = "2025-11-30T20:22:23.408Z" }, + { url = "https://files.pythonhosted.org/packages/d6/65/ad8dc1784a331fabbd740ef6f71ce2198c7ed0890dab595adb9ea2d775a1/rpds_py-0.30.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f8d1736cfb49381ba528cd5baa46f82fdc65c06e843dab24dd70b63d09121b3f", size = 514622, upload-time = "2025-11-30T20:22:25.16Z" }, + { url = "https://files.pythonhosted.org/packages/63/8e/0cfa7ae158e15e143fe03993b5bcd743a59f541f5952e1546b1ac1b5fd45/rpds_py-0.30.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d948b135c4693daff7bc2dcfc4ec57237a29bd37e60c2fabf5aff2bbacf3e2f1", size = 414492, upload-time = "2025-11-30T20:22:26.505Z" }, + { url = "https://files.pythonhosted.org/packages/60/1b/6f8f29f3f995c7ffdde46a626ddccd7c63aefc0efae881dc13b6e5d5bb16/rpds_py-0.30.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:47f236970bccb2233267d89173d3ad2703cd36a0e2a6e92d0560d333871a3d23", size = 394080, upload-time = "2025-11-30T20:22:27.934Z" }, + { url = "https://files.pythonhosted.org/packages/6d/d5/a266341051a7a3ca2f4b750a3aa4abc986378431fc2da508c5034d081b70/rpds_py-0.30.0-cp312-cp312-manylinux_2_31_riscv64.whl", hash = "sha256:2e6ecb5a5bcacf59c3f912155044479af1d0b6681280048b338b28e364aca1f6", size = 408680, upload-time = "2025-11-30T20:22:29.341Z" }, + { url = "https://files.pythonhosted.org/packages/10/3b/71b725851df9ab7a7a4e33cf36d241933da66040d195a84781f49c50490c/rpds_py-0.30.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:a8fa71a2e078c527c3e9dc9fc5a98c9db40bcc8a92b4e8858e36d329f8684b51", size = 423589, upload-time = "2025-11-30T20:22:31.469Z" }, + { url = "https://files.pythonhosted.org/packages/00/2b/e59e58c544dc9bd8bd8384ecdb8ea91f6727f0e37a7131baeff8d6f51661/rpds_py-0.30.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:73c67f2db7bc334e518d097c6d1e6fed021bbc9b7d678d6cc433478365d1d5f5", size = 573289, upload-time = "2025-11-30T20:22:32.997Z" }, + { url = "https://files.pythonhosted.org/packages/da/3e/a18e6f5b460893172a7d6a680e86d3b6bc87a54c1f0b03446a3c8c7b588f/rpds_py-0.30.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:5ba103fb455be00f3b1c2076c9d4264bfcb037c976167a6047ed82f23153f02e", size = 599737, upload-time = "2025-11-30T20:22:34.419Z" }, + { url = "https://files.pythonhosted.org/packages/5c/e2/714694e4b87b85a18e2c243614974413c60aa107fd815b8cbc42b873d1d7/rpds_py-0.30.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:7cee9c752c0364588353e627da8a7e808a66873672bcb5f52890c33fd965b394", size = 563120, upload-time = "2025-11-30T20:22:35.903Z" }, + { url = "https://files.pythonhosted.org/packages/6f/ab/d5d5e3bcedb0a77f4f613706b750e50a5a3ba1c15ccd3665ecc636c968fd/rpds_py-0.30.0-cp312-cp312-win32.whl", hash = "sha256:1ab5b83dbcf55acc8b08fc62b796ef672c457b17dbd7820a11d6c52c06839bdf", size = 223782, upload-time = "2025-11-30T20:22:37.271Z" }, + { url = "https://files.pythonhosted.org/packages/39/3b/f786af9957306fdc38a74cef405b7b93180f481fb48453a114bb6465744a/rpds_py-0.30.0-cp312-cp312-win_amd64.whl", hash = "sha256:a090322ca841abd453d43456ac34db46e8b05fd9b3b4ac0c78bcde8b089f959b", size = 240463, upload-time = "2025-11-30T20:22:39.021Z" }, + { url = "https://files.pythonhosted.org/packages/f3/d2/b91dc748126c1559042cfe41990deb92c4ee3e2b415f6b5234969ffaf0cc/rpds_py-0.30.0-cp312-cp312-win_arm64.whl", hash = "sha256:669b1805bd639dd2989b281be2cfd951c6121b65e729d9b843e9639ef1fd555e", size = 230868, upload-time = "2025-11-30T20:22:40.493Z" }, + { url = "https://files.pythonhosted.org/packages/69/71/3f34339ee70521864411f8b6992e7ab13ac30d8e4e3309e07c7361767d91/rpds_py-0.30.0-pp311-pypy311_pp73-macosx_10_12_x86_64.whl", hash = "sha256:c2262bdba0ad4fc6fb5545660673925c2d2a5d9e2e0fb603aad545427be0fc58", size = 372292, upload-time = "2025-11-30T20:24:16.537Z" }, + { url = "https://files.pythonhosted.org/packages/57/09/f183df9b8f2d66720d2ef71075c59f7e1b336bec7ee4c48f0a2b06857653/rpds_py-0.30.0-pp311-pypy311_pp73-macosx_11_0_arm64.whl", hash = "sha256:ee6af14263f25eedc3bb918a3c04245106a42dfd4f5c2285ea6f997b1fc3f89a", size = 362128, upload-time = "2025-11-30T20:24:18.086Z" }, + { url = "https://files.pythonhosted.org/packages/7a/68/5c2594e937253457342e078f0cc1ded3dd7b2ad59afdbf2d354869110a02/rpds_py-0.30.0-pp311-pypy311_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3adbb8179ce342d235c31ab8ec511e66c73faa27a47e076ccc92421add53e2bb", size = 391542, upload-time = "2025-11-30T20:24:20.092Z" }, + { url = "https://files.pythonhosted.org/packages/49/5c/31ef1afd70b4b4fbdb2800249f34c57c64beb687495b10aec0365f53dfc4/rpds_py-0.30.0-pp311-pypy311_pp73-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:250fa00e9543ac9b97ac258bd37367ff5256666122c2d0f2bc97577c60a1818c", size = 404004, upload-time = "2025-11-30T20:24:22.231Z" }, + { url = "https://files.pythonhosted.org/packages/e3/63/0cfbea38d05756f3440ce6534d51a491d26176ac045e2707adc99bb6e60a/rpds_py-0.30.0-pp311-pypy311_pp73-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9854cf4f488b3d57b9aaeb105f06d78e5529d3145b1e4a41750167e8c213c6d3", size = 527063, upload-time = "2025-11-30T20:24:24.302Z" }, + { url = "https://files.pythonhosted.org/packages/42/e6/01e1f72a2456678b0f618fc9a1a13f882061690893c192fcad9f2926553a/rpds_py-0.30.0-pp311-pypy311_pp73-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:993914b8e560023bc0a8bf742c5f303551992dcb85e247b1e5c7f4a7d145bda5", size = 413099, upload-time = "2025-11-30T20:24:25.916Z" }, + { url = "https://files.pythonhosted.org/packages/b8/25/8df56677f209003dcbb180765520c544525e3ef21ea72279c98b9aa7c7fb/rpds_py-0.30.0-pp311-pypy311_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:58edca431fb9b29950807e301826586e5bbf24163677732429770a697ffe6738", size = 392177, upload-time = "2025-11-30T20:24:27.834Z" }, + { url = "https://files.pythonhosted.org/packages/4a/b4/0a771378c5f16f8115f796d1f437950158679bcd2a7c68cf251cfb00ed5b/rpds_py-0.30.0-pp311-pypy311_pp73-manylinux_2_31_riscv64.whl", hash = "sha256:dea5b552272a944763b34394d04577cf0f9bd013207bc32323b5a89a53cf9c2f", size = 406015, upload-time = "2025-11-30T20:24:29.457Z" }, + { url = "https://files.pythonhosted.org/packages/36/d8/456dbba0af75049dc6f63ff295a2f92766b9d521fa00de67a2bd6427d57a/rpds_py-0.30.0-pp311-pypy311_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:ba3af48635eb83d03f6c9735dfb21785303e73d22ad03d489e88adae6eab8877", size = 423736, upload-time = "2025-11-30T20:24:31.22Z" }, + { url = "https://files.pythonhosted.org/packages/13/64/b4d76f227d5c45a7e0b796c674fd81b0a6c4fbd48dc29271857d8219571c/rpds_py-0.30.0-pp311-pypy311_pp73-musllinux_1_2_aarch64.whl", hash = "sha256:dff13836529b921e22f15cb099751209a60009731a68519630a24d61f0b1b30a", size = 573981, upload-time = "2025-11-30T20:24:32.934Z" }, + { url = "https://files.pythonhosted.org/packages/20/91/092bacadeda3edf92bf743cc96a7be133e13a39cdbfd7b5082e7ab638406/rpds_py-0.30.0-pp311-pypy311_pp73-musllinux_1_2_i686.whl", hash = "sha256:1b151685b23929ab7beec71080a8889d4d6d9fa9a983d213f07121205d48e2c4", size = 599782, upload-time = "2025-11-30T20:24:35.169Z" }, + { url = "https://files.pythonhosted.org/packages/d1/b7/b95708304cd49b7b6f82fdd039f1748b66ec2b21d6a45180910802f1abf1/rpds_py-0.30.0-pp311-pypy311_pp73-musllinux_1_2_x86_64.whl", hash = "sha256:ac37f9f516c51e5753f27dfdef11a88330f04de2d564be3991384b2f3535d02e", size = 562191, upload-time = "2025-11-30T20:24:36.853Z" }, +] + +[[package]] +name = "ruff" +version = "0.14.14" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/2e/06/f71e3a86b2df0dfa2d2f72195941cd09b44f87711cb7fa5193732cb9a5fc/ruff-0.14.14.tar.gz", hash = "sha256:2d0f819c9a90205f3a867dbbd0be083bee9912e170fd7d9704cc8ae45824896b", size = 4515732, upload-time = "2026-01-22T22:30:17.527Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/d2/89/20a12e97bc6b9f9f68343952da08a8099c57237aef953a56b82711d55edd/ruff-0.14.14-py3-none-linux_armv6l.whl", hash = "sha256:7cfe36b56e8489dee8fbc777c61959f60ec0f1f11817e8f2415f429552846aed", size = 10467650, upload-time = "2026-01-22T22:30:08.578Z" }, + { url = "https://files.pythonhosted.org/packages/a3/b1/c5de3fd2d5a831fcae21beda5e3589c0ba67eec8202e992388e4b17a6040/ruff-0.14.14-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:6006a0082336e7920b9573ef8a7f52eec837add1265cc74e04ea8a4368cd704c", size = 10883245, upload-time = "2026-01-22T22:30:04.155Z" }, + { url = "https://files.pythonhosted.org/packages/b8/7c/3c1db59a10e7490f8f6f8559d1db8636cbb13dccebf18686f4e3c9d7c772/ruff-0.14.14-py3-none-macosx_11_0_arm64.whl", hash = "sha256:026c1d25996818f0bf498636686199d9bd0d9d6341c9c2c3b62e2a0198b758de", size = 10231273, upload-time = "2026-01-22T22:30:34.642Z" }, + { url = "https://files.pythonhosted.org/packages/a1/6e/5e0e0d9674be0f8581d1f5e0f0a04761203affce3232c1a1189d0e3b4dad/ruff-0.14.14-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f666445819d31210b71e0a6d1c01e24447a20b85458eea25a25fe8142210ae0e", size = 10585753, upload-time = "2026-01-22T22:30:31.781Z" }, + { url = "https://files.pythonhosted.org/packages/23/09/754ab09f46ff1884d422dc26d59ba18b4e5d355be147721bb2518aa2a014/ruff-0.14.14-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:3c0f18b922c6d2ff9a5e6c3ee16259adc513ca775bcf82c67ebab7cbd9da5bc8", size = 10286052, upload-time = "2026-01-22T22:30:24.827Z" }, + { url = "https://files.pythonhosted.org/packages/c8/cc/e71f88dd2a12afb5f50733851729d6b571a7c3a35bfdb16c3035132675a0/ruff-0.14.14-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1629e67489c2dea43e8658c3dba659edbfd87361624b4040d1df04c9740ae906", size = 11043637, upload-time = "2026-01-22T22:30:13.239Z" }, + { url = "https://files.pythonhosted.org/packages/67/b2/397245026352494497dac935d7f00f1468c03a23a0c5db6ad8fc49ca3fb2/ruff-0.14.14-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:27493a2131ea0f899057d49d303e4292b2cae2bb57253c1ed1f256fbcd1da480", size = 12194761, upload-time = "2026-01-22T22:30:22.542Z" }, + { url = "https://files.pythonhosted.org/packages/5b/06/06ef271459f778323112c51b7587ce85230785cd64e91772034ddb88f200/ruff-0.14.14-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:01ff589aab3f5b539e35db38425da31a57521efd1e4ad1ae08fc34dbe30bd7df", size = 12005701, upload-time = "2026-01-22T22:30:20.499Z" }, + { url = "https://files.pythonhosted.org/packages/41/d6/99364514541cf811ccc5ac44362f88df66373e9fec1b9d1c4cc830593fe7/ruff-0.14.14-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:1cc12d74eef0f29f51775f5b755913eb523546b88e2d733e1d701fe65144e89b", size = 11282455, upload-time = "2026-01-22T22:29:59.679Z" }, + { url = "https://files.pythonhosted.org/packages/ca/71/37daa46f89475f8582b7762ecd2722492df26421714a33e72ccc9a84d7a5/ruff-0.14.14-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bb8481604b7a9e75eff53772496201690ce2687067e038b3cc31aaf16aa0b974", size = 11215882, upload-time = "2026-01-22T22:29:57.032Z" }, + { url = "https://files.pythonhosted.org/packages/2c/10/a31f86169ec91c0705e618443ee74ede0bdd94da0a57b28e72db68b2dbac/ruff-0.14.14-py3-none-manylinux_2_31_riscv64.whl", hash = "sha256:14649acb1cf7b5d2d283ebd2f58d56b75836ed8c6f329664fa91cdea19e76e66", size = 11180549, upload-time = "2026-01-22T22:30:27.175Z" }, + { url = "https://files.pythonhosted.org/packages/fd/1e/c723f20536b5163adf79bdd10c5f093414293cdf567eed9bdb7b83940f3f/ruff-0.14.14-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:e8058d2145566510790eab4e2fad186002e288dec5e0d343a92fe7b0bc1b3e13", size = 10543416, upload-time = "2026-01-22T22:30:01.964Z" }, + { url = "https://files.pythonhosted.org/packages/3e/34/8a84cea7e42c2d94ba5bde1d7a4fae164d6318f13f933d92da6d7c2041ff/ruff-0.14.14-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:e651e977a79e4c758eb807f0481d673a67ffe53cfa92209781dfa3a996cf8412", size = 10285491, upload-time = "2026-01-22T22:30:29.51Z" }, + { url = "https://files.pythonhosted.org/packages/55/ef/b7c5ea0be82518906c978e365e56a77f8de7678c8bb6651ccfbdc178c29f/ruff-0.14.14-py3-none-musllinux_1_2_i686.whl", hash = "sha256:cc8b22da8d9d6fdd844a68ae937e2a0adf9b16514e9a97cc60355e2d4b219fc3", size = 10733525, upload-time = "2026-01-22T22:30:06.499Z" }, + { url = "https://files.pythonhosted.org/packages/6a/5b/aaf1dfbcc53a2811f6cc0a1759de24e4b03e02ba8762daabd9b6bd8c59e3/ruff-0.14.14-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:16bc890fb4cc9781bb05beb5ab4cd51be9e7cb376bf1dd3580512b24eb3fda2b", size = 11315626, upload-time = "2026-01-22T22:30:36.848Z" }, + { url = "https://files.pythonhosted.org/packages/2c/aa/9f89c719c467dfaf8ad799b9bae0df494513fb21d31a6059cb5870e57e74/ruff-0.14.14-py3-none-win32.whl", hash = "sha256:b530c191970b143375b6a68e6f743800b2b786bbcf03a7965b06c4bf04568167", size = 10502442, upload-time = "2026-01-22T22:30:38.93Z" }, + { url = "https://files.pythonhosted.org/packages/87/44/90fa543014c45560cae1fffc63ea059fb3575ee6e1cb654562197e5d16fb/ruff-0.14.14-py3-none-win_amd64.whl", hash = "sha256:3dde1435e6b6fe5b66506c1dff67a421d0b7f6488d466f651c07f4cab3bf20fd", size = 11630486, upload-time = "2026-01-22T22:30:10.852Z" }, + { url = "https://files.pythonhosted.org/packages/9e/6a/40fee331a52339926a92e17ae748827270b288a35ef4a15c9c8f2ec54715/ruff-0.14.14-py3-none-win_arm64.whl", hash = "sha256:56e6981a98b13a32236a72a8da421d7839221fa308b223b9283312312e5ac76c", size = 10920448, upload-time = "2026-01-22T22:30:15.417Z" }, +] + +[[package]] +name = "send2trash" +version = "2.1.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/c5/f0/184b4b5f8d00f2a92cf96eec8967a3d550b52cf94362dad1100df9e48d57/send2trash-2.1.0.tar.gz", hash = "sha256:1c72b39f09457db3c05ce1d19158c2cbef4c32b8bedd02c155e49282b7ea7459", size = 17255, upload-time = "2026-01-14T06:27:36.056Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/1c/78/504fdd027da3b84ff1aecd9f6957e65f35134534ccc6da8628eb71e76d3f/send2trash-2.1.0-py3-none-any.whl", hash = "sha256:0da2f112e6d6bb22de6aa6daa7e144831a4febf2a87261451c4ad849fe9a873c", size = 17610, upload-time = "2026-01-14T06:27:35.218Z" }, +] + +[[package]] +name = "setuptools" +version = "80.10.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/76/95/faf61eb8363f26aa7e1d762267a8d602a1b26d4f3a1e758e92cb3cb8b054/setuptools-80.10.2.tar.gz", hash = "sha256:8b0e9d10c784bf7d262c4e5ec5d4ec94127ce206e8738f29a437945fbc219b70", size = 1200343, upload-time = "2026-01-25T22:38:17.252Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/94/b8/f1f62a5e3c0ad2ff1d189590bfa4c46b4f3b6e49cef6f26c6ee4e575394d/setuptools-80.10.2-py3-none-any.whl", hash = "sha256:95b30ddfb717250edb492926c92b5221f7ef3fbcc2b07579bcd4a27da21d0173", size = 1064234, upload-time = "2026-01-25T22:38:15.216Z" }, +] + +[[package]] +name = "six" +version = "1.17.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/94/e7/b2c673351809dca68a0e064b6af791aa332cf192da575fd474ed7d6f16a2/six-1.17.0.tar.gz", hash = "sha256:ff70335d468e7eb6ec65b95b99d3a2836546063f63acc5171de367e834932a81", size = 34031, upload-time = "2024-12-04T17:35:28.174Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/b7/ce/149a00dd41f10bc29e5921b496af8b574d8413afcd5e30dfa0ed46c2cc5e/six-1.17.0-py2.py3-none-any.whl", hash = "sha256:4721f391ed90541fddacab5acf947aa0d3dc7d27b2e1e8eda2be8970586c3274", size = 11050, upload-time = "2024-12-04T17:35:26.475Z" }, +] + +[[package]] +name = "sortedcontainers" +version = "2.4.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/e8/c4/ba2f8066cceb6f23394729afe52f3bf7adec04bf9ed2c820b39e19299111/sortedcontainers-2.4.0.tar.gz", hash = "sha256:25caa5a06cc30b6b83d11423433f65d1f9d76c4c6a0c90e3379eaa43b9bfdb88", size = 30594, upload-time = "2021-05-16T22:03:42.897Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/32/46/9cb0e58b2deb7f82b84065f37f3bffeb12413f947f9388e4cac22c4621ce/sortedcontainers-2.4.0-py2.py3-none-any.whl", hash = "sha256:a163dcaede0f1c021485e957a39245190e74249897e2ae4b2aa38595db237ee0", size = 29575, upload-time = "2021-05-16T22:03:41.177Z" }, +] + +[[package]] +name = "soupsieve" +version = "2.8.3" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/7b/ae/2d9c981590ed9999a0d91755b47fc74f74de286b0f5cee14c9269041e6c4/soupsieve-2.8.3.tar.gz", hash = "sha256:3267f1eeea4251fb42728b6dfb746edc9acaffc4a45b27e19450b676586e8349", size = 118627, upload-time = "2026-01-20T04:27:02.457Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/46/2c/1462b1d0a634697ae9e55b3cecdcb64788e8b7d63f54d923fcd0bb140aed/soupsieve-2.8.3-py3-none-any.whl", hash = "sha256:ed64f2ba4eebeab06cc4962affce381647455978ffc1e36bb79a545b91f45a95", size = 37016, upload-time = "2026-01-20T04:27:01.012Z" }, +] + +[[package]] +name = "sphobjinv" +version = "2.3.1.3" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "attrs" }, + { name = "certifi" }, + { name = "jsonschema" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/77/9a/4887ebe7b46f4669a896dc286a3ac559101d2ceadbbea4614472960c2222/sphobjinv-2.3.1.3.tar.gz", hash = "sha256:a1d51e4cf3d968b9e0d3ed1cbccea0071e5e5795f24a2d7401a4e37d6bd75717", size = 268835, upload-time = "2025-05-26T15:18:16.994Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/63/f9/f48a8f489c8ae8930f12c558b4dd26da96791837747fca87e9da2643f12d/sphobjinv-2.3.1.3-py3-none-any.whl", hash = "sha256:41fc39f6f740a707cfe5b24c1a3a4a6e4ddbdd6429a59bf21f0b5ef1fddf932a", size = 50812, upload-time = "2025-05-26T15:18:10.636Z" }, +] + +[[package]] +name = "sqlalchemy" +version = "2.0.46" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "greenlet", marker = "platform_machine == 'AMD64' or platform_machine == 'WIN32' or platform_machine == 'aarch64' or platform_machine == 'amd64' or platform_machine == 'ppc64le' or platform_machine == 'win32' or platform_machine == 'x86_64'" }, + { name = "typing-extensions" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/06/aa/9ce0f3e7a9829ead5c8ce549392f33a12c4555a6c0609bb27d882e9c7ddf/sqlalchemy-2.0.46.tar.gz", hash = "sha256:cf36851ee7219c170bb0793dbc3da3e80c582e04a5437bc601bfe8c85c9216d7", size = 9865393, upload-time = "2026-01-21T18:03:45.119Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/69/ac/b42ad16800d0885105b59380ad69aad0cce5a65276e269ce2729a2343b6a/sqlalchemy-2.0.46-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:261c4b1f101b4a411154f1da2b76497d73abbfc42740029205d4d01fa1052684", size = 2154851, upload-time = "2026-01-21T18:27:30.54Z" }, + { url = "https://files.pythonhosted.org/packages/a0/60/d8710068cb79f64d002ebed62a7263c00c8fd95f4ebd4b5be8f7ca93f2bc/sqlalchemy-2.0.46-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:181903fe8c1b9082995325f1b2e84ac078b1189e2819380c2303a5f90e114a62", size = 3311241, upload-time = "2026-01-21T18:32:33.45Z" }, + { url = "https://files.pythonhosted.org/packages/2b/0f/20c71487c7219ab3aa7421c7c62d93824c97c1460f2e8bb72404b0192d13/sqlalchemy-2.0.46-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:590be24e20e2424a4c3c1b0835e9405fa3d0af5823a1a9fc02e5dff56471515f", size = 3310741, upload-time = "2026-01-21T18:44:57.887Z" }, + { url = "https://files.pythonhosted.org/packages/65/80/d26d00b3b249ae000eee4db206fcfc564bf6ca5030e4747adf451f4b5108/sqlalchemy-2.0.46-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:7568fe771f974abadce52669ef3a03150ff03186d8eb82613bc8adc435a03f01", size = 3263116, upload-time = "2026-01-21T18:32:35.044Z" }, + { url = "https://files.pythonhosted.org/packages/da/ee/74dda7506640923821340541e8e45bd3edd8df78664f1f2e0aae8077192b/sqlalchemy-2.0.46-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:ebf7e1e78af38047e08836d33502c7a278915698b7c2145d045f780201679999", size = 3285327, upload-time = "2026-01-21T18:44:59.254Z" }, + { url = "https://files.pythonhosted.org/packages/9f/25/6dcf8abafff1389a21c7185364de145107b7394ecdcb05233815b236330d/sqlalchemy-2.0.46-cp311-cp311-win32.whl", hash = "sha256:9d80ea2ac519c364a7286e8d765d6cd08648f5b21ca855a8017d9871f075542d", size = 2114564, upload-time = "2026-01-21T18:33:15.85Z" }, + { url = "https://files.pythonhosted.org/packages/93/5f/e081490f8523adc0088f777e4ebad3cac21e498ec8a3d4067074e21447a1/sqlalchemy-2.0.46-cp311-cp311-win_amd64.whl", hash = "sha256:585af6afe518732d9ccd3aea33af2edaae4a7aa881af5d8f6f4fe3a368699597", size = 2139233, upload-time = "2026-01-21T18:33:17.528Z" }, + { url = "https://files.pythonhosted.org/packages/b6/35/d16bfa235c8b7caba3730bba43e20b1e376d2224f407c178fbf59559f23e/sqlalchemy-2.0.46-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:3a9a72b0da8387f15d5810f1facca8f879de9b85af8c645138cba61ea147968c", size = 2153405, upload-time = "2026-01-21T19:05:54.143Z" }, + { url = "https://files.pythonhosted.org/packages/06/6c/3192e24486749862f495ddc6584ed730c0c994a67550ec395d872a2ad650/sqlalchemy-2.0.46-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:2347c3f0efc4de367ba00218e0ae5c4ba2306e47216ef80d6e31761ac97cb0b9", size = 3334702, upload-time = "2026-01-21T18:46:45.384Z" }, + { url = "https://files.pythonhosted.org/packages/ea/a2/b9f33c8d68a3747d972a0bb758c6b63691f8fb8a49014bc3379ba15d4274/sqlalchemy-2.0.46-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:9094c8b3197db12aa6f05c51c05daaad0a92b8c9af5388569847b03b1007fb1b", size = 3347664, upload-time = "2026-01-21T18:40:09.979Z" }, + { url = "https://files.pythonhosted.org/packages/aa/d2/3e59e2a91eaec9db7e8dc6b37b91489b5caeb054f670f32c95bcba98940f/sqlalchemy-2.0.46-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:37fee2164cf21417478b6a906adc1a91d69ae9aba8f9533e67ce882f4bb1de53", size = 3277372, upload-time = "2026-01-21T18:46:47.168Z" }, + { url = "https://files.pythonhosted.org/packages/dd/dd/67bc2e368b524e2192c3927b423798deda72c003e73a1e94c21e74b20a85/sqlalchemy-2.0.46-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:b1e14b2f6965a685c7128bd315e27387205429c2e339eeec55cb75ca4ab0ea2e", size = 3312425, upload-time = "2026-01-21T18:40:11.548Z" }, + { url = "https://files.pythonhosted.org/packages/43/82/0ecd68e172bfe62247e96cb47867c2d68752566811a4e8c9d8f6e7c38a65/sqlalchemy-2.0.46-cp312-cp312-win32.whl", hash = "sha256:412f26bb4ba942d52016edc8d12fb15d91d3cd46b0047ba46e424213ad407bcb", size = 2113155, upload-time = "2026-01-21T18:42:49.748Z" }, + { url = "https://files.pythonhosted.org/packages/bc/2a/2821a45742073fc0331dc132552b30de68ba9563230853437cac54b2b53e/sqlalchemy-2.0.46-cp312-cp312-win_amd64.whl", hash = "sha256:ea3cd46b6713a10216323cda3333514944e510aa691c945334713fca6b5279ff", size = 2140078, upload-time = "2026-01-21T18:42:51.197Z" }, + { url = "https://files.pythonhosted.org/packages/fc/a1/9c4efa03300926601c19c18582531b45aededfb961ab3c3585f1e24f120b/sqlalchemy-2.0.46-py3-none-any.whl", hash = "sha256:f9c11766e7e7c0a2767dda5acb006a118640c9fc0a4104214b96269bfb78399e", size = 1937882, upload-time = "2026-01-21T18:22:10.456Z" }, +] + +[[package]] +name = "stack-data" +version = "0.6.3" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "asttokens" }, + { name = "executing" }, + { name = "pure-eval" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/28/e3/55dcc2cfbc3ca9c29519eb6884dd1415ecb53b0e934862d3559ddcb7e20b/stack_data-0.6.3.tar.gz", hash = "sha256:836a778de4fec4dcd1dcd89ed8abff8a221f58308462e1c4aa2a3cf30148f0b9", size = 44707, upload-time = "2023-09-30T13:58:05.479Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/f1/7b/ce1eafaf1a76852e2ec9b22edecf1daa58175c090266e9f6c64afcd81d91/stack_data-0.6.3-py3-none-any.whl", hash = "sha256:d5558e0c25a4cb0853cddad3d77da9891a08cb85dd9f9f91b9f8cd66e511e695", size = 24521, upload-time = "2023-09-30T13:58:03.53Z" }, +] + +[[package]] +name = "tabulate" +version = "0.9.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/ec/fe/802052aecb21e3797b8f7902564ab6ea0d60ff8ca23952079064155d1ae1/tabulate-0.9.0.tar.gz", hash = "sha256:0095b12bf5966de529c0feb1fa08671671b3368eec77d7ef7ab114be2c068b3c", size = 81090, upload-time = "2022-10-06T17:21:48.54Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/40/44/4a5f08c96eb108af5cb50b41f76142f0afa346dfa99d5296fe7202a11854/tabulate-0.9.0-py3-none-any.whl", hash = "sha256:024ca478df22e9340661486f85298cff5f6dcdba14f3813e8830015b9ed1948f", size = 35252, upload-time = "2022-10-06T17:21:44.262Z" }, +] + +[[package]] +name = "terminado" +version = "0.18.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "ptyprocess", marker = "os_name != 'nt'" }, + { name = "pywinpty", marker = "os_name == 'nt'" }, + { name = "tornado" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/8a/11/965c6fd8e5cc254f1fe142d547387da17a8ebfd75a3455f637c663fb38a0/terminado-0.18.1.tar.gz", hash = "sha256:de09f2c4b85de4765f7714688fff57d3e75bad1f909b589fde880460c753fd2e", size = 32701, upload-time = "2024-03-12T14:34:39.026Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/6a/9e/2064975477fdc887e47ad42157e214526dcad8f317a948dee17e1659a62f/terminado-0.18.1-py3-none-any.whl", hash = "sha256:a4468e1b37bb318f8a86514f65814e1afc977cf29b3992a4500d9dd305dcceb0", size = 14154, upload-time = "2024-03-12T14:34:36.569Z" }, +] + +[[package]] +name = "tinycss2" +version = "1.4.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "webencodings" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/7a/fd/7a5ee21fd08ff70d3d33a5781c255cbe779659bd03278feb98b19ee550f4/tinycss2-1.4.0.tar.gz", hash = "sha256:10c0972f6fc0fbee87c3edb76549357415e94548c1ae10ebccdea16fb404a9b7", size = 87085, upload-time = "2024-10-24T14:58:29.895Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/e6/34/ebdc18bae6aa14fbee1a08b63c015c72b64868ff7dae68808ab500c492e2/tinycss2-1.4.0-py3-none-any.whl", hash = "sha256:3a49cf47b7675da0b15d0c6e1df8df4ebd96e9394bb905a5775adb0d884c5289", size = 26610, upload-time = "2024-10-24T14:58:28.029Z" }, +] + +[[package]] +name = "tomli" +version = "2.4.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/82/30/31573e9457673ab10aa432461bee537ce6cef177667deca369efb79df071/tomli-2.4.0.tar.gz", hash = "sha256:aa89c3f6c277dd275d8e243ad24f3b5e701491a860d5121f2cdd399fbb31fc9c", size = 17477, upload-time = "2026-01-11T11:22:38.165Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/3c/d9/3dc2289e1f3b32eb19b9785b6a006b28ee99acb37d1d47f78d4c10e28bf8/tomli-2.4.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:b5ef256a3fd497d4973c11bf142e9ed78b150d36f5773f1ca6088c230ffc5867", size = 153663, upload-time = "2026-01-11T11:21:45.27Z" }, + { url = "https://files.pythonhosted.org/packages/51/32/ef9f6845e6b9ca392cd3f64f9ec185cc6f09f0a2df3db08cbe8809d1d435/tomli-2.4.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:5572e41282d5268eb09a697c89a7bee84fae66511f87533a6f88bd2f7b652da9", size = 148469, upload-time = "2026-01-11T11:21:46.873Z" }, + { url = "https://files.pythonhosted.org/packages/d6/c2/506e44cce89a8b1b1e047d64bd495c22c9f71f21e05f380f1a950dd9c217/tomli-2.4.0-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:551e321c6ba03b55676970b47cb1b73f14a0a4dce6a3e1a9458fd6d921d72e95", size = 236039, upload-time = "2026-01-11T11:21:48.503Z" }, + { url = "https://files.pythonhosted.org/packages/b3/40/e1b65986dbc861b7e986e8ec394598187fa8aee85b1650b01dd925ca0be8/tomli-2.4.0-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:5e3f639a7a8f10069d0e15408c0b96a2a828cfdec6fca05296ebcdcc28ca7c76", size = 243007, upload-time = "2026-01-11T11:21:49.456Z" }, + { url = "https://files.pythonhosted.org/packages/9c/6f/6e39ce66b58a5b7ae572a0f4352ff40c71e8573633deda43f6a379d56b3e/tomli-2.4.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:1b168f2731796b045128c45982d3a4874057626da0e2ef1fdd722848b741361d", size = 240875, upload-time = "2026-01-11T11:21:50.755Z" }, + { url = "https://files.pythonhosted.org/packages/aa/ad/cb089cb190487caa80204d503c7fd0f4d443f90b95cf4ef5cf5aa0f439b0/tomli-2.4.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:133e93646ec4300d651839d382d63edff11d8978be23da4cc106f5a18b7d0576", size = 246271, upload-time = "2026-01-11T11:21:51.81Z" }, + { url = "https://files.pythonhosted.org/packages/0b/63/69125220e47fd7a3a27fd0de0c6398c89432fec41bc739823bcc66506af6/tomli-2.4.0-cp311-cp311-win32.whl", hash = "sha256:b6c78bdf37764092d369722d9946cb65b8767bfa4110f902a1b2542d8d173c8a", size = 96770, upload-time = "2026-01-11T11:21:52.647Z" }, + { url = "https://files.pythonhosted.org/packages/1e/0d/a22bb6c83f83386b0008425a6cd1fa1c14b5f3dd4bad05e98cf3dbbf4a64/tomli-2.4.0-cp311-cp311-win_amd64.whl", hash = "sha256:d3d1654e11d724760cdb37a3d7691f0be9db5fbdaef59c9f532aabf87006dbaa", size = 107626, upload-time = "2026-01-11T11:21:53.459Z" }, + { url = "https://files.pythonhosted.org/packages/2f/6d/77be674a3485e75cacbf2ddba2b146911477bd887dda9d8c9dfb2f15e871/tomli-2.4.0-cp311-cp311-win_arm64.whl", hash = "sha256:cae9c19ed12d4e8f3ebf46d1a75090e4c0dc16271c5bce1c833ac168f08fb614", size = 94842, upload-time = "2026-01-11T11:21:54.831Z" }, + { url = "https://files.pythonhosted.org/packages/3c/43/7389a1869f2f26dba52404e1ef13b4784b6b37dac93bac53457e3ff24ca3/tomli-2.4.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:920b1de295e72887bafa3ad9f7a792f811847d57ea6b1215154030cf131f16b1", size = 154894, upload-time = "2026-01-11T11:21:56.07Z" }, + { url = "https://files.pythonhosted.org/packages/e9/05/2f9bf110b5294132b2edf13fe6ca6ae456204f3d749f623307cbb7a946f2/tomli-2.4.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:7d6d9a4aee98fac3eab4952ad1d73aee87359452d1c086b5ceb43ed02ddb16b8", size = 149053, upload-time = "2026-01-11T11:21:57.467Z" }, + { url = "https://files.pythonhosted.org/packages/e8/41/1eda3ca1abc6f6154a8db4d714a4d35c4ad90adc0bcf700657291593fbf3/tomli-2.4.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:36b9d05b51e65b254ea6c2585b59d2c4cb91c8a3d91d0ed0f17591a29aaea54a", size = 243481, upload-time = "2026-01-11T11:21:58.661Z" }, + { url = "https://files.pythonhosted.org/packages/d2/6d/02ff5ab6c8868b41e7d4b987ce2b5f6a51d3335a70aa144edd999e055a01/tomli-2.4.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:1c8a885b370751837c029ef9bc014f27d80840e48bac415f3412e6593bbc18c1", size = 251720, upload-time = "2026-01-11T11:22:00.178Z" }, + { url = "https://files.pythonhosted.org/packages/7b/57/0405c59a909c45d5b6f146107c6d997825aa87568b042042f7a9c0afed34/tomli-2.4.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:8768715ffc41f0008abe25d808c20c3d990f42b6e2e58305d5da280ae7d1fa3b", size = 247014, upload-time = "2026-01-11T11:22:01.238Z" }, + { url = "https://files.pythonhosted.org/packages/2c/0e/2e37568edd944b4165735687cbaf2fe3648129e440c26d02223672ee0630/tomli-2.4.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:7b438885858efd5be02a9a133caf5812b8776ee0c969fea02c45e8e3f296ba51", size = 251820, upload-time = "2026-01-11T11:22:02.727Z" }, + { url = "https://files.pythonhosted.org/packages/5a/1c/ee3b707fdac82aeeb92d1a113f803cf6d0f37bdca0849cb489553e1f417a/tomli-2.4.0-cp312-cp312-win32.whl", hash = "sha256:0408e3de5ec77cc7f81960c362543cbbd91ef883e3138e81b729fc3eea5b9729", size = 97712, upload-time = "2026-01-11T11:22:03.777Z" }, + { url = "https://files.pythonhosted.org/packages/69/13/c07a9177d0b3bab7913299b9278845fc6eaaca14a02667c6be0b0a2270c8/tomli-2.4.0-cp312-cp312-win_amd64.whl", hash = "sha256:685306e2cc7da35be4ee914fd34ab801a6acacb061b6a7abca922aaf9ad368da", size = 108296, upload-time = "2026-01-11T11:22:04.86Z" }, + { url = "https://files.pythonhosted.org/packages/18/27/e267a60bbeeee343bcc279bb9e8fbed0cbe224bc7b2a3dc2975f22809a09/tomli-2.4.0-cp312-cp312-win_arm64.whl", hash = "sha256:5aa48d7c2356055feef06a43611fc401a07337d5b006be13a30f6c58f869e3c3", size = 94553, upload-time = "2026-01-11T11:22:05.854Z" }, + { url = "https://files.pythonhosted.org/packages/23/d1/136eb2cb77520a31e1f64cbae9d33ec6df0d78bdf4160398e86eec8a8754/tomli-2.4.0-py3-none-any.whl", hash = "sha256:1f776e7d669ebceb01dee46484485f43a4048746235e683bcdffacdf1fb4785a", size = 14477, upload-time = "2026-01-11T11:22:37.446Z" }, +] + +[[package]] +name = "tornado" +version = "6.5.4" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/37/1d/0a336abf618272d53f62ebe274f712e213f5a03c0b2339575430b8362ef2/tornado-6.5.4.tar.gz", hash = "sha256:a22fa9047405d03260b483980635f0b041989d8bcc9a313f8fe18b411d84b1d7", size = 513632, upload-time = "2025-12-15T19:21:03.836Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/ab/a9/e94a9d5224107d7ce3cc1fab8d5dc97f5ea351ccc6322ee4fb661da94e35/tornado-6.5.4-cp39-abi3-macosx_10_9_universal2.whl", hash = "sha256:d6241c1a16b1c9e4cc28148b1cda97dd1c6cb4fb7068ac1bedc610768dff0ba9", size = 443909, upload-time = "2025-12-15T19:20:48.382Z" }, + { url = "https://files.pythonhosted.org/packages/db/7e/f7b8d8c4453f305a51f80dbb49014257bb7d28ccb4bbb8dd328ea995ecad/tornado-6.5.4-cp39-abi3-macosx_10_9_x86_64.whl", hash = "sha256:2d50f63dda1d2cac3ae1fa23d254e16b5e38153758470e9956cbc3d813d40843", size = 442163, upload-time = "2025-12-15T19:20:49.791Z" }, + { url = "https://files.pythonhosted.org/packages/ba/b5/206f82d51e1bfa940ba366a8d2f83904b15942c45a78dd978b599870ab44/tornado-6.5.4-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d1cf66105dc6acb5af613c054955b8137e34a03698aa53272dbda4afe252be17", size = 445746, upload-time = "2025-12-15T19:20:51.491Z" }, + { url = "https://files.pythonhosted.org/packages/8e/9d/1a3338e0bd30ada6ad4356c13a0a6c35fbc859063fa7eddb309183364ac1/tornado-6.5.4-cp39-abi3-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:50ff0a58b0dc97939d29da29cd624da010e7f804746621c78d14b80238669335", size = 445083, upload-time = "2025-12-15T19:20:52.778Z" }, + { url = "https://files.pythonhosted.org/packages/50/d4/e51d52047e7eb9a582da59f32125d17c0482d065afd5d3bc435ff2120dc5/tornado-6.5.4-cp39-abi3-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e5fb5e04efa54cf0baabdd10061eb4148e0be137166146fff835745f59ab9f7f", size = 445315, upload-time = "2025-12-15T19:20:53.996Z" }, + { url = "https://files.pythonhosted.org/packages/27/07/2273972f69ca63dbc139694a3fc4684edec3ea3f9efabf77ed32483b875c/tornado-6.5.4-cp39-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:9c86b1643b33a4cd415f8d0fe53045f913bf07b4a3ef646b735a6a86047dda84", size = 446003, upload-time = "2025-12-15T19:20:56.101Z" }, + { url = "https://files.pythonhosted.org/packages/d1/83/41c52e47502bf7260044413b6770d1a48dda2f0246f95ee1384a3cd9c44a/tornado-6.5.4-cp39-abi3-musllinux_1_2_i686.whl", hash = "sha256:6eb82872335a53dd063a4f10917b3efd28270b56a33db69009606a0312660a6f", size = 445412, upload-time = "2025-12-15T19:20:57.398Z" }, + { url = "https://files.pythonhosted.org/packages/10/c7/bc96917f06cbee182d44735d4ecde9c432e25b84f4c2086143013e7b9e52/tornado-6.5.4-cp39-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:6076d5dda368c9328ff41ab5d9dd3608e695e8225d1cd0fd1e006f05da3635a8", size = 445392, upload-time = "2025-12-15T19:20:58.692Z" }, + { url = "https://files.pythonhosted.org/packages/0c/1a/d7592328d037d36f2d2462f4bc1fbb383eec9278bc786c1b111cbbd44cfa/tornado-6.5.4-cp39-abi3-win32.whl", hash = "sha256:1768110f2411d5cd281bac0a090f707223ce77fd110424361092859e089b38d1", size = 446481, upload-time = "2025-12-15T19:21:00.008Z" }, + { url = "https://files.pythonhosted.org/packages/d6/6d/c69be695a0a64fd37a97db12355a035a6d90f79067a3cf936ec2b1dc38cd/tornado-6.5.4-cp39-abi3-win_amd64.whl", hash = "sha256:fa07d31e0cd85c60713f2b995da613588aa03e1303d75705dca6af8babc18ddc", size = 446886, upload-time = "2025-12-15T19:21:01.287Z" }, + { url = "https://files.pythonhosted.org/packages/50/49/8dc3fd90902f70084bd2cd059d576ddb4f8bb44c2c7c0e33a11422acb17e/tornado-6.5.4-cp39-abi3-win_arm64.whl", hash = "sha256:053e6e16701eb6cbe641f308f4c1a9541f91b6261991160391bfc342e8a551a1", size = 445910, upload-time = "2025-12-15T19:21:02.571Z" }, +] + +[[package]] +name = "traitlets" +version = "5.14.3" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/eb/79/72064e6a701c2183016abbbfedaba506d81e30e232a68c9f0d6f6fcd1574/traitlets-5.14.3.tar.gz", hash = "sha256:9ed0579d3502c94b4b3732ac120375cda96f923114522847de4b3bb98b96b6b7", size = 161621, upload-time = "2024-04-19T11:11:49.746Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/00/c0/8f5d070730d7836adc9c9b6408dec68c6ced86b304a9b26a14df072a6e8c/traitlets-5.14.3-py3-none-any.whl", hash = "sha256:b74e89e397b1ed28cc831db7aea759ba6640cb3de13090ca145426688ff1ac4f", size = 85359, upload-time = "2024-04-19T11:11:46.763Z" }, +] + +[[package]] +name = "typing-extensions" +version = "4.15.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/72/94/1a15dd82efb362ac84269196e94cf00f187f7ed21c242792a923cdb1c61f/typing_extensions-4.15.0.tar.gz", hash = "sha256:0cea48d173cc12fa28ecabc3b837ea3cf6f38c6d1136f85cbaaf598984861466", size = 109391, upload-time = "2025-08-25T13:49:26.313Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/18/67/36e9267722cc04a6b9f15c7f3441c2363321a3ea07da7ae0c0707beb2a9c/typing_extensions-4.15.0-py3-none-any.whl", hash = "sha256:f0fa19c6845758ab08074a0cfa8b7aecb71c999ca73d62883bc25cc018c4e548", size = 44614, upload-time = "2025-08-25T13:49:24.86Z" }, +] + +[[package]] +name = "typing-inspection" +version = "0.4.2" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "typing-extensions" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/55/e3/70399cb7dd41c10ac53367ae42139cf4b1ca5f36bb3dc6c9d33acdb43655/typing_inspection-0.4.2.tar.gz", hash = "sha256:ba561c48a67c5958007083d386c3295464928b01faa735ab8547c5692e87f464", size = 75949, upload-time = "2025-10-01T02:14:41.687Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/dc/9b/47798a6c91d8bdb567fe2698fe81e0c6b7cb7ef4d13da4114b41d239f65d/typing_inspection-0.4.2-py3-none-any.whl", hash = "sha256:4ed1cacbdc298c220f1bd249ed5287caa16f34d44ef4e9c3d0cbad5b521545e7", size = 14611, upload-time = "2025-10-01T02:14:40.154Z" }, +] + +[[package]] +name = "tzdata" +version = "2025.3" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/5e/a7/c202b344c5ca7daf398f3b8a477eeb205cf3b6f32e7ec3a6bac0629ca975/tzdata-2025.3.tar.gz", hash = "sha256:de39c2ca5dc7b0344f2eba86f49d614019d29f060fc4ebc8a417896a620b56a7", size = 196772, upload-time = "2025-12-13T17:45:35.667Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/c7/b0/003792df09decd6849a5e39c28b513c06e84436a54440380862b5aeff25d/tzdata-2025.3-py2.py3-none-any.whl", hash = "sha256:06a47e5700f3081aab02b2e513160914ff0694bce9947d6b76ebd6bf57cfc5d1", size = 348521, upload-time = "2025-12-13T17:45:33.889Z" }, +] + +[[package]] +name = "uri-template" +version = "1.3.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/31/c7/0336f2bd0bcbada6ccef7aaa25e443c118a704f828a0620c6fa0207c1b64/uri-template-1.3.0.tar.gz", hash = "sha256:0e00f8eb65e18c7de20d595a14336e9f337ead580c70934141624b6d1ffdacc7", size = 21678, upload-time = "2023-06-21T01:49:05.374Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/e7/00/3fca040d7cf8a32776d3d81a00c8ee7457e00f80c649f1e4a863c8321ae9/uri_template-1.3.0-py3-none-any.whl", hash = "sha256:a44a133ea12d44a0c0f06d7d42a52d71282e77e2f937d8abd5655b8d56fc1363", size = 11140, upload-time = "2023-06-21T01:49:03.467Z" }, +] + +[[package]] +name = "urllib3" +version = "2.6.3" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/c7/24/5f1b3bdffd70275f6661c76461e25f024d5a38a46f04aaca912426a2b1d3/urllib3-2.6.3.tar.gz", hash = "sha256:1b62b6884944a57dbe321509ab94fd4d3b307075e0c2eae991ac71ee15ad38ed", size = 435556, upload-time = "2026-01-07T16:24:43.925Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/39/08/aaaad47bc4e9dc8c725e68f9d04865dbcb2052843ff09c97b08904852d84/urllib3-2.6.3-py3-none-any.whl", hash = "sha256:bf272323e553dfb2e87d9bfd225ca7b0f467b919d7bbd355436d3fd37cb0acd4", size = 131584, upload-time = "2026-01-07T16:24:42.685Z" }, +] + +[[package]] +name = "watchdog" +version = "6.0.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/db/7d/7f3d619e951c88ed75c6037b246ddcf2d322812ee8ea189be89511721d54/watchdog-6.0.0.tar.gz", hash = "sha256:9ddf7c82fda3ae8e24decda1338ede66e1c99883db93711d8fb941eaa2d8c282", size = 131220, upload-time = "2024-11-01T14:07:13.037Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/e0/24/d9be5cd6642a6aa68352ded4b4b10fb0d7889cb7f45814fb92cecd35f101/watchdog-6.0.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:6eb11feb5a0d452ee41f824e271ca311a09e250441c262ca2fd7ebcf2461a06c", size = 96393, upload-time = "2024-11-01T14:06:31.756Z" }, + { url = "https://files.pythonhosted.org/packages/63/7a/6013b0d8dbc56adca7fdd4f0beed381c59f6752341b12fa0886fa7afc78b/watchdog-6.0.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:ef810fbf7b781a5a593894e4f439773830bdecb885e6880d957d5b9382a960d2", size = 88392, upload-time = "2024-11-01T14:06:32.99Z" }, + { url = "https://files.pythonhosted.org/packages/d1/40/b75381494851556de56281e053700e46bff5b37bf4c7267e858640af5a7f/watchdog-6.0.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:afd0fe1b2270917c5e23c2a65ce50c2a4abb63daafb0d419fde368e272a76b7c", size = 89019, upload-time = "2024-11-01T14:06:34.963Z" }, + { url = "https://files.pythonhosted.org/packages/39/ea/3930d07dafc9e286ed356a679aa02d777c06e9bfd1164fa7c19c288a5483/watchdog-6.0.0-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:bdd4e6f14b8b18c334febb9c4425a878a2ac20efd1e0b231978e7b150f92a948", size = 96471, upload-time = "2024-11-01T14:06:37.745Z" }, + { url = "https://files.pythonhosted.org/packages/12/87/48361531f70b1f87928b045df868a9fd4e253d9ae087fa4cf3f7113be363/watchdog-6.0.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:c7c15dda13c4eb00d6fb6fc508b3c0ed88b9d5d374056b239c4ad1611125c860", size = 88449, upload-time = "2024-11-01T14:06:39.748Z" }, + { url = "https://files.pythonhosted.org/packages/5b/7e/8f322f5e600812e6f9a31b75d242631068ca8f4ef0582dd3ae6e72daecc8/watchdog-6.0.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:6f10cb2d5902447c7d0da897e2c6768bca89174d0c6e1e30abec5421af97a5b0", size = 89054, upload-time = "2024-11-01T14:06:41.009Z" }, + { url = "https://files.pythonhosted.org/packages/a9/c7/ca4bf3e518cb57a686b2feb4f55a1892fd9a3dd13f470fca14e00f80ea36/watchdog-6.0.0-py3-none-manylinux2014_aarch64.whl", hash = "sha256:7607498efa04a3542ae3e05e64da8202e58159aa1fa4acddf7678d34a35d4f13", size = 79079, upload-time = "2024-11-01T14:06:59.472Z" }, + { url = "https://files.pythonhosted.org/packages/5c/51/d46dc9332f9a647593c947b4b88e2381c8dfc0942d15b8edc0310fa4abb1/watchdog-6.0.0-py3-none-manylinux2014_armv7l.whl", hash = "sha256:9041567ee8953024c83343288ccc458fd0a2d811d6a0fd68c4c22609e3490379", size = 79078, upload-time = "2024-11-01T14:07:01.431Z" }, + { url = "https://files.pythonhosted.org/packages/d4/57/04edbf5e169cd318d5f07b4766fee38e825d64b6913ca157ca32d1a42267/watchdog-6.0.0-py3-none-manylinux2014_i686.whl", hash = "sha256:82dc3e3143c7e38ec49d61af98d6558288c415eac98486a5c581726e0737c00e", size = 79076, upload-time = "2024-11-01T14:07:02.568Z" }, + { url = "https://files.pythonhosted.org/packages/ab/cc/da8422b300e13cb187d2203f20b9253e91058aaf7db65b74142013478e66/watchdog-6.0.0-py3-none-manylinux2014_ppc64.whl", hash = "sha256:212ac9b8bf1161dc91bd09c048048a95ca3a4c4f5e5d4a7d1b1a7d5752a7f96f", size = 79077, upload-time = "2024-11-01T14:07:03.893Z" }, + { url = "https://files.pythonhosted.org/packages/2c/3b/b8964e04ae1a025c44ba8e4291f86e97fac443bca31de8bd98d3263d2fcf/watchdog-6.0.0-py3-none-manylinux2014_ppc64le.whl", hash = "sha256:e3df4cbb9a450c6d49318f6d14f4bbc80d763fa587ba46ec86f99f9e6876bb26", size = 79078, upload-time = "2024-11-01T14:07:05.189Z" }, + { url = "https://files.pythonhosted.org/packages/62/ae/a696eb424bedff7407801c257d4b1afda455fe40821a2be430e173660e81/watchdog-6.0.0-py3-none-manylinux2014_s390x.whl", hash = "sha256:2cce7cfc2008eb51feb6aab51251fd79b85d9894e98ba847408f662b3395ca3c", size = 79077, upload-time = "2024-11-01T14:07:06.376Z" }, + { url = "https://files.pythonhosted.org/packages/b5/e8/dbf020b4d98251a9860752a094d09a65e1b436ad181faf929983f697048f/watchdog-6.0.0-py3-none-manylinux2014_x86_64.whl", hash = "sha256:20ffe5b202af80ab4266dcd3e91aae72bf2da48c0d33bdb15c66658e685e94e2", size = 79078, upload-time = "2024-11-01T14:07:07.547Z" }, + { url = "https://files.pythonhosted.org/packages/07/f6/d0e5b343768e8bcb4cda79f0f2f55051bf26177ecd5651f84c07567461cf/watchdog-6.0.0-py3-none-win32.whl", hash = "sha256:07df1fdd701c5d4c8e55ef6cf55b8f0120fe1aef7ef39a1c6fc6bc2e606d517a", size = 79065, upload-time = "2024-11-01T14:07:09.525Z" }, + { url = "https://files.pythonhosted.org/packages/db/d9/c495884c6e548fce18a8f40568ff120bc3a4b7b99813081c8ac0c936fa64/watchdog-6.0.0-py3-none-win_amd64.whl", hash = "sha256:cbafb470cf848d93b5d013e2ecb245d4aa1c8fd0504e863ccefa32445359d680", size = 79070, upload-time = "2024-11-01T14:07:10.686Z" }, + { url = "https://files.pythonhosted.org/packages/33/e8/e40370e6d74ddba47f002a32919d91310d6074130fe4e17dabcafc15cbf1/watchdog-6.0.0-py3-none-win_ia64.whl", hash = "sha256:a1914259fa9e1454315171103c6a30961236f508b9b623eae470268bbcc6a22f", size = 79067, upload-time = "2024-11-01T14:07:11.845Z" }, +] + +[[package]] +name = "wcwidth" +version = "0.5.3" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/c2/62/a7c072fbfefb2980a00f99ca994279cb9ecf310cb2e6b2a4d2a28fe192b3/wcwidth-0.5.3.tar.gz", hash = "sha256:53123b7af053c74e9fe2e92ac810301f6139e64379031f7124574212fb3b4091", size = 157587, upload-time = "2026-01-31T03:52:10.92Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/3c/c1/d73f12f8cdb1891334a2ccf7389eed244d3941e74d80dd220badb937f3fb/wcwidth-0.5.3-py3-none-any.whl", hash = "sha256:d584eff31cd4753e1e5ff6c12e1edfdb324c995713f75d26c29807bb84bf649e", size = 92981, upload-time = "2026-01-31T03:52:09.14Z" }, +] + +[[package]] +name = "webcolors" +version = "25.10.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/1d/7a/eb316761ec35664ea5174709a68bbd3389de60d4a1ebab8808bfc264ed67/webcolors-25.10.0.tar.gz", hash = "sha256:62abae86504f66d0f6364c2a8520de4a0c47b80c03fc3a5f1815fedbef7c19bf", size = 53491, upload-time = "2025-10-31T07:51:03.977Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/e2/cc/e097523dd85c9cf5d354f78310927f1656c422bd7b2613b2db3e3f9a0f2c/webcolors-25.10.0-py3-none-any.whl", hash = "sha256:032c727334856fc0b968f63daa252a1ac93d33db2f5267756623c210e57a4f1d", size = 14905, upload-time = "2025-10-31T07:51:01.778Z" }, +] + +[[package]] +name = "webencodings" +version = "0.5.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/0b/02/ae6ceac1baeda530866a85075641cec12989bd8d31af6d5ab4a3e8c92f47/webencodings-0.5.1.tar.gz", hash = "sha256:b36a1c245f2d304965eb4e0a82848379241dc04b865afcc4aab16748587e1923", size = 9721, upload-time = "2017-04-05T20:21:34.189Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/f4/24/2a3e3df732393fed8b3ebf2ec078f05546de641fe1b667ee316ec1dcf3b7/webencodings-0.5.1-py2.py3-none-any.whl", hash = "sha256:a0af1213f3c2226497a97e2b3aa01a7e4bee4f403f95be16fc9acd2947514a78", size = 11774, upload-time = "2017-04-05T20:21:32.581Z" }, +] + +[[package]] +name = "websocket-client" +version = "1.9.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/2c/41/aa4bf9664e4cda14c3b39865b12251e8e7d239f4cd0e3cc1b6c2ccde25c1/websocket_client-1.9.0.tar.gz", hash = "sha256:9e813624b6eb619999a97dc7958469217c3176312b3a16a4bd1bc7e08a46ec98", size = 70576, upload-time = "2025-10-07T21:16:36.495Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/34/db/b10e48aa8fff7407e67470363eac595018441cf32d5e1001567a7aeba5d2/websocket_client-1.9.0-py3-none-any.whl", hash = "sha256:af248a825037ef591efbf6ed20cc5faa03d3b47b9e5a2230a529eeee1c1fc3ef", size = 82616, upload-time = "2025-10-07T21:16:34.951Z" }, +] + +[[package]] +name = "widgetsnbextension" +version = "4.0.15" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/bd/f4/c67440c7fb409a71b7404b7aefcd7569a9c0d6bd071299bf4198ae7a5d95/widgetsnbextension-4.0.15.tar.gz", hash = "sha256:de8610639996f1567952d763a5a41af8af37f2575a41f9852a38f947eb82a3b9", size = 1097402, upload-time = "2025-11-01T21:15:55.178Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/3f/0e/fa3b193432cfc60c93b42f3be03365f5f909d2b3ea410295cf36df739e31/widgetsnbextension-4.0.15-py3-none-any.whl", hash = "sha256:8156704e4346a571d9ce73b84bee86a29906c9abfd7223b7228a28899ccf3366", size = 2196503, upload-time = "2025-11-01T21:15:53.565Z" }, +] + +[[package]] +name = "xdoctest" +version = "1.3.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/92/3a/425e9555e23409559fa01d3431b7e1ffbc4ad6fa3b808e9f7bac9e3afbb6/xdoctest-1.3.0.tar.gz", hash = "sha256:f92cb99a3be6011c57bb94613a26b09a268e0095e926b4559132d135d8f6c9d4", size = 207394, upload-time = "2025-09-08T15:02:46.256Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/a7/75/35c17f21153190386af9fb36aab5f76d9f865c69d2f13afdfeb0b3109481/xdoctest-1.3.0-py3-none-any.whl", hash = "sha256:b546accaecae2fd0a14e8d8e125550832f3f11981629324519d057e218dd348f", size = 152543, upload-time = "2025-09-08T15:02:43.245Z" }, +] + +[[package]] +name = "zipp" +version = "3.23.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/e3/02/0f2892c661036d50ede074e376733dca2ae7c6eb617489437771209d4180/zipp-3.23.0.tar.gz", hash = "sha256:a07157588a12518c9d4034df3fbbee09c814741a33ff63c05fa29d26a2404166", size = 25547, upload-time = "2025-06-08T17:06:39.4Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/2e/54/647ade08bf0db230bfea292f893923872fd20be6ac6f53b2b936ba839d75/zipp-3.23.0-py3-none-any.whl", hash = "sha256:071652d6115ed432f5ce1d34c336c0adfd6a884660d1e9712a256d3d3bd4b14e", size = 10276, upload-time = "2025-06-08T17:06:38.034Z" }, +] From a7a81d8c3922719a02e958d2867e95a31749804d Mon Sep 17 00:00:00 2001 From: Cameron Smith Date: Mon, 2 Feb 2026 14:39:19 -0500 Subject: [PATCH 013/134] refactor(nix): load packages independently via per-package workspaces Replace single root workspace with per-package loadWorkspace calls, following Pattern 3 from crane-uv2nix-integration architecture doc. Each package directory is loaded independently and overlays are composed via composeManyExtensions. Exposes packageWorkspaces instead of baseWorkspace for downstream module consumption. --- nix/modules/python.nix | 63 +++++++++++++++++++----------------------- 1 file changed, 28 insertions(+), 35 deletions(-) diff --git a/nix/modules/python.nix b/nix/modules/python.nix index 4e73027..cde218d 100644 --- a/nix/modules/python.nix +++ b/nix/modules/python.nix @@ -14,32 +14,37 @@ ... }: let - # Define supported Python versions pythonVersions = { py311 = pkgs.python311; py312 = pkgs.python312; }; - # Create workspace once - this is our pure functional core - baseWorkspace = inputs.uv2nix.lib.workspace.loadWorkspace { - workspaceRoot = ./../..; - }; - - # Function to create overlay with fixed preferences - makeOverlay = - workspace: - workspace.mkPyprojectOverlay { - sourcePreference = "wheel"; + # Load each Python package independently (no root workspace). + # Each package directory contains its own pyproject.toml and uv.lock, + # resolved independently following the LangChain federation model. + loadPackage = + name: path: + let + workspace = inputs.uv2nix.lib.workspace.loadWorkspace { + workspaceRoot = path; + }; + in + { + inherit workspace; + overlay = workspace.mkPyprojectOverlay { + sourcePreference = "wheel"; + }; + editableOverlay = workspace.mkEditablePyprojectOverlay { + root = "$REPO_ROOT"; + }; }; - # Function to create editable overlay - makeEditableOverlay = - workspace: - workspace.mkEditablePyprojectOverlay { - root = "$REPO_ROOT"; - }; + packageWorkspaces = { + pnt-functional = loadPackage "pnt-functional" ../../packages/pnt-functional; + python-nix-template = loadPackage "python-nix-template" ../../packages/python-nix-template; + }; - # Function to create Python package set + # Compose per-package uv2nix overlays with shared overrides mkPythonSet = python: (pkgs.callPackage inputs.pyproject-nix.build.packages { @@ -48,30 +53,20 @@ ( lib.composeManyExtensions [ inputs.pyproject-build-systems.overlays.default - (makeOverlay baseWorkspace) + packageWorkspaces.pnt-functional.overlay + packageWorkspaces.python-nix-template.overlay packageOverrides sdistOverrides ] ); - # Function to create editable Python package set mkEditablePythonSet = python: (mkPythonSet python).overrideScope ( lib.composeManyExtensions [ - (makeEditableOverlay baseWorkspace) + packageWorkspaces.pnt-functional.editableOverlay + packageWorkspaces.python-nix-template.editableOverlay (final: prev: { - # python-nix-template = prev.python-nix-template.overrideAttrs (old: { - # src = lib.fileset.toSource { - # root = old.src; - # fileset = lib.fileset.unions [ - # (old.src + "packages/python-nix-template/pyproject.toml") - # (old.src + "packages/python-nix-template/README.md") - # (old.src + "packages/python-nix-template/src/python_nix_template/__init__.py") - # ]; - # }; - # nativeBuildInputs = old.nativeBuildInputs ++ final.resolveBuildSystem { editables = [ ]; }; - # }); python-nix-template = prev.python-nix-template.overrideAttrs (old: { nativeBuildInputs = old.nativeBuildInputs @@ -90,15 +85,13 @@ ] ); - # Create package sets for each Python version pythonSets = lib.mapAttrs (_: mkPythonSet) pythonVersions; editablePythonSets = lib.mapAttrs (_: mkEditablePythonSet) pythonVersions; in { - # Expose constructed package sets for use in other modules _module.args = { inherit - baseWorkspace + packageWorkspaces pythonSets editablePythonSets pythonVersions From 83a19d827027f2b0bee01ca93fce9ca13bfb51ec Mon Sep 17 00:00:00 2001 From: Cameron Smith Date: Mon, 2 Feb 2026 14:39:29 -0500 Subject: [PATCH 014/134] refactor(nix): merge federated workspace deps in packages module Adapt packages.nix to consume packageWorkspaces instead of baseWorkspace. Merges deps.default from all independent package workspaces to construct the combined virtualenv. --- nix/modules/packages.nix | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/nix/modules/packages.nix b/nix/modules/packages.nix index 27b16e6..a948d75 100644 --- a/nix/modules/packages.nix +++ b/nix/modules/packages.nix @@ -9,20 +9,29 @@ self', pkgs, lib, - baseWorkspace, + packageWorkspaces, pythonSets, editablePythonSets, pythonVersions, ... }: + let + # Merge deps from all independent package workspaces + mergeWorkspaceDeps = + selector: + lib.foldlAttrs ( + acc: _: pkg: + acc // (selector pkg.workspace.deps) + ) { } packageWorkspaces; + + defaultDeps = mergeWorkspaceDeps (deps: deps.default); + in { - # nix build packages = rec { - pythonNixTemplate311 = pythonSets.py311.mkVirtualEnv "python-nix-template-3.11" baseWorkspace.deps.default; - pythonNixTemplate312 = pythonSets.py312.mkVirtualEnv "python-nix-template-3.12" baseWorkspace.deps.default; + pythonNixTemplate311 = pythonSets.py311.mkVirtualEnv "python-nix-template-3.11" defaultDeps; + pythonNixTemplate312 = pythonSets.py312.mkVirtualEnv "python-nix-template-3.12" defaultDeps; default = pythonNixTemplate312; }; - }; } From e5e4ccc3cb21854d153ab2f3b1d7da79042f55c3 Mon Sep 17 00:00:00 2001 From: Cameron Smith Date: Mon, 2 Feb 2026 14:39:36 -0500 Subject: [PATCH 015/134] refactor(nix): merge federated workspace deps in devshell module Adapt devshell.nix to consume packageWorkspaces instead of baseWorkspace. Merges deps.all from all independent package workspaces for the development virtualenv. --- nix/modules/devshell.nix | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/nix/modules/devshell.nix b/nix/modules/devshell.nix index d105fe2..c86e328 100644 --- a/nix/modules/devshell.nix +++ b/nix/modules/devshell.nix @@ -9,24 +9,27 @@ self', pkgs, lib, - baseWorkspace, + packageWorkspaces, editablePythonSets, pythonVersions, ... }: let - # Function to create development shell + # Merge deps from all independent package workspaces + allDeps = lib.foldlAttrs ( + acc: _: pkg: + acc // pkg.workspace.deps.all + ) { } packageWorkspaces; + mkDevShell = { name, pythonVersion, }: let - # Get the actual Python interpreter first python = pythonVersions.${pythonVersion}; - # Then create the editable environment pythonEnv = editablePythonSets.${pythonVersion}; - virtualenv = pythonEnv.mkVirtualEnv "${name}-dev-env" baseWorkspace.deps.all; + virtualenv = pythonEnv.mkVirtualEnv "${name}-dev-env" allDeps; in pkgs.mkShell { inherit name; @@ -60,7 +63,6 @@ in { devShells = rec { - # Create development shells for each Python version pythonNixTemplate311 = mkDevShell { name = "python-nix-template-3.11"; pythonVersion = "py311"; @@ -71,7 +73,6 @@ pythonVersion = "py312"; }; - # Default shell uses Python 3.12 default = pythonNixTemplate312; }; }; From a8a823fd8d74a763f3466e9b9da40d35954fc90d Mon Sep 17 00:00:00 2001 From: Cameron Smith Date: Mon, 2 Feb 2026 14:39:44 -0500 Subject: [PATCH 016/134] refactor(nix): merge federated workspace deps in containers module Adapt containers.nix to consume packageWorkspaces instead of baseWorkspace. Merges deps from all independent package workspaces for container image virtualenvs. --- nix/modules/containers.nix | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/nix/modules/containers.nix b/nix/modules/containers.nix index 763306c..f10eed3 100644 --- a/nix/modules/containers.nix +++ b/nix/modules/containers.nix @@ -11,7 +11,7 @@ pkgs, lib, system, - baseWorkspace, + packageWorkspaces, pythonSets, editablePythonSets, pythonVersions, @@ -24,8 +24,17 @@ defaultPythonSet = pythonSets.${defaultPythonVersion}; defaultEditablePythonSet = editablePythonSets.${defaultPythonVersion}; - defaultPythonEnv = defaultPythonSet.mkVirtualEnv "python-nix-template-env" baseWorkspace.deps.default; - defaultEditablePythonEnv = defaultEditablePythonSet.mkVirtualEnv "python-nix-template-editable-env" baseWorkspace.deps.all; + defaultDeps = lib.foldlAttrs ( + acc: _: pkg: + acc // pkg.workspace.deps.default + ) { } packageWorkspaces; + allDeps = lib.foldlAttrs ( + acc: _: pkg: + acc // pkg.workspace.deps.all + ) { } packageWorkspaces; + + defaultPythonEnv = defaultPythonSet.mkVirtualEnv "python-nix-template-env" defaultDeps; + defaultEditablePythonEnv = defaultEditablePythonSet.mkVirtualEnv "python-nix-template-editable-env" allDeps; buildMultiUserNixImage = import "${inputs.nixpod.outPath}/containers/nix.nix"; From 48d5a6613cc42646f6103667559282cecabf7cce Mon Sep 17 00:00:00 2001 From: Cameron Smith Date: Mon, 2 Feb 2026 14:40:07 -0500 Subject: [PATCH 017/134] chore(issues): close pnt-4jg.1 --- .beads/issues.jsonl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.beads/issues.jsonl b/.beads/issues.jsonl index 0aa70ab..da5cd7c 100644 --- a/.beads/issues.jsonl +++ b/.beads/issues.jsonl @@ -1,5 +1,5 @@ {"id":"pnt-4jg","title":"Dependency model migration","description":"Migrate from single-lock uv workspace to independent-lock multi-package pattern following langchain/langgraph approach. Include pixi feature-based composition for conda ecosystem parity.","status":"open","priority":2,"issue_type":"epic","owner":"cameron.ray.smith@gmail.com","created_at":"2026-01-19T11:54:40.744055-05:00","created_by":"Cameron Smith","updated_at":"2026-01-19T11:54:40.744055-05:00"} -{"id":"pnt-4jg.1","title":"Remove uv workspace, adopt path dependencies","description":"Remove [tool.uv.workspace] from root pyproject.toml. Each package gets own pyproject.toml with [tool.uv.sources] for sibling references using path sources with editable=true. Follow langchain pattern.","status":"in_progress","priority":2,"issue_type":"task","owner":"cameron.ray.smith@gmail.com","created_at":"2026-01-19T11:55:07.344057-05:00","created_by":"Cameron Smith","updated_at":"2026-02-02T14:36:54.635078-05:00","dependencies":[{"issue_id":"pnt-4jg.1","depends_on_id":"pnt-4jg","type":"parent-child","created_at":"2026-01-19T11:55:07.344659-05:00","created_by":"Cameron Smith"}]} +{"id":"pnt-4jg.1","title":"Remove uv workspace, adopt path dependencies","description":"Remove [tool.uv.workspace] from root pyproject.toml. Each package gets own pyproject.toml with [tool.uv.sources] for sibling references using path sources with editable=true. Follow langchain pattern.","status":"closed","priority":2,"issue_type":"task","owner":"cameron.ray.smith@gmail.com","created_at":"2026-01-19T11:55:07.344057-05:00","created_by":"Cameron Smith","updated_at":"2026-02-02T14:40:02.175394-05:00","closed_at":"2026-02-02T14:40:02.175394-05:00","close_reason":"Implemented in a8a823f. Removed root uv workspace, generated per-package locks, rewrote nix modules to Pattern 3 per-package loading.","dependencies":[{"issue_id":"pnt-4jg.1","depends_on_id":"pnt-4jg","type":"parent-child","created_at":"2026-01-19T11:55:07.344659-05:00","created_by":"Cameron Smith"}]} {"id":"pnt-4jg.2","title":"Configure pixi feature-based composition","description":"Implement pixi feature/environment pattern: [feature.X.dependencies] + [environments] composition. Single pixi.lock covering all environments. Per-feature task definitions. Target-specific dependencies for platform support.","status":"open","priority":2,"issue_type":"task","owner":"cameron.ray.smith@gmail.com","created_at":"2026-01-19T11:55:08.085592-05:00","created_by":"Cameron Smith","updated_at":"2026-01-19T11:55:08.085592-05:00","dependencies":[{"issue_id":"pnt-4jg.2","depends_on_id":"pnt-4jg","type":"parent-child","created_at":"2026-01-19T11:55:08.086155-05:00","created_by":"Cameron Smith"}]} {"id":"pnt-4jg.3","title":"Document package distribution channels","description":"Document which packages support uv/pypi vs pixi/conda distribution. Note dependency graph differences between channels. Update README and package metadata.","status":"open","priority":2,"issue_type":"task","owner":"cameron.ray.smith@gmail.com","created_at":"2026-01-19T11:55:09.051203-05:00","created_by":"Cameron Smith","updated_at":"2026-01-19T11:55:09.051203-05:00","dependencies":[{"issue_id":"pnt-4jg.3","depends_on_id":"pnt-4jg","type":"parent-child","created_at":"2026-01-19T11:55:09.051857-05:00","created_by":"Cameron Smith"},{"issue_id":"pnt-4jg.3","depends_on_id":"pnt-4jg.1","type":"blocks","created_at":"2026-01-19T12:20:13.557576-05:00","created_by":"Cameron Smith"},{"issue_id":"pnt-4jg.3","depends_on_id":"pnt-4jg.2","type":"blocks","created_at":"2026-01-19T12:20:16.147971-05:00","created_by":"Cameron Smith"}]} {"id":"pnt-btz","title":"pyo3/Rust extension integration","description":"Add Rust extension module support via maturin + pyo3, demonstrating Nix build integration with crane cargoArtifacts sharing and uv2nix overlay composition.\n\nArchitecture documented in: docs/notes/architecture/crane-uv2nix-integration.md\n\nKey patterns:\n- Per-package Rust workspace (crates/ inside Python package)\n- crane buildDepsOnly for artifact caching\n- uv2nix overlay injection for maturin builds\n- CI matrix with rust-deps/rust-checks/python-wheel categories\n\nReference implementations:\n- ~/projects/rust-workspace/ironstar (crane patterns)\n- ~/projects/planning-workspace/langchain (federated Python)\n","status":"open","priority":2,"issue_type":"epic","owner":"cameron.ray.smith@gmail.com","created_at":"2026-01-19T11:54:41.426256-05:00","created_by":"Cameron Smith","updated_at":"2026-01-28T14:43:57.637638-05:00","dependencies":[{"issue_id":"pnt-btz","depends_on_id":"pnt-dre","type":"blocks","created_at":"2026-01-19T11:55:32.690895-05:00","created_by":"Cameron Smith"},{"issue_id":"pnt-btz","depends_on_id":"pnt-4jg","type":"blocks","created_at":"2026-01-19T11:55:32.812602-05:00","created_by":"Cameron Smith"}]} From ce19a1726342a77edca8399bb1f562a49f928929 Mon Sep 17 00:00:00 2001 From: Cameron Smith Date: Mon, 2 Feb 2026 14:45:36 -0500 Subject: [PATCH 018/134] docs(issues): update pnt-dre.4 with per-package CI matrix concern post-federation --- .beads/issues.jsonl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.beads/issues.jsonl b/.beads/issues.jsonl index da5cd7c..fc5a983 100644 --- a/.beads/issues.jsonl +++ b/.beads/issues.jsonl @@ -10,5 +10,5 @@ {"id":"pnt-dre.1","title":"Refactor Makefile to bootstrap-only pattern","description":"Restrict Makefile to bootstrap targets only: install-nix, install-direnv, verify, setup-user, check-secrets, clean. Move all other targets to justfile.","status":"open","priority":2,"issue_type":"task","owner":"cameron.ray.smith@gmail.com","created_at":"2026-01-19T11:54:54.237851-05:00","created_by":"Cameron Smith","updated_at":"2026-01-19T11:54:54.237851-05:00","dependencies":[{"issue_id":"pnt-dre.1","depends_on_id":"pnt-dre","type":"parent-child","created_at":"2026-01-19T11:54:54.238477-05:00","created_by":"Cameron Smith"}]} {"id":"pnt-dre.2","title":"Adopt grouped justfile recipe pattern","description":"Reorganize justfile with grouped recipes and section headers following vanixiets pattern: nix, python, conda, docs, secrets, ci/cd groups. Add help comments for each recipe.","status":"open","priority":2,"issue_type":"task","owner":"cameron.ray.smith@gmail.com","created_at":"2026-01-19T11:54:55.145094-05:00","created_by":"Cameron Smith","updated_at":"2026-01-19T11:54:55.145094-05:00","dependencies":[{"issue_id":"pnt-dre.2","depends_on_id":"pnt-dre","type":"parent-child","created_at":"2026-01-19T11:54:55.145764-05:00","created_by":"Cameron Smith"}]} {"id":"pnt-dre.3","title":"Reorganize scripts/ directory structure","description":"Move scripts into subdirectories: scripts/ci/, scripts/docs/, scripts/sops/. IMPORTANT: scripts/bootstrap.sh must remain at stable path for curl one-liner URL. Update justfile and CI references.","status":"open","priority":2,"issue_type":"task","owner":"cameron.ray.smith@gmail.com","created_at":"2026-01-19T11:54:55.839371-05:00","created_by":"Cameron Smith","updated_at":"2026-01-19T12:20:05.527218-05:00","dependencies":[{"issue_id":"pnt-dre.3","depends_on_id":"pnt-dre","type":"parent-child","created_at":"2026-01-19T11:54:55.839951-05:00","created_by":"Cameron Smith"}]} -{"id":"pnt-dre.4","title":"Implement cached-ci-job composite action pattern","description":"Add .github/actions/cached-ci-job composite action following typescript-nix-template pattern. Content-addressed caching with hash-sources and force-run support. Update CI to use category-based matrix builds.","status":"open","priority":2,"issue_type":"task","owner":"cameron.ray.smith@gmail.com","created_at":"2026-01-19T11:54:56.79376-05:00","created_by":"Cameron Smith","updated_at":"2026-01-19T11:54:56.79376-05:00","dependencies":[{"issue_id":"pnt-dre.4","depends_on_id":"pnt-dre","type":"parent-child","created_at":"2026-01-19T11:54:56.794334-05:00","created_by":"Cameron Smith"}]} +{"id":"pnt-dre.4","title":"Implement cached-ci-job composite action pattern","description":"Add .github/actions/cached-ci-job composite action following typescript-nix-template pattern. Content-addressed caching with hash-sources and force-run support. Update CI to use category-based matrix builds.\n\nPost-federation CI adaptation: the migration from uv workspace to per-package independent locks (pnt-4jg.1) means CI must now discover and iterate packages under packages/. The matrix strategy needs a package axis in addition to the category axis, producing either a {package} x {category} matrix or per-package reusable workflow dispatches. Review how ci.yaml currently enumerates packages and ensure the composite action pattern supports per-package resolution of lock files, dependency caches, and build artifacts.\n\nAcceptance criteria:\n- .github/actions/cached-ci-job composite action implemented\n- Content-addressed caching with hash-sources and force-run support\n- CI matrix discovers packages/ dynamically (not hardcoded)\n- Matrix crosses package x category dimensions\n- Per-package uv.lock files used for cache keys (not root lock)\n- Category-based builds follow typescript-nix-template pattern","status":"open","priority":2,"issue_type":"task","owner":"cameron.ray.smith@gmail.com","created_at":"2026-01-19T11:54:56.79376-05:00","created_by":"Cameron Smith","updated_at":"2026-02-02T14:45:33.154802-05:00","dependencies":[{"issue_id":"pnt-dre.4","depends_on_id":"pnt-dre","type":"parent-child","created_at":"2026-01-19T11:54:56.794334-05:00","created_by":"Cameron Smith"}]} {"id":"pnt-dre.5","title":"Add omnix template integration","description":"Configure om.templates in flake with parameter definitions. Add template-verify justfile recipe. Create .github/workflows/template.yaml for CI validation.","status":"open","priority":2,"issue_type":"task","owner":"cameron.ray.smith@gmail.com","created_at":"2026-01-19T11:54:57.668262-05:00","created_by":"Cameron Smith","updated_at":"2026-01-19T11:54:57.668262-05:00","dependencies":[{"issue_id":"pnt-dre.5","depends_on_id":"pnt-dre","type":"parent-child","created_at":"2026-01-19T11:54:57.66888-05:00","created_by":"Cameron Smith"}]} From d0cab2a74b4f7756a4293f448f8cedbdf87b668e Mon Sep 17 00:00:00 2001 From: Cameron Smith Date: Mon, 2 Feb 2026 15:05:59 -0500 Subject: [PATCH 019/134] fix(ci): update lock file references for per-package federation Update cache-dependency-glob from root uv.lock to packages/*/uv.lock in python-test and package-release workflows. Move uv sync, lint, and test steps into per-package working directories since the root uv workspace no longer exists. Update ci.yaml path filters to match per-package lock file paths. --- .github/workflows/ci.yaml | 4 ++-- .github/workflows/package-release.yaml | 5 +++-- .github/workflows/python-test.yaml | 10 ++++++---- 3 files changed, 11 insertions(+), 8 deletions(-) diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index c7330b8..0e9466d 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -26,7 +26,7 @@ on: - "!flake.nix" - "!flake.lock" - "!pyproject.toml" - - "!uv.lock" + - "!packages/*/uv.lock" push: branches: - "main" @@ -37,7 +37,7 @@ on: - "!flake.nix" - "!flake.lock" - "!pyproject.toml" - - "!uv.lock" + - "!packages/*/uv.lock" defaults: run: diff --git a/.github/workflows/package-release.yaml b/.github/workflows/package-release.yaml index f73423c..79810d4 100644 --- a/.github/workflows/package-release.yaml +++ b/.github/workflows/package-release.yaml @@ -126,7 +126,7 @@ jobs: with: python-version: "3.12" enable-cache: true - cache-dependency-glob: "uv.lock" + cache-dependency-glob: "packages/*/uv.lock" version: "0.6.8" - name: Setup Yarn @@ -185,8 +185,9 @@ jobs: - name: Build package if: ${{ steps.semantic-release.outputs.new_release_published == 'true' || inputs.release-dry-run == 'true' }} + working-directory: ${{ inputs.package-path }} run: | - uv build --package ${{ inputs.package-name }} + uv build - name: Setup tmate debug session uses: mxschmitt/action-tmate@e5c7151931ca95bad1c6f4190c730ecf8c7dde48 # ratchet:mxschmitt/action-tmate@v3 diff --git a/.github/workflows/python-test.yaml b/.github/workflows/python-test.yaml index 62f4664..a4de449 100644 --- a/.github/workflows/python-test.yaml +++ b/.github/workflows/python-test.yaml @@ -63,21 +63,23 @@ jobs: with: python-version: ${{ inputs.python-version }} enable-cache: true - cache-dependency-glob: "uv.lock" + cache-dependency-glob: "packages/*/uv.lock" version: "0.6.8" - name: Install dependencies + working-directory: packages/${{ inputs.package-name }} run: | uv sync --all-extras --dev - name: Lint + working-directory: packages/${{ inputs.package-name }} run: | - uv run ruff check packages/ + uv run ruff check . - name: Test + working-directory: packages/${{ inputs.package-name }} run: | - echo "Testing package: ${{ inputs.package-name || 'all packages' }}" - cd packages/${{ inputs.package-name || '..' }} + echo "Testing package: ${{ inputs.package-name }}" uv run pytest - name: Upload coverage From 7b3e7ae9824e13d9d98dd1f4333caa07ff4768c2 Mon Sep 17 00:00:00 2001 From: Cameron Smith Date: Mon, 2 Feb 2026 15:06:35 -0500 Subject: [PATCH 020/134] fixup! refactor(nix): merge federated workspace deps in packages module Replace // (shallow merge) with lib.zipAttrsWith for dep-spec merging across federated package workspaces. The // operator silently drops extras from the first package when two packages share a dependency name with different extras lists. zipAttrsWith unions the lists instead. Applied consistently across packages.nix, devshell.nix, and containers.nix. --- nix/modules/containers.nix | 12 ++++++++++-- nix/modules/devshell.nix | 8 ++++++-- nix/modules/packages.nix | 8 ++++++-- 3 files changed, 22 insertions(+), 6 deletions(-) diff --git a/nix/modules/containers.nix b/nix/modules/containers.nix index f10eed3..c492e2b 100644 --- a/nix/modules/containers.nix +++ b/nix/modules/containers.nix @@ -24,13 +24,21 @@ defaultPythonSet = pythonSets.${defaultPythonVersion}; defaultEditablePythonSet = editablePythonSets.${defaultPythonVersion}; + # Merge deps from all independent package workspaces, unioning extras lists + # for shared dependency names rather than silently dropping via // defaultDeps = lib.foldlAttrs ( acc: _: pkg: - acc // pkg.workspace.deps.default + lib.zipAttrsWith (_: values: lib.unique (lib.flatten values)) [ + acc + pkg.workspace.deps.default + ] ) { } packageWorkspaces; allDeps = lib.foldlAttrs ( acc: _: pkg: - acc // pkg.workspace.deps.all + lib.zipAttrsWith (_: values: lib.unique (lib.flatten values)) [ + acc + pkg.workspace.deps.all + ] ) { } packageWorkspaces; defaultPythonEnv = defaultPythonSet.mkVirtualEnv "python-nix-template-env" defaultDeps; diff --git a/nix/modules/devshell.nix b/nix/modules/devshell.nix index c86e328..819adfe 100644 --- a/nix/modules/devshell.nix +++ b/nix/modules/devshell.nix @@ -15,10 +15,14 @@ ... }: let - # Merge deps from all independent package workspaces + # Merge deps from all independent package workspaces, unioning extras lists + # for shared dependency names rather than silently dropping via // allDeps = lib.foldlAttrs ( acc: _: pkg: - acc // pkg.workspace.deps.all + lib.zipAttrsWith (_: values: lib.unique (lib.flatten values)) [ + acc + pkg.workspace.deps.all + ] ) { } packageWorkspaces; mkDevShell = diff --git a/nix/modules/packages.nix b/nix/modules/packages.nix index a948d75..56c4143 100644 --- a/nix/modules/packages.nix +++ b/nix/modules/packages.nix @@ -16,12 +16,16 @@ ... }: let - # Merge deps from all independent package workspaces + # Merge deps from all independent package workspaces, unioning extras lists + # for shared dependency names rather than silently dropping via // mergeWorkspaceDeps = selector: lib.foldlAttrs ( acc: _: pkg: - acc // (selector pkg.workspace.deps) + lib.zipAttrsWith (_: values: lib.unique (lib.flatten values)) [ + acc + (selector pkg.workspace.deps) + ] ) { } packageWorkspaces; defaultDeps = mergeWorkspaceDeps (deps: deps.default); From 36eb8a7ecfe154f006ec00c83a66e77c7ee7146c Mon Sep 17 00:00:00 2001 From: Cameron Smith Date: Mon, 2 Feb 2026 15:07:11 -0500 Subject: [PATCH 021/134] fixup! refactor(nix): load packages independently via per-package workspaces MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Document the version-conflict invariant for federated overlay composition in python.nix and crane-uv2nix-integration.md. Per-package uv2nix overlays composed via composeManyExtensions silently override shared dependencies — packages must resolve compatible versions. --- nix/modules/python.nix | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/nix/modules/python.nix b/nix/modules/python.nix index cde218d..ec31c15 100644 --- a/nix/modules/python.nix +++ b/nix/modules/python.nix @@ -44,7 +44,15 @@ python-nix-template = loadPackage "python-nix-template" ../../packages/python-nix-template; }; - # Compose per-package uv2nix overlays with shared overrides + # Compose per-package uv2nix overlays with shared overrides. + # + # Invariant: all federated packages must resolve compatible versions for + # shared dependencies. Per-package uv2nix overlays are composed sequentially + # into a single package set — if two packages resolve different versions of + # the same dependency, the later overlay silently wins. Enforce version + # alignment across packages by running: + # uv lock --check + # in each package directory after updating any shared dependency. mkPythonSet = python: (pkgs.callPackage inputs.pyproject-nix.build.packages { From 774ec2676ae3b5953ac6f582d3cc266e3ee68f3f Mon Sep 17 00:00:00 2001 From: Cameron Smith Date: Mon, 2 Feb 2026 15:07:12 -0500 Subject: [PATCH 022/134] fixup! refactor(nix): load packages independently via per-package workspaces Document version-conflict invariant in architecture doc Pattern 3. --- docs/notes/architecture/crane-uv2nix-integration.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/docs/notes/architecture/crane-uv2nix-integration.md b/docs/notes/architecture/crane-uv2nix-integration.md index c5f49a6..4070c5c 100644 --- a/docs/notes/architecture/crane-uv2nix-integration.md +++ b/docs/notes/architecture/crane-uv2nix-integration.md @@ -168,6 +168,11 @@ in { The `nix/modules/python.nix` composes all package overlays into the final Python set. +Version-conflict invariant: all federated packages must resolve compatible versions for shared dependencies. +Per-package uv2nix overlays are composed sequentially into a single package set via `lib.composeManyExtensions`. +If two packages resolve different versions of the same dependency, the later overlay silently wins with no error. +Enforce version alignment by running `uv lock --check` in each package directory after updating any shared dependency. + ```nix # nix/modules/python.nix { inputs, ... }: From 1e1a9b2010472ce5d28d26c3a2327e301df45b9a Mon Sep 17 00:00:00 2001 From: Cameron Smith Date: Mon, 2 Feb 2026 15:17:07 -0500 Subject: [PATCH 023/134] chore(issues): add review fixup context to pnt-4jg.1, update pnt-dre.4 with CI scope --- .beads/issues.jsonl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.beads/issues.jsonl b/.beads/issues.jsonl index fc5a983..30f46ac 100644 --- a/.beads/issues.jsonl +++ b/.beads/issues.jsonl @@ -1,5 +1,5 @@ {"id":"pnt-4jg","title":"Dependency model migration","description":"Migrate from single-lock uv workspace to independent-lock multi-package pattern following langchain/langgraph approach. Include pixi feature-based composition for conda ecosystem parity.","status":"open","priority":2,"issue_type":"epic","owner":"cameron.ray.smith@gmail.com","created_at":"2026-01-19T11:54:40.744055-05:00","created_by":"Cameron Smith","updated_at":"2026-01-19T11:54:40.744055-05:00"} -{"id":"pnt-4jg.1","title":"Remove uv workspace, adopt path dependencies","description":"Remove [tool.uv.workspace] from root pyproject.toml. Each package gets own pyproject.toml with [tool.uv.sources] for sibling references using path sources with editable=true. Follow langchain pattern.","status":"closed","priority":2,"issue_type":"task","owner":"cameron.ray.smith@gmail.com","created_at":"2026-01-19T11:55:07.344057-05:00","created_by":"Cameron Smith","updated_at":"2026-02-02T14:40:02.175394-05:00","closed_at":"2026-02-02T14:40:02.175394-05:00","close_reason":"Implemented in a8a823f. Removed root uv workspace, generated per-package locks, rewrote nix modules to Pattern 3 per-package loading.","dependencies":[{"issue_id":"pnt-4jg.1","depends_on_id":"pnt-4jg","type":"parent-child","created_at":"2026-01-19T11:55:07.344659-05:00","created_by":"Cameron Smith"}]} +{"id":"pnt-4jg.1","title":"Remove uv workspace, adopt path dependencies","description":"Remove [tool.uv.workspace] from root pyproject.toml. Each package gets own pyproject.toml with [tool.uv.sources] for sibling references using path sources with editable=true. Follow langchain pattern.","status":"closed","priority":2,"issue_type":"task","owner":"cameron.ray.smith@gmail.com","created_at":"2026-01-19T11:55:07.344057-05:00","created_by":"Cameron Smith","updated_at":"2026-02-02T14:40:02.175394-05:00","closed_at":"2026-02-02T14:40:02.175394-05:00","close_reason":"Implemented in a8a823f. Removed root uv workspace, generated per-package locks, rewrote nix modules to Pattern 3 per-package loading.","dependencies":[{"issue_id":"pnt-4jg.1","depends_on_id":"pnt-4jg","type":"parent-child","created_at":"2026-01-19T11:55:07.344659-05:00","created_by":"Cameron Smith"}],"comments":[{"id":1,"issue_id":"pnt-4jg.1","author":"Cameron Smith","text":"Post-close fixup commits (774ec26):\n- fix(ci): update lock file references for per-package federation (d0cab2a)\n- fixup! merge federated workspace deps: replace // with zipAttrsWith for extras-safe dep merging (7b3e7ae)\n- fixup! load packages independently: document version-conflict invariant in python.nix and architecture doc (36eb8a7, 774ec26)\n\nReview findings addressed: stale CI cache-dependency-glob paths, fragile shallow-merge dep specs, undocumented overlay composition invariant. Full CI redesign (nix develop + justfile symmetry) deferred to pnt-dre.4.","created_at":"2026-02-02T20:17:00Z"}]} {"id":"pnt-4jg.2","title":"Configure pixi feature-based composition","description":"Implement pixi feature/environment pattern: [feature.X.dependencies] + [environments] composition. Single pixi.lock covering all environments. Per-feature task definitions. Target-specific dependencies for platform support.","status":"open","priority":2,"issue_type":"task","owner":"cameron.ray.smith@gmail.com","created_at":"2026-01-19T11:55:08.085592-05:00","created_by":"Cameron Smith","updated_at":"2026-01-19T11:55:08.085592-05:00","dependencies":[{"issue_id":"pnt-4jg.2","depends_on_id":"pnt-4jg","type":"parent-child","created_at":"2026-01-19T11:55:08.086155-05:00","created_by":"Cameron Smith"}]} {"id":"pnt-4jg.3","title":"Document package distribution channels","description":"Document which packages support uv/pypi vs pixi/conda distribution. Note dependency graph differences between channels. Update README and package metadata.","status":"open","priority":2,"issue_type":"task","owner":"cameron.ray.smith@gmail.com","created_at":"2026-01-19T11:55:09.051203-05:00","created_by":"Cameron Smith","updated_at":"2026-01-19T11:55:09.051203-05:00","dependencies":[{"issue_id":"pnt-4jg.3","depends_on_id":"pnt-4jg","type":"parent-child","created_at":"2026-01-19T11:55:09.051857-05:00","created_by":"Cameron Smith"},{"issue_id":"pnt-4jg.3","depends_on_id":"pnt-4jg.1","type":"blocks","created_at":"2026-01-19T12:20:13.557576-05:00","created_by":"Cameron Smith"},{"issue_id":"pnt-4jg.3","depends_on_id":"pnt-4jg.2","type":"blocks","created_at":"2026-01-19T12:20:16.147971-05:00","created_by":"Cameron Smith"}]} {"id":"pnt-btz","title":"pyo3/Rust extension integration","description":"Add Rust extension module support via maturin + pyo3, demonstrating Nix build integration with crane cargoArtifacts sharing and uv2nix overlay composition.\n\nArchitecture documented in: docs/notes/architecture/crane-uv2nix-integration.md\n\nKey patterns:\n- Per-package Rust workspace (crates/ inside Python package)\n- crane buildDepsOnly for artifact caching\n- uv2nix overlay injection for maturin builds\n- CI matrix with rust-deps/rust-checks/python-wheel categories\n\nReference implementations:\n- ~/projects/rust-workspace/ironstar (crane patterns)\n- ~/projects/planning-workspace/langchain (federated Python)\n","status":"open","priority":2,"issue_type":"epic","owner":"cameron.ray.smith@gmail.com","created_at":"2026-01-19T11:54:41.426256-05:00","created_by":"Cameron Smith","updated_at":"2026-01-28T14:43:57.637638-05:00","dependencies":[{"issue_id":"pnt-btz","depends_on_id":"pnt-dre","type":"blocks","created_at":"2026-01-19T11:55:32.690895-05:00","created_by":"Cameron Smith"},{"issue_id":"pnt-btz","depends_on_id":"pnt-4jg","type":"blocks","created_at":"2026-01-19T11:55:32.812602-05:00","created_by":"Cameron Smith"}]} @@ -10,5 +10,5 @@ {"id":"pnt-dre.1","title":"Refactor Makefile to bootstrap-only pattern","description":"Restrict Makefile to bootstrap targets only: install-nix, install-direnv, verify, setup-user, check-secrets, clean. Move all other targets to justfile.","status":"open","priority":2,"issue_type":"task","owner":"cameron.ray.smith@gmail.com","created_at":"2026-01-19T11:54:54.237851-05:00","created_by":"Cameron Smith","updated_at":"2026-01-19T11:54:54.237851-05:00","dependencies":[{"issue_id":"pnt-dre.1","depends_on_id":"pnt-dre","type":"parent-child","created_at":"2026-01-19T11:54:54.238477-05:00","created_by":"Cameron Smith"}]} {"id":"pnt-dre.2","title":"Adopt grouped justfile recipe pattern","description":"Reorganize justfile with grouped recipes and section headers following vanixiets pattern: nix, python, conda, docs, secrets, ci/cd groups. Add help comments for each recipe.","status":"open","priority":2,"issue_type":"task","owner":"cameron.ray.smith@gmail.com","created_at":"2026-01-19T11:54:55.145094-05:00","created_by":"Cameron Smith","updated_at":"2026-01-19T11:54:55.145094-05:00","dependencies":[{"issue_id":"pnt-dre.2","depends_on_id":"pnt-dre","type":"parent-child","created_at":"2026-01-19T11:54:55.145764-05:00","created_by":"Cameron Smith"}]} {"id":"pnt-dre.3","title":"Reorganize scripts/ directory structure","description":"Move scripts into subdirectories: scripts/ci/, scripts/docs/, scripts/sops/. IMPORTANT: scripts/bootstrap.sh must remain at stable path for curl one-liner URL. Update justfile and CI references.","status":"open","priority":2,"issue_type":"task","owner":"cameron.ray.smith@gmail.com","created_at":"2026-01-19T11:54:55.839371-05:00","created_by":"Cameron Smith","updated_at":"2026-01-19T12:20:05.527218-05:00","dependencies":[{"issue_id":"pnt-dre.3","depends_on_id":"pnt-dre","type":"parent-child","created_at":"2026-01-19T11:54:55.839951-05:00","created_by":"Cameron Smith"}]} -{"id":"pnt-dre.4","title":"Implement cached-ci-job composite action pattern","description":"Add .github/actions/cached-ci-job composite action following typescript-nix-template pattern. Content-addressed caching with hash-sources and force-run support. Update CI to use category-based matrix builds.\n\nPost-federation CI adaptation: the migration from uv workspace to per-package independent locks (pnt-4jg.1) means CI must now discover and iterate packages under packages/. The matrix strategy needs a package axis in addition to the category axis, producing either a {package} x {category} matrix or per-package reusable workflow dispatches. Review how ci.yaml currently enumerates packages and ensure the composite action pattern supports per-package resolution of lock files, dependency caches, and build artifacts.\n\nAcceptance criteria:\n- .github/actions/cached-ci-job composite action implemented\n- Content-addressed caching with hash-sources and force-run support\n- CI matrix discovers packages/ dynamically (not hardcoded)\n- Matrix crosses package x category dimensions\n- Per-package uv.lock files used for cache keys (not root lock)\n- Category-based builds follow typescript-nix-template pattern","status":"open","priority":2,"issue_type":"task","owner":"cameron.ray.smith@gmail.com","created_at":"2026-01-19T11:54:56.79376-05:00","created_by":"Cameron Smith","updated_at":"2026-02-02T14:45:33.154802-05:00","dependencies":[{"issue_id":"pnt-dre.4","depends_on_id":"pnt-dre","type":"parent-child","created_at":"2026-01-19T11:54:56.794334-05:00","created_by":"Cameron Smith"}]} +{"id":"pnt-dre.4","title":"Implement cached-ci-job composite action pattern","description":"Add .github/actions/cached-ci-job composite action following typescript-nix-template pattern. Content-addressed caching with hash-sources and force-run support. Update CI to use category-based matrix builds.\n\nPost-federation CI adaptation: the migration from uv workspace to per-package independent locks (pnt-4jg.1) means CI must now discover and iterate packages under packages/. The matrix strategy needs a package axis in addition to the category axis, producing either a {package} x {category} matrix or per-package reusable workflow dispatches. Review how ci.yaml currently enumerates packages and ensure the composite action pattern supports per-package resolution of lock files, dependency caches, and build artifacts.\n\nAcceptance criteria:\n- .github/actions/cached-ci-job composite action implemented\n- Content-addressed caching with hash-sources and force-run support\n- CI matrix discovers packages/ dynamically (not hardcoded)\n- Matrix crosses package x category dimensions\n- Per-package uv.lock files used for cache keys (not root lock)\n- Category-based builds follow typescript-nix-template pattern","status":"open","priority":2,"issue_type":"task","owner":"cameron.ray.smith@gmail.com","created_at":"2026-01-19T11:54:56.79376-05:00","created_by":"Cameron Smith","updated_at":"2026-02-02T14:45:33.154802-05:00","dependencies":[{"issue_id":"pnt-dre.4","depends_on_id":"pnt-dre","type":"parent-child","created_at":"2026-01-19T11:54:56.794334-05:00","created_by":"Cameron Smith"}],"comments":[{"id":2,"issue_id":"pnt-dre.4","author":"Cameron Smith","text":"Minimal CI path fixes applied in d0cab2a as part of pnt-4jg.1 fixups: cache-dependency-glob updated to packages/*/uv.lock, uv sync/lint/test moved into per-package working-directory, ci.yaml path filters updated.\n\nRemaining for pnt-dre.4: replace setup-python/setup-uv actions with nix develop -c just \u003crecipe\u003e pattern, add justfile recipes for per-package sync/test/lint/typecheck, implement cached-ci-job composite action, dynamic package discovery.","created_at":"2026-02-02T20:17:02Z"}]} {"id":"pnt-dre.5","title":"Add omnix template integration","description":"Configure om.templates in flake with parameter definitions. Add template-verify justfile recipe. Create .github/workflows/template.yaml for CI validation.","status":"open","priority":2,"issue_type":"task","owner":"cameron.ray.smith@gmail.com","created_at":"2026-01-19T11:54:57.668262-05:00","created_by":"Cameron Smith","updated_at":"2026-01-19T11:54:57.668262-05:00","dependencies":[{"issue_id":"pnt-dre.5","depends_on_id":"pnt-dre","type":"parent-child","created_at":"2026-01-19T11:54:57.66888-05:00","created_by":"Cameron Smith"}]} From f488768639ceec21a5f6163c839c2553a57a45c6 Mon Sep 17 00:00:00 2001 From: Cameron Smith Date: Mon, 2 Feb 2026 15:33:28 -0500 Subject: [PATCH 024/134] feat(pixi): add feature tasks to python-nix-template package Aligns with pnt-functional by defining test, lint, lint-check, and types tasks under their respective pixi feature sections. --- packages/python-nix-template/pyproject.toml | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/packages/python-nix-template/pyproject.toml b/packages/python-nix-template/pyproject.toml index 3a1e016..bf5bd50 100644 --- a/packages/python-nix-template/pyproject.toml +++ b/packages/python-nix-template/pyproject.toml @@ -71,6 +71,16 @@ lint = { features = ["lint"], solve-group = "default" } test = { features = ["test"], solve-group = "default" } types = { features = ["types"], solve-group = "default" } +[tool.pixi.feature.test.tasks] +test = "pytest" + +[tool.pixi.feature.lint.tasks] +lint = "ruff check --fix src/" +lint-check = "ruff check src/" + +[tool.pixi.feature.types.tasks] +types = "pyright src/" + [tool.pixi.package] name = "python-nix-template" version = "0.1.1" From 7be5c4b55d9ef9cf326ce6096ccd42cd84d9bd9f Mon Sep 17 00:00:00 2001 From: Cameron Smith Date: Mon, 2 Feb 2026 15:33:33 -0500 Subject: [PATCH 025/134] fix(justfile): delegate conda recipes to pixi task names Replaces raw tool invocations with pixi task delegation so that working directory resolution happens inside the package directory where pixi sets it relative to the manifest path. --- justfile | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/justfile b/justfile index d1b7153..d852cef 100644 --- a/justfile +++ b/justfile @@ -214,22 +214,22 @@ conda-lock package="python-nix-template": # Run tests in conda environment with pixi [group('conda package')] conda-test package="python-nix-template": - pixi run -e test --manifest-path=packages/{{package}}/pyproject.toml pytest + pixi run -e test --manifest-path=packages/{{package}}/pyproject.toml test # Run linting in conda environment with pixi [group('conda package')] conda-lint package="python-nix-template": - pixi run -e lint --manifest-path=packages/{{package}}/pyproject.toml ruff check src/ + pixi run -e lint --manifest-path=packages/{{package}}/pyproject.toml lint-check # Run linting and fix errors in conda environment with pixi [group('conda package')] conda-lint-fix package="python-nix-template": - pixi run -e lint --manifest-path=packages/{{package}}/pyproject.toml ruff check --fix src/ + pixi run -e lint --manifest-path=packages/{{package}}/pyproject.toml lint # Run type checking in conda environment with pixi [group('conda package')] conda-type package="python-nix-template": - pixi run -e types --manifest-path=packages/{{package}}/pyproject.toml pyright src/ + pixi run -e types --manifest-path=packages/{{package}}/pyproject.toml types # Run all checks in conda environment (lint, type, test) [group('conda package')] From 22e4ea94308ea780c35e327b743552dc3b6b8d2f Mon Sep 17 00:00:00 2001 From: Cameron Smith Date: Mon, 2 Feb 2026 15:35:17 -0500 Subject: [PATCH 026/134] fix(pixi): move build channels to backend.channels in pnt-functional Resolves deprecation warning for top-level channels in [package.build]. --- packages/pnt-functional/pyproject.toml | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/packages/pnt-functional/pyproject.toml b/packages/pnt-functional/pyproject.toml index 1d65f58..abd2a96 100644 --- a/packages/pnt-functional/pyproject.toml +++ b/packages/pnt-functional/pyproject.toml @@ -98,12 +98,13 @@ expression = ">=5.5.0" [tool.pixi.package.host-dependencies] hatchling = "*" -[tool.pixi.package.build] -backend = { name = "pixi-build-python", version = "0.1.*" } +[tool.pixi.package.build.backend] channels = [ "https://prefix.dev/conda-forge", "https://prefix.dev/pixi-build-backends", ] +name = "pixi-build-python" +version = "0.1.*" [tool.hatch.build.targets.wheel] packages = ["src/pnt_functional"] From da55cb6364a325393c3a906b4e91eabbdc0135d9 Mon Sep 17 00:00:00 2001 From: Cameron Smith Date: Mon, 2 Feb 2026 15:35:24 -0500 Subject: [PATCH 027/134] fix(pixi): move build channels to backend.channels in python-nix-template Resolves deprecation warning for top-level channels in [package.build]. --- packages/python-nix-template/pyproject.toml | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/packages/python-nix-template/pyproject.toml b/packages/python-nix-template/pyproject.toml index bf5bd50..82aedef 100644 --- a/packages/python-nix-template/pyproject.toml +++ b/packages/python-nix-template/pyproject.toml @@ -87,12 +87,13 @@ version = "0.1.1" [tool.pixi.package.run-dependencies] -[tool.pixi.package.build] -backend = { name = "pixi-build-python", version = "0.1.*" } +[tool.pixi.package.build.backend] channels = [ "https://prefix.dev/conda-forge", "https://prefix.dev/pixi-build-backends", ] +name = "pixi-build-python" +version = "0.1.*" [tool.pixi.package.host-dependencies] hatchling = "*" From 1ebaa3e59f071f4c24e0cb5d93225f1b2fbc31c0 Mon Sep 17 00:00:00 2001 From: Cameron Smith Date: Mon, 2 Feb 2026 15:36:32 -0500 Subject: [PATCH 028/134] chore(pixi): regenerate pnt-functional lock after build config change --- packages/pnt-functional/pixi.lock | 64 +++++++++++++++---------------- 1 file changed, 32 insertions(+), 32 deletions(-) diff --git a/packages/pnt-functional/pixi.lock b/packages/pnt-functional/pixi.lock index 0c13730..f1dd4ca 100644 --- a/packages/pnt-functional/pixi.lock +++ b/packages/pnt-functional/pixi.lock @@ -33,7 +33,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/noarch/typing-extensions-4.12.2-hd8ed1ab_1.conda - conda: https://conda.anaconda.org/conda-forge/noarch/typing_extensions-4.12.2-pyha770c72_1.conda - conda: https://conda.anaconda.org/conda-forge/noarch/tzdata-2025a-h78e105d_0.conda - - pypi: . + - pypi: ./ osx-arm64: - conda: https://conda.anaconda.org/conda-forge/noarch/beartype-0.19.0-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/bzip2-1.0.8-h99b78c6_7.conda @@ -54,7 +54,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/noarch/typing-extensions-4.12.2-hd8ed1ab_1.conda - conda: https://conda.anaconda.org/conda-forge/noarch/typing_extensions-4.12.2-pyha770c72_1.conda - conda: https://conda.anaconda.org/conda-forge/noarch/tzdata-2025a-h78e105d_0.conda - - pypi: . + - pypi: ./ dev: channels: - url: https://conda.anaconda.org/conda-forge/ @@ -117,7 +117,7 @@ environments: - pypi: https://files.pythonhosted.org/packages/00/c0/8f5d070730d7836adc9c9b6408dec68c6ced86b304a9b26a14df072a6e8c/traitlets-5.14.3-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/fd/84/fd2ba7aafacbad3c4201d395674fc6348826569da3c0937e75505ead3528/wcwidth-0.2.13-py2.py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/58/b8/e4722f5e5f592a665cc8e55a334ea721c359f09574e6b987dc551a1e1f4c/xdoctest-1.2.0-py3-none-any.whl - - pypi: . + - pypi: ./ osx-arm64: - conda: https://conda.anaconda.org/conda-forge/noarch/beartype-0.19.0-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/bzip2-1.0.8-h99b78c6_7.conda @@ -167,7 +167,7 @@ environments: - pypi: https://files.pythonhosted.org/packages/00/c0/8f5d070730d7836adc9c9b6408dec68c6ced86b304a9b26a14df072a6e8c/traitlets-5.14.3-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/fd/84/fd2ba7aafacbad3c4201d395674fc6348826569da3c0937e75505ead3528/wcwidth-0.2.13-py2.py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/58/b8/e4722f5e5f592a665cc8e55a334ea721c359f09574e6b987dc551a1e1f4c/xdoctest-1.2.0-py3-none-any.whl - - pypi: . + - pypi: ./ interactive: channels: - url: https://conda.anaconda.org/conda-forge/ @@ -217,7 +217,7 @@ environments: - pypi: https://files.pythonhosted.org/packages/f1/7b/ce1eafaf1a76852e2ec9b22edecf1daa58175c090266e9f6c64afcd81d91/stack_data-0.6.3-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/00/c0/8f5d070730d7836adc9c9b6408dec68c6ced86b304a9b26a14df072a6e8c/traitlets-5.14.3-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/fd/84/fd2ba7aafacbad3c4201d395674fc6348826569da3c0937e75505ead3528/wcwidth-0.2.13-py2.py3-none-any.whl - - pypi: . + - pypi: ./ osx-arm64: - conda: https://conda.anaconda.org/conda-forge/noarch/beartype-0.19.0-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/bzip2-1.0.8-h99b78c6_7.conda @@ -254,7 +254,7 @@ environments: - pypi: https://files.pythonhosted.org/packages/f1/7b/ce1eafaf1a76852e2ec9b22edecf1daa58175c090266e9f6c64afcd81d91/stack_data-0.6.3-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/00/c0/8f5d070730d7836adc9c9b6408dec68c6ced86b304a9b26a14df072a6e8c/traitlets-5.14.3-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/fd/84/fd2ba7aafacbad3c4201d395674fc6348826569da3c0937e75505ead3528/wcwidth-0.2.13-py2.py3-none-any.whl - - pypi: . + - pypi: ./ lint: channels: - url: https://conda.anaconda.org/conda-forge/ @@ -289,7 +289,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/noarch/typing_extensions-4.12.2-pyha770c72_1.conda - conda: https://conda.anaconda.org/conda-forge/noarch/tzdata-2025a-h78e105d_0.conda - pypi: https://files.pythonhosted.org/packages/5e/a6/cc472161cd04d30a09d5c90698696b70c169eeba2c41030344194242db45/ruff-0.9.10-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl - - pypi: . + - pypi: ./ osx-arm64: - conda: https://conda.anaconda.org/conda-forge/noarch/beartype-0.19.0-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/bzip2-1.0.8-h99b78c6_7.conda @@ -311,7 +311,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/noarch/typing_extensions-4.12.2-pyha770c72_1.conda - conda: https://conda.anaconda.org/conda-forge/noarch/tzdata-2025a-h78e105d_0.conda - pypi: https://files.pythonhosted.org/packages/02/49/1c79e0906b6ff551fb0894168763f705bf980864739572b2815ecd3c9df0/ruff-0.9.10-py3-none-macosx_11_0_arm64.whl - - pypi: . + - pypi: ./ test: channels: - url: https://conda.anaconda.org/conda-forge/ @@ -355,7 +355,7 @@ environments: - pypi: https://files.pythonhosted.org/packages/36/3b/48e79f2cd6a61dbbd4807b4ed46cb564b4fd50a76166b1c4ea5c1d9e2371/pytest_cov-6.0.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/32/46/9cb0e58b2deb7f82b84065f37f3bffeb12413f947f9388e4cac22c4621ce/sortedcontainers-2.4.0-py2.py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/58/b8/e4722f5e5f592a665cc8e55a334ea721c359f09574e6b987dc551a1e1f4c/xdoctest-1.2.0-py3-none-any.whl - - pypi: . + - pypi: ./ osx-arm64: - conda: https://conda.anaconda.org/conda-forge/noarch/beartype-0.19.0-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/bzip2-1.0.8-h99b78c6_7.conda @@ -386,7 +386,7 @@ environments: - pypi: https://files.pythonhosted.org/packages/36/3b/48e79f2cd6a61dbbd4807b4ed46cb564b4fd50a76166b1c4ea5c1d9e2371/pytest_cov-6.0.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/32/46/9cb0e58b2deb7f82b84065f37f3bffeb12413f947f9388e4cac22c4621ce/sortedcontainers-2.4.0-py2.py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/58/b8/e4722f5e5f592a665cc8e55a334ea721c359f09574e6b987dc551a1e1f4c/xdoctest-1.2.0-py3-none-any.whl - - pypi: . + - pypi: ./ types: channels: - url: https://conda.anaconda.org/conda-forge/ @@ -422,7 +422,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/noarch/tzdata-2025a-h78e105d_0.conda - pypi: https://files.pythonhosted.org/packages/d2/1d/1b658dbd2b9fa9c4c9f32accbfc0205d532c8c6194dc0f2a4c0428e7128a/nodeenv-1.9.1-py2.py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/80/be/ecb7cfb42d242b7ee764b52e6ff4782beeec00e3b943a3ec832b281f9da6/pyright-1.1.396-py3-none-any.whl - - pypi: . + - pypi: ./ osx-arm64: - conda: https://conda.anaconda.org/conda-forge/noarch/beartype-0.19.0-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/bzip2-1.0.8-h99b78c6_7.conda @@ -445,7 +445,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/noarch/tzdata-2025a-h78e105d_0.conda - pypi: https://files.pythonhosted.org/packages/d2/1d/1b658dbd2b9fa9c4c9f32accbfc0205d532c8c6194dc0f2a4c0428e7128a/nodeenv-1.9.1-py2.py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/80/be/ecb7cfb42d242b7ee764b52e6ff4782beeec00e3b943a3ec832b281f9da6/pyright-1.1.396-py3-none-any.whl - - pypi: . + - pypi: ./ packages: - conda: https://conda.anaconda.org/conda-forge/linux-64/_libgcc_mutex-0.1-conda_forge.tar.bz2 sha256: fe51de6107f9edc7aa4f786a70f4a883943bc9d39b3bb7307c04c41410990726 @@ -1025,10 +1025,10 @@ packages: - pytest ; extra == 'testing' - pytest-benchmark ; extra == 'testing' requires_python: '>=3.8' -- pypi: . +- pypi: ./ name: pnt-functional version: 0.1.1 - sha256: d764eca8765b99e6ee930d1ee377b1f1431f04d60e7c6019cddb597c5b00c554 + sha256: 194857609afe84765f74789b94ba6811b2cd72d008030f3be0a89439235dea1e requires_dist: - beartype>=0.19.0,<0.20.0 - expression>=5.5.0 @@ -1312,15 +1312,15 @@ packages: - attrs==19.2.0 ; extra == 'all-strict' - jupyter-core==4.7.0 ; extra == 'all-strict' - pyflakes==2.2.0 ; extra == 'all-strict' - - colorama==0.4.1 ; platform_system == 'Windows' and extra == 'all-strict' + - colorama==0.4.1 ; sys_platform == 'win32' and extra == 'all-strict' - debugpy==1.3.0 ; python_full_version == '3.9.*' and extra == 'all-strict' - pytest==4.6.0 ; python_full_version >= '3.7' and python_full_version < '3.10' and extra == 'all-strict' - tomli==0.2.0 ; python_full_version >= '3.6' and python_full_version < '3.11' and extra == 'all-strict' - - ipykernel==6.0.0 ; (python_full_version >= '3.7' and python_full_version < '3.12' and platform_python_implementation != 'PyPy' and extra == 'all-strict') or (python_full_version >= '3.7' and python_full_version < '3.12' and platform_system != 'Windows' and extra == 'all-strict') + - ipykernel==6.0.0 ; (python_full_version >= '3.7' and python_full_version < '3.12' and platform_python_implementation != 'PyPy' and extra == 'all-strict') or (python_full_version >= '3.7' and python_full_version < '3.12' and sys_platform != 'win32' and extra == 'all-strict') - pygments==2.0.0 ; python_full_version >= '2.7' and python_full_version < '3.5' and extra == 'all-strict' - nbconvert==6.0.0 ; python_full_version == '3.6.*' and platform_python_implementation != 'PyPy' and extra == 'all-strict' - debugpy==1.0.0 ; python_full_version == '3.8.*' and extra == 'all-strict' - - ipykernel==6.11.0 ; (python_full_version >= '3.12' and python_full_version < '4.0' and platform_python_implementation != 'PyPy' and extra == 'all-strict') or (python_full_version >= '3.12' and python_full_version < '4.0' and platform_system != 'Windows' and extra == 'all-strict') + - ipykernel==6.11.0 ; (python_full_version >= '3.12' and python_full_version < '4.0' and platform_python_implementation != 'PyPy' and extra == 'all-strict') or (python_full_version >= '3.12' and python_full_version < '4.0' and sys_platform != 'win32' and extra == 'all-strict') - debugpy==1.6.0 ; python_full_version >= '3.10' and extra == 'all-strict' - pytest==6.2.5 ; python_full_version >= '3.10' and extra == 'all-strict' - pygments==2.4.1 ; python_full_version >= '3.5' and extra == 'all-strict' @@ -1328,15 +1328,15 @@ packages: - ipython-genutils==0.2.0 ; python_full_version >= '3.6' and platform_python_implementation != 'PyPy' and extra == 'all-strict' - pytest-cov==3.0.0 ; python_full_version >= '3.6' and extra == 'all-strict' - nbconvert==6.1.0 ; python_full_version >= '3.7' and platform_python_implementation != 'PyPy' and extra == 'all-strict' - - colorama>=0.4.1 ; platform_system == 'Windows' and extra == 'all' + - colorama>=0.4.1 ; sys_platform == 'win32' and extra == 'all' - debugpy>=1.3.0 ; python_full_version == '3.9.*' and extra == 'all' - pytest>=4.6.0 ; python_full_version >= '3.7' and python_full_version < '3.10' and extra == 'all' - tomli>=0.2.0 ; python_full_version >= '3.6' and python_full_version < '3.11' and extra == 'all' - - ipykernel>=6.0.0 ; (python_full_version >= '3.7' and python_full_version < '3.12' and platform_python_implementation != 'PyPy' and extra == 'all') or (python_full_version >= '3.7' and python_full_version < '3.12' and platform_system != 'Windows' and extra == 'all') + - ipykernel>=6.0.0 ; (python_full_version >= '3.7' and python_full_version < '3.12' and platform_python_implementation != 'PyPy' and extra == 'all') or (python_full_version >= '3.7' and python_full_version < '3.12' and sys_platform != 'win32' and extra == 'all') - pygments>=2.0.0 ; python_full_version >= '2.7' and python_full_version < '3.5' and extra == 'all' - nbconvert>=6.0.0 ; python_full_version == '3.6.*' and platform_python_implementation != 'PyPy' and extra == 'all' - debugpy>=1.0.0 ; python_full_version == '3.8.*' and extra == 'all' - - ipykernel>=6.11.0 ; (python_full_version >= '3.12' and python_full_version < '4.0' and platform_python_implementation != 'PyPy' and extra == 'all') or (python_full_version >= '3.12' and python_full_version < '4.0' and platform_system != 'Windows' and extra == 'all') + - ipykernel>=6.11.0 ; (python_full_version >= '3.12' and python_full_version < '4.0' and platform_python_implementation != 'PyPy' and extra == 'all') or (python_full_version >= '3.12' and python_full_version < '4.0' and sys_platform != 'win32' and extra == 'all') - debugpy>=1.6.0 ; python_full_version >= '3.10' and extra == 'all' - pytest>=6.2.5 ; python_full_version >= '3.10' and extra == 'all' - pygments>=2.4.1 ; python_full_version >= '3.5' and extra == 'all' @@ -1344,10 +1344,10 @@ packages: - ipython-genutils>=0.2.0 ; python_full_version >= '3.6' and platform_python_implementation != 'PyPy' and extra == 'all' - pytest-cov>=3.0.0 ; python_full_version >= '3.6' and extra == 'all' - nbconvert>=6.1.0 ; python_full_version >= '3.7' and platform_python_implementation != 'PyPy' and extra == 'all' - - colorama==0.4.1 ; platform_system == 'Windows' and extra == 'colors-strict' + - colorama==0.4.1 ; sys_platform == 'win32' and extra == 'colors-strict' - pygments==2.0.0 ; python_full_version >= '2.7' and python_full_version < '3.5' and extra == 'colors-strict' - pygments==2.4.1 ; python_full_version >= '3.5' and extra == 'colors-strict' - - colorama>=0.4.1 ; platform_system == 'Windows' and extra == 'colors' + - colorama>=0.4.1 ; sys_platform == 'win32' and extra == 'colors' - pygments>=2.0.0 ; python_full_version >= '2.7' and python_full_version < '3.5' and extra == 'colors' - pygments>=2.4.1 ; python_full_version >= '3.5' and extra == 'colors' - sphinx>=5.0.1 ; extra == 'docs' @@ -1377,19 +1377,19 @@ packages: - attrs==19.2.0 ; extra == 'jupyter-strict' - jupyter-core==4.7.0 ; extra == 'jupyter-strict' - debugpy==1.3.0 ; python_full_version == '3.9.*' and extra == 'jupyter-strict' - - ipykernel==6.0.0 ; (python_full_version >= '3.7' and python_full_version < '3.12' and platform_python_implementation != 'PyPy' and extra == 'jupyter-strict') or (python_full_version >= '3.7' and python_full_version < '3.12' and platform_system != 'Windows' and extra == 'jupyter-strict') + - ipykernel==6.0.0 ; (python_full_version >= '3.7' and python_full_version < '3.12' and platform_python_implementation != 'PyPy' and extra == 'jupyter-strict') or (python_full_version >= '3.7' and python_full_version < '3.12' and sys_platform != 'win32' and extra == 'jupyter-strict') - nbconvert==6.0.0 ; python_full_version == '3.6.*' and platform_python_implementation != 'PyPy' and extra == 'jupyter-strict' - debugpy==1.0.0 ; python_full_version == '3.8.*' and extra == 'jupyter-strict' - - ipykernel==6.11.0 ; (python_full_version >= '3.12' and python_full_version < '4.0' and platform_python_implementation != 'PyPy' and extra == 'jupyter-strict') or (python_full_version >= '3.12' and python_full_version < '4.0' and platform_system != 'Windows' and extra == 'jupyter-strict') + - ipykernel==6.11.0 ; (python_full_version >= '3.12' and python_full_version < '4.0' and platform_python_implementation != 'PyPy' and extra == 'jupyter-strict') or (python_full_version >= '3.12' and python_full_version < '4.0' and sys_platform != 'win32' and extra == 'jupyter-strict') - debugpy==1.6.0 ; python_full_version >= '3.10' and extra == 'jupyter-strict' - jinja2==3.0.0 ; python_full_version >= '3.6' and platform_python_implementation != 'PyPy' and extra == 'jupyter-strict' - ipython-genutils==0.2.0 ; python_full_version >= '3.6' and platform_python_implementation != 'PyPy' and extra == 'jupyter-strict' - nbconvert==6.1.0 ; python_full_version >= '3.7' and platform_python_implementation != 'PyPy' and extra == 'jupyter-strict' - debugpy>=1.3.0 ; python_full_version == '3.9.*' and extra == 'jupyter' - - ipykernel>=6.0.0 ; (python_full_version >= '3.7' and python_full_version < '3.12' and platform_python_implementation != 'PyPy' and extra == 'jupyter') or (python_full_version >= '3.7' and python_full_version < '3.12' and platform_system != 'Windows' and extra == 'jupyter') + - ipykernel>=6.0.0 ; (python_full_version >= '3.7' and python_full_version < '3.12' and platform_python_implementation != 'PyPy' and extra == 'jupyter') or (python_full_version >= '3.7' and python_full_version < '3.12' and sys_platform != 'win32' and extra == 'jupyter') - nbconvert>=6.0.0 ; python_full_version == '3.6.*' and platform_python_implementation != 'PyPy' and extra == 'jupyter' - debugpy>=1.0.0 ; python_full_version == '3.8.*' and extra == 'jupyter' - - ipykernel>=6.11.0 ; (python_full_version >= '3.12' and python_full_version < '4.0' and platform_python_implementation != 'PyPy' and extra == 'jupyter') or (python_full_version >= '3.12' and python_full_version < '4.0' and platform_system != 'Windows' and extra == 'jupyter') + - ipykernel>=6.11.0 ; (python_full_version >= '3.12' and python_full_version < '4.0' and platform_python_implementation != 'PyPy' and extra == 'jupyter') or (python_full_version >= '3.12' and python_full_version < '4.0' and sys_platform != 'win32' and extra == 'jupyter') - debugpy>=1.6.0 ; python_full_version >= '3.10' and extra == 'jupyter' - jinja2>=3.0.0 ; python_full_version >= '3.6' and platform_python_implementation != 'PyPy' and extra == 'jupyter' - ipython-genutils>=0.2.0 ; python_full_version >= '3.6' and platform_python_implementation != 'PyPy' and extra == 'jupyter' @@ -1406,27 +1406,27 @@ packages: - attrs==19.2.0 ; extra == 'optional-strict' - jupyter-core==4.7.0 ; extra == 'optional-strict' - pyflakes==2.2.0 ; extra == 'optional-strict' - - colorama==0.4.1 ; platform_system == 'Windows' and extra == 'optional-strict' + - colorama==0.4.1 ; sys_platform == 'win32' and extra == 'optional-strict' - debugpy==1.3.0 ; python_full_version == '3.9.*' and extra == 'optional-strict' - tomli==0.2.0 ; python_full_version >= '3.6' and python_full_version < '3.11' and extra == 'optional-strict' - - ipykernel==6.0.0 ; (python_full_version >= '3.7' and python_full_version < '3.12' and platform_python_implementation != 'PyPy' and extra == 'optional-strict') or (python_full_version >= '3.7' and python_full_version < '3.12' and platform_system != 'Windows' and extra == 'optional-strict') + - ipykernel==6.0.0 ; (python_full_version >= '3.7' and python_full_version < '3.12' and platform_python_implementation != 'PyPy' and extra == 'optional-strict') or (python_full_version >= '3.7' and python_full_version < '3.12' and sys_platform != 'win32' and extra == 'optional-strict') - pygments==2.0.0 ; python_full_version >= '2.7' and python_full_version < '3.5' and extra == 'optional-strict' - nbconvert==6.0.0 ; python_full_version == '3.6.*' and platform_python_implementation != 'PyPy' and extra == 'optional-strict' - debugpy==1.0.0 ; python_full_version == '3.8.*' and extra == 'optional-strict' - - ipykernel==6.11.0 ; (python_full_version >= '3.12' and python_full_version < '4.0' and platform_python_implementation != 'PyPy' and extra == 'optional-strict') or (python_full_version >= '3.12' and python_full_version < '4.0' and platform_system != 'Windows' and extra == 'optional-strict') + - ipykernel==6.11.0 ; (python_full_version >= '3.12' and python_full_version < '4.0' and platform_python_implementation != 'PyPy' and extra == 'optional-strict') or (python_full_version >= '3.12' and python_full_version < '4.0' and sys_platform != 'win32' and extra == 'optional-strict') - debugpy==1.6.0 ; python_full_version >= '3.10' and extra == 'optional-strict' - pygments==2.4.1 ; python_full_version >= '3.5' and extra == 'optional-strict' - jinja2==3.0.0 ; python_full_version >= '3.6' and platform_python_implementation != 'PyPy' and extra == 'optional-strict' - ipython-genutils==0.2.0 ; python_full_version >= '3.6' and platform_python_implementation != 'PyPy' and extra == 'optional-strict' - nbconvert==6.1.0 ; python_full_version >= '3.7' and platform_python_implementation != 'PyPy' and extra == 'optional-strict' - - colorama>=0.4.1 ; platform_system == 'Windows' and extra == 'optional' + - colorama>=0.4.1 ; sys_platform == 'win32' and extra == 'optional' - debugpy>=1.3.0 ; python_full_version == '3.9.*' and extra == 'optional' - tomli>=0.2.0 ; python_full_version >= '3.6' and python_full_version < '3.11' and extra == 'optional' - - ipykernel>=6.0.0 ; (python_full_version >= '3.7' and python_full_version < '3.12' and platform_python_implementation != 'PyPy' and extra == 'optional') or (python_full_version >= '3.7' and python_full_version < '3.12' and platform_system != 'Windows' and extra == 'optional') + - ipykernel>=6.0.0 ; (python_full_version >= '3.7' and python_full_version < '3.12' and platform_python_implementation != 'PyPy' and extra == 'optional') or (python_full_version >= '3.7' and python_full_version < '3.12' and sys_platform != 'win32' and extra == 'optional') - pygments>=2.0.0 ; python_full_version >= '2.7' and python_full_version < '3.5' and extra == 'optional' - nbconvert>=6.0.0 ; python_full_version == '3.6.*' and platform_python_implementation != 'PyPy' and extra == 'optional' - debugpy>=1.0.0 ; python_full_version == '3.8.*' and extra == 'optional' - - ipykernel>=6.11.0 ; (python_full_version >= '3.12' and python_full_version < '4.0' and platform_python_implementation != 'PyPy' and extra == 'optional') or (python_full_version >= '3.12' and python_full_version < '4.0' and platform_system != 'Windows' and extra == 'optional') + - ipykernel>=6.11.0 ; (python_full_version >= '3.12' and python_full_version < '4.0' and platform_python_implementation != 'PyPy' and extra == 'optional') or (python_full_version >= '3.12' and python_full_version < '4.0' and sys_platform != 'win32' and extra == 'optional') - debugpy>=1.6.0 ; python_full_version >= '3.10' and extra == 'optional' - pygments>=2.4.1 ; python_full_version >= '3.5' and extra == 'optional' - jinja2>=3.0.0 ; python_full_version >= '3.6' and platform_python_implementation != 'PyPy' and extra == 'optional' From 09be341e4af072e904a3bbab7fea016fe5785619 Mon Sep 17 00:00:00 2001 From: Cameron Smith Date: Mon, 2 Feb 2026 15:36:33 -0500 Subject: [PATCH 029/134] chore(pixi): regenerate python-nix-template lock after build config change --- packages/python-nix-template/pixi.lock | 2350 +++++++++++++++++++++++- 1 file changed, 2310 insertions(+), 40 deletions(-) diff --git a/packages/python-nix-template/pixi.lock b/packages/python-nix-template/pixi.lock index b6b8cb8..b791adf 100644 --- a/packages/python-nix-template/pixi.lock +++ b/packages/python-nix-template/pixi.lock @@ -29,7 +29,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/linux-64/readline-8.2-h8c095d6_2.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/tk-8.6.13-noxft_h4845f30_101.conda - conda: https://conda.anaconda.org/conda-forge/noarch/tzdata-2025a-h78e105d_0.conda - - pypi: . + - pypi: ./ osx-arm64: - conda: https://conda.anaconda.org/conda-forge/osx-arm64/bzip2-1.0.8-h99b78c6_7.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/ca-certificates-2025.1.31-hf0a4a13_0.conda @@ -44,7 +44,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/osx-arm64/readline-8.2-h1d1bf99_2.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/tk-8.6.13-h5083fa2_1.conda - conda: https://conda.anaconda.org/conda-forge/noarch/tzdata-2025a-h78e105d_0.conda - - pypi: . + - pypi: ./ dev: channels: - url: https://conda.anaconda.org/conda-forge/ @@ -74,37 +74,141 @@ environments: - conda: https://conda.anaconda.org/conda-forge/linux-64/readline-8.2-h8c095d6_2.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/tk-8.6.13-noxft_h4845f30_101.conda - conda: https://conda.anaconda.org/conda-forge/noarch/tzdata-2025a-h78e105d_0.conda + - pypi: https://files.pythonhosted.org/packages/78/b6/6307fbef88d9b5ee7421e68d78a9f162e0da4900bc5f5793f6d3d0e34fb8/annotated_types-0.7.0-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/38/0e/27be9fdef66e72d64c0cdc3cc2823101b80585f8119b5c112c2e8f5f7dab/anyio-4.12.1-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/4f/d3/a8b22fa575b297cd6e3e3b0155c7e25db170edf1c74783d6a31a2490b8d9/argon2_cffi-25.1.0-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/09/52/94108adfdd6e2ddf58be64f959a0b9c7d4ef2fa71086c38356d22dc501ea/argon2_cffi_bindings-25.1.0-cp39-abi3-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl + - pypi: https://files.pythonhosted.org/packages/ed/c9/d7977eaacb9df673210491da99e6a247e93df98c715fc43fd136ce1d3d33/arrow-1.4.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/25/8a/c46dcc25341b5bce5472c718902eb3d38600a903b14fa6aeecef3f21a46f/asttokens-3.0.0-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/2e/e9/eb6a5db5ac505d5d45715388e92bced7a5bb556facc4d0865d192823f2d2/async_lru-2.1.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/fc/30/d4986a882011f9df997a55e6becd864812ccfcd821d64aac8570ee39f719/attrs-25.1.0-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/77/f5/21d2de20e8b8b0408f0681956ca2c69f1320a3848ac50e6e7f39c6159675/babel-2.18.0-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/71/cc/18245721fa7747065ab478316c7fea7c74777d07f37ae60db2e84f8172e8/beartype-0.22.9-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/1a/39/47f9197bdd44df24d67ac8893641e16f386c984a0619ef2ee4c51fbbc019/beautifulsoup4-4.14.3-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/8c/04/c96f79d7b93e8f09d9298b333ca0d31cd9b2ee6c46c274fd0f531de9dc61/black-26.1.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl + - pypi: https://files.pythonhosted.org/packages/cd/3a/577b549de0cc09d95f11087ee63c739bba856cd3952697eec4c4bb91350a/bleach-6.3.0-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/e6/ad/3cc14f097111b4de0040c83a525973216457bbeeb63739ef1ed275c1c021/certifi-2026.1.4-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/78/2d/7fa73dfa841b5ac06c7b8855cfc18622132e365f5b81d02230333ff26e9e/cffi-2.0.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl + - pypi: https://files.pythonhosted.org/packages/c0/10/d20b513afe03acc89ec33948320a5544d31f21b05368436d580dec4e234d/charset_normalizer-3.4.4-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl + - pypi: https://files.pythonhosted.org/packages/98/78/01c019cdb5d6498122777c1a43056ebb3ebfeef2076d9d026bfe15583b2b/click-8.3.1-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/d1/d6/3965ed04c63042e047cb6a3e6ed1a63a35087b6a609aa3a15ed8ac56c221/colorama-0.4.6-py2.py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/60/97/891a0971e1e4a8c5d2b20bbe0e524dc04548d2307fee33cdeba148fd4fc7/comm-0.2.3-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/c4/47/2ba744af8d2f0caa1f17e7746147e34dfc5f811fb65fc153153722d58835/coverage-7.6.12-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl + - pypi: https://files.pythonhosted.org/packages/e0/c3/7f67dea8ccf8fdcb9c99033bbe3e90b9e7395415843accb81428c441be2d/debugpy-1.8.20-py2.py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/4e/8c/f3147f5c4b73e7550fe5f9352eaa956ae838d5c51eb58e7a25b9f3e2643b/decorator-5.2.1-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/07/6c/aa3f2f849e01cb6a001cd8554a88d4c77c5c1a31c95bdf1cf9301e6d9ef4/defusedxml-0.7.1-py2.py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/7b/8f/c4d9bafc34ad7ad5d8dc16dd1347ee0e507a52c3adb6bfa8887e1c6a26ba/executing-2.2.0-py2.py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/cb/a8/20d0723294217e47de6d9e2e40fd4a9d2f7c4b6ef974babd482a59743694/fastjsonschema-2.21.2-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/cf/58/8acf1b3e91c58313ce5cb67df61001fc9dcd21be4fadb76c1a2d540e09ed/fqdn-1.5.1-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/cf/05/821587cf19e2ce1f2b24945d890b164401e5085f9d09cbd969b0c193cd20/greenlet-3.3.1-cp312-cp312-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl + - pypi: https://files.pythonhosted.org/packages/9c/83/3b1d03d36f224edded98e9affd0467630fc09d766c0e56fb1498cbb04a9b/griffe-1.15.0-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/c6/00/d204a616fd127ee7830f649cca860b814331f591995e12aaa3931da10c45/hypothesis-6.127.9-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/0e/61/66938bbb5fc52dbdf84594873d5b51fb1f7c7794e9c0f5bd885f30bc507b/idna-3.11-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/fa/5e/f8e9a1d23b9c20a551a8a02ea3637b4642e22c2626e3a13a9a29cdea99eb/importlib_metadata-8.7.1-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/a4/ed/1f1afb2e9e7f38a545d628f864d562a5ae64fe6f7a10e28ffb9b185b4e89/importlib_resources-6.5.2-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/ef/a6/62565a6e1cf69e10f5727360368e451d4b7f58beeac6173dc9db836a5b46/iniconfig-2.0.0-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/a3/17/20c2552266728ceba271967b87919664ecc0e33efca29c3efc6baf88c5f9/ipykernel-7.1.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/20/3a/917cb9e72f4e1a4ea13c862533205ae1319bd664119189ee5cc9e4e95ebf/ipython-9.0.2-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/d9/33/1f075bf72b0b747cb3288d011319aaf64083cf2efef8354174e3ed4540e2/ipython_pygments_lexers-1.1.1-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/56/6d/0d9848617b9f753b87f214f1c682592f7ca42de085f564352f10f0843026/ipywidgets-8.1.8-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/7b/55/e5326141505c5d5e34c5e0935d2908a74e4561eca44108fbfb9c13d2911a/isoduration-20.11.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/c0/5a/9cac0c82afec3d09ccd97c8b6502d48f165f9124db81b4bcb90b4af974ee/jedi-0.19.2-py2.py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/62/a1/3d680cbfd5f4b8f15abc1d571870c5fc3e594bb582bc3b64ea099db13e56/jinja2-3.1.6-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/d7/9e/038522f50ceb7e74f1f991bf1b699f24b0c2bbe7c390dd36ad69f4582258/json5-0.13.0-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/71/92/5e77f98553e9e75130c78900d000368476aed74276eb8ae8796f65f00918/jsonpointer-3.0.0-py2.py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/69/90/f63fb5873511e014207a475e2bb4e8b2e570d655b00ac19a9a0ca0a385ee/jsonschema-4.26.0-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/41/45/1a4ed80516f02155c51f51e8cedb3c1902296743db0bbc66608a0db2814f/jsonschema_specifications-2025.9.1-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/38/64/285f20a31679bf547b75602702f7800e74dbabae36ef324f716c02804753/jupyter-1.1.1-py2.py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/64/6b/67b87da9d36bff9df7d0efbd1a325fa372a43be7158effaf43ed7b22341d/jupyter_cache-1.0.1-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/2d/0b/ceb7694d864abc0a047649aec263878acb9f792e1fec3e676f22dc9015e3/jupyter_client-8.8.0-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/ca/77/71d78d58f15c22db16328a476426f7ac4a60d3a5a7ba3b9627ee2f7903d4/jupyter_console-6.6.3-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/e7/e7/80988e32bf6f73919a113473a604f5a8f09094de312b9d52b79c2df7612b/jupyter_core-5.9.1-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/e2/48/577993f1f99c552f18a0428731a755e06171f9902fa118c379eb7c04ea22/jupyter_events-0.12.0-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/1a/60/1f6cee0c46263de1173894f0fafcb3475ded276c472c14d25e0280c18d6d/jupyter_lsp-2.3.0-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/92/80/a24767e6ca280f5a49525d987bf3e4d7552bf67c8be07e8ccf20271f8568/jupyter_server-2.17.0-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/d1/2d/6674563f71c6320841fc300911a55143925112a72a883e2ca71fba4c618d/jupyter_server_terminals-0.5.4-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/9e/9a/0bf9a7a45f0006d7ff4fdc4fc313de4255acab02bf4db1887c65f0472c01/jupyterlab-4.5.3-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/b1/dd/ead9d8ea85bf202d90cc513b533f9c363121c7792674f78e0d8a854b63b4/jupyterlab_pygments-0.3.0-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/e0/07/a000fe835f76b7e1143242ab1122e6362ef1c03f23f83a045c38859c2ae0/jupyterlab_server-2.28.0-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/ab/b5/36c712098e6191d1b4e349304ef73a8d06aed77e56ceaac8c0a306c7bda1/jupyterlab_widgets-3.0.16-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/82/3d/14ce75ef66813643812f3093ab17e46d3a206942ce7376d31ec2d36229e7/lark-1.3.1-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/94/54/e7d793b573f298e1c9013b8c4dade17d481164aa517d1d7148619c2cedbf/markdown_it_py-4.0.0-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/3c/2e/8d0c2ab90a8c1d9a24f0399058ab8519a3279d1bd4289511d74e909f060e/markupsafe-3.0.3-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl - pypi: https://files.pythonhosted.org/packages/8f/8e/9ad090d3553c280a8060fbf6e24dc1c0c29704ee7d1c372f0c174aa59285/matplotlib_inline-0.1.7-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/b3/38/89ba8ad64ae25be8de66a6d463314cf1eb366222074cfda9ee839c56a4b4/mdurl-0.1.2-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/9b/f7/4a5e785ec9fbd65146a27b6b70b6cdc161a66f2024e4b04ac06a67f5578b/mistune-3.2.0-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/79/7b/2c79738432f5c924bef5071f933bcc9efd0473bac3b4aa584a6f7c1c8df8/mypy_extensions-1.1.0-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/83/a0/5b0c2f11142ed1dddec842457d3f65eaf71a0080894eb6f018755b319c3a/nbclient-0.10.4-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/0d/4b/8d5f796a792f8a25f6925a96032f098789f448571eb92011df1ae59e8ea8/nbconvert-7.17.0-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/a9/82/0340caa499416c78e5d8f5f05947ae4bc3cba53c9f038ab6e9ed964e22f1/nbformat-5.10.4-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/a0/c4/c2971a3ba4c6103a3d10c4b0f24f461ddc027f0f09763220cf35ca1401b3/nest_asyncio-1.6.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/d2/1d/1b658dbd2b9fa9c4c9f32accbfc0205d532c8c6194dc0f2a4c0428e7128a/nodeenv-1.9.1-py2.py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/96/98/9286e7f35e5584ebb79f997f2fb0cb66745c86f6c5fccf15ba32aac5e908/notebook-7.5.3-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/f9/33/bd5b9137445ea4b680023eb0469b2bb969d61303dedb2aac6560ff3d14a1/notebook_shim-0.2.4-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/88/ef/eb23f262cca3c0c4eb7ab1933c3b1f03d021f2c48f54763065b6f0e321be/packaging-24.2-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/ef/af/4fbc8cab944db5d21b7e2a5b8e9211a03a79852b1157e2c102fcc61ac440/pandocfilters-1.5.1-py2.py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/c6/ac/dac4a63f978e4dcb3c6d3a78c4d8e0192a113d288502a1216950c41b1027/parso-0.8.4-py2.py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/ef/3c/2c197d226f9ea224a9ab8d197933f9da0ae0aac5b6e0f884e2b8d9c8e9f7/pathspec-1.0.4-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/9e/c3/059298687310d527a58bb01f3b1965787ee3b40dce76752eda8b44e9a2c5/pexpect-4.9.0-py2.py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/cb/28/3bfe2fa5a7b9c46fe7e13c97bda14c895fb10fa2ebf1d0abb90e0cea7ee1/platformdirs-4.5.1-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/88/5f/e351af9a41f866ac3f1fac4ca0613908d9a41741cfcf2228f4ad853b697d/pluggy-1.5.0-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/42/88/71fa06eb487ed9d4fab0ad173300b7a58706385f98fb66b1ccdc3ec3d4dd/plum_dispatch-2.6.1-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/74/c3/24a2f845e3917201628ecaba4f18bab4d18a337834c1df2a159ee9d22a42/prometheus_client-0.24.1-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/e4/ea/d836f008d33151c7a1f62caf3d8dd782e4d15f6a43897f64480c2b8de2ad/prompt_toolkit-3.0.50-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/b5/70/5d8df3b09e25bce090399cf48e452d25c935ab72dad19406c77f4e828045/psutil-7.2.2-cp36-abi3-manylinux2010_x86_64.manylinux_2_12_x86_64.manylinux_2_28_x86_64.whl - pypi: https://files.pythonhosted.org/packages/22/a6/858897256d0deac81a172289110f31629fc4cee19b6f01283303e18c8db3/ptyprocess-0.7.0-py2.py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/8e/37/efad0257dc6e593a18957422533ff0f87ede7c9c6ea010a2177d738fb82f/pure_eval-0.2.3-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/0c/c3/44f3fbbfa403ea2a7c779186dc20772604442dde72947e7d01069cbe98e3/pycparser-3.0-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/5a/87/b70ad306ebb6f9b585f114d0ac2137d792b48be34d732d60e597c2f8465a/pydantic-2.12.5-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/0d/76/941cc9f73529988688a665a5c0ecff1112b3d95ab48f81db5f7606f522d3/pydantic_core-2.41.5-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl - pypi: https://files.pythonhosted.org/packages/8a/0b/9fcc47d19c48b59121088dd6da2488a49d5f72dacf8262e2790a1d2c7d15/pygments-2.19.1-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/80/be/ecb7cfb42d242b7ee764b52e6ff4782beeec00e3b943a3ec832b281f9da6/pyright-1.1.396-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/30/3d/64ad57c803f1fa1e963a7946b6e0fea4a70df53c1a7fed304586539c2bac/pytest-8.3.5-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/36/3b/48e79f2cd6a61dbbd4807b4ed46cb564b4fd50a76166b1c4ea5c1d9e2371/pytest_cov-6.0.0-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/ec/57/56b9bcc3c9c6a792fcbaf139543cee77261f3651ca9da0c93f5c1221264b/python_dateutil-2.9.0.post0-py2.py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/51/e5/fecf13f06e5e5f67e8837d777d1bc43fac0ed2b77a676804df5c34744727/python_json_logger-4.0.0-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/bf/3c/2d5297d82286f6f3d92770289fd439956b201c0a4fc7e72efb9b2293758e/pytokens-0.4.1-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl + - pypi: https://files.pythonhosted.org/packages/8b/9d/b3589d3877982d4f2329302ef98a8026e7f4443c765c46cfecc8858c6b4b/pyyaml-6.0.3-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl + - pypi: https://files.pythonhosted.org/packages/f8/9b/c108cdb55560eaf253f0cbdb61b29971e9fb34d9c3499b0e96e4e60ed8a5/pyzmq-27.1.0-cp312-abi3-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl + - pypi: https://files.pythonhosted.org/packages/75/d9/0b48d4184f9ca6a996c4fac46897a968698c9d1e0f0e43a6906746201323/quartodoc-0.11.1-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/2c/58/ca301544e1fa93ed4f80d724bf5b194f6e4b945841c5bfd555878eea9fcb/referencing-0.37.0-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/1e/db/4254e3eabe8020b458f1a747140d32277ec7a271daf1d235b70dc0b4e6e3/requests-2.32.5-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/7b/44/4e421b96b67b2daff264473f7465db72fbdf36a07e05494f50300cc7b0c6/rfc3339_validator-0.1.4-py2.py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/9e/51/17023c0f8f1869d8806b979a2bffa3f861f26a3f1a66b094288323fba52f/rfc3986_validator-0.1.1-py2.py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/7e/71/44ce230e1b7fadd372515a97e32a83011f906ddded8d03e3c6aafbdedbb7/rfc3987_syntax-1.1.0-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/ef/45/615f5babd880b4bd7d405cc0dc348234c5ffb6ed1ea33e152ede08b2072d/rich-14.3.2-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/60/1b/6f8f29f3f995c7ffdde46a626ddccd7c63aefc0efae881dc13b6e5d5bb16/rpds_py-0.30.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl - pypi: https://files.pythonhosted.org/packages/5e/a6/cc472161cd04d30a09d5c90698696b70c169eeba2c41030344194242db45/ruff-0.9.10-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl + - pypi: https://files.pythonhosted.org/packages/1c/78/504fdd027da3b84ff1aecd9f6957e65f35134534ccc6da8628eb71e76d3f/send2trash-2.1.0-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/94/b8/f1f62a5e3c0ad2ff1d189590bfa4c46b4f3b6e49cef6f26c6ee4e575394d/setuptools-80.10.2-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/b7/ce/149a00dd41f10bc29e5921b496af8b574d8413afcd5e30dfa0ed46c2cc5e/six-1.17.0-py2.py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/32/46/9cb0e58b2deb7f82b84065f37f3bffeb12413f947f9388e4cac22c4621ce/sortedcontainers-2.4.0-py2.py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/46/2c/1462b1d0a634697ae9e55b3cecdcb64788e8b7d63f54d923fcd0bb140aed/soupsieve-2.8.3-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/63/f9/f48a8f489c8ae8930f12c558b4dd26da96791837747fca87e9da2643f12d/sphobjinv-2.3.1.3-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/ea/a2/b9f33c8d68a3747d972a0bb758c6b63691f8fb8a49014bc3379ba15d4274/sqlalchemy-2.0.46-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl - pypi: https://files.pythonhosted.org/packages/f1/7b/ce1eafaf1a76852e2ec9b22edecf1daa58175c090266e9f6c64afcd81d91/stack_data-0.6.3-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/40/44/4a5f08c96eb108af5cb50b41f76142f0afa346dfa99d5296fe7202a11854/tabulate-0.9.0-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/6a/9e/2064975477fdc887e47ad42157e214526dcad8f317a948dee17e1659a62f/terminado-0.18.1-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/e6/34/ebdc18bae6aa14fbee1a08b63c015c72b64868ff7dae68808ab500c492e2/tinycss2-1.4.0-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/50/d4/e51d52047e7eb9a582da59f32125d17c0482d065afd5d3bc435ff2120dc5/tornado-6.5.4-cp39-abi3-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl - pypi: https://files.pythonhosted.org/packages/00/c0/8f5d070730d7836adc9c9b6408dec68c6ced86b304a9b26a14df072a6e8c/traitlets-5.14.3-py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/26/9f/ad63fc0248c5379346306f8668cda6e2e2e9c95e01216d2b8ffd9ff037d0/typing_extensions-4.12.2-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/18/67/36e9267722cc04a6b9f15c7f3441c2363321a3ea07da7ae0c0707beb2a9c/typing_extensions-4.15.0-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/dc/9b/47798a6c91d8bdb567fe2698fe81e0c6b7cb7ef4d13da4114b41d239f65d/typing_inspection-0.4.2-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/c7/b0/003792df09decd6849a5e39c28b513c06e84436a54440380862b5aeff25d/tzdata-2025.3-py2.py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/e7/00/3fca040d7cf8a32776d3d81a00c8ee7457e00f80c649f1e4a863c8321ae9/uri_template-1.3.0-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/39/08/aaaad47bc4e9dc8c725e68f9d04865dbcb2052843ff09c97b08904852d84/urllib3-2.6.3-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/b5/e8/dbf020b4d98251a9860752a094d09a65e1b436ad181faf929983f697048f/watchdog-6.0.0-py3-none-manylinux2014_x86_64.whl - pypi: https://files.pythonhosted.org/packages/fd/84/fd2ba7aafacbad3c4201d395674fc6348826569da3c0937e75505ead3528/wcwidth-0.2.13-py2.py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/e2/cc/e097523dd85c9cf5d354f78310927f1656c422bd7b2613b2db3e3f9a0f2c/webcolors-25.10.0-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/f4/24/2a3e3df732393fed8b3ebf2ec078f05546de641fe1b667ee316ec1dcf3b7/webencodings-0.5.1-py2.py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/34/db/b10e48aa8fff7407e67470363eac595018441cf32d5e1001567a7aeba5d2/websocket_client-1.9.0-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/3f/0e/fa3b193432cfc60c93b42f3be03365f5f909d2b3ea410295cf36df739e31/widgetsnbextension-4.0.15-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/58/b8/e4722f5e5f592a665cc8e55a334ea721c359f09574e6b987dc551a1e1f4c/xdoctest-1.2.0-py3-none-any.whl - - pypi: . + - pypi: https://files.pythonhosted.org/packages/2e/54/647ade08bf0db230bfea292f893923872fd20be6ac6f53b2b936ba839d75/zipp-3.23.0-py3-none-any.whl + - pypi: ./ osx-arm64: - conda: https://conda.anaconda.org/conda-forge/osx-arm64/bzip2-1.0.8-h99b78c6_7.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/ca-certificates-2025.1.31-hf0a4a13_0.conda @@ -119,37 +223,432 @@ environments: - conda: https://conda.anaconda.org/conda-forge/osx-arm64/readline-8.2-h1d1bf99_2.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/tk-8.6.13-h5083fa2_1.conda - conda: https://conda.anaconda.org/conda-forge/noarch/tzdata-2025a-h78e105d_0.conda + - pypi: https://files.pythonhosted.org/packages/78/b6/6307fbef88d9b5ee7421e68d78a9f162e0da4900bc5f5793f6d3d0e34fb8/annotated_types-0.7.0-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/38/0e/27be9fdef66e72d64c0cdc3cc2823101b80585f8119b5c112c2e8f5f7dab/anyio-4.12.1-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/81/29/5ecc3a15d5a33e31b26c11426c45c501e439cb865d0bff96315d86443b78/appnope-0.1.4-py2.py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/4f/d3/a8b22fa575b297cd6e3e3b0155c7e25db170edf1c74783d6a31a2490b8d9/argon2_cffi-25.1.0-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/b6/02/d297943bcacf05e4f2a94ab6f462831dc20158614e5d067c35d4e63b9acb/argon2_cffi_bindings-25.1.0-cp39-abi3-macosx_11_0_arm64.whl + - pypi: https://files.pythonhosted.org/packages/ed/c9/d7977eaacb9df673210491da99e6a247e93df98c715fc43fd136ce1d3d33/arrow-1.4.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/25/8a/c46dcc25341b5bce5472c718902eb3d38600a903b14fa6aeecef3f21a46f/asttokens-3.0.0-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/2e/e9/eb6a5db5ac505d5d45715388e92bced7a5bb556facc4d0865d192823f2d2/async_lru-2.1.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/fc/30/d4986a882011f9df997a55e6becd864812ccfcd821d64aac8570ee39f719/attrs-25.1.0-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/77/f5/21d2de20e8b8b0408f0681956ca2c69f1320a3848ac50e6e7f39c6159675/babel-2.18.0-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/71/cc/18245721fa7747065ab478316c7fea7c74777d07f37ae60db2e84f8172e8/beartype-0.22.9-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/1a/39/47f9197bdd44df24d67ac8893641e16f386c984a0619ef2ee4c51fbbc019/beautifulsoup4-4.14.3-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/79/a6/5179beaa57e5dbd2ec9f1c64016214057b4265647c62125aa6aeffb05392/black-26.1.0-cp312-cp312-macosx_11_0_arm64.whl + - pypi: https://files.pythonhosted.org/packages/cd/3a/577b549de0cc09d95f11087ee63c739bba856cd3952697eec4c4bb91350a/bleach-6.3.0-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/e6/ad/3cc14f097111b4de0040c83a525973216457bbeeb63739ef1ed275c1c021/certifi-2026.1.4-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/df/a2/781b623f57358e360d62cdd7a8c681f074a71d445418a776eef0aadb4ab4/cffi-2.0.0-cp312-cp312-macosx_11_0_arm64.whl + - pypi: https://files.pythonhosted.org/packages/f3/85/1637cd4af66fa687396e757dec650f28025f2a2f5a5531a3208dc0ec43f2/charset_normalizer-3.4.4-cp312-cp312-macosx_10_13_universal2.whl + - pypi: https://files.pythonhosted.org/packages/98/78/01c019cdb5d6498122777c1a43056ebb3ebfeef2076d9d026bfe15583b2b/click-8.3.1-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/d1/d6/3965ed04c63042e047cb6a3e6ed1a63a35087b6a609aa3a15ed8ac56c221/colorama-0.4.6-py2.py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/60/97/891a0971e1e4a8c5d2b20bbe0e524dc04548d2307fee33cdeba148fd4fc7/comm-0.2.3-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/dc/60/d19df912989117caa95123524d26fc973f56dc14aecdec5ccd7d0084e131/coverage-7.6.12-cp312-cp312-macosx_11_0_arm64.whl + - pypi: https://files.pythonhosted.org/packages/e0/c3/7f67dea8ccf8fdcb9c99033bbe3e90b9e7395415843accb81428c441be2d/debugpy-1.8.20-py2.py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/4e/8c/f3147f5c4b73e7550fe5f9352eaa956ae838d5c51eb58e7a25b9f3e2643b/decorator-5.2.1-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/07/6c/aa3f2f849e01cb6a001cd8554a88d4c77c5c1a31c95bdf1cf9301e6d9ef4/defusedxml-0.7.1-py2.py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/7b/8f/c4d9bafc34ad7ad5d8dc16dd1347ee0e507a52c3adb6bfa8887e1c6a26ba/executing-2.2.0-py2.py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/cb/a8/20d0723294217e47de6d9e2e40fd4a9d2f7c4b6ef974babd482a59743694/fastjsonschema-2.21.2-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/cf/58/8acf1b3e91c58313ce5cb67df61001fc9dcd21be4fadb76c1a2d540e09ed/fqdn-1.5.1-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/9c/83/3b1d03d36f224edded98e9affd0467630fc09d766c0e56fb1498cbb04a9b/griffe-1.15.0-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/c6/00/d204a616fd127ee7830f649cca860b814331f591995e12aaa3931da10c45/hypothesis-6.127.9-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/0e/61/66938bbb5fc52dbdf84594873d5b51fb1f7c7794e9c0f5bd885f30bc507b/idna-3.11-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/fa/5e/f8e9a1d23b9c20a551a8a02ea3637b4642e22c2626e3a13a9a29cdea99eb/importlib_metadata-8.7.1-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/a4/ed/1f1afb2e9e7f38a545d628f864d562a5ae64fe6f7a10e28ffb9b185b4e89/importlib_resources-6.5.2-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/ef/a6/62565a6e1cf69e10f5727360368e451d4b7f58beeac6173dc9db836a5b46/iniconfig-2.0.0-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/a3/17/20c2552266728ceba271967b87919664ecc0e33efca29c3efc6baf88c5f9/ipykernel-7.1.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/20/3a/917cb9e72f4e1a4ea13c862533205ae1319bd664119189ee5cc9e4e95ebf/ipython-9.0.2-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/d9/33/1f075bf72b0b747cb3288d011319aaf64083cf2efef8354174e3ed4540e2/ipython_pygments_lexers-1.1.1-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/56/6d/0d9848617b9f753b87f214f1c682592f7ca42de085f564352f10f0843026/ipywidgets-8.1.8-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/7b/55/e5326141505c5d5e34c5e0935d2908a74e4561eca44108fbfb9c13d2911a/isoduration-20.11.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/c0/5a/9cac0c82afec3d09ccd97c8b6502d48f165f9124db81b4bcb90b4af974ee/jedi-0.19.2-py2.py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/62/a1/3d680cbfd5f4b8f15abc1d571870c5fc3e594bb582bc3b64ea099db13e56/jinja2-3.1.6-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/d7/9e/038522f50ceb7e74f1f991bf1b699f24b0c2bbe7c390dd36ad69f4582258/json5-0.13.0-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/71/92/5e77f98553e9e75130c78900d000368476aed74276eb8ae8796f65f00918/jsonpointer-3.0.0-py2.py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/69/90/f63fb5873511e014207a475e2bb4e8b2e570d655b00ac19a9a0ca0a385ee/jsonschema-4.26.0-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/41/45/1a4ed80516f02155c51f51e8cedb3c1902296743db0bbc66608a0db2814f/jsonschema_specifications-2025.9.1-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/38/64/285f20a31679bf547b75602702f7800e74dbabae36ef324f716c02804753/jupyter-1.1.1-py2.py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/64/6b/67b87da9d36bff9df7d0efbd1a325fa372a43be7158effaf43ed7b22341d/jupyter_cache-1.0.1-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/2d/0b/ceb7694d864abc0a047649aec263878acb9f792e1fec3e676f22dc9015e3/jupyter_client-8.8.0-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/ca/77/71d78d58f15c22db16328a476426f7ac4a60d3a5a7ba3b9627ee2f7903d4/jupyter_console-6.6.3-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/e7/e7/80988e32bf6f73919a113473a604f5a8f09094de312b9d52b79c2df7612b/jupyter_core-5.9.1-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/e2/48/577993f1f99c552f18a0428731a755e06171f9902fa118c379eb7c04ea22/jupyter_events-0.12.0-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/1a/60/1f6cee0c46263de1173894f0fafcb3475ded276c472c14d25e0280c18d6d/jupyter_lsp-2.3.0-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/92/80/a24767e6ca280f5a49525d987bf3e4d7552bf67c8be07e8ccf20271f8568/jupyter_server-2.17.0-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/d1/2d/6674563f71c6320841fc300911a55143925112a72a883e2ca71fba4c618d/jupyter_server_terminals-0.5.4-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/9e/9a/0bf9a7a45f0006d7ff4fdc4fc313de4255acab02bf4db1887c65f0472c01/jupyterlab-4.5.3-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/b1/dd/ead9d8ea85bf202d90cc513b533f9c363121c7792674f78e0d8a854b63b4/jupyterlab_pygments-0.3.0-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/e0/07/a000fe835f76b7e1143242ab1122e6362ef1c03f23f83a045c38859c2ae0/jupyterlab_server-2.28.0-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/ab/b5/36c712098e6191d1b4e349304ef73a8d06aed77e56ceaac8c0a306c7bda1/jupyterlab_widgets-3.0.16-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/82/3d/14ce75ef66813643812f3093ab17e46d3a206942ce7376d31ec2d36229e7/lark-1.3.1-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/94/54/e7d793b573f298e1c9013b8c4dade17d481164aa517d1d7148619c2cedbf/markdown_it_py-4.0.0-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/9a/81/7e4e08678a1f98521201c3079f77db69fb552acd56067661f8c2f534a718/markupsafe-3.0.3-cp312-cp312-macosx_11_0_arm64.whl - pypi: https://files.pythonhosted.org/packages/8f/8e/9ad090d3553c280a8060fbf6e24dc1c0c29704ee7d1c372f0c174aa59285/matplotlib_inline-0.1.7-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/b3/38/89ba8ad64ae25be8de66a6d463314cf1eb366222074cfda9ee839c56a4b4/mdurl-0.1.2-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/9b/f7/4a5e785ec9fbd65146a27b6b70b6cdc161a66f2024e4b04ac06a67f5578b/mistune-3.2.0-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/79/7b/2c79738432f5c924bef5071f933bcc9efd0473bac3b4aa584a6f7c1c8df8/mypy_extensions-1.1.0-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/83/a0/5b0c2f11142ed1dddec842457d3f65eaf71a0080894eb6f018755b319c3a/nbclient-0.10.4-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/0d/4b/8d5f796a792f8a25f6925a96032f098789f448571eb92011df1ae59e8ea8/nbconvert-7.17.0-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/a9/82/0340caa499416c78e5d8f5f05947ae4bc3cba53c9f038ab6e9ed964e22f1/nbformat-5.10.4-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/a0/c4/c2971a3ba4c6103a3d10c4b0f24f461ddc027f0f09763220cf35ca1401b3/nest_asyncio-1.6.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/d2/1d/1b658dbd2b9fa9c4c9f32accbfc0205d532c8c6194dc0f2a4c0428e7128a/nodeenv-1.9.1-py2.py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/96/98/9286e7f35e5584ebb79f997f2fb0cb66745c86f6c5fccf15ba32aac5e908/notebook-7.5.3-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/f9/33/bd5b9137445ea4b680023eb0469b2bb969d61303dedb2aac6560ff3d14a1/notebook_shim-0.2.4-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/88/ef/eb23f262cca3c0c4eb7ab1933c3b1f03d021f2c48f54763065b6f0e321be/packaging-24.2-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/ef/af/4fbc8cab944db5d21b7e2a5b8e9211a03a79852b1157e2c102fcc61ac440/pandocfilters-1.5.1-py2.py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/c6/ac/dac4a63f978e4dcb3c6d3a78c4d8e0192a113d288502a1216950c41b1027/parso-0.8.4-py2.py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/ef/3c/2c197d226f9ea224a9ab8d197933f9da0ae0aac5b6e0f884e2b8d9c8e9f7/pathspec-1.0.4-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/9e/c3/059298687310d527a58bb01f3b1965787ee3b40dce76752eda8b44e9a2c5/pexpect-4.9.0-py2.py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/cb/28/3bfe2fa5a7b9c46fe7e13c97bda14c895fb10fa2ebf1d0abb90e0cea7ee1/platformdirs-4.5.1-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/88/5f/e351af9a41f866ac3f1fac4ca0613908d9a41741cfcf2228f4ad853b697d/pluggy-1.5.0-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/42/88/71fa06eb487ed9d4fab0ad173300b7a58706385f98fb66b1ccdc3ec3d4dd/plum_dispatch-2.6.1-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/74/c3/24a2f845e3917201628ecaba4f18bab4d18a337834c1df2a159ee9d22a42/prometheus_client-0.24.1-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/e4/ea/d836f008d33151c7a1f62caf3d8dd782e4d15f6a43897f64480c2b8de2ad/prompt_toolkit-3.0.50-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/80/c4/f5af4c1ca8c1eeb2e92ccca14ce8effdeec651d5ab6053c589b074eda6e1/psutil-7.2.2-cp36-abi3-macosx_11_0_arm64.whl - pypi: https://files.pythonhosted.org/packages/22/a6/858897256d0deac81a172289110f31629fc4cee19b6f01283303e18c8db3/ptyprocess-0.7.0-py2.py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/8e/37/efad0257dc6e593a18957422533ff0f87ede7c9c6ea010a2177d738fb82f/pure_eval-0.2.3-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/0c/c3/44f3fbbfa403ea2a7c779186dc20772604442dde72947e7d01069cbe98e3/pycparser-3.0-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/5a/87/b70ad306ebb6f9b585f114d0ac2137d792b48be34d732d60e597c2f8465a/pydantic-2.12.5-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/aa/32/9c2e8ccb57c01111e0fd091f236c7b371c1bccea0fa85247ac55b1e2b6b6/pydantic_core-2.41.5-cp312-cp312-macosx_11_0_arm64.whl - pypi: https://files.pythonhosted.org/packages/8a/0b/9fcc47d19c48b59121088dd6da2488a49d5f72dacf8262e2790a1d2c7d15/pygments-2.19.1-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/80/be/ecb7cfb42d242b7ee764b52e6ff4782beeec00e3b943a3ec832b281f9da6/pyright-1.1.396-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/30/3d/64ad57c803f1fa1e963a7946b6e0fea4a70df53c1a7fed304586539c2bac/pytest-8.3.5-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/36/3b/48e79f2cd6a61dbbd4807b4ed46cb564b4fd50a76166b1c4ea5c1d9e2371/pytest_cov-6.0.0-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/ec/57/56b9bcc3c9c6a792fcbaf139543cee77261f3651ca9da0c93f5c1221264b/python_dateutil-2.9.0.post0-py2.py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/51/e5/fecf13f06e5e5f67e8837d777d1bc43fac0ed2b77a676804df5c34744727/python_json_logger-4.0.0-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/41/5d/e44573011401fb82e9d51e97f1290ceb377800fb4eed650b96f4753b499c/pytokens-0.4.1-cp312-cp312-macosx_11_0_arm64.whl + - pypi: https://files.pythonhosted.org/packages/89/a0/6cf41a19a1f2f3feab0e9c0b74134aa2ce6849093d5517a0c550fe37a648/pyyaml-6.0.3-cp312-cp312-macosx_11_0_arm64.whl + - pypi: https://files.pythonhosted.org/packages/92/e7/038aab64a946d535901103da16b953c8c9cc9c961dadcbf3609ed6428d23/pyzmq-27.1.0-cp312-abi3-macosx_10_15_universal2.whl + - pypi: https://files.pythonhosted.org/packages/75/d9/0b48d4184f9ca6a996c4fac46897a968698c9d1e0f0e43a6906746201323/quartodoc-0.11.1-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/2c/58/ca301544e1fa93ed4f80d724bf5b194f6e4b945841c5bfd555878eea9fcb/referencing-0.37.0-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/1e/db/4254e3eabe8020b458f1a747140d32277ec7a271daf1d235b70dc0b4e6e3/requests-2.32.5-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/7b/44/4e421b96b67b2daff264473f7465db72fbdf36a07e05494f50300cc7b0c6/rfc3339_validator-0.1.4-py2.py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/9e/51/17023c0f8f1869d8806b979a2bffa3f861f26a3f1a66b094288323fba52f/rfc3986_validator-0.1.1-py2.py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/7e/71/44ce230e1b7fadd372515a97e32a83011f906ddded8d03e3c6aafbdedbb7/rfc3987_syntax-1.1.0-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/ef/45/615f5babd880b4bd7d405cc0dc348234c5ffb6ed1ea33e152ede08b2072d/rich-14.3.2-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/4d/a1/bca7fd3d452b272e13335db8d6b0b3ecde0f90ad6f16f3328c6fb150c889/rpds_py-0.30.0-cp312-cp312-macosx_11_0_arm64.whl - pypi: https://files.pythonhosted.org/packages/02/49/1c79e0906b6ff551fb0894168763f705bf980864739572b2815ecd3c9df0/ruff-0.9.10-py3-none-macosx_11_0_arm64.whl + - pypi: https://files.pythonhosted.org/packages/1c/78/504fdd027da3b84ff1aecd9f6957e65f35134534ccc6da8628eb71e76d3f/send2trash-2.1.0-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/94/b8/f1f62a5e3c0ad2ff1d189590bfa4c46b4f3b6e49cef6f26c6ee4e575394d/setuptools-80.10.2-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/b7/ce/149a00dd41f10bc29e5921b496af8b574d8413afcd5e30dfa0ed46c2cc5e/six-1.17.0-py2.py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/32/46/9cb0e58b2deb7f82b84065f37f3bffeb12413f947f9388e4cac22c4621ce/sortedcontainers-2.4.0-py2.py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/46/2c/1462b1d0a634697ae9e55b3cecdcb64788e8b7d63f54d923fcd0bb140aed/soupsieve-2.8.3-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/63/f9/f48a8f489c8ae8930f12c558b4dd26da96791837747fca87e9da2643f12d/sphobjinv-2.3.1.3-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/b6/35/d16bfa235c8b7caba3730bba43e20b1e376d2224f407c178fbf59559f23e/sqlalchemy-2.0.46-cp312-cp312-macosx_11_0_arm64.whl - pypi: https://files.pythonhosted.org/packages/f1/7b/ce1eafaf1a76852e2ec9b22edecf1daa58175c090266e9f6c64afcd81d91/stack_data-0.6.3-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/40/44/4a5f08c96eb108af5cb50b41f76142f0afa346dfa99d5296fe7202a11854/tabulate-0.9.0-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/6a/9e/2064975477fdc887e47ad42157e214526dcad8f317a948dee17e1659a62f/terminado-0.18.1-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/e6/34/ebdc18bae6aa14fbee1a08b63c015c72b64868ff7dae68808ab500c492e2/tinycss2-1.4.0-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/ab/a9/e94a9d5224107d7ce3cc1fab8d5dc97f5ea351ccc6322ee4fb661da94e35/tornado-6.5.4-cp39-abi3-macosx_10_9_universal2.whl - pypi: https://files.pythonhosted.org/packages/00/c0/8f5d070730d7836adc9c9b6408dec68c6ced86b304a9b26a14df072a6e8c/traitlets-5.14.3-py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/26/9f/ad63fc0248c5379346306f8668cda6e2e2e9c95e01216d2b8ffd9ff037d0/typing_extensions-4.12.2-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/18/67/36e9267722cc04a6b9f15c7f3441c2363321a3ea07da7ae0c0707beb2a9c/typing_extensions-4.15.0-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/dc/9b/47798a6c91d8bdb567fe2698fe81e0c6b7cb7ef4d13da4114b41d239f65d/typing_inspection-0.4.2-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/c7/b0/003792df09decd6849a5e39c28b513c06e84436a54440380862b5aeff25d/tzdata-2025.3-py2.py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/e7/00/3fca040d7cf8a32776d3d81a00c8ee7457e00f80c649f1e4a863c8321ae9/uri_template-1.3.0-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/39/08/aaaad47bc4e9dc8c725e68f9d04865dbcb2052843ff09c97b08904852d84/urllib3-2.6.3-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/5b/7e/8f322f5e600812e6f9a31b75d242631068ca8f4ef0582dd3ae6e72daecc8/watchdog-6.0.0-cp312-cp312-macosx_11_0_arm64.whl - pypi: https://files.pythonhosted.org/packages/fd/84/fd2ba7aafacbad3c4201d395674fc6348826569da3c0937e75505ead3528/wcwidth-0.2.13-py2.py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/e2/cc/e097523dd85c9cf5d354f78310927f1656c422bd7b2613b2db3e3f9a0f2c/webcolors-25.10.0-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/f4/24/2a3e3df732393fed8b3ebf2ec078f05546de641fe1b667ee316ec1dcf3b7/webencodings-0.5.1-py2.py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/34/db/b10e48aa8fff7407e67470363eac595018441cf32d5e1001567a7aeba5d2/websocket_client-1.9.0-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/3f/0e/fa3b193432cfc60c93b42f3be03365f5f909d2b3ea410295cf36df739e31/widgetsnbextension-4.0.15-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/58/b8/e4722f5e5f592a665cc8e55a334ea721c359f09574e6b987dc551a1e1f4c/xdoctest-1.2.0-py3-none-any.whl - - pypi: . + - pypi: https://files.pythonhosted.org/packages/2e/54/647ade08bf0db230bfea292f893923872fd20be6ac6f53b2b936ba839d75/zipp-3.23.0-py3-none-any.whl + - pypi: ./ + docs: + channels: + - url: https://conda.anaconda.org/conda-forge/ + indexes: + - https://pypi.org/simple + packages: + linux-64: + - conda: https://conda.anaconda.org/conda-forge/linux-64/_libgcc_mutex-0.1-conda_forge.tar.bz2 + - conda: https://conda.anaconda.org/conda-forge/linux-64/_openmp_mutex-4.5-2_gnu.tar.bz2 + - conda: https://conda.anaconda.org/conda-forge/linux-64/bzip2-1.0.8-h4bc722e_7.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/ca-certificates-2025.1.31-hbcca054_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/ld_impl_linux-64-2.43-h712a8e2_4.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libexpat-2.6.4-h5888daf_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libffi-3.4.6-h2dba641_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libgcc-14.2.0-h767d61c_2.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libgcc-ng-14.2.0-h69a702a_2.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libgomp-14.2.0-h767d61c_2.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/liblzma-5.6.4-hb9d3cd8_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libnsl-2.0.1-hd590300_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libsqlite-3.49.1-hee588c1_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libuuid-2.38.1-h0b41bf4_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libxcrypt-4.4.36-hd590300_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libzlib-1.3.1-hb9d3cd8_2.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/ncurses-6.5-h2d0b736_3.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/openssl-3.4.1-h7b32b05_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/python-3.12.9-h9e4cc4f_1_cpython.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/readline-8.2-h8c095d6_2.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/tk-8.6.13-noxft_h4845f30_101.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/tzdata-2025a-h78e105d_0.conda + - pypi: https://files.pythonhosted.org/packages/78/b6/6307fbef88d9b5ee7421e68d78a9f162e0da4900bc5f5793f6d3d0e34fb8/annotated_types-0.7.0-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/38/0e/27be9fdef66e72d64c0cdc3cc2823101b80585f8119b5c112c2e8f5f7dab/anyio-4.12.1-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/4f/d3/a8b22fa575b297cd6e3e3b0155c7e25db170edf1c74783d6a31a2490b8d9/argon2_cffi-25.1.0-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/09/52/94108adfdd6e2ddf58be64f959a0b9c7d4ef2fa71086c38356d22dc501ea/argon2_cffi_bindings-25.1.0-cp39-abi3-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl + - pypi: https://files.pythonhosted.org/packages/ed/c9/d7977eaacb9df673210491da99e6a247e93df98c715fc43fd136ce1d3d33/arrow-1.4.0-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/25/8a/c46dcc25341b5bce5472c718902eb3d38600a903b14fa6aeecef3f21a46f/asttokens-3.0.0-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/2e/e9/eb6a5db5ac505d5d45715388e92bced7a5bb556facc4d0865d192823f2d2/async_lru-2.1.0-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/fc/30/d4986a882011f9df997a55e6becd864812ccfcd821d64aac8570ee39f719/attrs-25.1.0-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/77/f5/21d2de20e8b8b0408f0681956ca2c69f1320a3848ac50e6e7f39c6159675/babel-2.18.0-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/71/cc/18245721fa7747065ab478316c7fea7c74777d07f37ae60db2e84f8172e8/beartype-0.22.9-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/1a/39/47f9197bdd44df24d67ac8893641e16f386c984a0619ef2ee4c51fbbc019/beautifulsoup4-4.14.3-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/8c/04/c96f79d7b93e8f09d9298b333ca0d31cd9b2ee6c46c274fd0f531de9dc61/black-26.1.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl + - pypi: https://files.pythonhosted.org/packages/cd/3a/577b549de0cc09d95f11087ee63c739bba856cd3952697eec4c4bb91350a/bleach-6.3.0-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/e6/ad/3cc14f097111b4de0040c83a525973216457bbeeb63739ef1ed275c1c021/certifi-2026.1.4-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/78/2d/7fa73dfa841b5ac06c7b8855cfc18622132e365f5b81d02230333ff26e9e/cffi-2.0.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl + - pypi: https://files.pythonhosted.org/packages/c0/10/d20b513afe03acc89ec33948320a5544d31f21b05368436d580dec4e234d/charset_normalizer-3.4.4-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl + - pypi: https://files.pythonhosted.org/packages/98/78/01c019cdb5d6498122777c1a43056ebb3ebfeef2076d9d026bfe15583b2b/click-8.3.1-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/d1/d6/3965ed04c63042e047cb6a3e6ed1a63a35087b6a609aa3a15ed8ac56c221/colorama-0.4.6-py2.py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/60/97/891a0971e1e4a8c5d2b20bbe0e524dc04548d2307fee33cdeba148fd4fc7/comm-0.2.3-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/e0/c3/7f67dea8ccf8fdcb9c99033bbe3e90b9e7395415843accb81428c441be2d/debugpy-1.8.20-py2.py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/4e/8c/f3147f5c4b73e7550fe5f9352eaa956ae838d5c51eb58e7a25b9f3e2643b/decorator-5.2.1-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/07/6c/aa3f2f849e01cb6a001cd8554a88d4c77c5c1a31c95bdf1cf9301e6d9ef4/defusedxml-0.7.1-py2.py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/7b/8f/c4d9bafc34ad7ad5d8dc16dd1347ee0e507a52c3adb6bfa8887e1c6a26ba/executing-2.2.0-py2.py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/cb/a8/20d0723294217e47de6d9e2e40fd4a9d2f7c4b6ef974babd482a59743694/fastjsonschema-2.21.2-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/cf/58/8acf1b3e91c58313ce5cb67df61001fc9dcd21be4fadb76c1a2d540e09ed/fqdn-1.5.1-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/cf/05/821587cf19e2ce1f2b24945d890b164401e5085f9d09cbd969b0c193cd20/greenlet-3.3.1-cp312-cp312-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl + - pypi: https://files.pythonhosted.org/packages/9c/83/3b1d03d36f224edded98e9affd0467630fc09d766c0e56fb1498cbb04a9b/griffe-1.15.0-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/0e/61/66938bbb5fc52dbdf84594873d5b51fb1f7c7794e9c0f5bd885f30bc507b/idna-3.11-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/fa/5e/f8e9a1d23b9c20a551a8a02ea3637b4642e22c2626e3a13a9a29cdea99eb/importlib_metadata-8.7.1-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/a4/ed/1f1afb2e9e7f38a545d628f864d562a5ae64fe6f7a10e28ffb9b185b4e89/importlib_resources-6.5.2-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/a3/17/20c2552266728ceba271967b87919664ecc0e33efca29c3efc6baf88c5f9/ipykernel-7.1.0-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/20/3a/917cb9e72f4e1a4ea13c862533205ae1319bd664119189ee5cc9e4e95ebf/ipython-9.0.2-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/d9/33/1f075bf72b0b747cb3288d011319aaf64083cf2efef8354174e3ed4540e2/ipython_pygments_lexers-1.1.1-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/56/6d/0d9848617b9f753b87f214f1c682592f7ca42de085f564352f10f0843026/ipywidgets-8.1.8-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/7b/55/e5326141505c5d5e34c5e0935d2908a74e4561eca44108fbfb9c13d2911a/isoduration-20.11.0-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/c0/5a/9cac0c82afec3d09ccd97c8b6502d48f165f9124db81b4bcb90b4af974ee/jedi-0.19.2-py2.py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/62/a1/3d680cbfd5f4b8f15abc1d571870c5fc3e594bb582bc3b64ea099db13e56/jinja2-3.1.6-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/d7/9e/038522f50ceb7e74f1f991bf1b699f24b0c2bbe7c390dd36ad69f4582258/json5-0.13.0-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/71/92/5e77f98553e9e75130c78900d000368476aed74276eb8ae8796f65f00918/jsonpointer-3.0.0-py2.py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/69/90/f63fb5873511e014207a475e2bb4e8b2e570d655b00ac19a9a0ca0a385ee/jsonschema-4.26.0-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/41/45/1a4ed80516f02155c51f51e8cedb3c1902296743db0bbc66608a0db2814f/jsonschema_specifications-2025.9.1-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/38/64/285f20a31679bf547b75602702f7800e74dbabae36ef324f716c02804753/jupyter-1.1.1-py2.py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/64/6b/67b87da9d36bff9df7d0efbd1a325fa372a43be7158effaf43ed7b22341d/jupyter_cache-1.0.1-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/2d/0b/ceb7694d864abc0a047649aec263878acb9f792e1fec3e676f22dc9015e3/jupyter_client-8.8.0-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/ca/77/71d78d58f15c22db16328a476426f7ac4a60d3a5a7ba3b9627ee2f7903d4/jupyter_console-6.6.3-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/e7/e7/80988e32bf6f73919a113473a604f5a8f09094de312b9d52b79c2df7612b/jupyter_core-5.9.1-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/e2/48/577993f1f99c552f18a0428731a755e06171f9902fa118c379eb7c04ea22/jupyter_events-0.12.0-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/1a/60/1f6cee0c46263de1173894f0fafcb3475ded276c472c14d25e0280c18d6d/jupyter_lsp-2.3.0-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/92/80/a24767e6ca280f5a49525d987bf3e4d7552bf67c8be07e8ccf20271f8568/jupyter_server-2.17.0-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/d1/2d/6674563f71c6320841fc300911a55143925112a72a883e2ca71fba4c618d/jupyter_server_terminals-0.5.4-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/9e/9a/0bf9a7a45f0006d7ff4fdc4fc313de4255acab02bf4db1887c65f0472c01/jupyterlab-4.5.3-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/b1/dd/ead9d8ea85bf202d90cc513b533f9c363121c7792674f78e0d8a854b63b4/jupyterlab_pygments-0.3.0-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/e0/07/a000fe835f76b7e1143242ab1122e6362ef1c03f23f83a045c38859c2ae0/jupyterlab_server-2.28.0-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/ab/b5/36c712098e6191d1b4e349304ef73a8d06aed77e56ceaac8c0a306c7bda1/jupyterlab_widgets-3.0.16-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/82/3d/14ce75ef66813643812f3093ab17e46d3a206942ce7376d31ec2d36229e7/lark-1.3.1-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/94/54/e7d793b573f298e1c9013b8c4dade17d481164aa517d1d7148619c2cedbf/markdown_it_py-4.0.0-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/3c/2e/8d0c2ab90a8c1d9a24f0399058ab8519a3279d1bd4289511d74e909f060e/markupsafe-3.0.3-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl + - pypi: https://files.pythonhosted.org/packages/8f/8e/9ad090d3553c280a8060fbf6e24dc1c0c29704ee7d1c372f0c174aa59285/matplotlib_inline-0.1.7-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/b3/38/89ba8ad64ae25be8de66a6d463314cf1eb366222074cfda9ee839c56a4b4/mdurl-0.1.2-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/9b/f7/4a5e785ec9fbd65146a27b6b70b6cdc161a66f2024e4b04ac06a67f5578b/mistune-3.2.0-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/79/7b/2c79738432f5c924bef5071f933bcc9efd0473bac3b4aa584a6f7c1c8df8/mypy_extensions-1.1.0-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/83/a0/5b0c2f11142ed1dddec842457d3f65eaf71a0080894eb6f018755b319c3a/nbclient-0.10.4-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/0d/4b/8d5f796a792f8a25f6925a96032f098789f448571eb92011df1ae59e8ea8/nbconvert-7.17.0-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/a9/82/0340caa499416c78e5d8f5f05947ae4bc3cba53c9f038ab6e9ed964e22f1/nbformat-5.10.4-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/a0/c4/c2971a3ba4c6103a3d10c4b0f24f461ddc027f0f09763220cf35ca1401b3/nest_asyncio-1.6.0-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/96/98/9286e7f35e5584ebb79f997f2fb0cb66745c86f6c5fccf15ba32aac5e908/notebook-7.5.3-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/f9/33/bd5b9137445ea4b680023eb0469b2bb969d61303dedb2aac6560ff3d14a1/notebook_shim-0.2.4-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/88/ef/eb23f262cca3c0c4eb7ab1933c3b1f03d021f2c48f54763065b6f0e321be/packaging-24.2-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/ef/af/4fbc8cab944db5d21b7e2a5b8e9211a03a79852b1157e2c102fcc61ac440/pandocfilters-1.5.1-py2.py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/c6/ac/dac4a63f978e4dcb3c6d3a78c4d8e0192a113d288502a1216950c41b1027/parso-0.8.4-py2.py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/ef/3c/2c197d226f9ea224a9ab8d197933f9da0ae0aac5b6e0f884e2b8d9c8e9f7/pathspec-1.0.4-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/9e/c3/059298687310d527a58bb01f3b1965787ee3b40dce76752eda8b44e9a2c5/pexpect-4.9.0-py2.py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/cb/28/3bfe2fa5a7b9c46fe7e13c97bda14c895fb10fa2ebf1d0abb90e0cea7ee1/platformdirs-4.5.1-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/42/88/71fa06eb487ed9d4fab0ad173300b7a58706385f98fb66b1ccdc3ec3d4dd/plum_dispatch-2.6.1-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/74/c3/24a2f845e3917201628ecaba4f18bab4d18a337834c1df2a159ee9d22a42/prometheus_client-0.24.1-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/e4/ea/d836f008d33151c7a1f62caf3d8dd782e4d15f6a43897f64480c2b8de2ad/prompt_toolkit-3.0.50-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/b5/70/5d8df3b09e25bce090399cf48e452d25c935ab72dad19406c77f4e828045/psutil-7.2.2-cp36-abi3-manylinux2010_x86_64.manylinux_2_12_x86_64.manylinux_2_28_x86_64.whl + - pypi: https://files.pythonhosted.org/packages/22/a6/858897256d0deac81a172289110f31629fc4cee19b6f01283303e18c8db3/ptyprocess-0.7.0-py2.py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/8e/37/efad0257dc6e593a18957422533ff0f87ede7c9c6ea010a2177d738fb82f/pure_eval-0.2.3-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/0c/c3/44f3fbbfa403ea2a7c779186dc20772604442dde72947e7d01069cbe98e3/pycparser-3.0-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/5a/87/b70ad306ebb6f9b585f114d0ac2137d792b48be34d732d60e597c2f8465a/pydantic-2.12.5-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/0d/76/941cc9f73529988688a665a5c0ecff1112b3d95ab48f81db5f7606f522d3/pydantic_core-2.41.5-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl + - pypi: https://files.pythonhosted.org/packages/8a/0b/9fcc47d19c48b59121088dd6da2488a49d5f72dacf8262e2790a1d2c7d15/pygments-2.19.1-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/ec/57/56b9bcc3c9c6a792fcbaf139543cee77261f3651ca9da0c93f5c1221264b/python_dateutil-2.9.0.post0-py2.py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/51/e5/fecf13f06e5e5f67e8837d777d1bc43fac0ed2b77a676804df5c34744727/python_json_logger-4.0.0-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/bf/3c/2d5297d82286f6f3d92770289fd439956b201c0a4fc7e72efb9b2293758e/pytokens-0.4.1-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl + - pypi: https://files.pythonhosted.org/packages/8b/9d/b3589d3877982d4f2329302ef98a8026e7f4443c765c46cfecc8858c6b4b/pyyaml-6.0.3-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl + - pypi: https://files.pythonhosted.org/packages/f8/9b/c108cdb55560eaf253f0cbdb61b29971e9fb34d9c3499b0e96e4e60ed8a5/pyzmq-27.1.0-cp312-abi3-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl + - pypi: https://files.pythonhosted.org/packages/75/d9/0b48d4184f9ca6a996c4fac46897a968698c9d1e0f0e43a6906746201323/quartodoc-0.11.1-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/2c/58/ca301544e1fa93ed4f80d724bf5b194f6e4b945841c5bfd555878eea9fcb/referencing-0.37.0-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/1e/db/4254e3eabe8020b458f1a747140d32277ec7a271daf1d235b70dc0b4e6e3/requests-2.32.5-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/7b/44/4e421b96b67b2daff264473f7465db72fbdf36a07e05494f50300cc7b0c6/rfc3339_validator-0.1.4-py2.py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/9e/51/17023c0f8f1869d8806b979a2bffa3f861f26a3f1a66b094288323fba52f/rfc3986_validator-0.1.1-py2.py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/7e/71/44ce230e1b7fadd372515a97e32a83011f906ddded8d03e3c6aafbdedbb7/rfc3987_syntax-1.1.0-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/ef/45/615f5babd880b4bd7d405cc0dc348234c5ffb6ed1ea33e152ede08b2072d/rich-14.3.2-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/60/1b/6f8f29f3f995c7ffdde46a626ddccd7c63aefc0efae881dc13b6e5d5bb16/rpds_py-0.30.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl + - pypi: https://files.pythonhosted.org/packages/1c/78/504fdd027da3b84ff1aecd9f6957e65f35134534ccc6da8628eb71e76d3f/send2trash-2.1.0-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/94/b8/f1f62a5e3c0ad2ff1d189590bfa4c46b4f3b6e49cef6f26c6ee4e575394d/setuptools-80.10.2-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/b7/ce/149a00dd41f10bc29e5921b496af8b574d8413afcd5e30dfa0ed46c2cc5e/six-1.17.0-py2.py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/46/2c/1462b1d0a634697ae9e55b3cecdcb64788e8b7d63f54d923fcd0bb140aed/soupsieve-2.8.3-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/63/f9/f48a8f489c8ae8930f12c558b4dd26da96791837747fca87e9da2643f12d/sphobjinv-2.3.1.3-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/ea/a2/b9f33c8d68a3747d972a0bb758c6b63691f8fb8a49014bc3379ba15d4274/sqlalchemy-2.0.46-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl + - pypi: https://files.pythonhosted.org/packages/f1/7b/ce1eafaf1a76852e2ec9b22edecf1daa58175c090266e9f6c64afcd81d91/stack_data-0.6.3-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/40/44/4a5f08c96eb108af5cb50b41f76142f0afa346dfa99d5296fe7202a11854/tabulate-0.9.0-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/6a/9e/2064975477fdc887e47ad42157e214526dcad8f317a948dee17e1659a62f/terminado-0.18.1-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/e6/34/ebdc18bae6aa14fbee1a08b63c015c72b64868ff7dae68808ab500c492e2/tinycss2-1.4.0-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/50/d4/e51d52047e7eb9a582da59f32125d17c0482d065afd5d3bc435ff2120dc5/tornado-6.5.4-cp39-abi3-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl + - pypi: https://files.pythonhosted.org/packages/00/c0/8f5d070730d7836adc9c9b6408dec68c6ced86b304a9b26a14df072a6e8c/traitlets-5.14.3-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/18/67/36e9267722cc04a6b9f15c7f3441c2363321a3ea07da7ae0c0707beb2a9c/typing_extensions-4.15.0-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/dc/9b/47798a6c91d8bdb567fe2698fe81e0c6b7cb7ef4d13da4114b41d239f65d/typing_inspection-0.4.2-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/c7/b0/003792df09decd6849a5e39c28b513c06e84436a54440380862b5aeff25d/tzdata-2025.3-py2.py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/e7/00/3fca040d7cf8a32776d3d81a00c8ee7457e00f80c649f1e4a863c8321ae9/uri_template-1.3.0-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/39/08/aaaad47bc4e9dc8c725e68f9d04865dbcb2052843ff09c97b08904852d84/urllib3-2.6.3-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/b5/e8/dbf020b4d98251a9860752a094d09a65e1b436ad181faf929983f697048f/watchdog-6.0.0-py3-none-manylinux2014_x86_64.whl + - pypi: https://files.pythonhosted.org/packages/fd/84/fd2ba7aafacbad3c4201d395674fc6348826569da3c0937e75505ead3528/wcwidth-0.2.13-py2.py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/e2/cc/e097523dd85c9cf5d354f78310927f1656c422bd7b2613b2db3e3f9a0f2c/webcolors-25.10.0-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/f4/24/2a3e3df732393fed8b3ebf2ec078f05546de641fe1b667ee316ec1dcf3b7/webencodings-0.5.1-py2.py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/34/db/b10e48aa8fff7407e67470363eac595018441cf32d5e1001567a7aeba5d2/websocket_client-1.9.0-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/3f/0e/fa3b193432cfc60c93b42f3be03365f5f909d2b3ea410295cf36df739e31/widgetsnbextension-4.0.15-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/2e/54/647ade08bf0db230bfea292f893923872fd20be6ac6f53b2b936ba839d75/zipp-3.23.0-py3-none-any.whl + - pypi: ./ + osx-arm64: + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/bzip2-1.0.8-h99b78c6_7.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/ca-certificates-2025.1.31-hf0a4a13_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libexpat-2.6.4-h286801f_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libffi-3.4.2-h3422bc3_5.tar.bz2 + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/liblzma-5.6.4-h39f12f2_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libsqlite-3.49.1-h3f77e49_1.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libzlib-1.3.1-h8359307_2.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/ncurses-6.5-h5e97a16_3.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/openssl-3.4.1-h81ee809_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/python-3.12.9-hc22306f_1_cpython.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/readline-8.2-h1d1bf99_2.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/tk-8.6.13-h5083fa2_1.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/tzdata-2025a-h78e105d_0.conda + - pypi: https://files.pythonhosted.org/packages/78/b6/6307fbef88d9b5ee7421e68d78a9f162e0da4900bc5f5793f6d3d0e34fb8/annotated_types-0.7.0-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/38/0e/27be9fdef66e72d64c0cdc3cc2823101b80585f8119b5c112c2e8f5f7dab/anyio-4.12.1-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/81/29/5ecc3a15d5a33e31b26c11426c45c501e439cb865d0bff96315d86443b78/appnope-0.1.4-py2.py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/4f/d3/a8b22fa575b297cd6e3e3b0155c7e25db170edf1c74783d6a31a2490b8d9/argon2_cffi-25.1.0-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/b6/02/d297943bcacf05e4f2a94ab6f462831dc20158614e5d067c35d4e63b9acb/argon2_cffi_bindings-25.1.0-cp39-abi3-macosx_11_0_arm64.whl + - pypi: https://files.pythonhosted.org/packages/ed/c9/d7977eaacb9df673210491da99e6a247e93df98c715fc43fd136ce1d3d33/arrow-1.4.0-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/25/8a/c46dcc25341b5bce5472c718902eb3d38600a903b14fa6aeecef3f21a46f/asttokens-3.0.0-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/2e/e9/eb6a5db5ac505d5d45715388e92bced7a5bb556facc4d0865d192823f2d2/async_lru-2.1.0-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/fc/30/d4986a882011f9df997a55e6becd864812ccfcd821d64aac8570ee39f719/attrs-25.1.0-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/77/f5/21d2de20e8b8b0408f0681956ca2c69f1320a3848ac50e6e7f39c6159675/babel-2.18.0-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/71/cc/18245721fa7747065ab478316c7fea7c74777d07f37ae60db2e84f8172e8/beartype-0.22.9-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/1a/39/47f9197bdd44df24d67ac8893641e16f386c984a0619ef2ee4c51fbbc019/beautifulsoup4-4.14.3-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/79/a6/5179beaa57e5dbd2ec9f1c64016214057b4265647c62125aa6aeffb05392/black-26.1.0-cp312-cp312-macosx_11_0_arm64.whl + - pypi: https://files.pythonhosted.org/packages/cd/3a/577b549de0cc09d95f11087ee63c739bba856cd3952697eec4c4bb91350a/bleach-6.3.0-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/e6/ad/3cc14f097111b4de0040c83a525973216457bbeeb63739ef1ed275c1c021/certifi-2026.1.4-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/df/a2/781b623f57358e360d62cdd7a8c681f074a71d445418a776eef0aadb4ab4/cffi-2.0.0-cp312-cp312-macosx_11_0_arm64.whl + - pypi: https://files.pythonhosted.org/packages/f3/85/1637cd4af66fa687396e757dec650f28025f2a2f5a5531a3208dc0ec43f2/charset_normalizer-3.4.4-cp312-cp312-macosx_10_13_universal2.whl + - pypi: https://files.pythonhosted.org/packages/98/78/01c019cdb5d6498122777c1a43056ebb3ebfeef2076d9d026bfe15583b2b/click-8.3.1-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/d1/d6/3965ed04c63042e047cb6a3e6ed1a63a35087b6a609aa3a15ed8ac56c221/colorama-0.4.6-py2.py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/60/97/891a0971e1e4a8c5d2b20bbe0e524dc04548d2307fee33cdeba148fd4fc7/comm-0.2.3-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/e0/c3/7f67dea8ccf8fdcb9c99033bbe3e90b9e7395415843accb81428c441be2d/debugpy-1.8.20-py2.py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/4e/8c/f3147f5c4b73e7550fe5f9352eaa956ae838d5c51eb58e7a25b9f3e2643b/decorator-5.2.1-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/07/6c/aa3f2f849e01cb6a001cd8554a88d4c77c5c1a31c95bdf1cf9301e6d9ef4/defusedxml-0.7.1-py2.py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/7b/8f/c4d9bafc34ad7ad5d8dc16dd1347ee0e507a52c3adb6bfa8887e1c6a26ba/executing-2.2.0-py2.py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/cb/a8/20d0723294217e47de6d9e2e40fd4a9d2f7c4b6ef974babd482a59743694/fastjsonschema-2.21.2-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/cf/58/8acf1b3e91c58313ce5cb67df61001fc9dcd21be4fadb76c1a2d540e09ed/fqdn-1.5.1-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/9c/83/3b1d03d36f224edded98e9affd0467630fc09d766c0e56fb1498cbb04a9b/griffe-1.15.0-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/0e/61/66938bbb5fc52dbdf84594873d5b51fb1f7c7794e9c0f5bd885f30bc507b/idna-3.11-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/fa/5e/f8e9a1d23b9c20a551a8a02ea3637b4642e22c2626e3a13a9a29cdea99eb/importlib_metadata-8.7.1-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/a4/ed/1f1afb2e9e7f38a545d628f864d562a5ae64fe6f7a10e28ffb9b185b4e89/importlib_resources-6.5.2-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/a3/17/20c2552266728ceba271967b87919664ecc0e33efca29c3efc6baf88c5f9/ipykernel-7.1.0-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/20/3a/917cb9e72f4e1a4ea13c862533205ae1319bd664119189ee5cc9e4e95ebf/ipython-9.0.2-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/d9/33/1f075bf72b0b747cb3288d011319aaf64083cf2efef8354174e3ed4540e2/ipython_pygments_lexers-1.1.1-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/56/6d/0d9848617b9f753b87f214f1c682592f7ca42de085f564352f10f0843026/ipywidgets-8.1.8-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/7b/55/e5326141505c5d5e34c5e0935d2908a74e4561eca44108fbfb9c13d2911a/isoduration-20.11.0-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/c0/5a/9cac0c82afec3d09ccd97c8b6502d48f165f9124db81b4bcb90b4af974ee/jedi-0.19.2-py2.py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/62/a1/3d680cbfd5f4b8f15abc1d571870c5fc3e594bb582bc3b64ea099db13e56/jinja2-3.1.6-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/d7/9e/038522f50ceb7e74f1f991bf1b699f24b0c2bbe7c390dd36ad69f4582258/json5-0.13.0-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/71/92/5e77f98553e9e75130c78900d000368476aed74276eb8ae8796f65f00918/jsonpointer-3.0.0-py2.py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/69/90/f63fb5873511e014207a475e2bb4e8b2e570d655b00ac19a9a0ca0a385ee/jsonschema-4.26.0-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/41/45/1a4ed80516f02155c51f51e8cedb3c1902296743db0bbc66608a0db2814f/jsonschema_specifications-2025.9.1-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/38/64/285f20a31679bf547b75602702f7800e74dbabae36ef324f716c02804753/jupyter-1.1.1-py2.py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/64/6b/67b87da9d36bff9df7d0efbd1a325fa372a43be7158effaf43ed7b22341d/jupyter_cache-1.0.1-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/2d/0b/ceb7694d864abc0a047649aec263878acb9f792e1fec3e676f22dc9015e3/jupyter_client-8.8.0-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/ca/77/71d78d58f15c22db16328a476426f7ac4a60d3a5a7ba3b9627ee2f7903d4/jupyter_console-6.6.3-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/e7/e7/80988e32bf6f73919a113473a604f5a8f09094de312b9d52b79c2df7612b/jupyter_core-5.9.1-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/e2/48/577993f1f99c552f18a0428731a755e06171f9902fa118c379eb7c04ea22/jupyter_events-0.12.0-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/1a/60/1f6cee0c46263de1173894f0fafcb3475ded276c472c14d25e0280c18d6d/jupyter_lsp-2.3.0-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/92/80/a24767e6ca280f5a49525d987bf3e4d7552bf67c8be07e8ccf20271f8568/jupyter_server-2.17.0-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/d1/2d/6674563f71c6320841fc300911a55143925112a72a883e2ca71fba4c618d/jupyter_server_terminals-0.5.4-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/9e/9a/0bf9a7a45f0006d7ff4fdc4fc313de4255acab02bf4db1887c65f0472c01/jupyterlab-4.5.3-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/b1/dd/ead9d8ea85bf202d90cc513b533f9c363121c7792674f78e0d8a854b63b4/jupyterlab_pygments-0.3.0-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/e0/07/a000fe835f76b7e1143242ab1122e6362ef1c03f23f83a045c38859c2ae0/jupyterlab_server-2.28.0-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/ab/b5/36c712098e6191d1b4e349304ef73a8d06aed77e56ceaac8c0a306c7bda1/jupyterlab_widgets-3.0.16-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/82/3d/14ce75ef66813643812f3093ab17e46d3a206942ce7376d31ec2d36229e7/lark-1.3.1-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/94/54/e7d793b573f298e1c9013b8c4dade17d481164aa517d1d7148619c2cedbf/markdown_it_py-4.0.0-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/9a/81/7e4e08678a1f98521201c3079f77db69fb552acd56067661f8c2f534a718/markupsafe-3.0.3-cp312-cp312-macosx_11_0_arm64.whl + - pypi: https://files.pythonhosted.org/packages/8f/8e/9ad090d3553c280a8060fbf6e24dc1c0c29704ee7d1c372f0c174aa59285/matplotlib_inline-0.1.7-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/b3/38/89ba8ad64ae25be8de66a6d463314cf1eb366222074cfda9ee839c56a4b4/mdurl-0.1.2-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/9b/f7/4a5e785ec9fbd65146a27b6b70b6cdc161a66f2024e4b04ac06a67f5578b/mistune-3.2.0-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/79/7b/2c79738432f5c924bef5071f933bcc9efd0473bac3b4aa584a6f7c1c8df8/mypy_extensions-1.1.0-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/83/a0/5b0c2f11142ed1dddec842457d3f65eaf71a0080894eb6f018755b319c3a/nbclient-0.10.4-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/0d/4b/8d5f796a792f8a25f6925a96032f098789f448571eb92011df1ae59e8ea8/nbconvert-7.17.0-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/a9/82/0340caa499416c78e5d8f5f05947ae4bc3cba53c9f038ab6e9ed964e22f1/nbformat-5.10.4-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/a0/c4/c2971a3ba4c6103a3d10c4b0f24f461ddc027f0f09763220cf35ca1401b3/nest_asyncio-1.6.0-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/96/98/9286e7f35e5584ebb79f997f2fb0cb66745c86f6c5fccf15ba32aac5e908/notebook-7.5.3-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/f9/33/bd5b9137445ea4b680023eb0469b2bb969d61303dedb2aac6560ff3d14a1/notebook_shim-0.2.4-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/88/ef/eb23f262cca3c0c4eb7ab1933c3b1f03d021f2c48f54763065b6f0e321be/packaging-24.2-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/ef/af/4fbc8cab944db5d21b7e2a5b8e9211a03a79852b1157e2c102fcc61ac440/pandocfilters-1.5.1-py2.py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/c6/ac/dac4a63f978e4dcb3c6d3a78c4d8e0192a113d288502a1216950c41b1027/parso-0.8.4-py2.py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/ef/3c/2c197d226f9ea224a9ab8d197933f9da0ae0aac5b6e0f884e2b8d9c8e9f7/pathspec-1.0.4-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/9e/c3/059298687310d527a58bb01f3b1965787ee3b40dce76752eda8b44e9a2c5/pexpect-4.9.0-py2.py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/cb/28/3bfe2fa5a7b9c46fe7e13c97bda14c895fb10fa2ebf1d0abb90e0cea7ee1/platformdirs-4.5.1-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/42/88/71fa06eb487ed9d4fab0ad173300b7a58706385f98fb66b1ccdc3ec3d4dd/plum_dispatch-2.6.1-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/74/c3/24a2f845e3917201628ecaba4f18bab4d18a337834c1df2a159ee9d22a42/prometheus_client-0.24.1-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/e4/ea/d836f008d33151c7a1f62caf3d8dd782e4d15f6a43897f64480c2b8de2ad/prompt_toolkit-3.0.50-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/80/c4/f5af4c1ca8c1eeb2e92ccca14ce8effdeec651d5ab6053c589b074eda6e1/psutil-7.2.2-cp36-abi3-macosx_11_0_arm64.whl + - pypi: https://files.pythonhosted.org/packages/22/a6/858897256d0deac81a172289110f31629fc4cee19b6f01283303e18c8db3/ptyprocess-0.7.0-py2.py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/8e/37/efad0257dc6e593a18957422533ff0f87ede7c9c6ea010a2177d738fb82f/pure_eval-0.2.3-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/0c/c3/44f3fbbfa403ea2a7c779186dc20772604442dde72947e7d01069cbe98e3/pycparser-3.0-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/5a/87/b70ad306ebb6f9b585f114d0ac2137d792b48be34d732d60e597c2f8465a/pydantic-2.12.5-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/aa/32/9c2e8ccb57c01111e0fd091f236c7b371c1bccea0fa85247ac55b1e2b6b6/pydantic_core-2.41.5-cp312-cp312-macosx_11_0_arm64.whl + - pypi: https://files.pythonhosted.org/packages/8a/0b/9fcc47d19c48b59121088dd6da2488a49d5f72dacf8262e2790a1d2c7d15/pygments-2.19.1-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/ec/57/56b9bcc3c9c6a792fcbaf139543cee77261f3651ca9da0c93f5c1221264b/python_dateutil-2.9.0.post0-py2.py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/51/e5/fecf13f06e5e5f67e8837d777d1bc43fac0ed2b77a676804df5c34744727/python_json_logger-4.0.0-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/41/5d/e44573011401fb82e9d51e97f1290ceb377800fb4eed650b96f4753b499c/pytokens-0.4.1-cp312-cp312-macosx_11_0_arm64.whl + - pypi: https://files.pythonhosted.org/packages/89/a0/6cf41a19a1f2f3feab0e9c0b74134aa2ce6849093d5517a0c550fe37a648/pyyaml-6.0.3-cp312-cp312-macosx_11_0_arm64.whl + - pypi: https://files.pythonhosted.org/packages/92/e7/038aab64a946d535901103da16b953c8c9cc9c961dadcbf3609ed6428d23/pyzmq-27.1.0-cp312-abi3-macosx_10_15_universal2.whl + - pypi: https://files.pythonhosted.org/packages/75/d9/0b48d4184f9ca6a996c4fac46897a968698c9d1e0f0e43a6906746201323/quartodoc-0.11.1-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/2c/58/ca301544e1fa93ed4f80d724bf5b194f6e4b945841c5bfd555878eea9fcb/referencing-0.37.0-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/1e/db/4254e3eabe8020b458f1a747140d32277ec7a271daf1d235b70dc0b4e6e3/requests-2.32.5-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/7b/44/4e421b96b67b2daff264473f7465db72fbdf36a07e05494f50300cc7b0c6/rfc3339_validator-0.1.4-py2.py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/9e/51/17023c0f8f1869d8806b979a2bffa3f861f26a3f1a66b094288323fba52f/rfc3986_validator-0.1.1-py2.py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/7e/71/44ce230e1b7fadd372515a97e32a83011f906ddded8d03e3c6aafbdedbb7/rfc3987_syntax-1.1.0-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/ef/45/615f5babd880b4bd7d405cc0dc348234c5ffb6ed1ea33e152ede08b2072d/rich-14.3.2-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/4d/a1/bca7fd3d452b272e13335db8d6b0b3ecde0f90ad6f16f3328c6fb150c889/rpds_py-0.30.0-cp312-cp312-macosx_11_0_arm64.whl + - pypi: https://files.pythonhosted.org/packages/1c/78/504fdd027da3b84ff1aecd9f6957e65f35134534ccc6da8628eb71e76d3f/send2trash-2.1.0-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/94/b8/f1f62a5e3c0ad2ff1d189590bfa4c46b4f3b6e49cef6f26c6ee4e575394d/setuptools-80.10.2-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/b7/ce/149a00dd41f10bc29e5921b496af8b574d8413afcd5e30dfa0ed46c2cc5e/six-1.17.0-py2.py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/46/2c/1462b1d0a634697ae9e55b3cecdcb64788e8b7d63f54d923fcd0bb140aed/soupsieve-2.8.3-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/63/f9/f48a8f489c8ae8930f12c558b4dd26da96791837747fca87e9da2643f12d/sphobjinv-2.3.1.3-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/b6/35/d16bfa235c8b7caba3730bba43e20b1e376d2224f407c178fbf59559f23e/sqlalchemy-2.0.46-cp312-cp312-macosx_11_0_arm64.whl + - pypi: https://files.pythonhosted.org/packages/f1/7b/ce1eafaf1a76852e2ec9b22edecf1daa58175c090266e9f6c64afcd81d91/stack_data-0.6.3-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/40/44/4a5f08c96eb108af5cb50b41f76142f0afa346dfa99d5296fe7202a11854/tabulate-0.9.0-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/6a/9e/2064975477fdc887e47ad42157e214526dcad8f317a948dee17e1659a62f/terminado-0.18.1-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/e6/34/ebdc18bae6aa14fbee1a08b63c015c72b64868ff7dae68808ab500c492e2/tinycss2-1.4.0-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/ab/a9/e94a9d5224107d7ce3cc1fab8d5dc97f5ea351ccc6322ee4fb661da94e35/tornado-6.5.4-cp39-abi3-macosx_10_9_universal2.whl + - pypi: https://files.pythonhosted.org/packages/00/c0/8f5d070730d7836adc9c9b6408dec68c6ced86b304a9b26a14df072a6e8c/traitlets-5.14.3-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/18/67/36e9267722cc04a6b9f15c7f3441c2363321a3ea07da7ae0c0707beb2a9c/typing_extensions-4.15.0-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/dc/9b/47798a6c91d8bdb567fe2698fe81e0c6b7cb7ef4d13da4114b41d239f65d/typing_inspection-0.4.2-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/c7/b0/003792df09decd6849a5e39c28b513c06e84436a54440380862b5aeff25d/tzdata-2025.3-py2.py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/e7/00/3fca040d7cf8a32776d3d81a00c8ee7457e00f80c649f1e4a863c8321ae9/uri_template-1.3.0-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/39/08/aaaad47bc4e9dc8c725e68f9d04865dbcb2052843ff09c97b08904852d84/urllib3-2.6.3-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/5b/7e/8f322f5e600812e6f9a31b75d242631068ca8f4ef0582dd3ae6e72daecc8/watchdog-6.0.0-cp312-cp312-macosx_11_0_arm64.whl + - pypi: https://files.pythonhosted.org/packages/fd/84/fd2ba7aafacbad3c4201d395674fc6348826569da3c0937e75505ead3528/wcwidth-0.2.13-py2.py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/e2/cc/e097523dd85c9cf5d354f78310927f1656c422bd7b2613b2db3e3f9a0f2c/webcolors-25.10.0-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/f4/24/2a3e3df732393fed8b3ebf2ec078f05546de641fe1b667ee316ec1dcf3b7/webencodings-0.5.1-py2.py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/34/db/b10e48aa8fff7407e67470363eac595018441cf32d5e1001567a7aeba5d2/websocket_client-1.9.0-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/3f/0e/fa3b193432cfc60c93b42f3be03365f5f909d2b3ea410295cf36df739e31/widgetsnbextension-4.0.15-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/2e/54/647ade08bf0db230bfea292f893923872fd20be6ac6f53b2b936ba839d75/zipp-3.23.0-py3-none-any.whl + - pypi: ./ interactive: channels: - url: https://conda.anaconda.org/conda-forge/ @@ -195,7 +694,7 @@ environments: - pypi: https://files.pythonhosted.org/packages/f1/7b/ce1eafaf1a76852e2ec9b22edecf1daa58175c090266e9f6c64afcd81d91/stack_data-0.6.3-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/00/c0/8f5d070730d7836adc9c9b6408dec68c6ced86b304a9b26a14df072a6e8c/traitlets-5.14.3-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/fd/84/fd2ba7aafacbad3c4201d395674fc6348826569da3c0937e75505ead3528/wcwidth-0.2.13-py2.py3-none-any.whl - - pypi: . + - pypi: ./ osx-arm64: - conda: https://conda.anaconda.org/conda-forge/osx-arm64/bzip2-1.0.8-h99b78c6_7.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/ca-certificates-2025.1.31-hf0a4a13_0.conda @@ -226,7 +725,7 @@ environments: - pypi: https://files.pythonhosted.org/packages/f1/7b/ce1eafaf1a76852e2ec9b22edecf1daa58175c090266e9f6c64afcd81d91/stack_data-0.6.3-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/00/c0/8f5d070730d7836adc9c9b6408dec68c6ced86b304a9b26a14df072a6e8c/traitlets-5.14.3-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/fd/84/fd2ba7aafacbad3c4201d395674fc6348826569da3c0937e75505ead3528/wcwidth-0.2.13-py2.py3-none-any.whl - - pypi: . + - pypi: ./ lint: channels: - url: https://conda.anaconda.org/conda-forge/ @@ -257,7 +756,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/linux-64/tk-8.6.13-noxft_h4845f30_101.conda - conda: https://conda.anaconda.org/conda-forge/noarch/tzdata-2025a-h78e105d_0.conda - pypi: https://files.pythonhosted.org/packages/5e/a6/cc472161cd04d30a09d5c90698696b70c169eeba2c41030344194242db45/ruff-0.9.10-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl - - pypi: . + - pypi: ./ osx-arm64: - conda: https://conda.anaconda.org/conda-forge/osx-arm64/bzip2-1.0.8-h99b78c6_7.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/ca-certificates-2025.1.31-hf0a4a13_0.conda @@ -273,7 +772,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/osx-arm64/tk-8.6.13-h5083fa2_1.conda - conda: https://conda.anaconda.org/conda-forge/noarch/tzdata-2025a-h78e105d_0.conda - pypi: https://files.pythonhosted.org/packages/02/49/1c79e0906b6ff551fb0894168763f705bf980864739572b2815ecd3c9df0/ruff-0.9.10-py3-none-macosx_11_0_arm64.whl - - pypi: . + - pypi: ./ test: channels: - url: https://conda.anaconda.org/conda-forge/ @@ -313,7 +812,7 @@ environments: - pypi: https://files.pythonhosted.org/packages/36/3b/48e79f2cd6a61dbbd4807b4ed46cb564b4fd50a76166b1c4ea5c1d9e2371/pytest_cov-6.0.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/32/46/9cb0e58b2deb7f82b84065f37f3bffeb12413f947f9388e4cac22c4621ce/sortedcontainers-2.4.0-py2.py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/58/b8/e4722f5e5f592a665cc8e55a334ea721c359f09574e6b987dc551a1e1f4c/xdoctest-1.2.0-py3-none-any.whl - - pypi: . + - pypi: ./ osx-arm64: - conda: https://conda.anaconda.org/conda-forge/osx-arm64/bzip2-1.0.8-h99b78c6_7.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/ca-certificates-2025.1.31-hf0a4a13_0.conda @@ -338,7 +837,7 @@ environments: - pypi: https://files.pythonhosted.org/packages/36/3b/48e79f2cd6a61dbbd4807b4ed46cb564b4fd50a76166b1c4ea5c1d9e2371/pytest_cov-6.0.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/32/46/9cb0e58b2deb7f82b84065f37f3bffeb12413f947f9388e4cac22c4621ce/sortedcontainers-2.4.0-py2.py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/58/b8/e4722f5e5f592a665cc8e55a334ea721c359f09574e6b987dc551a1e1f4c/xdoctest-1.2.0-py3-none-any.whl - - pypi: . + - pypi: ./ types: channels: - url: https://conda.anaconda.org/conda-forge/ @@ -370,8 +869,8 @@ environments: - conda: https://conda.anaconda.org/conda-forge/noarch/tzdata-2025a-h78e105d_0.conda - pypi: https://files.pythonhosted.org/packages/d2/1d/1b658dbd2b9fa9c4c9f32accbfc0205d532c8c6194dc0f2a4c0428e7128a/nodeenv-1.9.1-py2.py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/80/be/ecb7cfb42d242b7ee764b52e6ff4782beeec00e3b943a3ec832b281f9da6/pyright-1.1.396-py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/26/9f/ad63fc0248c5379346306f8668cda6e2e2e9c95e01216d2b8ffd9ff037d0/typing_extensions-4.12.2-py3-none-any.whl - - pypi: . + - pypi: https://files.pythonhosted.org/packages/18/67/36e9267722cc04a6b9f15c7f3441c2363321a3ea07da7ae0c0707beb2a9c/typing_extensions-4.15.0-py3-none-any.whl + - pypi: ./ osx-arm64: - conda: https://conda.anaconda.org/conda-forge/osx-arm64/bzip2-1.0.8-h99b78c6_7.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/ca-certificates-2025.1.31-hf0a4a13_0.conda @@ -388,8 +887,8 @@ environments: - conda: https://conda.anaconda.org/conda-forge/noarch/tzdata-2025a-h78e105d_0.conda - pypi: https://files.pythonhosted.org/packages/d2/1d/1b658dbd2b9fa9c4c9f32accbfc0205d532c8c6194dc0f2a4c0428e7128a/nodeenv-1.9.1-py2.py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/80/be/ecb7cfb42d242b7ee764b52e6ff4782beeec00e3b943a3ec832b281f9da6/pyright-1.1.396-py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/26/9f/ad63fc0248c5379346306f8668cda6e2e2e9c95e01216d2b8ffd9ff037d0/typing_extensions-4.12.2-py3-none-any.whl - - pypi: . + - pypi: https://files.pythonhosted.org/packages/18/67/36e9267722cc04a6b9f15c7f3441c2363321a3ea07da7ae0c0707beb2a9c/typing_extensions-4.15.0-py3-none-any.whl + - pypi: ./ packages: - conda: https://conda.anaconda.org/conda-forge/linux-64/_libgcc_mutex-0.1-conda_forge.tar.bz2 sha256: fe51de6107f9edc7aa4f786a70f4a883943bc9d39b3bb7307c04c41410990726 @@ -412,6 +911,73 @@ packages: purls: [] size: 23621 timestamp: 1650670423406 +- pypi: https://files.pythonhosted.org/packages/78/b6/6307fbef88d9b5ee7421e68d78a9f162e0da4900bc5f5793f6d3d0e34fb8/annotated_types-0.7.0-py3-none-any.whl + name: annotated-types + version: 0.7.0 + sha256: 1f02e8b43a8fbbc3f3e0d4f0f4bfc8131bcb4eebe8849b8e5c773f3a1c582a53 + requires_dist: + - typing-extensions>=4.0.0 ; python_full_version < '3.9' + requires_python: '>=3.8' +- pypi: https://files.pythonhosted.org/packages/38/0e/27be9fdef66e72d64c0cdc3cc2823101b80585f8119b5c112c2e8f5f7dab/anyio-4.12.1-py3-none-any.whl + name: anyio + version: 4.12.1 + sha256: d405828884fc140aa80a3c667b8beed277f1dfedec42ba031bd6ac3db606ab6c + requires_dist: + - exceptiongroup>=1.0.2 ; python_full_version < '3.11' + - idna>=2.8 + - typing-extensions>=4.5 ; python_full_version < '3.13' + - trio>=0.32.0 ; python_full_version >= '3.10' and extra == 'trio' + - trio>=0.31.0 ; python_full_version < '3.10' and extra == 'trio' + requires_python: '>=3.9' +- pypi: https://files.pythonhosted.org/packages/81/29/5ecc3a15d5a33e31b26c11426c45c501e439cb865d0bff96315d86443b78/appnope-0.1.4-py2.py3-none-any.whl + name: appnope + version: 0.1.4 + sha256: 502575ee11cd7a28c0205f379b525beefebab9d161b7c964670864014ed7213c + requires_python: '>=3.6' +- pypi: https://files.pythonhosted.org/packages/4f/d3/a8b22fa575b297cd6e3e3b0155c7e25db170edf1c74783d6a31a2490b8d9/argon2_cffi-25.1.0-py3-none-any.whl + name: argon2-cffi + version: 25.1.0 + sha256: fdc8b074db390fccb6eb4a3604ae7231f219aa669a2652e0f20e16ba513d5741 + requires_dist: + - argon2-cffi-bindings + requires_python: '>=3.8' +- pypi: https://files.pythonhosted.org/packages/09/52/94108adfdd6e2ddf58be64f959a0b9c7d4ef2fa71086c38356d22dc501ea/argon2_cffi_bindings-25.1.0-cp39-abi3-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl + name: argon2-cffi-bindings + version: 25.1.0 + sha256: d3e924cfc503018a714f94a49a149fdc0b644eaead5d1f089330399134fa028a + requires_dist: + - cffi>=1.0.1 ; python_full_version < '3.14' + - cffi>=2.0.0b1 ; python_full_version >= '3.14' + requires_python: '>=3.9' +- pypi: https://files.pythonhosted.org/packages/b6/02/d297943bcacf05e4f2a94ab6f462831dc20158614e5d067c35d4e63b9acb/argon2_cffi_bindings-25.1.0-cp39-abi3-macosx_11_0_arm64.whl + name: argon2-cffi-bindings + version: 25.1.0 + sha256: 7aef0c91e2c0fbca6fc68e7555aa60ef7008a739cbe045541e438373bc54d2b0 + requires_dist: + - cffi>=1.0.1 ; python_full_version < '3.14' + - cffi>=2.0.0b1 ; python_full_version >= '3.14' + requires_python: '>=3.9' +- pypi: https://files.pythonhosted.org/packages/ed/c9/d7977eaacb9df673210491da99e6a247e93df98c715fc43fd136ce1d3d33/arrow-1.4.0-py3-none-any.whl + name: arrow + version: 1.4.0 + sha256: 749f0769958ebdc79c173ff0b0670d59051a535fa26e8eba02953dc19eb43205 + requires_dist: + - python-dateutil>=2.7.0 + - backports-zoneinfo==0.2.1 ; python_full_version < '3.9' + - tzdata ; python_full_version >= '3.9' + - doc8 ; extra == 'doc' + - sphinx>=7.0.0 ; extra == 'doc' + - sphinx-autobuild ; extra == 'doc' + - sphinx-autodoc-typehints ; extra == 'doc' + - sphinx-rtd-theme>=1.3.0 ; extra == 'doc' + - dateparser==1.* ; extra == 'test' + - pre-commit ; extra == 'test' + - pytest ; extra == 'test' + - pytest-cov ; extra == 'test' + - pytest-mock ; extra == 'test' + - pytz==2025.2 ; extra == 'test' + - simplejson==3.* ; extra == 'test' + requires_python: '>=3.8' - pypi: https://files.pythonhosted.org/packages/25/8a/c46dcc25341b5bce5472c718902eb3d38600a903b14fa6aeecef3f21a46f/asttokens-3.0.0-py3-none-any.whl name: asttokens version: 3.0.0 @@ -423,6 +989,13 @@ packages: - pytest-cov ; extra == 'test' - pytest-xdist ; extra == 'test' requires_python: '>=3.8' +- pypi: https://files.pythonhosted.org/packages/2e/e9/eb6a5db5ac505d5d45715388e92bced7a5bb556facc4d0865d192823f2d2/async_lru-2.1.0-py3-none-any.whl + name: async-lru + version: 2.1.0 + sha256: fa12dcf99a42ac1280bc16c634bbaf06883809790f6304d85cdab3f666f33a7e + requires_dist: + - typing-extensions>=4.0.0 ; python_full_version < '3.11' + requires_python: '>=3.10' - pypi: https://files.pythonhosted.org/packages/fc/30/d4986a882011f9df997a55e6becd864812ccfcd821d64aac8570ee39f719/attrs-25.1.0-py3-none-any.whl name: attrs version: 25.1.0 @@ -469,6 +1042,185 @@ packages: - mypy>=1.11.1 ; python_full_version >= '3.10' and platform_python_implementation == 'CPython' and extra == 'tests-mypy' - pytest-mypy-plugins ; python_full_version >= '3.10' and platform_python_implementation == 'CPython' and extra == 'tests-mypy' requires_python: '>=3.8' +- pypi: https://files.pythonhosted.org/packages/77/f5/21d2de20e8b8b0408f0681956ca2c69f1320a3848ac50e6e7f39c6159675/babel-2.18.0-py3-none-any.whl + name: babel + version: 2.18.0 + sha256: e2b422b277c2b9a9630c1d7903c2a00d0830c409c59ac8cae9081c92f1aeba35 + requires_dist: + - pytz>=2015.7 ; python_full_version < '3.9' + - tzdata ; sys_platform == 'win32' and extra == 'dev' + - backports-zoneinfo ; python_full_version < '3.9' and extra == 'dev' + - freezegun~=1.0 ; extra == 'dev' + - jinja2>=3.0 ; extra == 'dev' + - pytest-cov ; extra == 'dev' + - pytest>=6.0 ; extra == 'dev' + - pytz ; extra == 'dev' + - setuptools ; extra == 'dev' + requires_python: '>=3.8' +- pypi: https://files.pythonhosted.org/packages/71/cc/18245721fa7747065ab478316c7fea7c74777d07f37ae60db2e84f8172e8/beartype-0.22.9-py3-none-any.whl + name: beartype + version: 0.22.9 + sha256: d16c9bbc61ea14637596c5f6fbff2ee99cbe3573e46a716401734ef50c3060c2 + requires_dist: + - autoapi>=0.9.0 ; extra == 'dev' + - celery ; extra == 'dev' + - click ; extra == 'dev' + - coverage>=5.5 ; extra == 'dev' + - docutils>=0.22.0 ; extra == 'dev' + - equinox ; python_full_version < '3.15' and sys_platform == 'linux' and extra == 'dev' + - fastmcp ; python_full_version < '3.14' and extra == 'dev' + - jax[cpu] ; python_full_version < '3.15' and sys_platform == 'linux' and extra == 'dev' + - jaxtyping ; sys_platform == 'linux' and extra == 'dev' + - langchain ; python_full_version < '3.14' and platform_python_implementation != 'PyPy' and sys_platform != 'darwin' and extra == 'dev' + - mypy>=0.800 ; platform_python_implementation != 'PyPy' and extra == 'dev' + - nuitka>=1.2.6 ; python_full_version < '3.14' and sys_platform == 'linux' and extra == 'dev' + - numba ; python_full_version < '3.14' and extra == 'dev' + - numpy ; python_full_version < '3.15' and platform_python_implementation != 'PyPy' and sys_platform != 'darwin' and extra == 'dev' + - pandera>=0.26.0 ; python_full_version < '3.14' and extra == 'dev' + - poetry ; extra == 'dev' + - polars ; python_full_version < '3.14' and extra == 'dev' + - pydata-sphinx-theme<=0.7.2 ; extra == 'dev' + - pygments ; extra == 'dev' + - pyinstaller ; extra == 'dev' + - pyright>=1.1.370 ; extra == 'dev' + - pytest>=6.2.0 ; extra == 'dev' + - redis ; extra == 'dev' + - rich-click ; extra == 'dev' + - setuptools ; extra == 'dev' + - sphinx ; extra == 'dev' + - sphinx>=4.2.0,<6.0.0 ; extra == 'dev' + - sphinxext-opengraph>=0.7.5 ; extra == 'dev' + - sqlalchemy ; extra == 'dev' + - torch ; python_full_version < '3.14' and sys_platform == 'linux' and extra == 'dev' + - tox>=3.20.1 ; extra == 'dev' + - typer ; extra == 'dev' + - typing-extensions>=3.10.0.0 ; extra == 'dev' + - xarray ; python_full_version < '3.15' and extra == 'dev' + - mkdocs-material[imaging]>=9.6.0 ; extra == 'doc-ghp' + - mkdocstrings-python-xref>=1.16.0 ; extra == 'doc-ghp' + - mkdocstrings-python>=1.16.0 ; extra == 'doc-ghp' + - autoapi>=0.9.0 ; extra == 'doc-rtd' + - pydata-sphinx-theme<=0.7.2 ; extra == 'doc-rtd' + - setuptools ; extra == 'doc-rtd' + - sphinx>=4.2.0,<6.0.0 ; extra == 'doc-rtd' + - sphinxext-opengraph>=0.7.5 ; extra == 'doc-rtd' + - celery ; extra == 'test' + - click ; extra == 'test' + - coverage>=5.5 ; extra == 'test' + - docutils>=0.22.0 ; extra == 'test' + - equinox ; python_full_version < '3.15' and sys_platform == 'linux' and extra == 'test' + - fastmcp ; python_full_version < '3.14' and extra == 'test' + - jax[cpu] ; python_full_version < '3.15' and sys_platform == 'linux' and extra == 'test' + - jaxtyping ; sys_platform == 'linux' and extra == 'test' + - langchain ; python_full_version < '3.14' and platform_python_implementation != 'PyPy' and sys_platform != 'darwin' and extra == 'test' + - mypy>=0.800 ; platform_python_implementation != 'PyPy' and extra == 'test' + - nuitka>=1.2.6 ; python_full_version < '3.14' and sys_platform == 'linux' and extra == 'test' + - numba ; python_full_version < '3.14' and extra == 'test' + - numpy ; python_full_version < '3.15' and platform_python_implementation != 'PyPy' and sys_platform != 'darwin' and extra == 'test' + - pandera>=0.26.0 ; python_full_version < '3.14' and extra == 'test' + - poetry ; extra == 'test' + - polars ; python_full_version < '3.14' and extra == 'test' + - pygments ; extra == 'test' + - pyinstaller ; extra == 'test' + - pyright>=1.1.370 ; extra == 'test' + - pytest>=6.2.0 ; extra == 'test' + - redis ; extra == 'test' + - rich-click ; extra == 'test' + - sphinx ; extra == 'test' + - sqlalchemy ; extra == 'test' + - torch ; python_full_version < '3.14' and sys_platform == 'linux' and extra == 'test' + - tox>=3.20.1 ; extra == 'test' + - typer ; extra == 'test' + - typing-extensions>=3.10.0.0 ; extra == 'test' + - xarray ; python_full_version < '3.15' and extra == 'test' + - celery ; extra == 'test-tox' + - click ; extra == 'test-tox' + - docutils>=0.22.0 ; extra == 'test-tox' + - equinox ; python_full_version < '3.15' and sys_platform == 'linux' and extra == 'test-tox' + - fastmcp ; python_full_version < '3.14' and extra == 'test-tox' + - jax[cpu] ; python_full_version < '3.15' and sys_platform == 'linux' and extra == 'test-tox' + - jaxtyping ; sys_platform == 'linux' and extra == 'test-tox' + - langchain ; python_full_version < '3.14' and platform_python_implementation != 'PyPy' and sys_platform != 'darwin' and extra == 'test-tox' + - mypy>=0.800 ; platform_python_implementation != 'PyPy' and extra == 'test-tox' + - nuitka>=1.2.6 ; python_full_version < '3.14' and sys_platform == 'linux' and extra == 'test-tox' + - numba ; python_full_version < '3.14' and extra == 'test-tox' + - numpy ; python_full_version < '3.15' and platform_python_implementation != 'PyPy' and sys_platform != 'darwin' and extra == 'test-tox' + - pandera>=0.26.0 ; python_full_version < '3.14' and extra == 'test-tox' + - poetry ; extra == 'test-tox' + - polars ; python_full_version < '3.14' and extra == 'test-tox' + - pygments ; extra == 'test-tox' + - pyinstaller ; extra == 'test-tox' + - pyright>=1.1.370 ; extra == 'test-tox' + - pytest>=6.2.0 ; extra == 'test-tox' + - redis ; extra == 'test-tox' + - rich-click ; extra == 'test-tox' + - sphinx ; extra == 'test-tox' + - sqlalchemy ; extra == 'test-tox' + - torch ; python_full_version < '3.14' and sys_platform == 'linux' and extra == 'test-tox' + - typer ; extra == 'test-tox' + - typing-extensions>=3.10.0.0 ; extra == 'test-tox' + - xarray ; python_full_version < '3.15' and extra == 'test-tox' + - coverage>=5.5 ; extra == 'test-tox-coverage' + requires_python: '>=3.10' +- pypi: https://files.pythonhosted.org/packages/1a/39/47f9197bdd44df24d67ac8893641e16f386c984a0619ef2ee4c51fbbc019/beautifulsoup4-4.14.3-py3-none-any.whl + name: beautifulsoup4 + version: 4.14.3 + sha256: 0918bfe44902e6ad8d57732ba310582e98da931428d231a5ecb9e7c703a735bb + requires_dist: + - soupsieve>=1.6.1 + - typing-extensions>=4.0.0 + - cchardet ; extra == 'cchardet' + - chardet ; extra == 'chardet' + - charset-normalizer ; extra == 'charset-normalizer' + - html5lib ; extra == 'html5lib' + - lxml ; extra == 'lxml' + requires_python: '>=3.7.0' +- pypi: https://files.pythonhosted.org/packages/79/a6/5179beaa57e5dbd2ec9f1c64016214057b4265647c62125aa6aeffb05392/black-26.1.0-cp312-cp312-macosx_11_0_arm64.whl + name: black + version: 26.1.0 + sha256: dd39eef053e58e60204f2cdf059e2442e2eb08f15989eefe259870f89614c8b6 + requires_dist: + - click>=8.0.0 + - mypy-extensions>=0.4.3 + - packaging>=22.0 + - pathspec>=1.0.0 + - platformdirs>=2 + - pytokens>=0.3.0 + - tomli>=1.1.0 ; python_full_version < '3.11' + - typing-extensions>=4.0.1 ; python_full_version < '3.11' + - colorama>=0.4.3 ; extra == 'colorama' + - aiohttp>=3.10 ; extra == 'd' + - ipython>=7.8.0 ; extra == 'jupyter' + - tokenize-rt>=3.2.0 ; extra == 'jupyter' + - uvloop>=0.15.2 ; extra == 'uvloop' + requires_python: '>=3.10' +- pypi: https://files.pythonhosted.org/packages/8c/04/c96f79d7b93e8f09d9298b333ca0d31cd9b2ee6c46c274fd0f531de9dc61/black-26.1.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl + name: black + version: 26.1.0 + sha256: 9459ad0d6cd483eacad4c6566b0f8e42af5e8b583cee917d90ffaa3778420a0a + requires_dist: + - click>=8.0.0 + - mypy-extensions>=0.4.3 + - packaging>=22.0 + - pathspec>=1.0.0 + - platformdirs>=2 + - pytokens>=0.3.0 + - tomli>=1.1.0 ; python_full_version < '3.11' + - typing-extensions>=4.0.1 ; python_full_version < '3.11' + - colorama>=0.4.3 ; extra == 'colorama' + - aiohttp>=3.10 ; extra == 'd' + - ipython>=7.8.0 ; extra == 'jupyter' + - tokenize-rt>=3.2.0 ; extra == 'jupyter' + - uvloop>=0.15.2 ; extra == 'uvloop' + requires_python: '>=3.10' +- pypi: https://files.pythonhosted.org/packages/cd/3a/577b549de0cc09d95f11087ee63c739bba856cd3952697eec4c4bb91350a/bleach-6.3.0-py3-none-any.whl + name: bleach + version: 6.3.0 + sha256: fe10ec77c93ddf3d13a73b035abaac7a9f5e436513864ccdad516693213c65d6 + requires_dist: + - webencodings + - tinycss2>=1.1.0,<1.5 ; extra == 'css' + requires_python: '>=3.10' - conda: https://conda.anaconda.org/conda-forge/linux-64/bzip2-1.0.8-h4bc722e_7.conda sha256: 5ced96500d945fb286c9c838e54fa759aa04a7129c59800f0846b4335cee770d md5: 62ee74e96c5ebb0af99386de58cf9553 @@ -504,6 +1256,54 @@ packages: purls: [] size: 158425 timestamp: 1738298167688 +- pypi: https://files.pythonhosted.org/packages/e6/ad/3cc14f097111b4de0040c83a525973216457bbeeb63739ef1ed275c1c021/certifi-2026.1.4-py3-none-any.whl + name: certifi + version: 2026.1.4 + sha256: 9943707519e4add1115f44c2bc244f782c0249876bf51b6599fee1ffbedd685c + requires_python: '>=3.7' +- pypi: https://files.pythonhosted.org/packages/78/2d/7fa73dfa841b5ac06c7b8855cfc18622132e365f5b81d02230333ff26e9e/cffi-2.0.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl + name: cffi + version: 2.0.0 + sha256: 3e17ed538242334bf70832644a32a7aae3d83b57567f9fd60a26257e992b79ba + requires_dist: + - pycparser ; implementation_name != 'PyPy' + requires_python: '>=3.9' +- pypi: https://files.pythonhosted.org/packages/df/a2/781b623f57358e360d62cdd7a8c681f074a71d445418a776eef0aadb4ab4/cffi-2.0.0-cp312-cp312-macosx_11_0_arm64.whl + name: cffi + version: 2.0.0 + sha256: 8eca2a813c1cb7ad4fb74d368c2ffbbb4789d377ee5bb8df98373c2cc0dee76c + requires_dist: + - pycparser ; implementation_name != 'PyPy' + requires_python: '>=3.9' +- pypi: https://files.pythonhosted.org/packages/c0/10/d20b513afe03acc89ec33948320a5544d31f21b05368436d580dec4e234d/charset_normalizer-3.4.4-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl + name: charset-normalizer + version: 3.4.4 + sha256: 11d694519d7f29d6cd09f6ac70028dba10f92f6cdd059096db198c283794ac86 + requires_python: '>=3.7' +- pypi: https://files.pythonhosted.org/packages/f3/85/1637cd4af66fa687396e757dec650f28025f2a2f5a5531a3208dc0ec43f2/charset_normalizer-3.4.4-cp312-cp312-macosx_10_13_universal2.whl + name: charset-normalizer + version: 3.4.4 + sha256: 0a98e6759f854bd25a58a73fa88833fba3b7c491169f86ce1180c948ab3fd394 + requires_python: '>=3.7' +- pypi: https://files.pythonhosted.org/packages/98/78/01c019cdb5d6498122777c1a43056ebb3ebfeef2076d9d026bfe15583b2b/click-8.3.1-py3-none-any.whl + name: click + version: 8.3.1 + sha256: 981153a64e25f12d547d3426c367a4857371575ee7ad18df2a6183ab0545b2a6 + requires_dist: + - colorama ; sys_platform == 'win32' + requires_python: '>=3.10' +- pypi: https://files.pythonhosted.org/packages/d1/d6/3965ed04c63042e047cb6a3e6ed1a63a35087b6a609aa3a15ed8ac56c221/colorama-0.4.6-py2.py3-none-any.whl + name: colorama + version: 0.4.6 + sha256: 4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6 + requires_python: '>=2.7,!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*' +- pypi: https://files.pythonhosted.org/packages/60/97/891a0971e1e4a8c5d2b20bbe0e524dc04548d2307fee33cdeba148fd4fc7/comm-0.2.3-py3-none-any.whl + name: comm + version: 0.2.3 + sha256: c615d91d75f7f04f095b30d1c1711babd43bdc6419c1be9886a85f2f4e489417 + requires_dist: + - pytest ; extra == 'test' + requires_python: '>=3.8' - pypi: https://files.pythonhosted.org/packages/c4/47/2ba744af8d2f0caa1f17e7746147e34dfc5f811fb65fc153153722d58835/coverage-7.6.12-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl name: coverage version: 7.6.12 @@ -518,11 +1318,21 @@ packages: requires_dist: - tomli ; python_full_version <= '3.11' and extra == 'toml' requires_python: '>=3.9' +- pypi: https://files.pythonhosted.org/packages/e0/c3/7f67dea8ccf8fdcb9c99033bbe3e90b9e7395415843accb81428c441be2d/debugpy-1.8.20-py2.py3-none-any.whl + name: debugpy + version: 1.8.20 + sha256: 5be9bed9ae3be00665a06acaa48f8329d2b9632f15fd09f6a9a8c8d9907e54d7 + requires_python: '>=3.8' - pypi: https://files.pythonhosted.org/packages/4e/8c/f3147f5c4b73e7550fe5f9352eaa956ae838d5c51eb58e7a25b9f3e2643b/decorator-5.2.1-py3-none-any.whl name: decorator version: 5.2.1 sha256: d316bb415a2d9e2d2b3abcc4084c6502fc09240e292cd76a76afc106a1c8e04a requires_python: '>=3.8' +- pypi: https://files.pythonhosted.org/packages/07/6c/aa3f2f849e01cb6a001cd8554a88d4c77c5c1a31c95bdf1cf9301e6d9ef4/defusedxml-0.7.1-py2.py3-none-any.whl + name: defusedxml + version: 0.7.1 + sha256: a352e7e428770286cc899e2542b6cdaedb2b4953ff269a210103ec58f6198a61 + requires_python: '>=2.7,!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*' - pypi: https://files.pythonhosted.org/packages/7b/8f/c4d9bafc34ad7ad5d8dc16dd1347ee0e507a52c3adb6bfa8887e1c6a26ba/executing-2.2.0-py2.py3-none-any.whl name: executing version: 2.2.0 @@ -536,6 +1346,82 @@ packages: - littleutils ; extra == 'tests' - rich ; python_full_version >= '3.11' and extra == 'tests' requires_python: '>=3.8' +- pypi: https://files.pythonhosted.org/packages/cb/a8/20d0723294217e47de6d9e2e40fd4a9d2f7c4b6ef974babd482a59743694/fastjsonschema-2.21.2-py3-none-any.whl + name: fastjsonschema + version: 2.21.2 + sha256: 1c797122d0a86c5cace2e54bf4e819c36223b552017172f32c5c024a6b77e463 + requires_dist: + - colorama ; extra == 'devel' + - jsonschema ; extra == 'devel' + - json-spec ; extra == 'devel' + - pylint ; extra == 'devel' + - pytest ; extra == 'devel' + - pytest-benchmark ; extra == 'devel' + - pytest-cache ; extra == 'devel' + - validictory ; extra == 'devel' +- pypi: https://files.pythonhosted.org/packages/cf/58/8acf1b3e91c58313ce5cb67df61001fc9dcd21be4fadb76c1a2d540e09ed/fqdn-1.5.1-py3-none-any.whl + name: fqdn + version: 1.5.1 + sha256: 3a179af3761e4df6eb2e026ff9e1a3033d3587bf980a0b1b2e1e5d08d7358014 + requires_dist: + - cached-property>=1.3.0 ; python_full_version < '3.8' + requires_python: '>=2.7,!=3.0,!=3.1,!=3.2,!=3.3,!=3.4,<4' +- pypi: https://files.pythonhosted.org/packages/cf/05/821587cf19e2ce1f2b24945d890b164401e5085f9d09cbd969b0c193cd20/greenlet-3.3.1-cp312-cp312-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl + name: greenlet + version: 3.3.1 + sha256: 14194f5f4305800ff329cbf02c5fcc88f01886cadd29941b807668a45f0d2336 + requires_dist: + - sphinx ; extra == 'docs' + - furo ; extra == 'docs' + - objgraph ; extra == 'test' + - psutil ; extra == 'test' + - setuptools ; extra == 'test' + requires_python: '>=3.10' +- pypi: https://files.pythonhosted.org/packages/9c/83/3b1d03d36f224edded98e9affd0467630fc09d766c0e56fb1498cbb04a9b/griffe-1.15.0-py3-none-any.whl + name: griffe + version: 1.15.0 + sha256: 6f6762661949411031f5fcda9593f586e6ce8340f0ba88921a0f2ef7a81eb9a3 + requires_dist: + - colorama>=0.4 + - pip>=24.0 ; extra == 'pypi' + - platformdirs>=4.2 ; extra == 'pypi' + - wheel>=0.42 ; extra == 'pypi' + requires_python: '>=3.10' +- pypi: https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl + name: h11 + version: 0.16.0 + sha256: 63cf8bbe7522de3bf65932fda1d9c2772064ffb3dae62d55932da54b31cb6c86 + requires_python: '>=3.8' +- pypi: https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl + name: httpcore + version: 1.0.9 + sha256: 2d400746a40668fc9dec9810239072b40b4484b640a8c38fd654a024c7a1bf55 + requires_dist: + - certifi + - h11>=0.16 + - anyio>=4.0,<5.0 ; extra == 'asyncio' + - h2>=3,<5 ; extra == 'http2' + - socksio==1.* ; extra == 'socks' + - trio>=0.22.0,<1.0 ; extra == 'trio' + requires_python: '>=3.8' +- pypi: https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl + name: httpx + version: 0.28.1 + sha256: d909fcccc110f8c7faf814ca82a9a4d816bc5a6dbfea25d6591d6985b8ba59ad + requires_dist: + - anyio + - certifi + - httpcore==1.* + - idna + - brotli ; platform_python_implementation == 'CPython' and extra == 'brotli' + - brotlicffi ; platform_python_implementation != 'CPython' and extra == 'brotli' + - click==8.* ; extra == 'cli' + - pygments==2.* ; extra == 'cli' + - rich>=10,<14 ; extra == 'cli' + - h2>=3,<5 ; extra == 'http2' + - socksio==1.* ; extra == 'socks' + - zstandard>=0.18.0 ; extra == 'zstd' + requires_python: '>=3.8' - pypi: https://files.pythonhosted.org/packages/c6/00/d204a616fd127ee7830f649cca860b814331f591995e12aaa3931da10c45/hypothesis-6.127.9-py3-none-any.whl name: hypothesis version: 6.127.9 @@ -580,11 +1466,108 @@ packages: - tzdata>=2025.1 ; (sys_platform == 'emscripten' and extra == 'all') or (sys_platform == 'win32' and extra == 'all') - watchdog>=4.0.0 ; extra == 'all' requires_python: '>=3.9' +- pypi: https://files.pythonhosted.org/packages/0e/61/66938bbb5fc52dbdf84594873d5b51fb1f7c7794e9c0f5bd885f30bc507b/idna-3.11-py3-none-any.whl + name: idna + version: '3.11' + sha256: 771a87f49d9defaf64091e6e6fe9c18d4833f140bd19464795bc32d966ca37ea + requires_dist: + - ruff>=0.6.2 ; extra == 'all' + - mypy>=1.11.2 ; extra == 'all' + - pytest>=8.3.2 ; extra == 'all' + - flake8>=7.1.1 ; extra == 'all' + requires_python: '>=3.8' +- pypi: https://files.pythonhosted.org/packages/fa/5e/f8e9a1d23b9c20a551a8a02ea3637b4642e22c2626e3a13a9a29cdea99eb/importlib_metadata-8.7.1-py3-none-any.whl + name: importlib-metadata + version: 8.7.1 + sha256: 5a1f80bf1daa489495071efbb095d75a634cf28a8bc299581244063b53176151 + requires_dist: + - zipp>=3.20 + - pytest>=6,!=8.1.* ; extra == 'test' + - packaging ; extra == 'test' + - pyfakefs ; extra == 'test' + - flufl-flake8 ; extra == 'test' + - pytest-perf>=0.9.2 ; extra == 'test' + - jaraco-test>=5.4 ; extra == 'test' + - sphinx>=3.5 ; extra == 'doc' + - jaraco-packaging>=9.3 ; extra == 'doc' + - rst-linker>=1.9 ; extra == 'doc' + - furo ; extra == 'doc' + - sphinx-lint ; extra == 'doc' + - jaraco-tidelift>=1.4 ; extra == 'doc' + - ipython ; extra == 'perf' + - pytest-checkdocs>=2.4 ; extra == 'check' + - pytest-ruff>=0.2.1 ; sys_platform != 'cygwin' and extra == 'check' + - pytest-cov ; extra == 'cover' + - pytest-enabler>=3.4 ; extra == 'enabler' + - pytest-mypy>=1.0.1 ; extra == 'type' + - mypy<1.19 ; platform_python_implementation == 'PyPy' and extra == 'type' + requires_python: '>=3.9' +- pypi: https://files.pythonhosted.org/packages/a4/ed/1f1afb2e9e7f38a545d628f864d562a5ae64fe6f7a10e28ffb9b185b4e89/importlib_resources-6.5.2-py3-none-any.whl + name: importlib-resources + version: 6.5.2 + sha256: 789cfdc3ed28c78b67a06acb8126751ced69a3d5f79c095a98298cd8a760ccec + requires_dist: + - zipp>=3.1.0 ; python_full_version < '3.10' + - pytest>=6,!=8.1.* ; extra == 'test' + - zipp>=3.17 ; extra == 'test' + - jaraco-test>=5.4 ; extra == 'test' + - sphinx>=3.5 ; extra == 'doc' + - jaraco-packaging>=9.3 ; extra == 'doc' + - rst-linker>=1.9 ; extra == 'doc' + - furo ; extra == 'doc' + - sphinx-lint ; extra == 'doc' + - jaraco-tidelift>=1.4 ; extra == 'doc' + - pytest-checkdocs>=2.4 ; extra == 'check' + - pytest-ruff>=0.2.1 ; sys_platform != 'cygwin' and extra == 'check' + - pytest-cov ; extra == 'cover' + - pytest-enabler>=2.2 ; extra == 'enabler' + - pytest-mypy ; extra == 'type' + requires_python: '>=3.9' - pypi: https://files.pythonhosted.org/packages/ef/a6/62565a6e1cf69e10f5727360368e451d4b7f58beeac6173dc9db836a5b46/iniconfig-2.0.0-py3-none-any.whl name: iniconfig version: 2.0.0 sha256: b6a85871a79d2e3b22d2d1b94ac2824226a63c6b741c88f7ae975f18b6778374 requires_python: '>=3.7' +- pypi: https://files.pythonhosted.org/packages/a3/17/20c2552266728ceba271967b87919664ecc0e33efca29c3efc6baf88c5f9/ipykernel-7.1.0-py3-none-any.whl + name: ipykernel + version: 7.1.0 + sha256: 763b5ec6c5b7776f6a8d7ce09b267693b4e5ce75cb50ae696aaefb3c85e1ea4c + requires_dist: + - appnope>=0.1.2 ; sys_platform == 'darwin' + - comm>=0.1.1 + - debugpy>=1.6.5 + - ipython>=7.23.1 + - jupyter-client>=8.0.0 + - jupyter-core>=4.12,!=5.0.* + - matplotlib-inline>=0.1 + - nest-asyncio>=1.4 + - packaging>=22 + - psutil>=5.7 + - pyzmq>=25 + - tornado>=6.2 + - traitlets>=5.4.0 + - coverage[toml] ; extra == 'cov' + - matplotlib ; extra == 'cov' + - pytest-cov ; extra == 'cov' + - trio ; extra == 'cov' + - intersphinx-registry ; extra == 'docs' + - myst-parser ; extra == 'docs' + - pydata-sphinx-theme ; extra == 'docs' + - sphinx-autodoc-typehints ; extra == 'docs' + - sphinx<8.2.0 ; extra == 'docs' + - sphinxcontrib-github-alt ; extra == 'docs' + - sphinxcontrib-spelling ; extra == 'docs' + - trio ; extra == 'docs' + - pyqt5 ; extra == 'pyqt5' + - pyside6 ; extra == 'pyside6' + - flaky ; extra == 'test' + - ipyparallel ; extra == 'test' + - pre-commit ; extra == 'test' + - pytest-asyncio>=0.23.5 ; extra == 'test' + - pytest-cov ; extra == 'test' + - pytest-timeout ; extra == 'test' + - pytest>=7.0,<9 ; extra == 'test' + requires_python: '>=3.10' - pypi: https://files.pythonhosted.org/packages/20/3a/917cb9e72f4e1a4ea13c862533205ae1319bd664119189ee5cc9e4e95ebf/ipython-9.0.2-py3-none-any.whl name: ipython version: 9.0.2 @@ -634,6 +1617,29 @@ packages: requires_dist: - pygments requires_python: '>=3.8' +- pypi: https://files.pythonhosted.org/packages/56/6d/0d9848617b9f753b87f214f1c682592f7ca42de085f564352f10f0843026/ipywidgets-8.1.8-py3-none-any.whl + name: ipywidgets + version: 8.1.8 + sha256: ecaca67aed704a338f88f67b1181b58f821ab5dc89c1f0f5ef99db43c1c2921e + requires_dist: + - comm>=0.1.3 + - ipython>=6.1.0 + - traitlets>=4.3.1 + - widgetsnbextension~=4.0.14 + - jupyterlab-widgets~=3.0.15 + - jsonschema ; extra == 'test' + - ipykernel ; extra == 'test' + - pytest>=3.6.0 ; extra == 'test' + - pytest-cov ; extra == 'test' + - pytz ; extra == 'test' + requires_python: '>=3.7' +- pypi: https://files.pythonhosted.org/packages/7b/55/e5326141505c5d5e34c5e0935d2908a74e4561eca44108fbfb9c13d2911a/isoduration-20.11.0-py3-none-any.whl + name: isoduration + version: 20.11.0 + sha256: b2904c2a4228c3d44f409c8ae8e2370eb21a26f7ac2ec5446df141dde3452042 + requires_dist: + - arrow>=0.15.0 + requires_python: '>=3.7' - pypi: https://files.pythonhosted.org/packages/c0/5a/9cac0c82afec3d09ccd97c8b6502d48f165f9124db81b4bcb90b4af974ee/jedi-0.19.2-py2.py3-none-any.whl name: jedi version: 0.19.2 @@ -674,6 +1680,395 @@ packages: - docopt ; extra == 'testing' - pytest<9.0.0 ; extra == 'testing' requires_python: '>=3.6' +- pypi: https://files.pythonhosted.org/packages/62/a1/3d680cbfd5f4b8f15abc1d571870c5fc3e594bb582bc3b64ea099db13e56/jinja2-3.1.6-py3-none-any.whl + name: jinja2 + version: 3.1.6 + sha256: 85ece4451f492d0c13c5dd7c13a64681a86afae63a5f347908daf103ce6d2f67 + requires_dist: + - markupsafe>=2.0 + - babel>=2.7 ; extra == 'i18n' + requires_python: '>=3.7' +- pypi: https://files.pythonhosted.org/packages/d7/9e/038522f50ceb7e74f1f991bf1b699f24b0c2bbe7c390dd36ad69f4582258/json5-0.13.0-py3-none-any.whl + name: json5 + version: 0.13.0 + sha256: 9a08e1dd65f6a4d4c6fa82d216cf2477349ec2346a38fd70cc11d2557499fbcc + requires_python: '>=3.8.0' +- pypi: https://files.pythonhosted.org/packages/71/92/5e77f98553e9e75130c78900d000368476aed74276eb8ae8796f65f00918/jsonpointer-3.0.0-py2.py3-none-any.whl + name: jsonpointer + version: 3.0.0 + sha256: 13e088adc14fca8b6aa8177c044e12701e6ad4b28ff10e65f2267a90109c9942 + requires_python: '>=3.7' +- pypi: https://files.pythonhosted.org/packages/69/90/f63fb5873511e014207a475e2bb4e8b2e570d655b00ac19a9a0ca0a385ee/jsonschema-4.26.0-py3-none-any.whl + name: jsonschema + version: 4.26.0 + sha256: d489f15263b8d200f8387e64b4c3a75f06629559fb73deb8fdfb525f2dab50ce + requires_dist: + - attrs>=22.2.0 + - jsonschema-specifications>=2023.3.6 + - referencing>=0.28.4 + - rpds-py>=0.25.0 + - fqdn ; extra == 'format' + - idna ; extra == 'format' + - isoduration ; extra == 'format' + - jsonpointer>1.13 ; extra == 'format' + - rfc3339-validator ; extra == 'format' + - rfc3987 ; extra == 'format' + - uri-template ; extra == 'format' + - webcolors>=1.11 ; extra == 'format' + - fqdn ; extra == 'format-nongpl' + - idna ; extra == 'format-nongpl' + - isoduration ; extra == 'format-nongpl' + - jsonpointer>1.13 ; extra == 'format-nongpl' + - rfc3339-validator ; extra == 'format-nongpl' + - rfc3986-validator>0.1.0 ; extra == 'format-nongpl' + - rfc3987-syntax>=1.1.0 ; extra == 'format-nongpl' + - uri-template ; extra == 'format-nongpl' + - webcolors>=24.6.0 ; extra == 'format-nongpl' + requires_python: '>=3.10' +- pypi: https://files.pythonhosted.org/packages/41/45/1a4ed80516f02155c51f51e8cedb3c1902296743db0bbc66608a0db2814f/jsonschema_specifications-2025.9.1-py3-none-any.whl + name: jsonschema-specifications + version: 2025.9.1 + sha256: 98802fee3a11ee76ecaca44429fda8a41bff98b00a0f2838151b113f210cc6fe + requires_dist: + - referencing>=0.31.0 + requires_python: '>=3.9' +- pypi: https://files.pythonhosted.org/packages/38/64/285f20a31679bf547b75602702f7800e74dbabae36ef324f716c02804753/jupyter-1.1.1-py2.py3-none-any.whl + name: jupyter + version: 1.1.1 + sha256: 7a59533c22af65439b24bbe60373a4e95af8f16ac65a6c00820ad378e3f7cc83 + requires_dist: + - notebook + - jupyter-console + - nbconvert + - ipykernel + - ipywidgets + - jupyterlab +- pypi: https://files.pythonhosted.org/packages/64/6b/67b87da9d36bff9df7d0efbd1a325fa372a43be7158effaf43ed7b22341d/jupyter_cache-1.0.1-py3-none-any.whl + name: jupyter-cache + version: 1.0.1 + sha256: 9c3cafd825ba7da8b5830485343091143dff903e4d8c69db9349b728b140abf6 + requires_dist: + - attrs + - click + - importlib-metadata + - nbclient>=0.2 + - nbformat + - pyyaml + - sqlalchemy>=1.3.12,<3 + - tabulate + - click-log ; extra == 'cli' + - pre-commit>=2.12 ; extra == 'code-style' + - nbdime ; extra == 'rtd' + - ipykernel ; extra == 'rtd' + - jupytext ; extra == 'rtd' + - myst-nb ; extra == 'rtd' + - sphinx-book-theme ; extra == 'rtd' + - sphinx-copybutton ; extra == 'rtd' + - nbdime ; extra == 'testing' + - coverage ; extra == 'testing' + - ipykernel ; extra == 'testing' + - jupytext ; extra == 'testing' + - matplotlib ; extra == 'testing' + - nbformat>=5.1 ; extra == 'testing' + - numpy ; extra == 'testing' + - pandas ; extra == 'testing' + - pytest>=6 ; extra == 'testing' + - pytest-cov ; extra == 'testing' + - pytest-regressions ; extra == 'testing' + - sympy ; extra == 'testing' + requires_python: '>=3.9' +- pypi: https://files.pythonhosted.org/packages/2d/0b/ceb7694d864abc0a047649aec263878acb9f792e1fec3e676f22dc9015e3/jupyter_client-8.8.0-py3-none-any.whl + name: jupyter-client + version: 8.8.0 + sha256: f93a5b99c5e23a507b773d3a1136bd6e16c67883ccdbd9a829b0bbdb98cd7d7a + requires_dist: + - jupyter-core>=5.1 + - python-dateutil>=2.8.2 + - pyzmq>=25.0 + - tornado>=6.4.1 + - traitlets>=5.3 + - ipykernel ; extra == 'docs' + - myst-parser ; extra == 'docs' + - pydata-sphinx-theme ; extra == 'docs' + - sphinx-autodoc-typehints ; extra == 'docs' + - sphinx>=4 ; extra == 'docs' + - sphinxcontrib-github-alt ; extra == 'docs' + - sphinxcontrib-spelling ; extra == 'docs' + - orjson ; extra == 'orjson' + - anyio ; extra == 'test' + - coverage ; extra == 'test' + - ipykernel>=6.14 ; extra == 'test' + - msgpack ; extra == 'test' + - mypy ; platform_python_implementation != 'PyPy' and extra == 'test' + - paramiko ; sys_platform == 'win32' and extra == 'test' + - pre-commit ; extra == 'test' + - pytest ; extra == 'test' + - pytest-cov ; extra == 'test' + - pytest-jupyter[client]>=0.6.2 ; extra == 'test' + - pytest-timeout ; extra == 'test' + requires_python: '>=3.10' +- pypi: https://files.pythonhosted.org/packages/ca/77/71d78d58f15c22db16328a476426f7ac4a60d3a5a7ba3b9627ee2f7903d4/jupyter_console-6.6.3-py3-none-any.whl + name: jupyter-console + version: 6.6.3 + sha256: 309d33409fcc92ffdad25f0bcdf9a4a9daa61b6f341177570fdac03de5352485 + requires_dist: + - ipykernel>=6.14 + - ipython + - jupyter-client>=7.0.0 + - jupyter-core>=4.12,!=5.0.* + - prompt-toolkit>=3.0.30 + - pygments + - pyzmq>=17 + - traitlets>=5.4 + - flaky ; extra == 'test' + - pexpect ; extra == 'test' + - pytest ; extra == 'test' + requires_python: '>=3.7' +- pypi: https://files.pythonhosted.org/packages/e7/e7/80988e32bf6f73919a113473a604f5a8f09094de312b9d52b79c2df7612b/jupyter_core-5.9.1-py3-none-any.whl + name: jupyter-core + version: 5.9.1 + sha256: ebf87fdc6073d142e114c72c9e29a9d7ca03fad818c5d300ce2adc1fb0743407 + requires_dist: + - platformdirs>=2.5 + - traitlets>=5.3 + - intersphinx-registry ; extra == 'docs' + - myst-parser ; extra == 'docs' + - pydata-sphinx-theme ; extra == 'docs' + - sphinx-autodoc-typehints ; extra == 'docs' + - sphinxcontrib-spelling ; extra == 'docs' + - traitlets ; extra == 'docs' + - ipykernel ; extra == 'test' + - pre-commit ; extra == 'test' + - pytest-cov ; extra == 'test' + - pytest-timeout ; extra == 'test' + - pytest<9 ; extra == 'test' + requires_python: '>=3.10' +- pypi: https://files.pythonhosted.org/packages/e2/48/577993f1f99c552f18a0428731a755e06171f9902fa118c379eb7c04ea22/jupyter_events-0.12.0-py3-none-any.whl + name: jupyter-events + version: 0.12.0 + sha256: 6464b2fa5ad10451c3d35fabc75eab39556ae1e2853ad0c0cc31b656731a97fb + requires_dist: + - jsonschema[format-nongpl]>=4.18.0 + - packaging + - python-json-logger>=2.0.4 + - pyyaml>=5.3 + - referencing + - rfc3339-validator + - rfc3986-validator>=0.1.1 + - traitlets>=5.3 + - click ; extra == 'cli' + - rich ; extra == 'cli' + - jupyterlite-sphinx ; extra == 'docs' + - myst-parser ; extra == 'docs' + - pydata-sphinx-theme>=0.16 ; extra == 'docs' + - sphinx>=8 ; extra == 'docs' + - sphinxcontrib-spelling ; extra == 'docs' + - click ; extra == 'test' + - pre-commit ; extra == 'test' + - pytest-asyncio>=0.19.0 ; extra == 'test' + - pytest-console-scripts ; extra == 'test' + - pytest>=7.0 ; extra == 'test' + - rich ; extra == 'test' + requires_python: '>=3.9' +- pypi: https://files.pythonhosted.org/packages/1a/60/1f6cee0c46263de1173894f0fafcb3475ded276c472c14d25e0280c18d6d/jupyter_lsp-2.3.0-py3-none-any.whl + name: jupyter-lsp + version: 2.3.0 + sha256: e914a3cb2addf48b1c7710914771aaf1819d46b2e5a79b0f917b5478ec93f34f + requires_dist: + - jupyter-server>=1.1.2 + - importlib-metadata>=4.8.3 ; python_full_version < '3.10' + requires_python: '>=3.8' +- pypi: https://files.pythonhosted.org/packages/92/80/a24767e6ca280f5a49525d987bf3e4d7552bf67c8be07e8ccf20271f8568/jupyter_server-2.17.0-py3-none-any.whl + name: jupyter-server + version: 2.17.0 + sha256: e8cb9c7db4251f51ed307e329b81b72ccf2056ff82d50524debde1ee1870e13f + requires_dist: + - anyio>=3.1.0 + - argon2-cffi>=21.1 + - jinja2>=3.0.3 + - jupyter-client>=7.4.4 + - jupyter-core>=4.12,!=5.0.* + - jupyter-events>=0.11.0 + - jupyter-server-terminals>=0.4.4 + - nbconvert>=6.4.4 + - nbformat>=5.3.0 + - overrides>=5.0 ; python_full_version < '3.12' + - packaging>=22.0 + - prometheus-client>=0.9 + - pywinpty>=2.0.1 ; os_name == 'nt' + - pyzmq>=24 + - send2trash>=1.8.2 + - terminado>=0.8.3 + - tornado>=6.2.0 + - traitlets>=5.6.0 + - websocket-client>=1.7 + - ipykernel ; extra == 'docs' + - jinja2 ; extra == 'docs' + - jupyter-client ; extra == 'docs' + - myst-parser ; extra == 'docs' + - nbformat ; extra == 'docs' + - prometheus-client ; extra == 'docs' + - pydata-sphinx-theme ; extra == 'docs' + - send2trash ; extra == 'docs' + - sphinx-autodoc-typehints ; extra == 'docs' + - sphinxcontrib-github-alt ; extra == 'docs' + - sphinxcontrib-openapi>=0.8.0 ; extra == 'docs' + - sphinxcontrib-spelling ; extra == 'docs' + - sphinxemoji ; extra == 'docs' + - tornado ; extra == 'docs' + - typing-extensions ; extra == 'docs' + - flaky ; extra == 'test' + - ipykernel ; extra == 'test' + - pre-commit ; extra == 'test' + - pytest-console-scripts ; extra == 'test' + - pytest-jupyter[server]>=0.7 ; extra == 'test' + - pytest-timeout ; extra == 'test' + - pytest>=7.0,<9 ; extra == 'test' + - requests ; extra == 'test' + requires_python: '>=3.9' +- pypi: https://files.pythonhosted.org/packages/d1/2d/6674563f71c6320841fc300911a55143925112a72a883e2ca71fba4c618d/jupyter_server_terminals-0.5.4-py3-none-any.whl + name: jupyter-server-terminals + version: 0.5.4 + sha256: 55be353fc74a80bc7f3b20e6be50a55a61cd525626f578dcb66a5708e2007d14 + requires_dist: + - pywinpty>=2.0.3 ; os_name == 'nt' + - terminado>=0.8.3 + - jinja2 ; extra == 'docs' + - jupyter-server ; extra == 'docs' + - mistune<4.0 ; extra == 'docs' + - myst-parser ; extra == 'docs' + - nbformat ; extra == 'docs' + - packaging ; extra == 'docs' + - pydata-sphinx-theme ; extra == 'docs' + - sphinxcontrib-github-alt ; extra == 'docs' + - sphinxcontrib-openapi ; extra == 'docs' + - sphinxcontrib-spelling ; extra == 'docs' + - sphinxemoji ; extra == 'docs' + - tornado ; extra == 'docs' + - jupyter-server>=2.0.0 ; extra == 'test' + - pytest-jupyter[server]>=0.5.3 ; extra == 'test' + - pytest-timeout ; extra == 'test' + - pytest>=7.0 ; extra == 'test' + requires_python: '>=3.8' +- pypi: https://files.pythonhosted.org/packages/9e/9a/0bf9a7a45f0006d7ff4fdc4fc313de4255acab02bf4db1887c65f0472c01/jupyterlab-4.5.3-py3-none-any.whl + name: jupyterlab + version: 4.5.3 + sha256: 63c9f3a48de72ba00df766ad6eed416394f5bb883829f11eeff0872302520ba7 + requires_dist: + - async-lru>=1.0.0 + - httpx>=0.25.0,<1 + - importlib-metadata>=4.8.3 ; python_full_version < '3.10' + - ipykernel>=6.5.0,!=6.30.0 + - jinja2>=3.0.3 + - jupyter-core + - jupyter-lsp>=2.0.0 + - jupyter-server>=2.4.0,<3 + - jupyterlab-server>=2.28.0,<3 + - notebook-shim>=0.2 + - packaging + - setuptools>=41.1.0 + - tomli>=1.2.2 ; python_full_version < '3.11' + - tornado>=6.2.0 + - traitlets + - build ; extra == 'dev' + - bump2version ; extra == 'dev' + - coverage ; extra == 'dev' + - hatch ; extra == 'dev' + - pre-commit ; extra == 'dev' + - pytest-cov ; extra == 'dev' + - ruff==0.11.12 ; extra == 'dev' + - jsx-lexer ; extra == 'docs' + - myst-parser ; extra == 'docs' + - pydata-sphinx-theme>=0.13.0 ; extra == 'docs' + - pytest ; extra == 'docs' + - pytest-check-links ; extra == 'docs' + - pytest-jupyter ; extra == 'docs' + - sphinx-copybutton ; extra == 'docs' + - sphinx>=1.8,<8.2.0 ; extra == 'docs' + - altair==6.0.0 ; extra == 'docs-screenshots' + - ipython==8.16.1 ; extra == 'docs-screenshots' + - ipywidgets==8.1.5 ; extra == 'docs-screenshots' + - jupyterlab-geojson==3.4.0 ; extra == 'docs-screenshots' + - jupyterlab-language-pack-zh-cn==4.3.post1 ; extra == 'docs-screenshots' + - matplotlib==3.10.0 ; extra == 'docs-screenshots' + - nbconvert>=7.0.0 ; extra == 'docs-screenshots' + - pandas==2.2.3 ; extra == 'docs-screenshots' + - scipy==1.15.1 ; extra == 'docs-screenshots' + - coverage ; extra == 'test' + - pytest-check-links>=0.7 ; extra == 'test' + - pytest-console-scripts ; extra == 'test' + - pytest-cov ; extra == 'test' + - pytest-jupyter>=0.5.3 ; extra == 'test' + - pytest-timeout ; extra == 'test' + - pytest-tornasync ; extra == 'test' + - pytest>=7.0 ; extra == 'test' + - requests ; extra == 'test' + - requests-cache ; extra == 'test' + - virtualenv ; extra == 'test' + - copier>=9,<10 ; extra == 'upgrade-extension' + - jinja2-time<0.3 ; extra == 'upgrade-extension' + - pydantic<3.0 ; extra == 'upgrade-extension' + - pyyaml-include<3.0 ; extra == 'upgrade-extension' + - tomli-w<2.0 ; extra == 'upgrade-extension' + requires_python: '>=3.9' +- pypi: https://files.pythonhosted.org/packages/b1/dd/ead9d8ea85bf202d90cc513b533f9c363121c7792674f78e0d8a854b63b4/jupyterlab_pygments-0.3.0-py3-none-any.whl + name: jupyterlab-pygments + version: 0.3.0 + sha256: 841a89020971da1d8693f1a99997aefc5dc424bb1b251fd6322462a1b8842780 + requires_python: '>=3.8' +- pypi: https://files.pythonhosted.org/packages/e0/07/a000fe835f76b7e1143242ab1122e6362ef1c03f23f83a045c38859c2ae0/jupyterlab_server-2.28.0-py3-none-any.whl + name: jupyterlab-server + version: 2.28.0 + sha256: e4355b148fdcf34d312bbbc80f22467d6d20460e8b8736bf235577dd18506968 + requires_dist: + - babel>=2.10 + - importlib-metadata>=4.8.3 ; python_full_version < '3.10' + - jinja2>=3.0.3 + - json5>=0.9.0 + - jsonschema>=4.18.0 + - jupyter-server>=1.21,<3 + - packaging>=21.3 + - requests>=2.31 + - autodoc-traits ; extra == 'docs' + - jinja2<3.2.0 ; extra == 'docs' + - mistune<4 ; extra == 'docs' + - myst-parser ; extra == 'docs' + - pydata-sphinx-theme ; extra == 'docs' + - sphinx ; extra == 'docs' + - sphinx-copybutton ; extra == 'docs' + - sphinxcontrib-openapi>0.8 ; extra == 'docs' + - openapi-core~=0.18.0 ; extra == 'openapi' + - ruamel-yaml ; extra == 'openapi' + - hatch ; extra == 'test' + - ipykernel ; extra == 'test' + - openapi-core~=0.18.0 ; extra == 'test' + - openapi-spec-validator>=0.6.0,<0.8.0 ; extra == 'test' + - pytest-console-scripts ; extra == 'test' + - pytest-cov ; extra == 'test' + - pytest-jupyter[server]>=0.6.2 ; extra == 'test' + - pytest-timeout ; extra == 'test' + - pytest>=7.0,<8 ; extra == 'test' + - requests-mock ; extra == 'test' + - ruamel-yaml ; extra == 'test' + - sphinxcontrib-spelling ; extra == 'test' + - strict-rfc3339 ; extra == 'test' + - werkzeug ; extra == 'test' + requires_python: '>=3.8' +- pypi: https://files.pythonhosted.org/packages/ab/b5/36c712098e6191d1b4e349304ef73a8d06aed77e56ceaac8c0a306c7bda1/jupyterlab_widgets-3.0.16-py3-none-any.whl + name: jupyterlab-widgets + version: 3.0.16 + sha256: 45fa36d9c6422cf2559198e4db481aa243c7a32d9926b500781c830c80f7ecf8 + requires_python: '>=3.7' +- pypi: https://files.pythonhosted.org/packages/82/3d/14ce75ef66813643812f3093ab17e46d3a206942ce7376d31ec2d36229e7/lark-1.3.1-py3-none-any.whl + name: lark + version: 1.3.1 + sha256: c629b661023a014c37da873b4ff58a817398d12635d3bbb2c5a03be7fe5d1e12 + requires_dist: + - regex ; extra == 'regex' + - js2py ; extra == 'nearley' + - atomicwrites ; extra == 'atomic-cache' + - interegular>=0.3.1,<0.4.0 ; extra == 'interegular' + requires_python: '>=3.8' - conda: https://conda.anaconda.org/conda-forge/linux-64/ld_impl_linux-64-2.43-h712a8e2_4.conda sha256: db73f38155d901a610b2320525b9dd3b31e4949215c870685fd92ea61b5ce472 md5: 01f8d123c96816249efd255a31ad7712 @@ -858,6 +2253,49 @@ packages: purls: [] size: 46438 timestamp: 1727963202283 +- pypi: https://files.pythonhosted.org/packages/94/54/e7d793b573f298e1c9013b8c4dade17d481164aa517d1d7148619c2cedbf/markdown_it_py-4.0.0-py3-none-any.whl + name: markdown-it-py + version: 4.0.0 + sha256: 87327c59b172c5011896038353a81343b6754500a08cd7a4973bb48c6d578147 + requires_dist: + - mdurl~=0.1 + - psutil ; extra == 'benchmarking' + - pytest ; extra == 'benchmarking' + - pytest-benchmark ; extra == 'benchmarking' + - commonmark~=0.9 ; extra == 'compare' + - markdown~=3.4 ; extra == 'compare' + - mistletoe~=1.0 ; extra == 'compare' + - mistune~=3.0 ; extra == 'compare' + - panflute~=2.3 ; extra == 'compare' + - markdown-it-pyrs ; extra == 'compare' + - linkify-it-py>=1,<3 ; extra == 'linkify' + - mdit-py-plugins>=0.5.0 ; extra == 'plugins' + - gprof2dot ; extra == 'profiling' + - mdit-py-plugins>=0.5.0 ; extra == 'rtd' + - myst-parser ; extra == 'rtd' + - pyyaml ; extra == 'rtd' + - sphinx ; extra == 'rtd' + - sphinx-copybutton ; extra == 'rtd' + - sphinx-design ; extra == 'rtd' + - sphinx-book-theme~=1.0 ; extra == 'rtd' + - jupyter-sphinx ; extra == 'rtd' + - ipykernel ; extra == 'rtd' + - coverage ; extra == 'testing' + - pytest ; extra == 'testing' + - pytest-cov ; extra == 'testing' + - pytest-regressions ; extra == 'testing' + - requests ; extra == 'testing' + requires_python: '>=3.10' +- pypi: https://files.pythonhosted.org/packages/3c/2e/8d0c2ab90a8c1d9a24f0399058ab8519a3279d1bd4289511d74e909f060e/markupsafe-3.0.3-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl + name: markupsafe + version: 3.0.3 + sha256: d6dd0be5b5b189d31db7cda48b91d7e0a9795f31430b7f271219ab30f1d3ac9d + requires_python: '>=3.9' +- pypi: https://files.pythonhosted.org/packages/9a/81/7e4e08678a1f98521201c3079f77db69fb552acd56067661f8c2f534a718/markupsafe-3.0.3-cp312-cp312-macosx_11_0_arm64.whl + name: markupsafe + version: 3.0.3 + sha256: 1872df69a4de6aead3491198eaf13810b565bdbeec3ae2dc8780f14458ec73ce + requires_python: '>=3.9' - pypi: https://files.pythonhosted.org/packages/8f/8e/9ad090d3553c280a8060fbf6e24dc1c0c29704ee7d1c372f0c174aa59285/matplotlib_inline-0.1.7-py3-none-any.whl name: matplotlib-inline version: 0.1.7 @@ -865,6 +2303,131 @@ packages: requires_dist: - traitlets requires_python: '>=3.8' +- pypi: https://files.pythonhosted.org/packages/b3/38/89ba8ad64ae25be8de66a6d463314cf1eb366222074cfda9ee839c56a4b4/mdurl-0.1.2-py3-none-any.whl + name: mdurl + version: 0.1.2 + sha256: 84008a41e51615a49fc9966191ff91509e3c40b939176e643fd50a5c2196b8f8 + requires_python: '>=3.7' +- pypi: https://files.pythonhosted.org/packages/9b/f7/4a5e785ec9fbd65146a27b6b70b6cdc161a66f2024e4b04ac06a67f5578b/mistune-3.2.0-py3-none-any.whl + name: mistune + version: 3.2.0 + sha256: febdc629a3c78616b94393c6580551e0e34cc289987ec6c35ed3f4be42d0eee1 + requires_dist: + - typing-extensions ; python_full_version < '3.11' + requires_python: '>=3.8' +- pypi: https://files.pythonhosted.org/packages/79/7b/2c79738432f5c924bef5071f933bcc9efd0473bac3b4aa584a6f7c1c8df8/mypy_extensions-1.1.0-py3-none-any.whl + name: mypy-extensions + version: 1.1.0 + sha256: 1be4cccdb0f2482337c4743e60421de3a356cd97508abadd57d47403e94f5505 + requires_python: '>=3.8' +- pypi: https://files.pythonhosted.org/packages/83/a0/5b0c2f11142ed1dddec842457d3f65eaf71a0080894eb6f018755b319c3a/nbclient-0.10.4-py3-none-any.whl + name: nbclient + version: 0.10.4 + sha256: 9162df5a7373d70d606527300a95a975a47c137776cd942e52d9c7e29ff83440 + requires_dist: + - jupyter-client>=6.1.12 + - jupyter-core>=4.12,!=5.0.* + - nbformat>=5.1.3 + - traitlets>=5.4 + - pre-commit ; extra == 'dev' + - autodoc-traits ; extra == 'docs' + - flaky ; extra == 'docs' + - ipykernel>=6.19.3 ; extra == 'docs' + - ipython ; extra == 'docs' + - ipywidgets ; extra == 'docs' + - mock ; extra == 'docs' + - moto ; extra == 'docs' + - myst-parser ; extra == 'docs' + - nbconvert>=7.1.0 ; extra == 'docs' + - pytest-asyncio>=1.3.0 ; extra == 'docs' + - pytest-cov>=4.0 ; extra == 'docs' + - pytest>=9.0.1,<10 ; extra == 'docs' + - sphinx-book-theme ; extra == 'docs' + - sphinx>=1.7 ; extra == 'docs' + - sphinxcontrib-spelling ; extra == 'docs' + - testpath ; extra == 'docs' + - xmltodict ; extra == 'docs' + - flaky ; extra == 'test' + - ipykernel>=6.19.3 ; extra == 'test' + - ipython ; extra == 'test' + - ipywidgets ; extra == 'test' + - nbconvert>=7.1.0 ; extra == 'test' + - pytest-asyncio>=1.3.0 ; extra == 'test' + - pytest-cov>=4.0 ; extra == 'test' + - pytest>=9.0.1,<10 ; extra == 'test' + - testpath ; extra == 'test' + - xmltodict ; extra == 'test' + requires_python: '>=3.10.0' +- pypi: https://files.pythonhosted.org/packages/0d/4b/8d5f796a792f8a25f6925a96032f098789f448571eb92011df1ae59e8ea8/nbconvert-7.17.0-py3-none-any.whl + name: nbconvert + version: 7.17.0 + sha256: 4f99a63b337b9a23504347afdab24a11faa7d86b405e5c8f9881cd313336d518 + requires_dist: + - beautifulsoup4 + - bleach[css]!=5.0.0 + - defusedxml + - importlib-metadata>=3.6 ; python_full_version < '3.10' + - jinja2>=3.0 + - jupyter-core>=4.7 + - jupyterlab-pygments + - markupsafe>=2.0 + - mistune>=2.0.3,<4 + - nbclient>=0.5.0 + - nbformat>=5.7 + - packaging + - pandocfilters>=1.4.1 + - pygments>=2.4.1 + - traitlets>=5.1 + - flaky ; extra == 'all' + - intersphinx-registry ; extra == 'all' + - ipykernel ; extra == 'all' + - ipython ; extra == 'all' + - ipywidgets>=7.5 ; extra == 'all' + - myst-parser ; extra == 'all' + - nbsphinx>=0.2.12 ; extra == 'all' + - playwright ; extra == 'all' + - pydata-sphinx-theme ; extra == 'all' + - pyqtwebengine>=5.15 ; extra == 'all' + - pytest>=7 ; extra == 'all' + - sphinx>=5.0.2 ; extra == 'all' + - sphinxcontrib-spelling ; extra == 'all' + - tornado>=6.1 ; extra == 'all' + - intersphinx-registry ; extra == 'docs' + - ipykernel ; extra == 'docs' + - ipython ; extra == 'docs' + - myst-parser ; extra == 'docs' + - nbsphinx>=0.2.12 ; extra == 'docs' + - pydata-sphinx-theme ; extra == 'docs' + - sphinx>=5.0.2 ; extra == 'docs' + - sphinxcontrib-spelling ; extra == 'docs' + - pyqtwebengine>=5.15 ; extra == 'qtpdf' + - pyqtwebengine>=5.15 ; extra == 'qtpng' + - tornado>=6.1 ; extra == 'serve' + - flaky ; extra == 'test' + - ipykernel ; extra == 'test' + - ipywidgets>=7.5 ; extra == 'test' + - pytest>=7 ; extra == 'test' + - playwright ; extra == 'webpdf' + requires_python: '>=3.9' +- pypi: https://files.pythonhosted.org/packages/a9/82/0340caa499416c78e5d8f5f05947ae4bc3cba53c9f038ab6e9ed964e22f1/nbformat-5.10.4-py3-none-any.whl + name: nbformat + version: 5.10.4 + sha256: 3b48d6c8fbca4b299bf3982ea7db1af21580e4fec269ad087b9e81588891200b + requires_dist: + - fastjsonschema>=2.15 + - jsonschema>=2.6 + - jupyter-core>=4.12,!=5.0.* + - traitlets>=5.1 + - myst-parser ; extra == 'docs' + - pydata-sphinx-theme ; extra == 'docs' + - sphinx ; extra == 'docs' + - sphinxcontrib-github-alt ; extra == 'docs' + - sphinxcontrib-spelling ; extra == 'docs' + - pep440 ; extra == 'test' + - pre-commit ; extra == 'test' + - pytest ; extra == 'test' + - testpath ; extra == 'test' + requires_python: '>=3.8' - conda: https://conda.anaconda.org/conda-forge/linux-64/ncurses-6.5-h2d0b736_3.conda sha256: 3fde293232fa3fca98635e1167de6b7c7fda83caf24b9d6c91ec9eefb4f4d586 md5: 47e340acb35de30501a76c7c799c41d7 @@ -884,11 +2447,56 @@ packages: purls: [] size: 797030 timestamp: 1738196177597 +- pypi: https://files.pythonhosted.org/packages/a0/c4/c2971a3ba4c6103a3d10c4b0f24f461ddc027f0f09763220cf35ca1401b3/nest_asyncio-1.6.0-py3-none-any.whl + name: nest-asyncio + version: 1.6.0 + sha256: 87af6efd6b5e897c81050477ef65c62e2b2f35d51703cae01aff2905b1852e1c + requires_python: '>=3.5' - pypi: https://files.pythonhosted.org/packages/d2/1d/1b658dbd2b9fa9c4c9f32accbfc0205d532c8c6194dc0f2a4c0428e7128a/nodeenv-1.9.1-py2.py3-none-any.whl name: nodeenv version: 1.9.1 sha256: ba11c9782d29c27c70ffbdda2d7415098754709be8a7056d79a737cd901155c9 requires_python: '>=2.7,!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*' +- pypi: https://files.pythonhosted.org/packages/96/98/9286e7f35e5584ebb79f997f2fb0cb66745c86f6c5fccf15ba32aac5e908/notebook-7.5.3-py3-none-any.whl + name: notebook + version: 7.5.3 + sha256: c997bfa1a2a9eb58c9bbb7e77d50428befb1033dd6f02c482922e96851d67354 + requires_dist: + - jupyter-server>=2.4.0,<3 + - jupyterlab-server>=2.28.0,<3 + - jupyterlab>=4.5.3,<4.6 + - notebook-shim>=0.2,<0.3 + - tornado>=6.2.0 + - hatch ; extra == 'dev' + - pre-commit ; extra == 'dev' + - myst-parser ; extra == 'docs' + - nbsphinx ; extra == 'docs' + - pydata-sphinx-theme ; extra == 'docs' + - sphinx>=1.3.6 ; extra == 'docs' + - sphinxcontrib-github-alt ; extra == 'docs' + - sphinxcontrib-spelling ; extra == 'docs' + - importlib-resources>=5.0 ; python_full_version < '3.10' and extra == 'test' + - ipykernel ; extra == 'test' + - jupyter-server[test]>=2.4.0,<3 ; extra == 'test' + - jupyterlab-server[test]>=2.28.0,<3 ; extra == 'test' + - nbval ; extra == 'test' + - pytest-console-scripts ; extra == 'test' + - pytest-timeout ; extra == 'test' + - pytest-tornasync ; extra == 'test' + - pytest>=7.0 ; extra == 'test' + - requests ; extra == 'test' + requires_python: '>=3.9' +- pypi: https://files.pythonhosted.org/packages/f9/33/bd5b9137445ea4b680023eb0469b2bb969d61303dedb2aac6560ff3d14a1/notebook_shim-0.2.4-py3-none-any.whl + name: notebook-shim + version: 0.2.4 + sha256: 411a5be4e9dc882a074ccbcae671eda64cceb068767e9a3419096986560e1cef + requires_dist: + - jupyter-server>=1.8,<3 + - pytest ; extra == 'test' + - pytest-console-scripts ; extra == 'test' + - pytest-jupyter ; extra == 'test' + - pytest-tornasync ; extra == 'test' + requires_python: '>=3.7' - conda: https://conda.anaconda.org/conda-forge/linux-64/openssl-3.4.1-h7b32b05_0.conda sha256: cbf62df3c79a5c2d113247ddea5658e9ff3697b6e741c210656e239ecaf1768f md5: 41adf927e746dc75ecf0ef841c454e48 @@ -917,6 +2525,11 @@ packages: version: '24.2' sha256: 09abb1bccd265c01f4a3aa3f7a7db064b36514d2cba19a2f694fe6150451a759 requires_python: '>=3.8' +- pypi: https://files.pythonhosted.org/packages/ef/af/4fbc8cab944db5d21b7e2a5b8e9211a03a79852b1157e2c102fcc61ac440/pandocfilters-1.5.1-py2.py3-none-any.whl + name: pandocfilters + version: 1.5.1 + sha256: 93be382804a9cdb0a7267585f157e5d1731bbe5545a85b268d6f5fe6232de2bc + requires_python: '>=2.7,!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*' - pypi: https://files.pythonhosted.org/packages/c6/ac/dac4a63f978e4dcb3c6d3a78c4d8e0192a113d288502a1216950c41b1027/parso-0.8.4-py2.py3-none-any.whl name: parso version: 0.8.4 @@ -928,12 +2541,39 @@ packages: - docopt ; extra == 'testing' - pytest ; extra == 'testing' requires_python: '>=3.6' +- pypi: https://files.pythonhosted.org/packages/ef/3c/2c197d226f9ea224a9ab8d197933f9da0ae0aac5b6e0f884e2b8d9c8e9f7/pathspec-1.0.4-py3-none-any.whl + name: pathspec + version: 1.0.4 + sha256: fb6ae2fd4e7c921a165808a552060e722767cfa526f99ca5156ed2ce45a5c723 + requires_dist: + - hyperscan>=0.7 ; extra == 'hyperscan' + - typing-extensions>=4 ; extra == 'optional' + - google-re2>=1.1 ; extra == 're2' + - pytest>=9 ; extra == 'tests' + - typing-extensions>=4.15 ; extra == 'tests' + requires_python: '>=3.9' - pypi: https://files.pythonhosted.org/packages/9e/c3/059298687310d527a58bb01f3b1965787ee3b40dce76752eda8b44e9a2c5/pexpect-4.9.0-py2.py3-none-any.whl name: pexpect version: 4.9.0 sha256: 7236d1e080e4936be2dc3e326cec0af72acf9212a7e1d060210e70a47e253523 requires_dist: - ptyprocess>=0.5 +- pypi: https://files.pythonhosted.org/packages/cb/28/3bfe2fa5a7b9c46fe7e13c97bda14c895fb10fa2ebf1d0abb90e0cea7ee1/platformdirs-4.5.1-py3-none-any.whl + name: platformdirs + version: 4.5.1 + sha256: d03afa3963c806a9bed9d5125c8f4cb2fdaf74a55ab60e5d59b3fde758104d31 + requires_dist: + - furo>=2025.9.25 ; extra == 'docs' + - proselint>=0.14 ; extra == 'docs' + - sphinx-autodoc-typehints>=3.2 ; extra == 'docs' + - sphinx>=8.2.3 ; extra == 'docs' + - appdirs==1.4.4 ; extra == 'test' + - covdefaults>=2.3 ; extra == 'test' + - pytest-cov>=7 ; extra == 'test' + - pytest-mock>=3.15.1 ; extra == 'test' + - pytest>=8.4.2 ; extra == 'test' + - mypy>=1.18.2 ; extra == 'type' + requires_python: '>=3.10' - pypi: https://files.pythonhosted.org/packages/88/5f/e351af9a41f866ac3f1fac4ca0613908d9a41741cfcf2228f4ad853b697d/pluggy-1.5.0-py3-none-any.whl name: pluggy version: 1.5.0 @@ -944,6 +2584,24 @@ packages: - pytest ; extra == 'testing' - pytest-benchmark ; extra == 'testing' requires_python: '>=3.8' +- pypi: https://files.pythonhosted.org/packages/42/88/71fa06eb487ed9d4fab0ad173300b7a58706385f98fb66b1ccdc3ec3d4dd/plum_dispatch-2.6.1-py3-none-any.whl + name: plum-dispatch + version: 2.6.1 + sha256: 49cd83027498e35eac32c7a93ecd6a99970d72d90f4141cc93be760c7ba831c4 + requires_dist: + - beartype>=0.16.2 + - rich>=10.0 + - typing-extensions>=4.9.0 + requires_python: '>=3.10' +- pypi: https://files.pythonhosted.org/packages/74/c3/24a2f845e3917201628ecaba4f18bab4d18a337834c1df2a159ee9d22a42/prometheus_client-0.24.1-py3-none-any.whl + name: prometheus-client + version: 0.24.1 + sha256: 150db128af71a5c2482b36e588fc8a6b95e498750da4b17065947c16070f4055 + requires_dist: + - twisted ; extra == 'twisted' + - aiohttp ; extra == 'aiohttp' + - django ; extra == 'django' + requires_python: '>=3.9' - pypi: https://files.pythonhosted.org/packages/e4/ea/d836f008d33151c7a1f62caf3d8dd782e4d15f6a43897f64480c2b8de2ad/prompt_toolkit-3.0.50-py3-none-any.whl name: prompt-toolkit version: 3.0.50 @@ -951,6 +2609,94 @@ packages: requires_dist: - wcwidth requires_python: '>=3.8.0' +- pypi: https://files.pythonhosted.org/packages/80/c4/f5af4c1ca8c1eeb2e92ccca14ce8effdeec651d5ab6053c589b074eda6e1/psutil-7.2.2-cp36-abi3-macosx_11_0_arm64.whl + name: psutil + version: 7.2.2 + sha256: 1a7b04c10f32cc88ab39cbf606e117fd74721c831c98a27dc04578deb0c16979 + requires_dist: + - psleak ; extra == 'dev' + - pytest ; extra == 'dev' + - pytest-instafail ; extra == 'dev' + - pytest-xdist ; extra == 'dev' + - setuptools ; extra == 'dev' + - abi3audit ; extra == 'dev' + - black ; extra == 'dev' + - check-manifest ; extra == 'dev' + - coverage ; extra == 'dev' + - packaging ; extra == 'dev' + - pylint ; extra == 'dev' + - pyperf ; extra == 'dev' + - pypinfo ; extra == 'dev' + - pytest-cov ; extra == 'dev' + - requests ; extra == 'dev' + - rstcheck ; extra == 'dev' + - ruff ; extra == 'dev' + - sphinx ; extra == 'dev' + - sphinx-rtd-theme ; extra == 'dev' + - toml-sort ; extra == 'dev' + - twine ; extra == 'dev' + - validate-pyproject[all] ; extra == 'dev' + - virtualenv ; extra == 'dev' + - vulture ; extra == 'dev' + - wheel ; extra == 'dev' + - colorama ; os_name == 'nt' and extra == 'dev' + - pyreadline3 ; os_name == 'nt' and extra == 'dev' + - pywin32 ; implementation_name != 'pypy' and os_name == 'nt' and extra == 'dev' + - wheel ; implementation_name != 'pypy' and os_name == 'nt' and extra == 'dev' + - wmi ; implementation_name != 'pypy' and os_name == 'nt' and extra == 'dev' + - psleak ; extra == 'test' + - pytest ; extra == 'test' + - pytest-instafail ; extra == 'test' + - pytest-xdist ; extra == 'test' + - setuptools ; extra == 'test' + - pywin32 ; implementation_name != 'pypy' and os_name == 'nt' and extra == 'test' + - wheel ; implementation_name != 'pypy' and os_name == 'nt' and extra == 'test' + - wmi ; implementation_name != 'pypy' and os_name == 'nt' and extra == 'test' + requires_python: '>=3.6' +- pypi: https://files.pythonhosted.org/packages/b5/70/5d8df3b09e25bce090399cf48e452d25c935ab72dad19406c77f4e828045/psutil-7.2.2-cp36-abi3-manylinux2010_x86_64.manylinux_2_12_x86_64.manylinux_2_28_x86_64.whl + name: psutil + version: 7.2.2 + sha256: 076a2d2f923fd4821644f5ba89f059523da90dc9014e85f8e45a5774ca5bc6f9 + requires_dist: + - psleak ; extra == 'dev' + - pytest ; extra == 'dev' + - pytest-instafail ; extra == 'dev' + - pytest-xdist ; extra == 'dev' + - setuptools ; extra == 'dev' + - abi3audit ; extra == 'dev' + - black ; extra == 'dev' + - check-manifest ; extra == 'dev' + - coverage ; extra == 'dev' + - packaging ; extra == 'dev' + - pylint ; extra == 'dev' + - pyperf ; extra == 'dev' + - pypinfo ; extra == 'dev' + - pytest-cov ; extra == 'dev' + - requests ; extra == 'dev' + - rstcheck ; extra == 'dev' + - ruff ; extra == 'dev' + - sphinx ; extra == 'dev' + - sphinx-rtd-theme ; extra == 'dev' + - toml-sort ; extra == 'dev' + - twine ; extra == 'dev' + - validate-pyproject[all] ; extra == 'dev' + - virtualenv ; extra == 'dev' + - vulture ; extra == 'dev' + - wheel ; extra == 'dev' + - colorama ; os_name == 'nt' and extra == 'dev' + - pyreadline3 ; os_name == 'nt' and extra == 'dev' + - pywin32 ; implementation_name != 'pypy' and os_name == 'nt' and extra == 'dev' + - wheel ; implementation_name != 'pypy' and os_name == 'nt' and extra == 'dev' + - wmi ; implementation_name != 'pypy' and os_name == 'nt' and extra == 'dev' + - psleak ; extra == 'test' + - pytest ; extra == 'test' + - pytest-instafail ; extra == 'test' + - pytest-xdist ; extra == 'test' + - setuptools ; extra == 'test' + - pywin32 ; implementation_name != 'pypy' and os_name == 'nt' and extra == 'test' + - wheel ; implementation_name != 'pypy' and os_name == 'nt' and extra == 'test' + - wmi ; implementation_name != 'pypy' and os_name == 'nt' and extra == 'test' + requires_python: '>=3.6' - pypi: https://files.pythonhosted.org/packages/22/a6/858897256d0deac81a172289110f31629fc4cee19b6f01283303e18c8db3/ptyprocess-0.7.0-py2.py3-none-any.whl name: ptyprocess version: 0.7.0 @@ -961,6 +2707,37 @@ packages: sha256: 1db8e35b67b3d218d818ae653e27f06c3aa420901fa7b081ca98cbedc874e0d0 requires_dist: - pytest ; extra == 'tests' +- pypi: https://files.pythonhosted.org/packages/0c/c3/44f3fbbfa403ea2a7c779186dc20772604442dde72947e7d01069cbe98e3/pycparser-3.0-py3-none-any.whl + name: pycparser + version: '3.0' + sha256: b727414169a36b7d524c1c3e31839a521725078d7b2ff038656844266160a992 + requires_python: '>=3.10' +- pypi: https://files.pythonhosted.org/packages/5a/87/b70ad306ebb6f9b585f114d0ac2137d792b48be34d732d60e597c2f8465a/pydantic-2.12.5-py3-none-any.whl + name: pydantic + version: 2.12.5 + sha256: e561593fccf61e8a20fc46dfc2dfe075b8be7d0188df33f221ad1f0139180f9d + requires_dist: + - annotated-types>=0.6.0 + - pydantic-core==2.41.5 + - typing-extensions>=4.14.1 + - typing-inspection>=0.4.2 + - email-validator>=2.0.0 ; extra == 'email' + - tzdata ; python_full_version >= '3.9' and sys_platform == 'win32' and extra == 'timezone' + requires_python: '>=3.9' +- pypi: https://files.pythonhosted.org/packages/0d/76/941cc9f73529988688a665a5c0ecff1112b3d95ab48f81db5f7606f522d3/pydantic_core-2.41.5-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl + name: pydantic-core + version: 2.41.5 + sha256: eceb81a8d74f9267ef4081e246ffd6d129da5d87e37a77c9bde550cb04870c1c + requires_dist: + - typing-extensions>=4.14.1 + requires_python: '>=3.9' +- pypi: https://files.pythonhosted.org/packages/aa/32/9c2e8ccb57c01111e0fd091f236c7b371c1bccea0fa85247ac55b1e2b6b6/pydantic_core-2.41.5-cp312-cp312-macosx_11_0_arm64.whl + name: pydantic-core + version: 2.41.5 + sha256: 070259a8818988b9a84a449a2a7337c7f430a22acc0859c6b110aa7212a6d9c0 + requires_dist: + - typing-extensions>=4.14.1 + requires_python: '>=3.9' - pypi: https://files.pythonhosted.org/packages/8a/0b/9fcc47d19c48b59121088dd6da2488a49d5f72dacf8262e2790a1d2c7d15/pygments-2.19.1-py3-none-any.whl name: pygments version: 2.19.1 @@ -1064,12 +2841,125 @@ packages: purls: [] size: 13042031 timestamp: 1741128584924 -- pypi: . +- pypi: https://files.pythonhosted.org/packages/ec/57/56b9bcc3c9c6a792fcbaf139543cee77261f3651ca9da0c93f5c1221264b/python_dateutil-2.9.0.post0-py2.py3-none-any.whl + name: python-dateutil + version: 2.9.0.post0 + sha256: a8b2bc7bffae282281c8140a97d3aa9c14da0b136dfe83f850eea9a5f7470427 + requires_dist: + - six>=1.5 + requires_python: '>=2.7,!=3.0.*,!=3.1.*,!=3.2.*' +- pypi: https://files.pythonhosted.org/packages/51/e5/fecf13f06e5e5f67e8837d777d1bc43fac0ed2b77a676804df5c34744727/python_json_logger-4.0.0-py3-none-any.whl + name: python-json-logger + version: 4.0.0 + sha256: af09c9daf6a813aa4cc7180395f50f2a9e5fa056034c9953aec92e381c5ba1e2 + requires_dist: + - typing-extensions ; python_full_version < '3.10' + - orjson ; implementation_name != 'pypy' and extra == 'dev' + - msgspec ; implementation_name != 'pypy' and extra == 'dev' + - validate-pyproject[all] ; extra == 'dev' + - black ; extra == 'dev' + - pylint ; extra == 'dev' + - mypy ; extra == 'dev' + - pytest ; extra == 'dev' + - freezegun ; extra == 'dev' + - backports-zoneinfo ; python_full_version < '3.9' and extra == 'dev' + - tzdata ; extra == 'dev' + - build ; extra == 'dev' + - mkdocs ; extra == 'dev' + - mkdocs-material>=8.5 ; extra == 'dev' + - mkdocs-awesome-pages-plugin ; extra == 'dev' + - mdx-truly-sane-lists ; extra == 'dev' + - mkdocstrings[python] ; extra == 'dev' + - mkdocs-gen-files ; extra == 'dev' + - mkdocs-literate-nav ; extra == 'dev' + - mike ; extra == 'dev' + requires_python: '>=3.8' +- pypi: ./ name: python-nix-template version: 0.1.1 - sha256: ef9655370d07a32a8d391d075635314bff2c4203307bd9bda2167aa5dd089692 + sha256: 6625dc33374e5095266440951f7084244089de29d0ce6bc866a2adf6a0e34f1f requires_python: '>=3.11,<3.13' editable: true +- pypi: https://files.pythonhosted.org/packages/41/5d/e44573011401fb82e9d51e97f1290ceb377800fb4eed650b96f4753b499c/pytokens-0.4.1-cp312-cp312-macosx_11_0_arm64.whl + name: pytokens + version: 0.4.1 + sha256: 140709331e846b728475786df8aeb27d24f48cbcf7bcd449f8de75cae7a45083 + requires_dist: + - black ; extra == 'dev' + - build ; extra == 'dev' + - mypy ; extra == 'dev' + - pytest ; extra == 'dev' + - pytest-cov ; extra == 'dev' + - setuptools ; extra == 'dev' + - tox ; extra == 'dev' + - twine ; extra == 'dev' + - wheel ; extra == 'dev' + requires_python: '>=3.8' +- pypi: https://files.pythonhosted.org/packages/bf/3c/2d5297d82286f6f3d92770289fd439956b201c0a4fc7e72efb9b2293758e/pytokens-0.4.1-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl + name: pytokens + version: 0.4.1 + sha256: 24afde1f53d95348b5a0eb19488661147285ca4dd7ed752bbc3e1c6242a304d1 + requires_dist: + - black ; extra == 'dev' + - build ; extra == 'dev' + - mypy ; extra == 'dev' + - pytest ; extra == 'dev' + - pytest-cov ; extra == 'dev' + - setuptools ; extra == 'dev' + - tox ; extra == 'dev' + - twine ; extra == 'dev' + - wheel ; extra == 'dev' + requires_python: '>=3.8' +- pypi: https://files.pythonhosted.org/packages/89/a0/6cf41a19a1f2f3feab0e9c0b74134aa2ce6849093d5517a0c550fe37a648/pyyaml-6.0.3-cp312-cp312-macosx_11_0_arm64.whl + name: pyyaml + version: 6.0.3 + sha256: fc09d0aa354569bc501d4e787133afc08552722d3ab34836a80547331bb5d4a0 + requires_python: '>=3.8' +- pypi: https://files.pythonhosted.org/packages/8b/9d/b3589d3877982d4f2329302ef98a8026e7f4443c765c46cfecc8858c6b4b/pyyaml-6.0.3-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl + name: pyyaml + version: 6.0.3 + sha256: ba1cc08a7ccde2d2ec775841541641e4548226580ab850948cbfda66a1befcdc + requires_python: '>=3.8' +- pypi: https://files.pythonhosted.org/packages/92/e7/038aab64a946d535901103da16b953c8c9cc9c961dadcbf3609ed6428d23/pyzmq-27.1.0-cp312-abi3-macosx_10_15_universal2.whl + name: pyzmq + version: 27.1.0 + sha256: 452631b640340c928fa343801b0d07eb0c3789a5ffa843f6e1a9cee0ba4eb4fc + requires_dist: + - cffi ; implementation_name == 'pypy' + requires_python: '>=3.8' +- pypi: https://files.pythonhosted.org/packages/f8/9b/c108cdb55560eaf253f0cbdb61b29971e9fb34d9c3499b0e96e4e60ed8a5/pyzmq-27.1.0-cp312-abi3-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl + name: pyzmq + version: 27.1.0 + sha256: 43ad9a73e3da1fab5b0e7e13402f0b2fb934ae1c876c51d0afff0e7c052eca31 + requires_dist: + - cffi ; implementation_name == 'pypy' + requires_python: '>=3.8' +- pypi: https://files.pythonhosted.org/packages/75/d9/0b48d4184f9ca6a996c4fac46897a968698c9d1e0f0e43a6906746201323/quartodoc-0.11.1-py3-none-any.whl + name: quartodoc + version: 0.11.1 + sha256: 0776eb8e53d89385e2c9a8ae0ec08e8c307c1410dd1bd78bb28e8b1823dbb6ad + requires_dist: + - black + - click + - griffe>=0.33 + - sphobjinv>=2.3.1 + - tabulate>=0.9.0 + - importlib-metadata>=5.1.0 + - importlib-resources>=5.10.2 + - pydantic + - pyyaml + - requests + - typing-extensions>=4.4.0 + - watchdog>=3.0.0 + - plum-dispatch<2.0.0 ; python_full_version < '3.10' + - plum-dispatch>2.0.0 ; python_full_version >= '3.10' + - pytest<8.0.0 ; extra == 'dev' + - pytest-cov ; extra == 'dev' + - jupyterlab ; extra == 'dev' + - jupytext ; extra == 'dev' + - syrupy ; extra == 'dev' + - pre-commit ; extra == 'dev' + requires_python: '>=3.9' - conda: https://conda.anaconda.org/conda-forge/linux-64/readline-8.2-h8c095d6_2.conda sha256: 2d6d0c026902561ed77cd646b5021aef2d4db22e57a5b0178dfc669231e06d2c md5: 283b96675859b20a825f8fa30f311446 @@ -1091,6 +2981,66 @@ packages: purls: [] size: 252359 timestamp: 1740379663071 +- pypi: https://files.pythonhosted.org/packages/2c/58/ca301544e1fa93ed4f80d724bf5b194f6e4b945841c5bfd555878eea9fcb/referencing-0.37.0-py3-none-any.whl + name: referencing + version: 0.37.0 + sha256: 381329a9f99628c9069361716891d34ad94af76e461dcb0335825aecc7692231 + requires_dist: + - attrs>=22.2.0 + - rpds-py>=0.7.0 + - typing-extensions>=4.4.0 ; python_full_version < '3.13' + requires_python: '>=3.10' +- pypi: https://files.pythonhosted.org/packages/1e/db/4254e3eabe8020b458f1a747140d32277ec7a271daf1d235b70dc0b4e6e3/requests-2.32.5-py3-none-any.whl + name: requests + version: 2.32.5 + sha256: 2462f94637a34fd532264295e186976db0f5d453d1cdd31473c85a6a161affb6 + requires_dist: + - charset-normalizer>=2,<4 + - idna>=2.5,<4 + - urllib3>=1.21.1,<3 + - certifi>=2017.4.17 + - pysocks>=1.5.6,!=1.5.7 ; extra == 'socks' + - chardet>=3.0.2,<6 ; extra == 'use-chardet-on-py3' + requires_python: '>=3.9' +- pypi: https://files.pythonhosted.org/packages/7b/44/4e421b96b67b2daff264473f7465db72fbdf36a07e05494f50300cc7b0c6/rfc3339_validator-0.1.4-py2.py3-none-any.whl + name: rfc3339-validator + version: 0.1.4 + sha256: 24f6ec1eda14ef823da9e36ec7113124b39c04d50a4d3d3a3c2859577e7791fa + requires_dist: + - six + requires_python: '>=2.7,!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*' +- pypi: https://files.pythonhosted.org/packages/9e/51/17023c0f8f1869d8806b979a2bffa3f861f26a3f1a66b094288323fba52f/rfc3986_validator-0.1.1-py2.py3-none-any.whl + name: rfc3986-validator + version: 0.1.1 + sha256: 2f235c432ef459970b4306369336b9d5dbdda31b510ca1e327636e01f528bfa9 + requires_python: '>=2.7,!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*' +- pypi: https://files.pythonhosted.org/packages/7e/71/44ce230e1b7fadd372515a97e32a83011f906ddded8d03e3c6aafbdedbb7/rfc3987_syntax-1.1.0-py3-none-any.whl + name: rfc3987-syntax + version: 1.1.0 + sha256: 6c3d97604e4c5ce9f714898e05401a0445a641cfa276432b0a648c80856f6a3f + requires_dist: + - lark>=1.2.2 + - pytest>=8.3.5 ; extra == 'testing' + requires_python: '>=3.9' +- pypi: https://files.pythonhosted.org/packages/ef/45/615f5babd880b4bd7d405cc0dc348234c5ffb6ed1ea33e152ede08b2072d/rich-14.3.2-py3-none-any.whl + name: rich + version: 14.3.2 + sha256: 08e67c3e90884651da3239ea668222d19bea7b589149d8014a21c633420dbb69 + requires_dist: + - ipywidgets>=7.5.1,<9 ; extra == 'jupyter' + - markdown-it-py>=2.2.0 + - pygments>=2.13.0,<3.0.0 + requires_python: '>=3.8.0' +- pypi: https://files.pythonhosted.org/packages/4d/a1/bca7fd3d452b272e13335db8d6b0b3ecde0f90ad6f16f3328c6fb150c889/rpds_py-0.30.0-cp312-cp312-macosx_11_0_arm64.whl + name: rpds-py + version: 0.30.0 + sha256: 6abc8880d9d036ecaafe709079969f56e876fcf107f7a8e9920ba6d5a3878d05 + requires_python: '>=3.10' +- pypi: https://files.pythonhosted.org/packages/60/1b/6f8f29f3f995c7ffdde46a626ddccd7c63aefc0efae881dc13b6e5d5bb16/rpds_py-0.30.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl + name: rpds-py + version: 0.30.0 + sha256: 47f236970bccb2233267d89173d3ad2703cd36a0e2a6e92d0560d333871a3d23 + requires_python: '>=3.10' - pypi: https://files.pythonhosted.org/packages/02/49/1c79e0906b6ff551fb0894168763f705bf980864739572b2815ecd3c9df0/ruff-0.9.10-py3-none-macosx_11_0_arm64.whl name: ruff version: 0.9.10 @@ -1101,10 +3051,171 @@ packages: version: 0.9.10 sha256: b60dec7201c0b10d6d11be00e8f2dbb6f40ef1828ee75ed739923799513db24c requires_python: '>=3.7' +- pypi: https://files.pythonhosted.org/packages/1c/78/504fdd027da3b84ff1aecd9f6957e65f35134534ccc6da8628eb71e76d3f/send2trash-2.1.0-py3-none-any.whl + name: send2trash + version: 2.1.0 + sha256: 0da2f112e6d6bb22de6aa6daa7e144831a4febf2a87261451c4ad849fe9a873c + requires_dist: + - pytest>=8 ; extra == 'test' + - pywin32>=305 ; sys_platform == 'win32' and extra == 'nativelib' + - pyobjc>=9.0 ; sys_platform == 'darwin' and extra == 'nativelib' + requires_python: '>=3.8' +- pypi: https://files.pythonhosted.org/packages/94/b8/f1f62a5e3c0ad2ff1d189590bfa4c46b4f3b6e49cef6f26c6ee4e575394d/setuptools-80.10.2-py3-none-any.whl + name: setuptools + version: 80.10.2 + sha256: 95b30ddfb717250edb492926c92b5221f7ef3fbcc2b07579bcd4a27da21d0173 + requires_dist: + - pytest>=6,!=8.1.* ; extra == 'test' + - virtualenv>=13.0.0 ; extra == 'test' + - wheel>=0.44.0 ; extra == 'test' + - pip>=19.1 ; extra == 'test' + - packaging>=24.2 ; extra == 'test' + - jaraco-envs>=2.2 ; extra == 'test' + - pytest-xdist>=3 ; extra == 'test' + - jaraco-path>=3.7.2 ; extra == 'test' + - build[virtualenv]>=1.0.3 ; extra == 'test' + - filelock>=3.4.0 ; extra == 'test' + - ini2toml[lite]>=0.14 ; extra == 'test' + - tomli-w>=1.0.0 ; extra == 'test' + - pytest-timeout ; extra == 'test' + - pytest-perf ; sys_platform != 'cygwin' and extra == 'test' + - jaraco-develop>=7.21 ; python_full_version >= '3.9' and sys_platform != 'cygwin' and extra == 'test' + - pytest-home>=0.5 ; extra == 'test' + - pytest-subprocess ; extra == 'test' + - pyproject-hooks!=1.1 ; extra == 'test' + - jaraco-test>=5.5 ; extra == 'test' + - sphinx>=3.5 ; extra == 'doc' + - jaraco-packaging>=9.3 ; extra == 'doc' + - rst-linker>=1.9 ; extra == 'doc' + - furo ; extra == 'doc' + - sphinx-lint ; extra == 'doc' + - jaraco-tidelift>=1.4 ; extra == 'doc' + - pygments-github-lexers==0.0.5 ; extra == 'doc' + - sphinx-favicon ; extra == 'doc' + - sphinx-inline-tabs ; extra == 'doc' + - sphinx-reredirects ; extra == 'doc' + - sphinxcontrib-towncrier ; extra == 'doc' + - sphinx-notfound-page>=1,<2 ; extra == 'doc' + - pyproject-hooks!=1.1 ; extra == 'doc' + - towncrier<24.7 ; extra == 'doc' + - packaging>=24.2 ; extra == 'core' + - more-itertools>=8.8 ; extra == 'core' + - jaraco-text>=3.7 ; extra == 'core' + - importlib-metadata>=6 ; python_full_version < '3.10' and extra == 'core' + - tomli>=2.0.1 ; python_full_version < '3.11' and extra == 'core' + - wheel>=0.43.0 ; extra == 'core' + - platformdirs>=4.2.2 ; extra == 'core' + - jaraco-functools>=4 ; extra == 'core' + - more-itertools ; extra == 'core' + - pytest-checkdocs>=2.4 ; extra == 'check' + - pytest-ruff>=0.2.1 ; sys_platform != 'cygwin' and extra == 'check' + - ruff>=0.8.0 ; sys_platform != 'cygwin' and extra == 'check' + - pytest-cov ; extra == 'cover' + - pytest-enabler>=2.2 ; extra == 'enabler' + - pytest-mypy ; extra == 'type' + - mypy==1.14.* ; extra == 'type' + - importlib-metadata>=7.0.2 ; python_full_version < '3.10' and extra == 'type' + - jaraco-develop>=7.21 ; sys_platform != 'cygwin' and extra == 'type' + requires_python: '>=3.9' +- pypi: https://files.pythonhosted.org/packages/b7/ce/149a00dd41f10bc29e5921b496af8b574d8413afcd5e30dfa0ed46c2cc5e/six-1.17.0-py2.py3-none-any.whl + name: six + version: 1.17.0 + sha256: 4721f391ed90541fddacab5acf947aa0d3dc7d27b2e1e8eda2be8970586c3274 + requires_python: '>=2.7,!=3.0.*,!=3.1.*,!=3.2.*' - pypi: https://files.pythonhosted.org/packages/32/46/9cb0e58b2deb7f82b84065f37f3bffeb12413f947f9388e4cac22c4621ce/sortedcontainers-2.4.0-py2.py3-none-any.whl name: sortedcontainers version: 2.4.0 sha256: a163dcaede0f1c021485e957a39245190e74249897e2ae4b2aa38595db237ee0 +- pypi: https://files.pythonhosted.org/packages/46/2c/1462b1d0a634697ae9e55b3cecdcb64788e8b7d63f54d923fcd0bb140aed/soupsieve-2.8.3-py3-none-any.whl + name: soupsieve + version: 2.8.3 + sha256: ed64f2ba4eebeab06cc4962affce381647455978ffc1e36bb79a545b91f45a95 + requires_python: '>=3.9' +- pypi: https://files.pythonhosted.org/packages/63/f9/f48a8f489c8ae8930f12c558b4dd26da96791837747fca87e9da2643f12d/sphobjinv-2.3.1.3-py3-none-any.whl + name: sphobjinv + version: 2.3.1.3 + sha256: 41fc39f6f740a707cfe5b24c1a3a4a6e4ddbdd6429a59bf21f0b5ef1fddf932a + requires_dist: + - attrs>=19.2 + - certifi + - jsonschema>=3.0 + requires_python: '>=3.9' +- pypi: https://files.pythonhosted.org/packages/b6/35/d16bfa235c8b7caba3730bba43e20b1e376d2224f407c178fbf59559f23e/sqlalchemy-2.0.46-cp312-cp312-macosx_11_0_arm64.whl + name: sqlalchemy + version: 2.0.46 + sha256: 3a9a72b0da8387f15d5810f1facca8f879de9b85af8c645138cba61ea147968c + requires_dist: + - importlib-metadata ; python_full_version < '3.8' + - greenlet>=1 ; platform_machine == 'AMD64' or platform_machine == 'WIN32' or platform_machine == 'aarch64' or platform_machine == 'amd64' or platform_machine == 'ppc64le' or platform_machine == 'win32' or platform_machine == 'x86_64' + - typing-extensions>=4.6.0 + - greenlet>=1 ; extra == 'asyncio' + - mypy>=0.910 ; extra == 'mypy' + - pyodbc ; extra == 'mssql' + - pymssql ; extra == 'mssql-pymssql' + - pyodbc ; extra == 'mssql-pyodbc' + - mysqlclient>=1.4.0 ; extra == 'mysql' + - mysql-connector-python ; extra == 'mysql-connector' + - mariadb>=1.0.1,!=1.1.2,!=1.1.5,!=1.1.10 ; extra == 'mariadb-connector' + - cx-oracle>=8 ; extra == 'oracle' + - oracledb>=1.0.1 ; extra == 'oracle-oracledb' + - psycopg2>=2.7 ; extra == 'postgresql' + - pg8000>=1.29.1 ; extra == 'postgresql-pg8000' + - greenlet>=1 ; extra == 'postgresql-asyncpg' + - asyncpg ; extra == 'postgresql-asyncpg' + - psycopg2-binary ; extra == 'postgresql-psycopg2binary' + - psycopg2cffi ; extra == 'postgresql-psycopg2cffi' + - psycopg>=3.0.7 ; extra == 'postgresql-psycopg' + - psycopg[binary]>=3.0.7 ; extra == 'postgresql-psycopgbinary' + - pymysql ; extra == 'pymysql' + - greenlet>=1 ; extra == 'aiomysql' + - aiomysql>=0.2.0 ; extra == 'aiomysql' + - greenlet>=1 ; extra == 'aioodbc' + - aioodbc ; extra == 'aioodbc' + - greenlet>=1 ; extra == 'asyncmy' + - asyncmy>=0.2.3,!=0.2.4,!=0.2.6 ; extra == 'asyncmy' + - greenlet>=1 ; extra == 'aiosqlite' + - aiosqlite ; extra == 'aiosqlite' + - typing-extensions!=3.10.0.1 ; extra == 'aiosqlite' + - sqlcipher3-binary ; extra == 'sqlcipher' + requires_python: '>=3.7' +- pypi: https://files.pythonhosted.org/packages/ea/a2/b9f33c8d68a3747d972a0bb758c6b63691f8fb8a49014bc3379ba15d4274/sqlalchemy-2.0.46-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl + name: sqlalchemy + version: 2.0.46 + sha256: 9094c8b3197db12aa6f05c51c05daaad0a92b8c9af5388569847b03b1007fb1b + requires_dist: + - importlib-metadata ; python_full_version < '3.8' + - greenlet>=1 ; platform_machine == 'AMD64' or platform_machine == 'WIN32' or platform_machine == 'aarch64' or platform_machine == 'amd64' or platform_machine == 'ppc64le' or platform_machine == 'win32' or platform_machine == 'x86_64' + - typing-extensions>=4.6.0 + - greenlet>=1 ; extra == 'asyncio' + - mypy>=0.910 ; extra == 'mypy' + - pyodbc ; extra == 'mssql' + - pymssql ; extra == 'mssql-pymssql' + - pyodbc ; extra == 'mssql-pyodbc' + - mysqlclient>=1.4.0 ; extra == 'mysql' + - mysql-connector-python ; extra == 'mysql-connector' + - mariadb>=1.0.1,!=1.1.2,!=1.1.5,!=1.1.10 ; extra == 'mariadb-connector' + - cx-oracle>=8 ; extra == 'oracle' + - oracledb>=1.0.1 ; extra == 'oracle-oracledb' + - psycopg2>=2.7 ; extra == 'postgresql' + - pg8000>=1.29.1 ; extra == 'postgresql-pg8000' + - greenlet>=1 ; extra == 'postgresql-asyncpg' + - asyncpg ; extra == 'postgresql-asyncpg' + - psycopg2-binary ; extra == 'postgresql-psycopg2binary' + - psycopg2cffi ; extra == 'postgresql-psycopg2cffi' + - psycopg>=3.0.7 ; extra == 'postgresql-psycopg' + - psycopg[binary]>=3.0.7 ; extra == 'postgresql-psycopgbinary' + - pymysql ; extra == 'pymysql' + - greenlet>=1 ; extra == 'aiomysql' + - aiomysql>=0.2.0 ; extra == 'aiomysql' + - greenlet>=1 ; extra == 'aioodbc' + - aioodbc ; extra == 'aioodbc' + - greenlet>=1 ; extra == 'asyncmy' + - asyncmy>=0.2.3,!=0.2.4,!=0.2.6 ; extra == 'asyncmy' + - greenlet>=1 ; extra == 'aiosqlite' + - aiosqlite ; extra == 'aiosqlite' + - typing-extensions!=3.10.0.1 ; extra == 'aiosqlite' + - sqlcipher3-binary ; extra == 'sqlcipher' + requires_python: '>=3.7' - pypi: https://files.pythonhosted.org/packages/f1/7b/ce1eafaf1a76852e2ec9b22edecf1daa58175c090266e9f6c64afcd81d91/stack_data-0.6.3-py3-none-any.whl name: stack-data version: 0.6.3 @@ -1118,6 +3229,41 @@ packages: - pygments ; extra == 'tests' - littleutils ; extra == 'tests' - cython ; extra == 'tests' +- pypi: https://files.pythonhosted.org/packages/40/44/4a5f08c96eb108af5cb50b41f76142f0afa346dfa99d5296fe7202a11854/tabulate-0.9.0-py3-none-any.whl + name: tabulate + version: 0.9.0 + sha256: 024ca478df22e9340661486f85298cff5f6dcdba14f3813e8830015b9ed1948f + requires_dist: + - wcwidth ; extra == 'widechars' + requires_python: '>=3.7' +- pypi: https://files.pythonhosted.org/packages/6a/9e/2064975477fdc887e47ad42157e214526dcad8f317a948dee17e1659a62f/terminado-0.18.1-py3-none-any.whl + name: terminado + version: 0.18.1 + sha256: a4468e1b37bb318f8a86514f65814e1afc977cf29b3992a4500d9dd305dcceb0 + requires_dist: + - ptyprocess ; os_name != 'nt' + - pywinpty>=1.1.0 ; os_name == 'nt' + - tornado>=6.1.0 + - myst-parser ; extra == 'docs' + - pydata-sphinx-theme ; extra == 'docs' + - sphinx ; extra == 'docs' + - pre-commit ; extra == 'test' + - pytest-timeout ; extra == 'test' + - pytest>=7.0 ; extra == 'test' + - mypy~=1.6 ; extra == 'typing' + - traitlets>=5.11.1 ; extra == 'typing' + requires_python: '>=3.8' +- pypi: https://files.pythonhosted.org/packages/e6/34/ebdc18bae6aa14fbee1a08b63c015c72b64868ff7dae68808ab500c492e2/tinycss2-1.4.0-py3-none-any.whl + name: tinycss2 + version: 1.4.0 + sha256: 3a49cf47b7675da0b15d0c6e1df8df4ebd96e9394bb905a5775adb0d884c5289 + requires_dist: + - webencodings>=0.4 + - sphinx ; extra == 'doc' + - sphinx-rtd-theme ; extra == 'doc' + - pytest ; extra == 'test' + - ruff ; extra == 'test' + requires_python: '>=3.8' - conda: https://conda.anaconda.org/conda-forge/linux-64/tk-8.6.13-noxft_h4845f30_101.conda sha256: e0569c9caa68bf476bead1bed3d79650bb080b532c64a4af7d8ca286c08dea4e md5: d453b98d9c83e71da0741bb0ff4d76bc @@ -1139,6 +3285,16 @@ packages: purls: [] size: 3145523 timestamp: 1699202432999 +- pypi: https://files.pythonhosted.org/packages/50/d4/e51d52047e7eb9a582da59f32125d17c0482d065afd5d3bc435ff2120dc5/tornado-6.5.4-cp39-abi3-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl + name: tornado + version: 6.5.4 + sha256: e5fb5e04efa54cf0baabdd10061eb4148e0be137166146fff835745f59ab9f7f + requires_python: '>=3.9' +- pypi: https://files.pythonhosted.org/packages/ab/a9/e94a9d5224107d7ce3cc1fab8d5dc97f5ea351ccc6322ee4fb661da94e35/tornado-6.5.4-cp39-abi3-macosx_10_9_universal2.whl + name: tornado + version: 6.5.4 + sha256: d6241c1a16b1c9e4cc28148b1cda97dd1c6cb4fb7068ac1bedc610768dff0ba9 + requires_python: '>=3.9' - pypi: https://files.pythonhosted.org/packages/00/c0/8f5d070730d7836adc9c9b6408dec68c6ced86b304a9b26a14df072a6e8c/traitlets-5.14.3-py3-none-any.whl name: traitlets version: 5.14.3 @@ -1154,11 +3310,23 @@ packages: - pytest-mypy-testing ; extra == 'test' - pytest>=7.0,<8.2 ; extra == 'test' requires_python: '>=3.8' -- pypi: https://files.pythonhosted.org/packages/26/9f/ad63fc0248c5379346306f8668cda6e2e2e9c95e01216d2b8ffd9ff037d0/typing_extensions-4.12.2-py3-none-any.whl +- pypi: https://files.pythonhosted.org/packages/18/67/36e9267722cc04a6b9f15c7f3441c2363321a3ea07da7ae0c0707beb2a9c/typing_extensions-4.15.0-py3-none-any.whl name: typing-extensions - version: 4.12.2 - sha256: 04e5ca0351e0f3f85c6853954072df659d0d13fac324d0072316b67d7794700d - requires_python: '>=3.8' + version: 4.15.0 + sha256: f0fa19c6845758ab08074a0cfa8b7aecb71c999ca73d62883bc25cc018c4e548 + requires_python: '>=3.9' +- pypi: https://files.pythonhosted.org/packages/dc/9b/47798a6c91d8bdb567fe2698fe81e0c6b7cb7ef4d13da4114b41d239f65d/typing_inspection-0.4.2-py3-none-any.whl + name: typing-inspection + version: 0.4.2 + sha256: 4ed1cacbdc298c220f1bd249ed5287caa16f34d44ef4e9c3d0cbad5b521545e7 + requires_dist: + - typing-extensions>=4.12.0 + requires_python: '>=3.9' +- pypi: https://files.pythonhosted.org/packages/c7/b0/003792df09decd6849a5e39c28b513c06e84436a54440380862b5aeff25d/tzdata-2025.3-py2.py3-none-any.whl + name: tzdata + version: '2025.3' + sha256: 06a47e5700f3081aab02b2e513160914ff0694bce9947d6b76ebd6bf57cfc5d1 + requires_python: '>=2' - conda: https://conda.anaconda.org/conda-forge/noarch/tzdata-2025a-h78e105d_0.conda sha256: c4b1ae8a2931fe9b274c44af29c5475a85b37693999f8c792dad0f8c6734b1de md5: dbcace4706afdfb7eb891f7b37d07c04 @@ -1166,12 +3334,90 @@ packages: purls: [] size: 122921 timestamp: 1737119101255 +- pypi: https://files.pythonhosted.org/packages/e7/00/3fca040d7cf8a32776d3d81a00c8ee7457e00f80c649f1e4a863c8321ae9/uri_template-1.3.0-py3-none-any.whl + name: uri-template + version: 1.3.0 + sha256: a44a133ea12d44a0c0f06d7d42a52d71282e77e2f937d8abd5655b8d56fc1363 + requires_dist: + - types-pyyaml ; extra == 'dev' + - mypy ; extra == 'dev' + - flake8 ; extra == 'dev' + - flake8-annotations ; extra == 'dev' + - flake8-bandit ; extra == 'dev' + - flake8-bugbear ; extra == 'dev' + - flake8-commas ; extra == 'dev' + - flake8-comprehensions ; extra == 'dev' + - flake8-continuation ; extra == 'dev' + - flake8-datetimez ; extra == 'dev' + - flake8-docstrings ; extra == 'dev' + - flake8-import-order ; extra == 'dev' + - flake8-literal ; extra == 'dev' + - flake8-modern-annotations ; extra == 'dev' + - flake8-noqa ; extra == 'dev' + - flake8-pyproject ; extra == 'dev' + - flake8-requirements ; extra == 'dev' + - flake8-typechecking-import ; extra == 'dev' + - flake8-use-fstring ; extra == 'dev' + - pep8-naming ; extra == 'dev' + requires_python: '>=3.7' +- pypi: https://files.pythonhosted.org/packages/39/08/aaaad47bc4e9dc8c725e68f9d04865dbcb2052843ff09c97b08904852d84/urllib3-2.6.3-py3-none-any.whl + name: urllib3 + version: 2.6.3 + sha256: bf272323e553dfb2e87d9bfd225ca7b0f467b919d7bbd355436d3fd37cb0acd4 + requires_dist: + - brotli>=1.2.0 ; platform_python_implementation == 'CPython' and extra == 'brotli' + - brotlicffi>=1.2.0.0 ; platform_python_implementation != 'CPython' and extra == 'brotli' + - h2>=4,<5 ; extra == 'h2' + - pysocks>=1.5.6,!=1.5.7,<2.0 ; extra == 'socks' + - backports-zstd>=1.0.0 ; python_full_version < '3.14' and extra == 'zstd' + requires_python: '>=3.9' +- pypi: https://files.pythonhosted.org/packages/5b/7e/8f322f5e600812e6f9a31b75d242631068ca8f4ef0582dd3ae6e72daecc8/watchdog-6.0.0-cp312-cp312-macosx_11_0_arm64.whl + name: watchdog + version: 6.0.0 + sha256: 6f10cb2d5902447c7d0da897e2c6768bca89174d0c6e1e30abec5421af97a5b0 + requires_dist: + - pyyaml>=3.10 ; extra == 'watchmedo' + requires_python: '>=3.9' +- pypi: https://files.pythonhosted.org/packages/b5/e8/dbf020b4d98251a9860752a094d09a65e1b436ad181faf929983f697048f/watchdog-6.0.0-py3-none-manylinux2014_x86_64.whl + name: watchdog + version: 6.0.0 + sha256: 20ffe5b202af80ab4266dcd3e91aae72bf2da48c0d33bdb15c66658e685e94e2 + requires_dist: + - pyyaml>=3.10 ; extra == 'watchmedo' + requires_python: '>=3.9' - pypi: https://files.pythonhosted.org/packages/fd/84/fd2ba7aafacbad3c4201d395674fc6348826569da3c0937e75505ead3528/wcwidth-0.2.13-py2.py3-none-any.whl name: wcwidth version: 0.2.13 sha256: 3da69048e4540d84af32131829ff948f1e022c1c6bdb8d6102117aac784f6859 requires_dist: - backports-functools-lru-cache>=1.2.1 ; python_full_version < '3.2' +- pypi: https://files.pythonhosted.org/packages/e2/cc/e097523dd85c9cf5d354f78310927f1656c422bd7b2613b2db3e3f9a0f2c/webcolors-25.10.0-py3-none-any.whl + name: webcolors + version: 25.10.0 + sha256: 032c727334856fc0b968f63daa252a1ac93d33db2f5267756623c210e57a4f1d + requires_python: '>=3.10' +- pypi: https://files.pythonhosted.org/packages/f4/24/2a3e3df732393fed8b3ebf2ec078f05546de641fe1b667ee316ec1dcf3b7/webencodings-0.5.1-py2.py3-none-any.whl + name: webencodings + version: 0.5.1 + sha256: a0af1213f3c2226497a97e2b3aa01a7e4bee4f403f95be16fc9acd2947514a78 +- pypi: https://files.pythonhosted.org/packages/34/db/b10e48aa8fff7407e67470363eac595018441cf32d5e1001567a7aeba5d2/websocket_client-1.9.0-py3-none-any.whl + name: websocket-client + version: 1.9.0 + sha256: af248a825037ef591efbf6ed20cc5faa03d3b47b9e5a2230a529eeee1c1fc3ef + requires_dist: + - pytest ; extra == 'test' + - websockets ; extra == 'test' + - python-socks ; extra == 'optional' + - wsaccel ; extra == 'optional' + - sphinx>=6.0 ; extra == 'docs' + - sphinx-rtd-theme>=1.1.0 ; extra == 'docs' + - myst-parser>=2.0.0 ; extra == 'docs' + requires_python: '>=3.9' +- pypi: https://files.pythonhosted.org/packages/3f/0e/fa3b193432cfc60c93b42f3be03365f5f909d2b3ea410295cf36df739e31/widgetsnbextension-4.0.15-py3-none-any.whl + name: widgetsnbextension + version: 4.0.15 + sha256: 8156704e4346a571d9ce73b84bee86a29906c9abfd7223b7228a28899ccf3366 + requires_python: '>=3.7' - pypi: https://files.pythonhosted.org/packages/58/b8/e4722f5e5f592a665cc8e55a334ea721c359f09574e6b987dc551a1e1f4c/xdoctest-1.2.0-py3-none-any.whl name: xdoctest version: 1.2.0 @@ -1189,15 +3435,15 @@ packages: - attrs==19.2.0 ; extra == 'all-strict' - jupyter-core==4.7.0 ; extra == 'all-strict' - pyflakes==2.2.0 ; extra == 'all-strict' - - colorama==0.4.1 ; platform_system == 'Windows' and extra == 'all-strict' + - colorama==0.4.1 ; sys_platform == 'win32' and extra == 'all-strict' - debugpy==1.3.0 ; python_full_version == '3.9.*' and extra == 'all-strict' - pytest==4.6.0 ; python_full_version >= '3.7' and python_full_version < '3.10' and extra == 'all-strict' - tomli==0.2.0 ; python_full_version >= '3.6' and python_full_version < '3.11' and extra == 'all-strict' - - ipykernel==6.0.0 ; (python_full_version >= '3.7' and python_full_version < '3.12' and platform_python_implementation != 'PyPy' and extra == 'all-strict') or (python_full_version >= '3.7' and python_full_version < '3.12' and platform_system != 'Windows' and extra == 'all-strict') + - ipykernel==6.0.0 ; (python_full_version >= '3.7' and python_full_version < '3.12' and platform_python_implementation != 'PyPy' and extra == 'all-strict') or (python_full_version >= '3.7' and python_full_version < '3.12' and sys_platform != 'win32' and extra == 'all-strict') - pygments==2.0.0 ; python_full_version >= '2.7' and python_full_version < '3.5' and extra == 'all-strict' - nbconvert==6.0.0 ; python_full_version == '3.6.*' and platform_python_implementation != 'PyPy' and extra == 'all-strict' - debugpy==1.0.0 ; python_full_version == '3.8.*' and extra == 'all-strict' - - ipykernel==6.11.0 ; (python_full_version >= '3.12' and python_full_version < '4.0' and platform_python_implementation != 'PyPy' and extra == 'all-strict') or (python_full_version >= '3.12' and python_full_version < '4.0' and platform_system != 'Windows' and extra == 'all-strict') + - ipykernel==6.11.0 ; (python_full_version >= '3.12' and python_full_version < '4.0' and platform_python_implementation != 'PyPy' and extra == 'all-strict') or (python_full_version >= '3.12' and python_full_version < '4.0' and sys_platform != 'win32' and extra == 'all-strict') - debugpy==1.6.0 ; python_full_version >= '3.10' and extra == 'all-strict' - pytest==6.2.5 ; python_full_version >= '3.10' and extra == 'all-strict' - pygments==2.4.1 ; python_full_version >= '3.5' and extra == 'all-strict' @@ -1205,15 +3451,15 @@ packages: - ipython-genutils==0.2.0 ; python_full_version >= '3.6' and platform_python_implementation != 'PyPy' and extra == 'all-strict' - pytest-cov==3.0.0 ; python_full_version >= '3.6' and extra == 'all-strict' - nbconvert==6.1.0 ; python_full_version >= '3.7' and platform_python_implementation != 'PyPy' and extra == 'all-strict' - - colorama>=0.4.1 ; platform_system == 'Windows' and extra == 'all' + - colorama>=0.4.1 ; sys_platform == 'win32' and extra == 'all' - debugpy>=1.3.0 ; python_full_version == '3.9.*' and extra == 'all' - pytest>=4.6.0 ; python_full_version >= '3.7' and python_full_version < '3.10' and extra == 'all' - tomli>=0.2.0 ; python_full_version >= '3.6' and python_full_version < '3.11' and extra == 'all' - - ipykernel>=6.0.0 ; (python_full_version >= '3.7' and python_full_version < '3.12' and platform_python_implementation != 'PyPy' and extra == 'all') or (python_full_version >= '3.7' and python_full_version < '3.12' and platform_system != 'Windows' and extra == 'all') + - ipykernel>=6.0.0 ; (python_full_version >= '3.7' and python_full_version < '3.12' and platform_python_implementation != 'PyPy' and extra == 'all') or (python_full_version >= '3.7' and python_full_version < '3.12' and sys_platform != 'win32' and extra == 'all') - pygments>=2.0.0 ; python_full_version >= '2.7' and python_full_version < '3.5' and extra == 'all' - nbconvert>=6.0.0 ; python_full_version == '3.6.*' and platform_python_implementation != 'PyPy' and extra == 'all' - debugpy>=1.0.0 ; python_full_version == '3.8.*' and extra == 'all' - - ipykernel>=6.11.0 ; (python_full_version >= '3.12' and python_full_version < '4.0' and platform_python_implementation != 'PyPy' and extra == 'all') or (python_full_version >= '3.12' and python_full_version < '4.0' and platform_system != 'Windows' and extra == 'all') + - ipykernel>=6.11.0 ; (python_full_version >= '3.12' and python_full_version < '4.0' and platform_python_implementation != 'PyPy' and extra == 'all') or (python_full_version >= '3.12' and python_full_version < '4.0' and sys_platform != 'win32' and extra == 'all') - debugpy>=1.6.0 ; python_full_version >= '3.10' and extra == 'all' - pytest>=6.2.5 ; python_full_version >= '3.10' and extra == 'all' - pygments>=2.4.1 ; python_full_version >= '3.5' and extra == 'all' @@ -1221,10 +3467,10 @@ packages: - ipython-genutils>=0.2.0 ; python_full_version >= '3.6' and platform_python_implementation != 'PyPy' and extra == 'all' - pytest-cov>=3.0.0 ; python_full_version >= '3.6' and extra == 'all' - nbconvert>=6.1.0 ; python_full_version >= '3.7' and platform_python_implementation != 'PyPy' and extra == 'all' - - colorama==0.4.1 ; platform_system == 'Windows' and extra == 'colors-strict' + - colorama==0.4.1 ; sys_platform == 'win32' and extra == 'colors-strict' - pygments==2.0.0 ; python_full_version >= '2.7' and python_full_version < '3.5' and extra == 'colors-strict' - pygments==2.4.1 ; python_full_version >= '3.5' and extra == 'colors-strict' - - colorama>=0.4.1 ; platform_system == 'Windows' and extra == 'colors' + - colorama>=0.4.1 ; sys_platform == 'win32' and extra == 'colors' - pygments>=2.0.0 ; python_full_version >= '2.7' and python_full_version < '3.5' and extra == 'colors' - pygments>=2.4.1 ; python_full_version >= '3.5' and extra == 'colors' - sphinx>=5.0.1 ; extra == 'docs' @@ -1254,19 +3500,19 @@ packages: - attrs==19.2.0 ; extra == 'jupyter-strict' - jupyter-core==4.7.0 ; extra == 'jupyter-strict' - debugpy==1.3.0 ; python_full_version == '3.9.*' and extra == 'jupyter-strict' - - ipykernel==6.0.0 ; (python_full_version >= '3.7' and python_full_version < '3.12' and platform_python_implementation != 'PyPy' and extra == 'jupyter-strict') or (python_full_version >= '3.7' and python_full_version < '3.12' and platform_system != 'Windows' and extra == 'jupyter-strict') + - ipykernel==6.0.0 ; (python_full_version >= '3.7' and python_full_version < '3.12' and platform_python_implementation != 'PyPy' and extra == 'jupyter-strict') or (python_full_version >= '3.7' and python_full_version < '3.12' and sys_platform != 'win32' and extra == 'jupyter-strict') - nbconvert==6.0.0 ; python_full_version == '3.6.*' and platform_python_implementation != 'PyPy' and extra == 'jupyter-strict' - debugpy==1.0.0 ; python_full_version == '3.8.*' and extra == 'jupyter-strict' - - ipykernel==6.11.0 ; (python_full_version >= '3.12' and python_full_version < '4.0' and platform_python_implementation != 'PyPy' and extra == 'jupyter-strict') or (python_full_version >= '3.12' and python_full_version < '4.0' and platform_system != 'Windows' and extra == 'jupyter-strict') + - ipykernel==6.11.0 ; (python_full_version >= '3.12' and python_full_version < '4.0' and platform_python_implementation != 'PyPy' and extra == 'jupyter-strict') or (python_full_version >= '3.12' and python_full_version < '4.0' and sys_platform != 'win32' and extra == 'jupyter-strict') - debugpy==1.6.0 ; python_full_version >= '3.10' and extra == 'jupyter-strict' - jinja2==3.0.0 ; python_full_version >= '3.6' and platform_python_implementation != 'PyPy' and extra == 'jupyter-strict' - ipython-genutils==0.2.0 ; python_full_version >= '3.6' and platform_python_implementation != 'PyPy' and extra == 'jupyter-strict' - nbconvert==6.1.0 ; python_full_version >= '3.7' and platform_python_implementation != 'PyPy' and extra == 'jupyter-strict' - debugpy>=1.3.0 ; python_full_version == '3.9.*' and extra == 'jupyter' - - ipykernel>=6.0.0 ; (python_full_version >= '3.7' and python_full_version < '3.12' and platform_python_implementation != 'PyPy' and extra == 'jupyter') or (python_full_version >= '3.7' and python_full_version < '3.12' and platform_system != 'Windows' and extra == 'jupyter') + - ipykernel>=6.0.0 ; (python_full_version >= '3.7' and python_full_version < '3.12' and platform_python_implementation != 'PyPy' and extra == 'jupyter') or (python_full_version >= '3.7' and python_full_version < '3.12' and sys_platform != 'win32' and extra == 'jupyter') - nbconvert>=6.0.0 ; python_full_version == '3.6.*' and platform_python_implementation != 'PyPy' and extra == 'jupyter' - debugpy>=1.0.0 ; python_full_version == '3.8.*' and extra == 'jupyter' - - ipykernel>=6.11.0 ; (python_full_version >= '3.12' and python_full_version < '4.0' and platform_python_implementation != 'PyPy' and extra == 'jupyter') or (python_full_version >= '3.12' and python_full_version < '4.0' and platform_system != 'Windows' and extra == 'jupyter') + - ipykernel>=6.11.0 ; (python_full_version >= '3.12' and python_full_version < '4.0' and platform_python_implementation != 'PyPy' and extra == 'jupyter') or (python_full_version >= '3.12' and python_full_version < '4.0' and sys_platform != 'win32' and extra == 'jupyter') - debugpy>=1.6.0 ; python_full_version >= '3.10' and extra == 'jupyter' - jinja2>=3.0.0 ; python_full_version >= '3.6' and platform_python_implementation != 'PyPy' and extra == 'jupyter' - ipython-genutils>=0.2.0 ; python_full_version >= '3.6' and platform_python_implementation != 'PyPy' and extra == 'jupyter' @@ -1283,27 +3529,27 @@ packages: - attrs==19.2.0 ; extra == 'optional-strict' - jupyter-core==4.7.0 ; extra == 'optional-strict' - pyflakes==2.2.0 ; extra == 'optional-strict' - - colorama==0.4.1 ; platform_system == 'Windows' and extra == 'optional-strict' + - colorama==0.4.1 ; sys_platform == 'win32' and extra == 'optional-strict' - debugpy==1.3.0 ; python_full_version == '3.9.*' and extra == 'optional-strict' - tomli==0.2.0 ; python_full_version >= '3.6' and python_full_version < '3.11' and extra == 'optional-strict' - - ipykernel==6.0.0 ; (python_full_version >= '3.7' and python_full_version < '3.12' and platform_python_implementation != 'PyPy' and extra == 'optional-strict') or (python_full_version >= '3.7' and python_full_version < '3.12' and platform_system != 'Windows' and extra == 'optional-strict') + - ipykernel==6.0.0 ; (python_full_version >= '3.7' and python_full_version < '3.12' and platform_python_implementation != 'PyPy' and extra == 'optional-strict') or (python_full_version >= '3.7' and python_full_version < '3.12' and sys_platform != 'win32' and extra == 'optional-strict') - pygments==2.0.0 ; python_full_version >= '2.7' and python_full_version < '3.5' and extra == 'optional-strict' - nbconvert==6.0.0 ; python_full_version == '3.6.*' and platform_python_implementation != 'PyPy' and extra == 'optional-strict' - debugpy==1.0.0 ; python_full_version == '3.8.*' and extra == 'optional-strict' - - ipykernel==6.11.0 ; (python_full_version >= '3.12' and python_full_version < '4.0' and platform_python_implementation != 'PyPy' and extra == 'optional-strict') or (python_full_version >= '3.12' and python_full_version < '4.0' and platform_system != 'Windows' and extra == 'optional-strict') + - ipykernel==6.11.0 ; (python_full_version >= '3.12' and python_full_version < '4.0' and platform_python_implementation != 'PyPy' and extra == 'optional-strict') or (python_full_version >= '3.12' and python_full_version < '4.0' and sys_platform != 'win32' and extra == 'optional-strict') - debugpy==1.6.0 ; python_full_version >= '3.10' and extra == 'optional-strict' - pygments==2.4.1 ; python_full_version >= '3.5' and extra == 'optional-strict' - jinja2==3.0.0 ; python_full_version >= '3.6' and platform_python_implementation != 'PyPy' and extra == 'optional-strict' - ipython-genutils==0.2.0 ; python_full_version >= '3.6' and platform_python_implementation != 'PyPy' and extra == 'optional-strict' - nbconvert==6.1.0 ; python_full_version >= '3.7' and platform_python_implementation != 'PyPy' and extra == 'optional-strict' - - colorama>=0.4.1 ; platform_system == 'Windows' and extra == 'optional' + - colorama>=0.4.1 ; sys_platform == 'win32' and extra == 'optional' - debugpy>=1.3.0 ; python_full_version == '3.9.*' and extra == 'optional' - tomli>=0.2.0 ; python_full_version >= '3.6' and python_full_version < '3.11' and extra == 'optional' - - ipykernel>=6.0.0 ; (python_full_version >= '3.7' and python_full_version < '3.12' and platform_python_implementation != 'PyPy' and extra == 'optional') or (python_full_version >= '3.7' and python_full_version < '3.12' and platform_system != 'Windows' and extra == 'optional') + - ipykernel>=6.0.0 ; (python_full_version >= '3.7' and python_full_version < '3.12' and platform_python_implementation != 'PyPy' and extra == 'optional') or (python_full_version >= '3.7' and python_full_version < '3.12' and sys_platform != 'win32' and extra == 'optional') - pygments>=2.0.0 ; python_full_version >= '2.7' and python_full_version < '3.5' and extra == 'optional' - nbconvert>=6.0.0 ; python_full_version == '3.6.*' and platform_python_implementation != 'PyPy' and extra == 'optional' - debugpy>=1.0.0 ; python_full_version == '3.8.*' and extra == 'optional' - - ipykernel>=6.11.0 ; (python_full_version >= '3.12' and python_full_version < '4.0' and platform_python_implementation != 'PyPy' and extra == 'optional') or (python_full_version >= '3.12' and python_full_version < '4.0' and platform_system != 'Windows' and extra == 'optional') + - ipykernel>=6.11.0 ; (python_full_version >= '3.12' and python_full_version < '4.0' and platform_python_implementation != 'PyPy' and extra == 'optional') or (python_full_version >= '3.12' and python_full_version < '4.0' and sys_platform != 'win32' and extra == 'optional') - debugpy>=1.6.0 ; python_full_version >= '3.10' and extra == 'optional' - pygments>=2.4.1 ; python_full_version >= '3.5' and extra == 'optional' - jinja2>=3.0.0 ; python_full_version >= '3.6' and platform_python_implementation != 'PyPy' and extra == 'optional' @@ -1332,3 +3578,27 @@ packages: - pytest>=6.2.5 ; python_full_version >= '3.10' and extra == 'tests' - pytest-cov>=3.0.0 ; python_full_version >= '3.6' and extra == 'tests' requires_python: '>=3.8' +- pypi: https://files.pythonhosted.org/packages/2e/54/647ade08bf0db230bfea292f893923872fd20be6ac6f53b2b936ba839d75/zipp-3.23.0-py3-none-any.whl + name: zipp + version: 3.23.0 + sha256: 071652d6115ed432f5ce1d34c336c0adfd6a884660d1e9712a256d3d3bd4b14e + requires_dist: + - pytest>=6,!=8.1.* ; extra == 'test' + - jaraco-itertools ; extra == 'test' + - jaraco-functools ; extra == 'test' + - more-itertools ; extra == 'test' + - big-o ; extra == 'test' + - pytest-ignore-flaky ; extra == 'test' + - jaraco-test ; extra == 'test' + - sphinx>=3.5 ; extra == 'doc' + - jaraco-packaging>=9.3 ; extra == 'doc' + - rst-linker>=1.9 ; extra == 'doc' + - furo ; extra == 'doc' + - sphinx-lint ; extra == 'doc' + - jaraco-tidelift>=1.4 ; extra == 'doc' + - pytest-checkdocs>=2.4 ; extra == 'check' + - pytest-ruff>=0.2.1 ; sys_platform != 'cygwin' and extra == 'check' + - pytest-cov ; extra == 'cover' + - pytest-enabler>=2.2 ; extra == 'enabler' + - pytest-mypy ; extra == 'type' + requires_python: '>=3.9' From cd33dcc785d99d1fb049657b7a26e3ddf2007f88 Mon Sep 17 00:00:00 2001 From: Cameron Smith Date: Mon, 2 Feb 2026 15:36:54 -0500 Subject: [PATCH 030/134] chore(issues): close pnt-4jg.2, pixi feature composition verified --- .beads/issues.jsonl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.beads/issues.jsonl b/.beads/issues.jsonl index 30f46ac..15303e3 100644 --- a/.beads/issues.jsonl +++ b/.beads/issues.jsonl @@ -1,6 +1,6 @@ {"id":"pnt-4jg","title":"Dependency model migration","description":"Migrate from single-lock uv workspace to independent-lock multi-package pattern following langchain/langgraph approach. Include pixi feature-based composition for conda ecosystem parity.","status":"open","priority":2,"issue_type":"epic","owner":"cameron.ray.smith@gmail.com","created_at":"2026-01-19T11:54:40.744055-05:00","created_by":"Cameron Smith","updated_at":"2026-01-19T11:54:40.744055-05:00"} {"id":"pnt-4jg.1","title":"Remove uv workspace, adopt path dependencies","description":"Remove [tool.uv.workspace] from root pyproject.toml. Each package gets own pyproject.toml with [tool.uv.sources] for sibling references using path sources with editable=true. Follow langchain pattern.","status":"closed","priority":2,"issue_type":"task","owner":"cameron.ray.smith@gmail.com","created_at":"2026-01-19T11:55:07.344057-05:00","created_by":"Cameron Smith","updated_at":"2026-02-02T14:40:02.175394-05:00","closed_at":"2026-02-02T14:40:02.175394-05:00","close_reason":"Implemented in a8a823f. Removed root uv workspace, generated per-package locks, rewrote nix modules to Pattern 3 per-package loading.","dependencies":[{"issue_id":"pnt-4jg.1","depends_on_id":"pnt-4jg","type":"parent-child","created_at":"2026-01-19T11:55:07.344659-05:00","created_by":"Cameron Smith"}],"comments":[{"id":1,"issue_id":"pnt-4jg.1","author":"Cameron Smith","text":"Post-close fixup commits (774ec26):\n- fix(ci): update lock file references for per-package federation (d0cab2a)\n- fixup! merge federated workspace deps: replace // with zipAttrsWith for extras-safe dep merging (7b3e7ae)\n- fixup! load packages independently: document version-conflict invariant in python.nix and architecture doc (36eb8a7, 774ec26)\n\nReview findings addressed: stale CI cache-dependency-glob paths, fragile shallow-merge dep specs, undocumented overlay composition invariant. Full CI redesign (nix develop + justfile symmetry) deferred to pnt-dre.4.","created_at":"2026-02-02T20:17:00Z"}]} -{"id":"pnt-4jg.2","title":"Configure pixi feature-based composition","description":"Implement pixi feature/environment pattern: [feature.X.dependencies] + [environments] composition. Single pixi.lock covering all environments. Per-feature task definitions. Target-specific dependencies for platform support.","status":"open","priority":2,"issue_type":"task","owner":"cameron.ray.smith@gmail.com","created_at":"2026-01-19T11:55:08.085592-05:00","created_by":"Cameron Smith","updated_at":"2026-01-19T11:55:08.085592-05:00","dependencies":[{"issue_id":"pnt-4jg.2","depends_on_id":"pnt-4jg","type":"parent-child","created_at":"2026-01-19T11:55:08.086155-05:00","created_by":"Cameron Smith"}]} +{"id":"pnt-4jg.2","title":"Configure pixi feature-based composition","description":"Implement pixi feature/environment pattern: [feature.X.dependencies] + [environments] composition. Single pixi.lock covering all environments. Per-feature task definitions. Target-specific dependencies for platform support.","status":"closed","priority":2,"issue_type":"task","owner":"cameron.ray.smith@gmail.com","created_at":"2026-01-19T11:55:08.085592-05:00","created_by":"Cameron Smith","updated_at":"2026-02-02T15:36:49.459815-05:00","closed_at":"2026-02-02T15:36:49.459815-05:00","close_reason":"Verified pixi feature composition via nix develop -c just \u003crecipe\u003e. Fixed: added missing feature tasks to python-nix-template, delegated justfile conda recipes to pixi task names for correct working directory, moved deprecated build channels to backend.channels.","dependencies":[{"issue_id":"pnt-4jg.2","depends_on_id":"pnt-4jg","type":"parent-child","created_at":"2026-01-19T11:55:08.086155-05:00","created_by":"Cameron Smith"}]} {"id":"pnt-4jg.3","title":"Document package distribution channels","description":"Document which packages support uv/pypi vs pixi/conda distribution. Note dependency graph differences between channels. Update README and package metadata.","status":"open","priority":2,"issue_type":"task","owner":"cameron.ray.smith@gmail.com","created_at":"2026-01-19T11:55:09.051203-05:00","created_by":"Cameron Smith","updated_at":"2026-01-19T11:55:09.051203-05:00","dependencies":[{"issue_id":"pnt-4jg.3","depends_on_id":"pnt-4jg","type":"parent-child","created_at":"2026-01-19T11:55:09.051857-05:00","created_by":"Cameron Smith"},{"issue_id":"pnt-4jg.3","depends_on_id":"pnt-4jg.1","type":"blocks","created_at":"2026-01-19T12:20:13.557576-05:00","created_by":"Cameron Smith"},{"issue_id":"pnt-4jg.3","depends_on_id":"pnt-4jg.2","type":"blocks","created_at":"2026-01-19T12:20:16.147971-05:00","created_by":"Cameron Smith"}]} {"id":"pnt-btz","title":"pyo3/Rust extension integration","description":"Add Rust extension module support via maturin + pyo3, demonstrating Nix build integration with crane cargoArtifacts sharing and uv2nix overlay composition.\n\nArchitecture documented in: docs/notes/architecture/crane-uv2nix-integration.md\n\nKey patterns:\n- Per-package Rust workspace (crates/ inside Python package)\n- crane buildDepsOnly for artifact caching\n- uv2nix overlay injection for maturin builds\n- CI matrix with rust-deps/rust-checks/python-wheel categories\n\nReference implementations:\n- ~/projects/rust-workspace/ironstar (crane patterns)\n- ~/projects/planning-workspace/langchain (federated Python)\n","status":"open","priority":2,"issue_type":"epic","owner":"cameron.ray.smith@gmail.com","created_at":"2026-01-19T11:54:41.426256-05:00","created_by":"Cameron Smith","updated_at":"2026-01-28T14:43:57.637638-05:00","dependencies":[{"issue_id":"pnt-btz","depends_on_id":"pnt-dre","type":"blocks","created_at":"2026-01-19T11:55:32.690895-05:00","created_by":"Cameron Smith"},{"issue_id":"pnt-btz","depends_on_id":"pnt-4jg","type":"blocks","created_at":"2026-01-19T11:55:32.812602-05:00","created_by":"Cameron Smith"}]} {"id":"pnt-btz.1","title":"Create pnt-cli package scaffold with Rust crates","description":"Create packages/pnt-cli/ with federated structure:\n\nDirectory structure:\n- packages/pnt-cli/pyproject.toml (maturin build-backend, manifest-path binding)\n- packages/pnt-cli/src/pnt_cli/__init__.py (Python wrapper)\n- packages/pnt-cli/crates/Cargo.toml ([workspace] with member crates)\n- packages/pnt-cli/crates/pnt-cli-core/Cargo.toml (pure Rust library)\n- packages/pnt-cli/crates/pnt-cli-py/Cargo.toml (pyo3 bindings, depends on core)\n\npyproject.toml configuration:\n- [build-system] requires maturin\u003e=1.5\n- [tool.maturin] manifest-path = \"crates/pnt-cli-py/Cargo.toml\"\n- [tool.maturin] module-name = \"pnt_cli._native\"\n\nMinimal proof-of-concept: expose a simple function from Rust to Python.\n\nSee: docs/notes/architecture/crane-uv2nix-integration.md\n","status":"open","priority":2,"issue_type":"task","owner":"cameron.ray.smith@gmail.com","created_at":"2026-01-19T11:55:17.885691-05:00","created_by":"Cameron Smith","updated_at":"2026-01-28T14:43:57.882216-05:00","dependencies":[{"issue_id":"pnt-btz.1","depends_on_id":"pnt-btz","type":"parent-child","created_at":"2026-01-19T11:55:17.886287-05:00","created_by":"Cameron Smith"},{"issue_id":"pnt-btz.1","depends_on_id":"pnt-4jg.1","type":"blocks","created_at":"2026-01-19T12:20:18.940008-05:00","created_by":"Cameron Smith"}]} From 0ed16147fe8f1511946e526ee8c55d7f99d2dedd Mon Sep 17 00:00:00 2001 From: Cameron Smith Date: Mon, 2 Feb 2026 15:37:32 -0500 Subject: [PATCH 031/134] docs(architecture): document package distribution channels Covers uv/PyPI and pixi/conda-forge support per package, dependency graph differences between channels, and justfile recipe mapping. --- .../package-distribution-channels.md | 56 +++++++++++++++++++ 1 file changed, 56 insertions(+) create mode 100644 docs/notes/architecture/package-distribution-channels.md diff --git a/docs/notes/architecture/package-distribution-channels.md b/docs/notes/architecture/package-distribution-channels.md new file mode 100644 index 0000000..dc1cecb --- /dev/null +++ b/docs/notes/architecture/package-distribution-channels.md @@ -0,0 +1,56 @@ +# Package distribution channels + +This document describes the distribution channel support for each package in the repository, covering the uv/PyPI and pixi/conda-forge dependency resolution paths. + +## Channel overview + +Both packages support dual-channel distribution through uv (PyPI) and pixi (conda-forge). +Each package maintains independent lock files for both channels: `uv.lock` for PyPI resolution and `pixi.lock` for conda-forge resolution. + +The nix devshell is the primary execution environment. +Justfile recipes wrap both uv and pixi commands, invoked via `nix develop -c just `. +uv and pixi serve as dependency resolution tools consumed by the nix layer, not standalone execution contexts. + +## Per-package channel support + +### pnt-functional + +| Channel | Supported | Lock file | Runtime dependencies | +|---------|-----------|-----------|---------------------| +| uv/PyPI | Yes | `packages/pnt-functional/uv.lock` | beartype, expression | +| pixi/conda-forge | Yes | `packages/pnt-functional/pixi.lock` | beartype, expression, python | + +Runtime dependencies (`beartype`, `expression`) are available on both PyPI and conda-forge. +No channel-specific dependency graph differences for this package. + +### python-nix-template + +| Channel | Supported | Lock file | Runtime dependencies | +|---------|-----------|-----------|---------------------| +| uv/PyPI | Yes | `packages/python-nix-template/uv.lock` | (none) | +| pixi/conda-forge | Yes | `packages/python-nix-template/pixi.lock` | python | + +This package has no runtime dependencies beyond the Python interpreter. +Dev dependencies (pytest, ruff, hypothesis, pyright, jupyter, quartodoc) are available on both channels. + +## Dependency graph differences + +The conda-forge channel resolves the full native dependency tree including system libraries (libffi, openssl, ncurses, etc.) that PyPI assumes are provided by the system. +This means pixi.lock files are substantially larger than uv.lock files for the same package, reflecting the completeness of the conda dependency graph. + +The pixi configuration includes `pixi-build` preview feature for conda package building via `pixi-build-python` backend. +This allows packages to be built as conda packages in addition to PyPI wheels. + +## Justfile recipe mapping + +| Operation | uv/PyPI recipe | pixi/conda recipe | +|-----------|---------------|-------------------| +| Test | `just test ` | `just conda-test ` | +| Lint | `just lint ` | `just conda-lint ` | +| Lint + fix | `just lint-fix ` | `just conda-lint-fix ` | +| Type check | `just type ` | `just conda-type ` | +| All checks | `just check ` | `just conda-check ` | +| Build | `just uv-build ` | `just conda-build ` | +| Lock | `just uv-lock ` | `just pixi-lock ` | + +All recipes accept a package parameter defaulting to `python-nix-template`. From 5a170b62672b5615d9f5cae23477ad036ea3415d Mon Sep 17 00:00:00 2001 From: Cameron Smith Date: Mon, 2 Feb 2026 15:37:48 -0500 Subject: [PATCH 032/134] chore(issues): close pnt-4jg.3 and pnt-4jg epic, dependency migration complete --- .beads/issues.jsonl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.beads/issues.jsonl b/.beads/issues.jsonl index 15303e3..a720000 100644 --- a/.beads/issues.jsonl +++ b/.beads/issues.jsonl @@ -1,7 +1,7 @@ -{"id":"pnt-4jg","title":"Dependency model migration","description":"Migrate from single-lock uv workspace to independent-lock multi-package pattern following langchain/langgraph approach. Include pixi feature-based composition for conda ecosystem parity.","status":"open","priority":2,"issue_type":"epic","owner":"cameron.ray.smith@gmail.com","created_at":"2026-01-19T11:54:40.744055-05:00","created_by":"Cameron Smith","updated_at":"2026-01-19T11:54:40.744055-05:00"} +{"id":"pnt-4jg","title":"Dependency model migration","description":"Migrate from single-lock uv workspace to independent-lock multi-package pattern following langchain/langgraph approach. Include pixi feature-based composition for conda ecosystem parity.","status":"closed","priority":2,"issue_type":"epic","owner":"cameron.ray.smith@gmail.com","created_at":"2026-01-19T11:54:40.744055-05:00","created_by":"Cameron Smith","updated_at":"2026-02-02T15:37:43.167289-05:00","closed_at":"2026-02-02T15:37:43.167289-05:00","close_reason":"All children closed: pnt-4jg.1 (uv workspace removal), pnt-4jg.2 (pixi feature composition), pnt-4jg.3 (distribution channel docs). Dependency model migration complete."} {"id":"pnt-4jg.1","title":"Remove uv workspace, adopt path dependencies","description":"Remove [tool.uv.workspace] from root pyproject.toml. Each package gets own pyproject.toml with [tool.uv.sources] for sibling references using path sources with editable=true. Follow langchain pattern.","status":"closed","priority":2,"issue_type":"task","owner":"cameron.ray.smith@gmail.com","created_at":"2026-01-19T11:55:07.344057-05:00","created_by":"Cameron Smith","updated_at":"2026-02-02T14:40:02.175394-05:00","closed_at":"2026-02-02T14:40:02.175394-05:00","close_reason":"Implemented in a8a823f. Removed root uv workspace, generated per-package locks, rewrote nix modules to Pattern 3 per-package loading.","dependencies":[{"issue_id":"pnt-4jg.1","depends_on_id":"pnt-4jg","type":"parent-child","created_at":"2026-01-19T11:55:07.344659-05:00","created_by":"Cameron Smith"}],"comments":[{"id":1,"issue_id":"pnt-4jg.1","author":"Cameron Smith","text":"Post-close fixup commits (774ec26):\n- fix(ci): update lock file references for per-package federation (d0cab2a)\n- fixup! merge federated workspace deps: replace // with zipAttrsWith for extras-safe dep merging (7b3e7ae)\n- fixup! load packages independently: document version-conflict invariant in python.nix and architecture doc (36eb8a7, 774ec26)\n\nReview findings addressed: stale CI cache-dependency-glob paths, fragile shallow-merge dep specs, undocumented overlay composition invariant. Full CI redesign (nix develop + justfile symmetry) deferred to pnt-dre.4.","created_at":"2026-02-02T20:17:00Z"}]} {"id":"pnt-4jg.2","title":"Configure pixi feature-based composition","description":"Implement pixi feature/environment pattern: [feature.X.dependencies] + [environments] composition. Single pixi.lock covering all environments. Per-feature task definitions. Target-specific dependencies for platform support.","status":"closed","priority":2,"issue_type":"task","owner":"cameron.ray.smith@gmail.com","created_at":"2026-01-19T11:55:08.085592-05:00","created_by":"Cameron Smith","updated_at":"2026-02-02T15:36:49.459815-05:00","closed_at":"2026-02-02T15:36:49.459815-05:00","close_reason":"Verified pixi feature composition via nix develop -c just \u003crecipe\u003e. Fixed: added missing feature tasks to python-nix-template, delegated justfile conda recipes to pixi task names for correct working directory, moved deprecated build channels to backend.channels.","dependencies":[{"issue_id":"pnt-4jg.2","depends_on_id":"pnt-4jg","type":"parent-child","created_at":"2026-01-19T11:55:08.086155-05:00","created_by":"Cameron Smith"}]} -{"id":"pnt-4jg.3","title":"Document package distribution channels","description":"Document which packages support uv/pypi vs pixi/conda distribution. Note dependency graph differences between channels. Update README and package metadata.","status":"open","priority":2,"issue_type":"task","owner":"cameron.ray.smith@gmail.com","created_at":"2026-01-19T11:55:09.051203-05:00","created_by":"Cameron Smith","updated_at":"2026-01-19T11:55:09.051203-05:00","dependencies":[{"issue_id":"pnt-4jg.3","depends_on_id":"pnt-4jg","type":"parent-child","created_at":"2026-01-19T11:55:09.051857-05:00","created_by":"Cameron Smith"},{"issue_id":"pnt-4jg.3","depends_on_id":"pnt-4jg.1","type":"blocks","created_at":"2026-01-19T12:20:13.557576-05:00","created_by":"Cameron Smith"},{"issue_id":"pnt-4jg.3","depends_on_id":"pnt-4jg.2","type":"blocks","created_at":"2026-01-19T12:20:16.147971-05:00","created_by":"Cameron Smith"}]} +{"id":"pnt-4jg.3","title":"Document package distribution channels","description":"Document which packages support uv/pypi vs pixi/conda distribution. Note dependency graph differences between channels. Update README and package metadata.","status":"closed","priority":2,"issue_type":"task","owner":"cameron.ray.smith@gmail.com","created_at":"2026-01-19T11:55:09.051203-05:00","created_by":"Cameron Smith","updated_at":"2026-02-02T15:37:38.374454-05:00","closed_at":"2026-02-02T15:37:38.374454-05:00","close_reason":"Documented in docs/notes/architecture/package-distribution-channels.md. Both packages support dual-channel (uv/PyPI + pixi/conda-forge) with independent locks. No blocking dependency graph differences between channels.","dependencies":[{"issue_id":"pnt-4jg.3","depends_on_id":"pnt-4jg","type":"parent-child","created_at":"2026-01-19T11:55:09.051857-05:00","created_by":"Cameron Smith"},{"issue_id":"pnt-4jg.3","depends_on_id":"pnt-4jg.1","type":"blocks","created_at":"2026-01-19T12:20:13.557576-05:00","created_by":"Cameron Smith"},{"issue_id":"pnt-4jg.3","depends_on_id":"pnt-4jg.2","type":"blocks","created_at":"2026-01-19T12:20:16.147971-05:00","created_by":"Cameron Smith"}]} {"id":"pnt-btz","title":"pyo3/Rust extension integration","description":"Add Rust extension module support via maturin + pyo3, demonstrating Nix build integration with crane cargoArtifacts sharing and uv2nix overlay composition.\n\nArchitecture documented in: docs/notes/architecture/crane-uv2nix-integration.md\n\nKey patterns:\n- Per-package Rust workspace (crates/ inside Python package)\n- crane buildDepsOnly for artifact caching\n- uv2nix overlay injection for maturin builds\n- CI matrix with rust-deps/rust-checks/python-wheel categories\n\nReference implementations:\n- ~/projects/rust-workspace/ironstar (crane patterns)\n- ~/projects/planning-workspace/langchain (federated Python)\n","status":"open","priority":2,"issue_type":"epic","owner":"cameron.ray.smith@gmail.com","created_at":"2026-01-19T11:54:41.426256-05:00","created_by":"Cameron Smith","updated_at":"2026-01-28T14:43:57.637638-05:00","dependencies":[{"issue_id":"pnt-btz","depends_on_id":"pnt-dre","type":"blocks","created_at":"2026-01-19T11:55:32.690895-05:00","created_by":"Cameron Smith"},{"issue_id":"pnt-btz","depends_on_id":"pnt-4jg","type":"blocks","created_at":"2026-01-19T11:55:32.812602-05:00","created_by":"Cameron Smith"}]} {"id":"pnt-btz.1","title":"Create pnt-cli package scaffold with Rust crates","description":"Create packages/pnt-cli/ with federated structure:\n\nDirectory structure:\n- packages/pnt-cli/pyproject.toml (maturin build-backend, manifest-path binding)\n- packages/pnt-cli/src/pnt_cli/__init__.py (Python wrapper)\n- packages/pnt-cli/crates/Cargo.toml ([workspace] with member crates)\n- packages/pnt-cli/crates/pnt-cli-core/Cargo.toml (pure Rust library)\n- packages/pnt-cli/crates/pnt-cli-py/Cargo.toml (pyo3 bindings, depends on core)\n\npyproject.toml configuration:\n- [build-system] requires maturin\u003e=1.5\n- [tool.maturin] manifest-path = \"crates/pnt-cli-py/Cargo.toml\"\n- [tool.maturin] module-name = \"pnt_cli._native\"\n\nMinimal proof-of-concept: expose a simple function from Rust to Python.\n\nSee: docs/notes/architecture/crane-uv2nix-integration.md\n","status":"open","priority":2,"issue_type":"task","owner":"cameron.ray.smith@gmail.com","created_at":"2026-01-19T11:55:17.885691-05:00","created_by":"Cameron Smith","updated_at":"2026-01-28T14:43:57.882216-05:00","dependencies":[{"issue_id":"pnt-btz.1","depends_on_id":"pnt-btz","type":"parent-child","created_at":"2026-01-19T11:55:17.886287-05:00","created_by":"Cameron Smith"},{"issue_id":"pnt-btz.1","depends_on_id":"pnt-4jg.1","type":"blocks","created_at":"2026-01-19T12:20:18.940008-05:00","created_by":"Cameron Smith"}]} {"id":"pnt-btz.2","title":"Implement crane + uv2nix Nix modules","description":"Create Nix modules implementing the crane + uv2nix integration pattern.\n\nFiles to create:\n- nix/packages/pnt-cli/rust.nix (crane configuration)\n- nix/packages/pnt-cli/default.nix (Python + Rust composition)\n- nix/modules/rust/lib.nix (shared crane utilities, optional)\n\nrust.nix pattern:\n- crane-lib.buildDepsOnly for cargoArtifacts caching\n- commonArgs pattern for derivation hash consistency\n- crane-lib.vendorCargoDeps for maturin's cargo invocation\n- Export cargoArtifacts, cargoVendorDir, clippy, nextest\n\ndefault.nix pattern:\n- Import rust.nix\n- Create overlay injecting cargoVendorDir and CARGO_TARGET_DIR\n- Export overlay and checks for flake composition\n\nUpdate nix/modules/python.nix:\n- Load pnt-cli workspace independently (federated pattern)\n- Compose Rust overlay with uv2nix overlays\n\nSee: docs/notes/architecture/crane-uv2nix-integration.md\n","status":"open","priority":2,"issue_type":"task","owner":"cameron.ray.smith@gmail.com","created_at":"2026-01-19T11:55:18.885252-05:00","created_by":"Cameron Smith","updated_at":"2026-01-28T14:43:58.112357-05:00","dependencies":[{"issue_id":"pnt-btz.2","depends_on_id":"pnt-btz","type":"parent-child","created_at":"2026-01-19T11:55:18.885818-05:00","created_by":"Cameron Smith"},{"issue_id":"pnt-btz.2","depends_on_id":"pnt-btz.1","type":"blocks","created_at":"2026-01-19T12:20:08.210077-05:00","created_by":"Cameron Smith"}]} From bfb8fb8aedf116ad8f9ae5e97cb3bf769c6f5a46 Mon Sep 17 00:00:00 2001 From: Cameron Smith Date: Mon, 2 Feb 2026 15:39:39 -0500 Subject: [PATCH 033/134] feat(makefile): add verify, setup-user, and check-secrets targets Aligns with vanixiets bootstrap-only Makefile pattern. Adds: - verify: checks nix, flakes, direnv, flake validity, devShell tools - setup-user: generates age key for sops-nix secrets - check-secrets: verifies shared secrets decryption - updated bootstrap output with numbered next-steps sequence --- Makefile | 110 ++++++++++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 97 insertions(+), 13 deletions(-) diff --git a/Makefile b/Makefile index 91704ad..c84196a 100644 --- a/Makefile +++ b/Makefile @@ -1,11 +1,15 @@ +# infra bootstrap makefile +# # tl;dr: # # 1. Run 'make bootstrap' to install nix and direnv -# 2. Run 'nix develop' to enter the development environment -# 3. Use 'just ...' to run tasks +# 2. Run 'make verify' to check the installation +# 3. Run 'make setup-user' to generate sops-nix age key +# 4. Run 'nix develop' to enter the development environment +# 5. Use 'just ...' to run tasks # -# This Makefile helps bootstrap a development environment with nix and direnv. -# After this is complete, see the justfile for running development tasks. +# This Makefile handles bootstrap only. After this is complete, +# see the justfile for development and configuration tasks. .DEFAULT_GOAL := help @@ -47,15 +51,19 @@ help-targets: ## eval "$(make help-targets HELP_TARGETS_PATTERN=bootstrap | sed .PHONY: bootstrap bootstrap: ## Main bootstrap target that runs all necessary setup steps bootstrap: install-nix install-direnv - @printf "\nBootstrap of nix and direnv complete! Please note:\n\n" - @echo "- Start a new shell session before continuing" - @echo "- Run 'nix develop' to enter the development environment" - @echo "" - @echo "- If you would like to automatically activate the development environment when you enter the project directory" - @echo " - see https://direnv.net/docs/hook.html to add direnv to your shell" - @echo " - start a new shell session" - @echo " - 'cd' out and back into the project directory" - @echo " - allow direnv by running 'direnv allow'" + @printf "\nBootstrap of nix and direnv complete!\n\n" + @printf "Next steps:\n\n" + @printf " 1. Start a new shell session\n" + @printf " 2. Run 'make verify' to check the installation\n" + @printf " 3. Run 'make setup-user' to generate your age key for secrets\n" + @printf " 4. Run 'nix develop' to enter the development environment\n" + @printf " 5. Use 'just ...' to run tasks\n" + @printf "\n" + @printf "To auto-activate the dev environment on directory entry:\n" + @printf " - see https://direnv.net/docs/hook.html to add direnv to your shell\n" + @printf " - start a new shell session\n" + @printf " - 'cd' out and back into the project directory\n" + @printf " - allow direnv by running 'direnv allow'\n" .PHONY: install-nix install-nix: ## Install Nix using the Determinate Systems installer @@ -77,6 +85,82 @@ install-direnv: ## Install direnv using the official installation script @echo "" @echo "See https://direnv.net/docs/hook.html if you would like to add direnv to your shell" +#------- +##@ verify +#------- + +.PHONY: verify +verify: ## Verify nix installation and environment setup + @printf "\nVerifying installation...\n\n" + @printf "Checking nix installation: " + @if command -v nix >/dev/null 2>&1; then \ + printf "found at %s\n" "$$(command -v nix)"; \ + nix --version; \ + else \ + printf "not found\n"; \ + printf "Run 'make install-nix' to install nix\n"; \ + exit 1; \ + fi + @printf "\nChecking nix flakes support: " + @if nix flake --help >/dev/null 2>&1; then \ + printf "enabled\n"; \ + else \ + printf "not enabled\n"; \ + exit 1; \ + fi + @printf "\nChecking direnv installation: " + @if command -v direnv >/dev/null 2>&1; then \ + printf "found\n"; \ + else \ + printf "not found (optional but recommended)\n"; \ + printf "Run 'make install-direnv' to install\n"; \ + fi + @printf "\nChecking flake validity: " + @if nix flake metadata . >/dev/null 2>&1; then \ + printf "valid\n"; \ + else \ + printf "flake has errors\n"; \ + exit 1; \ + fi + @printf "\nChecking required tools in devShell: " + @if nix develop --command bash -c 'command -v just && command -v python && command -v uv && command -v pixi && command -v ruff' >/dev/null 2>&1; then \ + printf "just, python, uv, pixi, ruff available\n"; \ + else \ + printf "some tools missing from devShell\n"; \ + exit 1; \ + fi + @printf "\nAll verification checks passed.\n\n" + +#------- +##@ setup +#------- + +.PHONY: setup-user +setup-user: ## Generate age key for sops-nix secrets + @if [ -f "$$HOME/.config/sops/age/keys.txt" ]; then \ + printf "Age key already exists at $$HOME/.config/sops/age/keys.txt\n"; \ + printf "Public key: "; \ + grep 'public key:' "$$HOME/.config/sops/age/keys.txt" | awk '{print $$NF}'; \ + else \ + mkdir -p "$$HOME/.config/sops/age"; \ + nix develop --command age-keygen -o "$$HOME/.config/sops/age/keys.txt" 2>&1 | tee /dev/stderr; \ + printf "\nAge key generated. Share the public key above with the team.\n"; \ + fi + +.PHONY: check-secrets +check-secrets: ## Verify you can decrypt shared secrets + @if [ ! -f "$$HOME/.config/sops/age/keys.txt" ]; then \ + printf "No age key found. Run 'make setup-user' first.\n"; \ + exit 1; \ + fi + @if [ -f secrets/shared.yaml ]; then \ + nix develop --command sops -d secrets/shared.yaml > /dev/null 2>&1 && \ + printf "Secrets decryption verified.\n" || \ + (printf "Cannot decrypt secrets. Your age key may not be registered.\n"; exit 1); \ + else \ + printf "No secrets/shared.yaml found. Secrets not yet configured for this project.\n"; \ + fi + #------- ##@ clean #------- From e25e1201b584873b1ce580426efd6765d91d9ccc Mon Sep 17 00:00:00 2001 From: Cameron Smith Date: Mon, 2 Feb 2026 15:39:51 -0500 Subject: [PATCH 034/134] chore(issues): close pnt-dre.1, Makefile bootstrap-only aligned --- .beads/issues.jsonl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.beads/issues.jsonl b/.beads/issues.jsonl index a720000..399143e 100644 --- a/.beads/issues.jsonl +++ b/.beads/issues.jsonl @@ -7,7 +7,7 @@ {"id":"pnt-btz.2","title":"Implement crane + uv2nix Nix modules","description":"Create Nix modules implementing the crane + uv2nix integration pattern.\n\nFiles to create:\n- nix/packages/pnt-cli/rust.nix (crane configuration)\n- nix/packages/pnt-cli/default.nix (Python + Rust composition)\n- nix/modules/rust/lib.nix (shared crane utilities, optional)\n\nrust.nix pattern:\n- crane-lib.buildDepsOnly for cargoArtifacts caching\n- commonArgs pattern for derivation hash consistency\n- crane-lib.vendorCargoDeps for maturin's cargo invocation\n- Export cargoArtifacts, cargoVendorDir, clippy, nextest\n\ndefault.nix pattern:\n- Import rust.nix\n- Create overlay injecting cargoVendorDir and CARGO_TARGET_DIR\n- Export overlay and checks for flake composition\n\nUpdate nix/modules/python.nix:\n- Load pnt-cli workspace independently (federated pattern)\n- Compose Rust overlay with uv2nix overlays\n\nSee: docs/notes/architecture/crane-uv2nix-integration.md\n","status":"open","priority":2,"issue_type":"task","owner":"cameron.ray.smith@gmail.com","created_at":"2026-01-19T11:55:18.885252-05:00","created_by":"Cameron Smith","updated_at":"2026-01-28T14:43:58.112357-05:00","dependencies":[{"issue_id":"pnt-btz.2","depends_on_id":"pnt-btz","type":"parent-child","created_at":"2026-01-19T11:55:18.885818-05:00","created_by":"Cameron Smith"},{"issue_id":"pnt-btz.2","depends_on_id":"pnt-btz.1","type":"blocks","created_at":"2026-01-19T12:20:08.210077-05:00","created_by":"Cameron Smith"}]} {"id":"pnt-btz.3","title":"Validate integration and update CI","description":"Validate the full crane + uv2nix + maturin integration and update CI.\n\nValidation checklist:\n- [ ] nix build .#pnt-cli produces working wheel\n- [ ] Python import succeeds: from pnt_cli._native import ...\n- [ ] Rust changes trigger minimal rebuilds (cargoArtifacts cached)\n- [ ] Python-only changes don't rebuild Rust\n- [ ] cargoClippy and cargoNextest checks pass\n\nCI updates (.github/workflows/ci.yaml):\n- Add rust-deps matrix category for cargoArtifacts caching\n- Add rust-checks matrix category for clippy/nextest\n- Ensure proper cache key based on Cargo.lock hash\n- Follow ironstar CI matrix pattern\n\nDocumentation updates:\n- Add usage example to README\n- Document development workflow (uv sync + maturin develop vs nix build)\n- Note editable install limitations\n\nSee: docs/notes/architecture/crane-uv2nix-integration.md\n","status":"open","priority":2,"issue_type":"task","owner":"cameron.ray.smith@gmail.com","created_at":"2026-01-19T11:55:19.746622-05:00","created_by":"Cameron Smith","updated_at":"2026-01-28T14:43:58.351336-05:00","dependencies":[{"issue_id":"pnt-btz.3","depends_on_id":"pnt-btz","type":"parent-child","created_at":"2026-01-19T11:55:19.74722-05:00","created_by":"Cameron Smith"},{"issue_id":"pnt-btz.3","depends_on_id":"pnt-btz.2","type":"blocks","created_at":"2026-01-19T12:20:11.013516-05:00","created_by":"Cameron Smith"}]} {"id":"pnt-dre","title":"Infrastructure alignment","description":"Align Makefile, justfile, scripts/, and CI with vanixiets and typescript-nix-template patterns. Makefile bootstrap-only, grouped justfile recipes, cached-ci-job CI pattern, omnix template integration.","status":"open","priority":2,"issue_type":"epic","owner":"cameron.ray.smith@gmail.com","created_at":"2026-01-19T11:54:39.841346-05:00","created_by":"Cameron Smith","updated_at":"2026-01-19T11:54:39.841346-05:00"} -{"id":"pnt-dre.1","title":"Refactor Makefile to bootstrap-only pattern","description":"Restrict Makefile to bootstrap targets only: install-nix, install-direnv, verify, setup-user, check-secrets, clean. Move all other targets to justfile.","status":"open","priority":2,"issue_type":"task","owner":"cameron.ray.smith@gmail.com","created_at":"2026-01-19T11:54:54.237851-05:00","created_by":"Cameron Smith","updated_at":"2026-01-19T11:54:54.237851-05:00","dependencies":[{"issue_id":"pnt-dre.1","depends_on_id":"pnt-dre","type":"parent-child","created_at":"2026-01-19T11:54:54.238477-05:00","created_by":"Cameron Smith"}]} +{"id":"pnt-dre.1","title":"Refactor Makefile to bootstrap-only pattern","description":"Restrict Makefile to bootstrap targets only: install-nix, install-direnv, verify, setup-user, check-secrets, clean. Move all other targets to justfile.","status":"closed","priority":2,"issue_type":"task","owner":"cameron.ray.smith@gmail.com","created_at":"2026-01-19T11:54:54.237851-05:00","created_by":"Cameron Smith","updated_at":"2026-02-02T15:39:45.088007-05:00","closed_at":"2026-02-02T15:39:45.088007-05:00","close_reason":"Added verify, setup-user, check-secrets targets aligned with vanixiets. Updated bootstrap output with numbered next-steps. Makefile was already bootstrap-only; no targets removed.","dependencies":[{"issue_id":"pnt-dre.1","depends_on_id":"pnt-dre","type":"parent-child","created_at":"2026-01-19T11:54:54.238477-05:00","created_by":"Cameron Smith"}]} {"id":"pnt-dre.2","title":"Adopt grouped justfile recipe pattern","description":"Reorganize justfile with grouped recipes and section headers following vanixiets pattern: nix, python, conda, docs, secrets, ci/cd groups. Add help comments for each recipe.","status":"open","priority":2,"issue_type":"task","owner":"cameron.ray.smith@gmail.com","created_at":"2026-01-19T11:54:55.145094-05:00","created_by":"Cameron Smith","updated_at":"2026-01-19T11:54:55.145094-05:00","dependencies":[{"issue_id":"pnt-dre.2","depends_on_id":"pnt-dre","type":"parent-child","created_at":"2026-01-19T11:54:55.145764-05:00","created_by":"Cameron Smith"}]} {"id":"pnt-dre.3","title":"Reorganize scripts/ directory structure","description":"Move scripts into subdirectories: scripts/ci/, scripts/docs/, scripts/sops/. IMPORTANT: scripts/bootstrap.sh must remain at stable path for curl one-liner URL. Update justfile and CI references.","status":"open","priority":2,"issue_type":"task","owner":"cameron.ray.smith@gmail.com","created_at":"2026-01-19T11:54:55.839371-05:00","created_by":"Cameron Smith","updated_at":"2026-01-19T12:20:05.527218-05:00","dependencies":[{"issue_id":"pnt-dre.3","depends_on_id":"pnt-dre","type":"parent-child","created_at":"2026-01-19T11:54:55.839951-05:00","created_by":"Cameron Smith"}]} {"id":"pnt-dre.4","title":"Implement cached-ci-job composite action pattern","description":"Add .github/actions/cached-ci-job composite action following typescript-nix-template pattern. Content-addressed caching with hash-sources and force-run support. Update CI to use category-based matrix builds.\n\nPost-federation CI adaptation: the migration from uv workspace to per-package independent locks (pnt-4jg.1) means CI must now discover and iterate packages under packages/. The matrix strategy needs a package axis in addition to the category axis, producing either a {package} x {category} matrix or per-package reusable workflow dispatches. Review how ci.yaml currently enumerates packages and ensure the composite action pattern supports per-package resolution of lock files, dependency caches, and build artifacts.\n\nAcceptance criteria:\n- .github/actions/cached-ci-job composite action implemented\n- Content-addressed caching with hash-sources and force-run support\n- CI matrix discovers packages/ dynamically (not hardcoded)\n- Matrix crosses package x category dimensions\n- Per-package uv.lock files used for cache keys (not root lock)\n- Category-based builds follow typescript-nix-template pattern","status":"open","priority":2,"issue_type":"task","owner":"cameron.ray.smith@gmail.com","created_at":"2026-01-19T11:54:56.79376-05:00","created_by":"Cameron Smith","updated_at":"2026-02-02T14:45:33.154802-05:00","dependencies":[{"issue_id":"pnt-dre.4","depends_on_id":"pnt-dre","type":"parent-child","created_at":"2026-01-19T11:54:56.794334-05:00","created_by":"Cameron Smith"}],"comments":[{"id":2,"issue_id":"pnt-dre.4","author":"Cameron Smith","text":"Minimal CI path fixes applied in d0cab2a as part of pnt-4jg.1 fixups: cache-dependency-glob updated to packages/*/uv.lock, uv sync/lint/test moved into per-package working-directory, ci.yaml path filters updated.\n\nRemaining for pnt-dre.4: replace setup-python/setup-uv actions with nix develop -c just \u003crecipe\u003e pattern, add justfile recipes for per-package sync/test/lint/typecheck, implement cached-ci-job composite action, dynamic package discovery.","created_at":"2026-02-02T20:17:02Z"}]} From 3bc2becd224d87aa9713b0fea86ecf94ccad84a2 Mon Sep 17 00:00:00 2001 From: Cameron Smith Date: Mon, 2 Feb 2026 15:42:17 -0500 Subject: [PATCH 035/134] refactor(justfile): align group naming and structure with conventions Renames multi-word group names to single-word lowercase ('conda', 'python'), fixes Documentation/Docs header inconsistency, demotes GCP sub-section from ## to #, corrects type recipe comment, and moves _ensure-venv helper to end of file. --- justfile | 71 ++++++++++++++++++++++++++++---------------------------- 1 file changed, 36 insertions(+), 35 deletions(-) diff --git a/justfile b/justfile index d852cef..e1912cb 100644 --- a/justfile +++ b/justfile @@ -4,10 +4,10 @@ default: # Contents ## CI/CD -## Conda package +## Conda ## Docs ## Nix -## Python package +## Python ## Release ## Secrets ## Template @@ -187,52 +187,52 @@ gh-docs-cancel run_id="": gh run cancel {{run_id}} --repo $REPO fi -## Conda package +## Conda # Package commands (conda) -[group('conda package')] +[group('conda')] conda-build package="python-nix-template": pixi build --manifest-path=packages/{{package}}/pyproject.toml # Create and sync conda environment with pixi -[group('conda package')] +[group('conda')] conda-env package="python-nix-template": pixi install --manifest-path=packages/{{package}}/pyproject.toml @echo "Conda environment is ready. Activate it with 'pixi shell'" # Update pixi lockfile -[group('conda package')] +[group('conda')] pixi-lock package="python-nix-template": pixi list --manifest-path=packages/{{package}}/pyproject.toml pixi tree --manifest-path=packages/{{package}}/pyproject.toml # Update conda environment -[group('conda package')] +[group('conda')] conda-lock package="python-nix-template": pixi project export conda-explicit-spec packages/{{package}}/conda/ --manifest-path=packages/{{package}}/pyproject.toml --ignore-pypi-errors # Run tests in conda environment with pixi -[group('conda package')] +[group('conda')] conda-test package="python-nix-template": pixi run -e test --manifest-path=packages/{{package}}/pyproject.toml test # Run linting in conda environment with pixi -[group('conda package')] +[group('conda')] conda-lint package="python-nix-template": pixi run -e lint --manifest-path=packages/{{package}}/pyproject.toml lint-check # Run linting and fix errors in conda environment with pixi -[group('conda package')] +[group('conda')] conda-lint-fix package="python-nix-template": pixi run -e lint --manifest-path=packages/{{package}}/pyproject.toml lint # Run type checking in conda environment with pixi -[group('conda package')] +[group('conda')] conda-type package="python-nix-template": pixi run -e types --manifest-path=packages/{{package}}/pyproject.toml types # Run all checks in conda environment (lint, type, test) -[group('conda package')] +[group('conda')] conda-check package="python-nix-template": (conda-lint package) (conda-type package) (conda-test package) @printf "\n\033[92mAll conda checks passed!\033[0m\n" @@ -280,76 +280,69 @@ container-run: docker load < $(nix build .#containerImage --print-out-paths) docker run -it --rm -p 8888:8888 mypackage:latest -## Python package +## Python # Package commands -[group('python package')] +[group('python')] uv-build: _ensure-venv uv build # Sync and enter uv virtual environment -[group('python package')] +[group('python')] venv: _ensure-venv uv sync @echo "Virtual environment is ready. Activate it with 'source .venv/bin/activate'" # Update lockfile from pyproject.toml -[group('python package')] +[group('python')] uv-lock: _ensure-venv uv lock # Run tests -[group('python package')] +[group('python')] test: pytest # Run tests in uv virtual environment -[group('python package')] +[group('python')] uv-test: _ensure-venv uv run pytest # Run linting -[group('python package')] +[group('python')] lint: ruff check src/ # Run linting in uv virtual environment -[group('python package')] +[group('python')] uv-lint: _ensure-venv uvx ruff check src/ # Run linting and fix errors -[group('python package')] +[group('python')] lint-fix: ruff check --fix src/ # Run linting and fix errors in uv virtual environment -[group('python package')] +[group('python')] uv-lint-fix: _ensure-venv uvx ruff check --fix src/ -# Run type checking in uv virtual environment -[group('python package')] +# Run type checking +[group('python')] type: pyright src/ # Run type checking in uv virtual environment -[group('python package')] +[group('python')] uv-type: _ensure-venv uv run pyright src/ # Run all checks (lint, type, test) -[group('python package')] +[group('python')] check: lint type test @printf "\n\033[92mAll checks passed!\033[0m\n" -# Helper recipes -_ensure-venv: - #!/usr/bin/env bash - if [ ! -d ".venv" ]; then - uv venv - fi - ## Secrets # Show existing secrets using sops @@ -505,7 +498,7 @@ template-verify: cd ./tmp-verify-template && nix flake check rm -rf ./tmp-verify-template -## GCP Service Account for DVC +# GCP service account for DVC # Enable Google Drive API in GCP project [group('secrets')] @@ -616,7 +609,7 @@ test-release-direct: test-package-release package-name="python-nix-template" branch="main": yarn workspace {{package-name}} test-release -b {{branch}} -## Documentation +## Docs # Add quartodoc extension [group('docs')] @@ -686,3 +679,11 @@ docs-sync: uvx --with dvc-gdrive,dvc-gs dvc status git status printf "\n\033[92mCommit relevant updates to the docs/_freeze.dvc lock file to the git repo\033[0m\n" + +# Helpers + +_ensure-venv: + #!/usr/bin/env bash + if [ ! -d ".venv" ]; then + uv venv + fi From 664c9cf5ff9740059e08f5368c2b16682628e7dc Mon Sep 17 00:00:00 2001 From: Cameron Smith Date: Mon, 2 Feb 2026 15:42:25 -0500 Subject: [PATCH 036/134] chore(issues): close pnt-dre.2, justfile groups aligned --- .beads/issues.jsonl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.beads/issues.jsonl b/.beads/issues.jsonl index 399143e..c9c0645 100644 --- a/.beads/issues.jsonl +++ b/.beads/issues.jsonl @@ -8,7 +8,7 @@ {"id":"pnt-btz.3","title":"Validate integration and update CI","description":"Validate the full crane + uv2nix + maturin integration and update CI.\n\nValidation checklist:\n- [ ] nix build .#pnt-cli produces working wheel\n- [ ] Python import succeeds: from pnt_cli._native import ...\n- [ ] Rust changes trigger minimal rebuilds (cargoArtifacts cached)\n- [ ] Python-only changes don't rebuild Rust\n- [ ] cargoClippy and cargoNextest checks pass\n\nCI updates (.github/workflows/ci.yaml):\n- Add rust-deps matrix category for cargoArtifacts caching\n- Add rust-checks matrix category for clippy/nextest\n- Ensure proper cache key based on Cargo.lock hash\n- Follow ironstar CI matrix pattern\n\nDocumentation updates:\n- Add usage example to README\n- Document development workflow (uv sync + maturin develop vs nix build)\n- Note editable install limitations\n\nSee: docs/notes/architecture/crane-uv2nix-integration.md\n","status":"open","priority":2,"issue_type":"task","owner":"cameron.ray.smith@gmail.com","created_at":"2026-01-19T11:55:19.746622-05:00","created_by":"Cameron Smith","updated_at":"2026-01-28T14:43:58.351336-05:00","dependencies":[{"issue_id":"pnt-btz.3","depends_on_id":"pnt-btz","type":"parent-child","created_at":"2026-01-19T11:55:19.74722-05:00","created_by":"Cameron Smith"},{"issue_id":"pnt-btz.3","depends_on_id":"pnt-btz.2","type":"blocks","created_at":"2026-01-19T12:20:11.013516-05:00","created_by":"Cameron Smith"}]} {"id":"pnt-dre","title":"Infrastructure alignment","description":"Align Makefile, justfile, scripts/, and CI with vanixiets and typescript-nix-template patterns. Makefile bootstrap-only, grouped justfile recipes, cached-ci-job CI pattern, omnix template integration.","status":"open","priority":2,"issue_type":"epic","owner":"cameron.ray.smith@gmail.com","created_at":"2026-01-19T11:54:39.841346-05:00","created_by":"Cameron Smith","updated_at":"2026-01-19T11:54:39.841346-05:00"} {"id":"pnt-dre.1","title":"Refactor Makefile to bootstrap-only pattern","description":"Restrict Makefile to bootstrap targets only: install-nix, install-direnv, verify, setup-user, check-secrets, clean. Move all other targets to justfile.","status":"closed","priority":2,"issue_type":"task","owner":"cameron.ray.smith@gmail.com","created_at":"2026-01-19T11:54:54.237851-05:00","created_by":"Cameron Smith","updated_at":"2026-02-02T15:39:45.088007-05:00","closed_at":"2026-02-02T15:39:45.088007-05:00","close_reason":"Added verify, setup-user, check-secrets targets aligned with vanixiets. Updated bootstrap output with numbered next-steps. Makefile was already bootstrap-only; no targets removed.","dependencies":[{"issue_id":"pnt-dre.1","depends_on_id":"pnt-dre","type":"parent-child","created_at":"2026-01-19T11:54:54.238477-05:00","created_by":"Cameron Smith"}]} -{"id":"pnt-dre.2","title":"Adopt grouped justfile recipe pattern","description":"Reorganize justfile with grouped recipes and section headers following vanixiets pattern: nix, python, conda, docs, secrets, ci/cd groups. Add help comments for each recipe.","status":"open","priority":2,"issue_type":"task","owner":"cameron.ray.smith@gmail.com","created_at":"2026-01-19T11:54:55.145094-05:00","created_by":"Cameron Smith","updated_at":"2026-01-19T11:54:55.145094-05:00","dependencies":[{"issue_id":"pnt-dre.2","depends_on_id":"pnt-dre","type":"parent-child","created_at":"2026-01-19T11:54:55.145764-05:00","created_by":"Cameron Smith"}]} +{"id":"pnt-dre.2","title":"Adopt grouped justfile recipe pattern","description":"Reorganize justfile with grouped recipes and section headers following vanixiets pattern: nix, python, conda, docs, secrets, ci/cd groups. Add help comments for each recipe.","status":"closed","priority":2,"issue_type":"task","owner":"cameron.ray.smith@gmail.com","created_at":"2026-01-19T11:54:55.145094-05:00","created_by":"Cameron Smith","updated_at":"2026-02-02T15:42:24.899403-05:00","closed_at":"2026-02-02T15:42:24.899403-05:00","close_reason":"Aligned group naming (conda package→conda, python package→python), fixed Documentation→Docs header, demoted GCP sub-section, corrected type recipe comment, moved helper to EOF.","dependencies":[{"issue_id":"pnt-dre.2","depends_on_id":"pnt-dre","type":"parent-child","created_at":"2026-01-19T11:54:55.145764-05:00","created_by":"Cameron Smith"}]} {"id":"pnt-dre.3","title":"Reorganize scripts/ directory structure","description":"Move scripts into subdirectories: scripts/ci/, scripts/docs/, scripts/sops/. IMPORTANT: scripts/bootstrap.sh must remain at stable path for curl one-liner URL. Update justfile and CI references.","status":"open","priority":2,"issue_type":"task","owner":"cameron.ray.smith@gmail.com","created_at":"2026-01-19T11:54:55.839371-05:00","created_by":"Cameron Smith","updated_at":"2026-01-19T12:20:05.527218-05:00","dependencies":[{"issue_id":"pnt-dre.3","depends_on_id":"pnt-dre","type":"parent-child","created_at":"2026-01-19T11:54:55.839951-05:00","created_by":"Cameron Smith"}]} {"id":"pnt-dre.4","title":"Implement cached-ci-job composite action pattern","description":"Add .github/actions/cached-ci-job composite action following typescript-nix-template pattern. Content-addressed caching with hash-sources and force-run support. Update CI to use category-based matrix builds.\n\nPost-federation CI adaptation: the migration from uv workspace to per-package independent locks (pnt-4jg.1) means CI must now discover and iterate packages under packages/. The matrix strategy needs a package axis in addition to the category axis, producing either a {package} x {category} matrix or per-package reusable workflow dispatches. Review how ci.yaml currently enumerates packages and ensure the composite action pattern supports per-package resolution of lock files, dependency caches, and build artifacts.\n\nAcceptance criteria:\n- .github/actions/cached-ci-job composite action implemented\n- Content-addressed caching with hash-sources and force-run support\n- CI matrix discovers packages/ dynamically (not hardcoded)\n- Matrix crosses package x category dimensions\n- Per-package uv.lock files used for cache keys (not root lock)\n- Category-based builds follow typescript-nix-template pattern","status":"open","priority":2,"issue_type":"task","owner":"cameron.ray.smith@gmail.com","created_at":"2026-01-19T11:54:56.79376-05:00","created_by":"Cameron Smith","updated_at":"2026-02-02T14:45:33.154802-05:00","dependencies":[{"issue_id":"pnt-dre.4","depends_on_id":"pnt-dre","type":"parent-child","created_at":"2026-01-19T11:54:56.794334-05:00","created_by":"Cameron Smith"}],"comments":[{"id":2,"issue_id":"pnt-dre.4","author":"Cameron Smith","text":"Minimal CI path fixes applied in d0cab2a as part of pnt-4jg.1 fixups: cache-dependency-glob updated to packages/*/uv.lock, uv sync/lint/test moved into per-package working-directory, ci.yaml path filters updated.\n\nRemaining for pnt-dre.4: replace setup-python/setup-uv actions with nix develop -c just \u003crecipe\u003e pattern, add justfile recipes for per-package sync/test/lint/typecheck, implement cached-ci-job composite action, dynamic package discovery.","created_at":"2026-02-02T20:17:02Z"}]} {"id":"pnt-dre.5","title":"Add omnix template integration","description":"Configure om.templates in flake with parameter definitions. Add template-verify justfile recipe. Create .github/workflows/template.yaml for CI validation.","status":"open","priority":2,"issue_type":"task","owner":"cameron.ray.smith@gmail.com","created_at":"2026-01-19T11:54:57.668262-05:00","created_by":"Cameron Smith","updated_at":"2026-01-19T11:54:57.668262-05:00","dependencies":[{"issue_id":"pnt-dre.5","depends_on_id":"pnt-dre","type":"parent-child","created_at":"2026-01-19T11:54:57.66888-05:00","created_by":"Cameron Smith"}]} From 4ac6a6b5f3e6b1c29bae0b9f940fc31c070e9849 Mon Sep 17 00:00:00 2001 From: Cameron Smith Date: Mon, 2 Feb 2026 15:45:10 -0500 Subject: [PATCH 037/134] feat(scripts): add self-contained bootstrap script for curl one-liner Replicates Makefile bootstrap logic (install nix, install direnv, verify) as a standalone script at a stable URL path for pre-clone onboarding. --- scripts/bootstrap.sh | 64 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 64 insertions(+) create mode 100755 scripts/bootstrap.sh diff --git a/scripts/bootstrap.sh b/scripts/bootstrap.sh new file mode 100755 index 0000000..83a2c40 --- /dev/null +++ b/scripts/bootstrap.sh @@ -0,0 +1,64 @@ +#!/usr/bin/env bash +# Self-contained bootstrap script for python-nix-template. +# Intended for curl one-liner pre-clone onboarding: +# curl -sSf https://raw.githubusercontent.com/sciexp/python-nix-template/main/scripts/bootstrap.sh | bash +# +# This script must be kept in sync with the Makefile bootstrap targets +# manually (discipline-based, not DRY import) since it must remain +# self-contained for the curl use case. +set -euo pipefail + +echo "python-nix-template bootstrap" +echo "==============================" +echo + +# Install Nix +echo "Checking Nix installation..." +if command -v nix >/dev/null 2>&1; then + echo "Nix is already installed." + nix --version +else + echo "Installing Nix via Determinate Systems installer..." + curl --proto '=https' --tlsv1.2 -sSf -L https://install.determinate.systems/nix | sh -s -- install +fi +echo + +# Install direnv +echo "Checking direnv installation..." +if command -v direnv >/dev/null 2>&1; then + echo "direnv is already installed." +else + echo "Installing direnv..." + curl -sfL https://direnv.net/install.sh | bash +fi +echo + +# Verify +echo "Verifying installation..." +echo + +if ! command -v nix >/dev/null 2>&1; then + echo "Nix not found after installation. Start a new shell session and re-run." + exit 1 +fi + +if ! nix flake --help >/dev/null 2>&1; then + echo "Nix flakes not enabled." + exit 1 +fi + +echo "Nix and flakes verified." +echo + +echo "Bootstrap complete." +echo +echo "Next steps:" +echo " 1. Start a new shell session" +echo " 2. Clone the repository" +echo " 3. cd into the project directory" +echo " 4. Run 'nix develop' to enter the development environment" +echo " 5. Run 'make verify' for full environment verification" +echo " 6. Run 'make setup-user' to generate your age key for secrets" +echo " 7. Use 'just ...' to run tasks" +echo +echo "See https://direnv.net/docs/hook.html to set up automatic environment activation." From 2056806e89d9b6f3bbe40c6599144428ac14cbda Mon Sep 17 00:00:00 2001 From: Cameron Smith Date: Mon, 2 Feb 2026 15:45:15 -0500 Subject: [PATCH 038/134] feat(scripts): extract maximize-build-space script for CI runners Canonical version of the disk space reclamation logic currently duplicated inline in deploy-docs.yaml and build-nix-images.yaml. Workflow step references will be updated in the CI redesign. --- scripts/ci/maximize-build-space.sh | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) create mode 100755 scripts/ci/maximize-build-space.sh diff --git a/scripts/ci/maximize-build-space.sh b/scripts/ci/maximize-build-space.sh new file mode 100755 index 0000000..8d4256c --- /dev/null +++ b/scripts/ci/maximize-build-space.sh @@ -0,0 +1,17 @@ +#!/usr/bin/env bash +# Maximize available disk space on GitHub Actions runners by removing +# unused pre-installed software. Based on: +# https://github.com/easimon/maximize-build-space/blob/v10/action.yml#L121-L137 +set -euo pipefail + +echo "Available storage before removing unused software:" +sudo df -h +echo +sudo rm -rf /usr/local/lib/android +echo "Available storage after removing android:" +sudo df -h +echo +sudo rm -rf /opt/hostedtoolcache/CodeQL +echo "Available storage after removing codeql:" +sudo df -h +echo From 08bb2a9470fe88a22f97daccefb99da12ed15ca5 Mon Sep 17 00:00:00 2001 From: Cameron Smith Date: Mon, 2 Feb 2026 15:45:23 -0500 Subject: [PATCH 039/134] chore(issues): close pnt-dre.3, scripts directory reorganized --- .beads/issues.jsonl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.beads/issues.jsonl b/.beads/issues.jsonl index c9c0645..72e0aa2 100644 --- a/.beads/issues.jsonl +++ b/.beads/issues.jsonl @@ -9,6 +9,6 @@ {"id":"pnt-dre","title":"Infrastructure alignment","description":"Align Makefile, justfile, scripts/, and CI with vanixiets and typescript-nix-template patterns. Makefile bootstrap-only, grouped justfile recipes, cached-ci-job CI pattern, omnix template integration.","status":"open","priority":2,"issue_type":"epic","owner":"cameron.ray.smith@gmail.com","created_at":"2026-01-19T11:54:39.841346-05:00","created_by":"Cameron Smith","updated_at":"2026-01-19T11:54:39.841346-05:00"} {"id":"pnt-dre.1","title":"Refactor Makefile to bootstrap-only pattern","description":"Restrict Makefile to bootstrap targets only: install-nix, install-direnv, verify, setup-user, check-secrets, clean. Move all other targets to justfile.","status":"closed","priority":2,"issue_type":"task","owner":"cameron.ray.smith@gmail.com","created_at":"2026-01-19T11:54:54.237851-05:00","created_by":"Cameron Smith","updated_at":"2026-02-02T15:39:45.088007-05:00","closed_at":"2026-02-02T15:39:45.088007-05:00","close_reason":"Added verify, setup-user, check-secrets targets aligned with vanixiets. Updated bootstrap output with numbered next-steps. Makefile was already bootstrap-only; no targets removed.","dependencies":[{"issue_id":"pnt-dre.1","depends_on_id":"pnt-dre","type":"parent-child","created_at":"2026-01-19T11:54:54.238477-05:00","created_by":"Cameron Smith"}]} {"id":"pnt-dre.2","title":"Adopt grouped justfile recipe pattern","description":"Reorganize justfile with grouped recipes and section headers following vanixiets pattern: nix, python, conda, docs, secrets, ci/cd groups. Add help comments for each recipe.","status":"closed","priority":2,"issue_type":"task","owner":"cameron.ray.smith@gmail.com","created_at":"2026-01-19T11:54:55.145094-05:00","created_by":"Cameron Smith","updated_at":"2026-02-02T15:42:24.899403-05:00","closed_at":"2026-02-02T15:42:24.899403-05:00","close_reason":"Aligned group naming (conda package→conda, python package→python), fixed Documentation→Docs header, demoted GCP sub-section, corrected type recipe comment, moved helper to EOF.","dependencies":[{"issue_id":"pnt-dre.2","depends_on_id":"pnt-dre","type":"parent-child","created_at":"2026-01-19T11:54:55.145764-05:00","created_by":"Cameron Smith"}]} -{"id":"pnt-dre.3","title":"Reorganize scripts/ directory structure","description":"Move scripts into subdirectories: scripts/ci/, scripts/docs/, scripts/sops/. IMPORTANT: scripts/bootstrap.sh must remain at stable path for curl one-liner URL. Update justfile and CI references.","status":"open","priority":2,"issue_type":"task","owner":"cameron.ray.smith@gmail.com","created_at":"2026-01-19T11:54:55.839371-05:00","created_by":"Cameron Smith","updated_at":"2026-01-19T12:20:05.527218-05:00","dependencies":[{"issue_id":"pnt-dre.3","depends_on_id":"pnt-dre","type":"parent-child","created_at":"2026-01-19T11:54:55.839951-05:00","created_by":"Cameron Smith"}]} +{"id":"pnt-dre.3","title":"Reorganize scripts/ directory structure","description":"Move scripts into subdirectories: scripts/ci/, scripts/docs/, scripts/sops/. IMPORTANT: scripts/bootstrap.sh must remain at stable path for curl one-liner URL. Update justfile and CI references.","status":"closed","priority":2,"issue_type":"task","owner":"cameron.ray.smith@gmail.com","created_at":"2026-01-19T11:54:55.839371-05:00","created_by":"Cameron Smith","updated_at":"2026-02-02T15:45:23.076616-05:00","closed_at":"2026-02-02T15:45:23.076616-05:00","close_reason":"Created scripts/bootstrap.sh (stable URL for curl one-liner) and scripts/ci/maximize-build-space.sh (canonical version of duplicated CI logic). Workflow inline references deferred to pnt-dre.4 CI redesign due to pre-checkout step ordering. scripts/sops/ and scripts/docs/ skipped — no duplication issues warranting extraction.","dependencies":[{"issue_id":"pnt-dre.3","depends_on_id":"pnt-dre","type":"parent-child","created_at":"2026-01-19T11:54:55.839951-05:00","created_by":"Cameron Smith"}]} {"id":"pnt-dre.4","title":"Implement cached-ci-job composite action pattern","description":"Add .github/actions/cached-ci-job composite action following typescript-nix-template pattern. Content-addressed caching with hash-sources and force-run support. Update CI to use category-based matrix builds.\n\nPost-federation CI adaptation: the migration from uv workspace to per-package independent locks (pnt-4jg.1) means CI must now discover and iterate packages under packages/. The matrix strategy needs a package axis in addition to the category axis, producing either a {package} x {category} matrix or per-package reusable workflow dispatches. Review how ci.yaml currently enumerates packages and ensure the composite action pattern supports per-package resolution of lock files, dependency caches, and build artifacts.\n\nAcceptance criteria:\n- .github/actions/cached-ci-job composite action implemented\n- Content-addressed caching with hash-sources and force-run support\n- CI matrix discovers packages/ dynamically (not hardcoded)\n- Matrix crosses package x category dimensions\n- Per-package uv.lock files used for cache keys (not root lock)\n- Category-based builds follow typescript-nix-template pattern","status":"open","priority":2,"issue_type":"task","owner":"cameron.ray.smith@gmail.com","created_at":"2026-01-19T11:54:56.79376-05:00","created_by":"Cameron Smith","updated_at":"2026-02-02T14:45:33.154802-05:00","dependencies":[{"issue_id":"pnt-dre.4","depends_on_id":"pnt-dre","type":"parent-child","created_at":"2026-01-19T11:54:56.794334-05:00","created_by":"Cameron Smith"}],"comments":[{"id":2,"issue_id":"pnt-dre.4","author":"Cameron Smith","text":"Minimal CI path fixes applied in d0cab2a as part of pnt-4jg.1 fixups: cache-dependency-glob updated to packages/*/uv.lock, uv sync/lint/test moved into per-package working-directory, ci.yaml path filters updated.\n\nRemaining for pnt-dre.4: replace setup-python/setup-uv actions with nix develop -c just \u003crecipe\u003e pattern, add justfile recipes for per-package sync/test/lint/typecheck, implement cached-ci-job composite action, dynamic package discovery.","created_at":"2026-02-02T20:17:02Z"}]} {"id":"pnt-dre.5","title":"Add omnix template integration","description":"Configure om.templates in flake with parameter definitions. Add template-verify justfile recipe. Create .github/workflows/template.yaml for CI validation.","status":"open","priority":2,"issue_type":"task","owner":"cameron.ray.smith@gmail.com","created_at":"2026-01-19T11:54:57.668262-05:00","created_by":"Cameron Smith","updated_at":"2026-01-19T11:54:57.668262-05:00","dependencies":[{"issue_id":"pnt-dre.5","depends_on_id":"pnt-dre","type":"parent-child","created_at":"2026-01-19T11:54:57.66888-05:00","created_by":"Cameron Smith"}]} From 44abfe5d297ddaa44abd6c239638482150af81b4 Mon Sep 17 00:00:00 2001 From: Cameron Smith Date: Mon, 2 Feb 2026 15:51:37 -0500 Subject: [PATCH 040/134] feat(ci): add cached-ci-job composite action Content-addressed execution caching for CI jobs. Computes hash from specified source files, checks actions/cache for prior success, and outputs should-run decision. Ported from typescript-nix-template. --- .github/actions/cached-ci-job/action.yaml | 183 ++++++++++++++++++++++ 1 file changed, 183 insertions(+) create mode 100644 .github/actions/cached-ci-job/action.yaml diff --git a/.github/actions/cached-ci-job/action.yaml b/.github/actions/cached-ci-job/action.yaml new file mode 100644 index 0000000..01064af --- /dev/null +++ b/.github/actions/cached-ci-job/action.yaml @@ -0,0 +1,183 @@ +name: Cached CI Job +description: Execute job only if not already successful for this commit SHA + +inputs: + check-name: + description: Full check run name (defaults to github.job, include matrix values for matrix jobs) + required: false + default: ${{ github.job }} + hash-sources: + description: | + Glob patterns for files to hash (one per line or space-separated). + Used to compute content-addressed cache key. + Example: '**/*.nix flake.lock justfile' + The workflow file is automatically included. + required: false + default: '' + force-run: + description: Force execution even if already successful + required: false + default: 'false' + +outputs: + should-run: + description: Whether job should execute (true/false) + value: ${{ steps.decide.outputs.should-run }} + cache-source: + description: 'Where cache hit occurred (actions-cache or none)' + value: ${{ steps.decide.outputs.cache-source }} + cache-key: + description: 'Content-addressed cache key' + value: ${{ steps.compute-hash.outputs.cache-key }} + cache-path: + description: 'Cache directory path for job result marker' + value: ${{ steps.compute-hash.outputs.cache-path }} + +runs: + using: composite + steps: + - name: Compute content-addressed cache key + id: compute-hash + shell: bash + env: + CHECK_NAME: ${{ inputs.check-name }} + HASH_SOURCES: ${{ inputs.hash-sources }} + run: | + # Sanitize check name + SANITIZED=$(echo "$CHECK_NAME" | tr -d '()' | tr ', ' '-' | tr -s '-') + + # Get workflow file path (automatically included in hash) + WORKFLOW_FILE=$(echo "$GITHUB_WORKFLOW_REF" | sed 's|^[^/]*/[^/]*/||' | sed 's|@.*||') + echo "Workflow file: $WORKFLOW_FILE" + + # Auto-include the composite action itself + CACHE_ACTION=".github/actions/cached-ci-job/action.yaml" + + # Combine user sources + workflow file + cache action + if [ -n "$HASH_SOURCES" ]; then + ALL_SOURCES="$HASH_SOURCES $WORKFLOW_FILE $CACHE_ACTION" + else + ALL_SOURCES="$WORKFLOW_FILE $CACHE_ACTION" + fi + + echo "Hash sources: $ALL_SOURCES" + + # Compute content hash of all source files + # Disable glob expansion to preserve patterns for manual processing + set -f + CONTENT_HASH="" + for pattern in $ALL_SOURCES; do + if [ -f "$pattern" ]; then + case "$pattern" in + docs/notes/*) + continue + ;; + esac + FILE_HASH=$(git hash-object "$pattern" 2>/dev/null || echo "missing") + CONTENT_HASH="${CONTENT_HASH}${FILE_HASH}" + elif [[ "$pattern" == *"*"* ]]; then + if [[ "$pattern" == *"/"* ]]; then + BASE_DIR="${pattern%%/**}" + FILE_PATTERN="${pattern##*/}" + else + BASE_DIR="." + FILE_PATTERN="$pattern" + fi + + if [[ "$pattern" == "**/"* ]]; then + BASE_DIR="." + FILE_PATTERN="${pattern#**/}" + fi + + if [ -d "$BASE_DIR" ]; then + while IFS= read -r file; do + case "$file" in + docs/notes/*) + continue + ;; + esac + FILE_HASH=$(git hash-object "$file" 2>/dev/null || echo "missing") + CONTENT_HASH="${CONTENT_HASH}${FILE_HASH}" + done < <(find "$BASE_DIR" -type f -name "$FILE_PATTERN" 2>/dev/null | sort) + else + echo "::warning::Pattern base directory not found: $BASE_DIR (pattern: $pattern)" + fi + else + echo "::warning::Source file not found: $pattern" + fi + done + set +f + + FINAL_HASH=$(echo -n "$CONTENT_HASH" | sha256sum | cut -c1-12) + CACHE_KEY="job-result-${SANITIZED}-${FINAL_HASH}" + CACHE_PATH=".cache/job-results/${SANITIZED}" + + echo "Content hash: $FINAL_HASH" + echo "Cache key: $CACHE_KEY" + echo "Cache path: $CACHE_PATH" + + echo "cache-key=$CACHE_KEY" >> $GITHUB_OUTPUT + echo "cache-path=$CACHE_PATH" >> $GITHUB_OUTPUT + echo "content-hash=$FINAL_HASH" >> $GITHUB_OUTPUT + + - name: Prepare cache restore keys + id: cache-result + shell: bash + env: + CHECK_NAME: ${{ inputs.check-name }} + run: | + SANITIZED=$(echo "$CHECK_NAME" | tr -d '()' | tr ', ' '-' | tr -s '-') + RESTORE_KEYS="job-result-${SANITIZED}-" + echo "Restore keys pattern: ${RESTORE_KEYS}*" + echo "restore-keys=$RESTORE_KEYS" >> $GITHUB_OUTPUT + + - name: Lookup job result in actions/cache + id: cache-lookup + uses: actions/cache/restore@9255dc7a253b0ccc959486e2bca901246202afeb # v5 + with: + path: ${{ steps.compute-hash.outputs.cache-path }} + key: ${{ steps.compute-hash.outputs.cache-key }} + restore-keys: ${{ steps.cache-result.outputs.restore-keys }} + lookup-only: true + + - name: Make execution decision + id: decide + shell: bash + env: + FORCE: ${{ inputs.force-run }} + CACHE_HIT: ${{ steps.cache-lookup.outputs.cache-hit || 'false' }} + CACHE_KEY: ${{ steps.compute-hash.outputs.cache-key }} + CHECK_NAME: ${{ inputs.check-name }} + run: | + echo "=== Execution Decision ===" + echo "Force run: $FORCE" + echo "Cache key: $CACHE_KEY" + echo "Actions cache hit: $CACHE_HIT" + echo "" + + SANITIZED_NAME=$(echo "$CHECK_NAME" | tr -d '()' | tr ', ' '-' | tr -s '-') + + if [ "$FORCE" = "true" ]; then + echo "should-run=true" >> $GITHUB_OUTPUT + if [ "$CACHE_HIT" = "true" ]; then + echo "cache-source=actions-cache" >> $GITHUB_OUTPUT + else + echo "cache-source=none" >> $GITHUB_OUTPUT + fi + echo "::notice title=CI Cache | ${SANITIZED_NAME}::RUN | ${CACHE_KEY} | Forced" + echo "Decision: RUN (forced by input)" + exit 0 + fi + + if [ "$CACHE_HIT" = "true" ]; then + echo "should-run=false" >> $GITHUB_OUTPUT + echo "cache-source=actions-cache" >> $GITHUB_OUTPUT + echo "::notice title=CI Cache | ${SANITIZED_NAME}::SKIP | ${CACHE_KEY} | Cached" + echo "Decision: SKIP (cached result found)" + exit 0 + fi + + echo "should-run=true" >> $GITHUB_OUTPUT + echo "cache-source=none" >> $GITHUB_OUTPUT + echo "::notice title=CI Cache | ${SANITIZED_NAME}::RUN | ${CACHE_KEY} | Cache miss" + echo "Decision: RUN (no cached result found)" From 900235a69e8fc4a45d05c8379945eaee530be2fe Mon Sep 17 00:00:00 2001 From: Cameron Smith Date: Mon, 2 Feb 2026 15:53:49 -0500 Subject: [PATCH 041/134] feat(justfile): add per-package CI recipes for local/CI symmetry Adds list-packages-json, ci-sync, ci-lint, ci-test, ci-typecheck, and ci-check recipes. Each operates per-package via uv run inside the nix devshell, providing the same interface locally and in CI. --- justfile | 34 ++++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/justfile b/justfile index e1912cb..c0f7e3e 100644 --- a/justfile +++ b/justfile @@ -187,6 +187,40 @@ gh-docs-cancel run_id="": gh run cancel {{run_id}} --repo $REPO fi +# Discover packages as JSON array for CI matrix +[group('CI/CD')] +list-packages-json: + @ls -d packages/*/pyproject.toml | while read f; do \ + d=$(dirname "$f"); \ + n=$(basename "$d"); \ + printf '{"name":"%s","path":"%s"}\n' "$n" "$d"; \ + done | jq -sc '.' + +# Sync dependencies for a package via uv +[group('CI/CD')] +ci-sync package: + cd packages/{{package}} && uv sync --all-extras --dev + +# Run linting for a package +[group('CI/CD')] +ci-lint package: + cd packages/{{package}} && uv run ruff check src/ + +# Run tests for a package +[group('CI/CD')] +ci-test package: + cd packages/{{package}} && uv run pytest + +# Run type checking for a package +[group('CI/CD')] +ci-typecheck package: + cd packages/{{package}} && uv run pyright src/ + +# Run all checks for a package (lint, typecheck, test) +[group('CI/CD')] +ci-check package: (ci-lint package) (ci-typecheck package) (ci-test package) + @printf "\nAll CI checks passed for {{package}}.\n" + ## Conda # Package commands (conda) From ed1e3659a26caf9634e83c308a4aea00ce5e5543 Mon Sep 17 00:00:00 2001 From: Cameron Smith Date: Mon, 2 Feb 2026 15:54:21 -0500 Subject: [PATCH 042/134] refactor(ci): rewrite python-test workflow to use nix develop Replaces setup-uv/setup-python with nix develop -c just pattern. Removes python-version matrix dimension (nix devshell pins Python). Adds cached-ci-job integration with per-package hash sources and job result markers. --- .github/workflows/python-test.yaml | 100 ++++++++++++++++++----------- 1 file changed, 64 insertions(+), 36 deletions(-) diff --git a/.github/workflows/python-test.yaml b/.github/workflows/python-test.yaml index a4de449..8514301 100644 --- a/.github/workflows/python-test.yaml +++ b/.github/workflows/python-test.yaml @@ -3,16 +3,10 @@ name: Python Test on: workflow_dispatch: inputs: - python-version: - description: "Python version to use" - required: true - type: string - default: "3.12" package-name: description: "Name of the package to test" - required: false + required: true type: string - default: "" debug_enabled: description: "Run with tmate.io debugging enabled" required: false @@ -23,18 +17,18 @@ on: required: false type: string default: "" + force_run: + description: "Force execution even if cached" + required: false + type: boolean + default: false workflow_call: inputs: - python-version: - description: "Python version to use" - required: true - type: string package-name: description: "Name of the package to test" - required: false + required: true type: string - default: "" debug_enabled: description: "Run with tmate.io debugging enabled" required: false @@ -45,6 +39,11 @@ on: required: false type: string default: "" + force_run: + description: "Force execution even if cached" + required: false + type: string + default: "false" jobs: test: @@ -54,35 +53,47 @@ jobs: with: ref: ${{ inputs.checkout_ref != '' && inputs.checkout_ref || github.ref }} - - name: Setup tmate debug session - uses: mxschmitt/action-tmate@e5c7151931ca95bad1c6f4190c730ecf8c7dde48 # ratchet:mxschmitt/action-tmate@v3 - if: ${{ inputs.debug_enabled == 'true' }} + - name: Check execution cache + id: cache + uses: ./.github/actions/cached-ci-job + with: + check-name: test (${{ inputs.package-name }}) + hash-sources: 'packages/${{ inputs.package-name }}/**/*.py packages/${{ inputs.package-name }}/pyproject.toml packages/${{ inputs.package-name }}/uv.lock justfile **/*.nix flake.lock' + force-run: ${{ inputs.force_run || 'false' }} - - name: Install uv - uses: astral-sh/setup-uv@v5 + - name: Install Nix + if: steps.cache.outputs.should-run == 'true' + uses: DeterminateSystems/nix-installer-action@786fff0690178f1234e4e1fe9b536e94f5433196 # ratchet:DeterminateSystems/nix-installer-action@main with: - python-version: ${{ inputs.python-version }} - enable-cache: true - cache-dependency-glob: "packages/*/uv.lock" - version: "0.6.8" + extra-conf: "system-features = nixos-test benchmark big-parallel kvm" - - name: Install dependencies - working-directory: packages/${{ inputs.package-name }} - run: | - uv sync --all-extras --dev + - name: Setup remote cache + if: steps.cache.outputs.should-run == 'true' + uses: cachix/cachix-action@be5295a636153b6ad194d3245f78f8e0b78dc704 # ratchet:cachix/cachix-action@master + continue-on-error: true + with: + name: "${{ vars.CACHIX_CACHE_NAME }}" + authToken: "${{ secrets.CACHIX_AUTH_TOKEN }}" + extraPullNames: nix-community,pyproject-nix,sciexp + + - name: Setup tmate debug session + if: steps.cache.outputs.should-run == 'true' && inputs.debug_enabled == 'true' + uses: mxschmitt/action-tmate@e5c7151931ca95bad1c6f4190c730ecf8c7dde48 # ratchet:mxschmitt/action-tmate@v3 + + - name: Sync dependencies + if: steps.cache.outputs.should-run == 'true' + run: nix develop --accept-flake-config -c just ci-sync ${{ inputs.package-name }} - name: Lint - working-directory: packages/${{ inputs.package-name }} - run: | - uv run ruff check . + if: steps.cache.outputs.should-run == 'true' + run: nix develop --accept-flake-config -c just ci-lint ${{ inputs.package-name }} - name: Test - working-directory: packages/${{ inputs.package-name }} - run: | - echo "Testing package: ${{ inputs.package-name }}" - uv run pytest + if: steps.cache.outputs.should-run == 'true' + run: nix develop --accept-flake-config -c just ci-test ${{ inputs.package-name }} - name: Upload coverage + if: steps.cache.outputs.should-run == 'true' uses: codecov/codecov-action@0565863a31f2c772f9f0395002a31e3f06189574 # ratchet:codecov/codecov-action@v5.4.0 continue-on-error: true with: @@ -90,6 +101,23 @@ jobs: fail_ci_if_error: false verbose: true - - name: Minimize uv cache - run: uv cache prune --ci - if: always() + - name: Create job result marker + if: success() && steps.cache.outputs.should-run == 'true' && steps.cache.outputs.cache-source == 'none' + run: | + mkdir -p "${{ steps.cache.outputs.cache-path }}" + cat > "${{ steps.cache.outputs.cache-path }}/marker" < Date: Mon, 2 Feb 2026 15:55:21 -0500 Subject: [PATCH 043/134] refactor(ci): add cached-ci-job, dynamic package discovery, force_run Integrates cached-ci-job composite action into scan and nixci jobs. Adds dynamic package discovery via set-variables outputs replacing hardcoded matrices in test-python and test-release-packages. Removes python-version matrix dimension from test-python. Adds force_run workflow dispatch input, concurrency group, and path triggers for justfile and packages/*/pyproject.toml. --- .github/workflows/ci.yaml | 146 ++++++++++++++++++++++++-------------- 1 file changed, 94 insertions(+), 52 deletions(-) diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 0e9466d..803e28a 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -18,6 +18,11 @@ on: required: false type: boolean default: false + force_run: + description: "Force execution even if already successful for this commit" + required: false + type: boolean + default: false pull_request: types: [opened, labeled, reopened, synchronize] paths-ignore: @@ -26,7 +31,9 @@ on: - "!flake.nix" - "!flake.lock" - "!pyproject.toml" + - "!justfile" - "!packages/*/uv.lock" + - "!packages/*/pyproject.toml" push: branches: - "main" @@ -37,7 +44,13 @@ on: - "!flake.nix" - "!flake.lock" - "!pyproject.toml" + - "!justfile" - "!packages/*/uv.lock" + - "!packages/*/pyproject.toml" + +concurrency: + group: ci-${{ github.event.pull_request.number || github.ref }} + cancel-in-progress: true defaults: run: @@ -58,8 +71,16 @@ jobs: - name: Checkout uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # ratchet:actions/checkout@v4 with: - fetch-depth: 0 # fetch all history so multiple commits can be scanned + fetch-depth: 0 + + - name: Check execution cache + id: cache + uses: ./.github/actions/cached-ci-job + with: + force-run: ${{ inputs.force_run || 'false' }} + - name: GitGuardian scan + if: steps.cache.outputs.should-run == 'true' uses: GitGuardian/ggshield-action@455483042671cc73b40d0e753baddffef7309a1f # ratchet:GitGuardian/ggshield-action@v1.37.0 env: GITHUB_PUSH_BEFORE_SHA: ${{ github.event.before }} @@ -68,6 +89,19 @@ jobs: GITHUB_DEFAULT_BRANCH: ${{ github.event.repository.default_branch }} GITGUARDIAN_API_KEY: ${{ secrets.GITGUARDIAN_API_KEY }} + - name: Create job result marker + if: success() && steps.cache.outputs.should-run == 'true' && steps.cache.outputs.cache-source == 'none' + run: | + mkdir -p "${{ steps.cache.outputs.cache-path }}" + echo '{"success":true}' > "${{ steps.cache.outputs.cache-path }}/marker" + + - name: Save execution cache + if: success() && steps.cache.outputs.should-run == 'true' && steps.cache.outputs.cache-source == 'none' + uses: actions/cache/save@5a3ec84eff668545956fd18022155c47e93e2684 # ratchet:actions/cache/save@v4 + with: + path: ${{ steps.cache.outputs.cache-path }} + key: ${{ steps.cache.outputs.cache-key }} + set-variables: needs: scan runs-on: ubuntu-latest @@ -79,13 +113,16 @@ jobs: checkout_ref: ${{ steps.set-variables.outputs.checkout_ref }} checkout_rev: ${{ steps.set-variables.outputs.checkout_rev }} has_docs: ${{ steps.check-docs.outputs.has_docs }} + packages: ${{ steps.discover-packages.outputs.packages }} steps: - - name: Checkout for docs check + - name: Checkout for discovery uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # ratchet:actions/checkout@v4 with: sparse-checkout: | docs + packages + justfile sparse-checkout-cone-mode: false - name: Check if docs exist @@ -93,10 +130,8 @@ jobs: run: | if [ -d "docs" ] && [ "$(ls -A docs 2>/dev/null)" ]; then echo "has_docs=true" >> $GITHUB_OUTPUT - echo "Documentation directory exists and is not empty" else echo "has_docs=false" >> $GITHUB_OUTPUT - echo "Documentation directory does not exist or is empty" fi - name: Set action variables @@ -131,18 +166,23 @@ jobs: CHECKOUT_REV="${{ github.sha }}" fi - echo "DEBUG=$DEBUG" - echo "SKIP_CI=$SKIP_CI" - echo "SKIP_TESTS=$SKIP_TESTS" - echo "CHECKOUT_REF=$CHECKOUT_REF" - echo "CHECKOUT_REV=$CHECKOUT_REV" + echo "debug=$DEBUG" >> $GITHUB_OUTPUT + echo "skip_ci=$SKIP_CI" >> $GITHUB_OUTPUT + echo "skip_tests=$SKIP_TESTS" >> $GITHUB_OUTPUT + echo "dry_run_release=$DRY_RUN_RELEASE" >> $GITHUB_OUTPUT + echo "checkout_ref=$CHECKOUT_REF" >> $GITHUB_OUTPUT + echo "checkout_rev=$CHECKOUT_REV" >> $GITHUB_OUTPUT - echo "DEBUG=$DEBUG" >> $GITHUB_OUTPUT - echo "SKIP_CI=$SKIP_CI" >> $GITHUB_OUTPUT - echo "SKIP_TESTS=$SKIP_TESTS" >> $GITHUB_OUTPUT - echo "DRY_RUN_RELEASE=$DRY_RUN_RELEASE" >> $GITHUB_OUTPUT - echo "CHECKOUT_REF=$CHECKOUT_REF" >> $GITHUB_OUTPUT - echo "CHECKOUT_REV=$CHECKOUT_REV" >> $GITHUB_OUTPUT + - name: Discover packages + id: discover-packages + run: | + PACKAGES=$(ls -d packages/*/pyproject.toml | while read f; do + d=$(dirname "$f") + n=$(basename "$d") + printf '{"name":"%s","path":"%s"}\n' "$n" "$d" + done | jq -sc '.') + echo "packages=$PACKAGES" >> $GITHUB_OUTPUT + echo "Discovered packages: $PACKAGES" preview-docs: needs: set-variables @@ -160,77 +200,85 @@ jobs: secrets: inherit nixci: - runs-on: ${{ matrix.os }} - strategy: - matrix: - os: [ - ubuntu-latest, - # macos-latest - ] + runs-on: ubuntu-latest needs: set-variables if: ${{ needs.set-variables.outputs.skip_ci != 'true' }} concurrency: group: nixci-${{ github.workflow }}-${{ github.event_name == 'pull_request' && github.event.pull_request.number || github.ref_name }} cancel-in-progress: true steps: + - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # ratchet:actions/checkout@v4 + + - name: Check execution cache + id: cache + uses: ./.github/actions/cached-ci-job + with: + hash-sources: '**/*.nix flake.lock justfile packages/*/pyproject.toml packages/*/uv.lock' + force-run: ${{ inputs.force_run || 'false' }} + - name: Install dependencies - shell: bash + if: steps.cache.outputs.should-run == 'true' run: | sudo apt-get update sudo apt-get install -yq zstd sudo apt-get clean - - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # ratchet:actions/checkout@v4 + - name: Install Nix + if: steps.cache.outputs.should-run == 'true' uses: DeterminateSystems/nix-installer-action@786fff0690178f1234e4e1fe9b536e94f5433196 # ratchet:DeterminateSystems/nix-installer-action@main with: extra-conf: "system-features = nixos-test benchmark big-parallel kvm" - # - name: Install Nix - # uses: nixbuild/nix-quick-install-action@v33 - # with: - # nix_conf: "system-features = nixos-test benchmark big-parallel kvm" + - name: Setup remote cache - # TODO: disable continue-on-error https://www.github.com/cachix/cachix-action/issues/200 + if: steps.cache.outputs.should-run == 'true' uses: cachix/cachix-action@be5295a636153b6ad194d3245f78f8e0b78dc704 # ratchet:cachix/cachix-action@master continue-on-error: true with: name: "${{ vars.CACHIX_CACHE_NAME }}" authToken: "${{ secrets.CACHIX_AUTH_TOKEN }}" extraPullNames: nix-community,pyproject-nix,sciexp,srid + - name: Setup tmate debug session + if: steps.cache.outputs.should-run == 'true' && needs.set-variables.outputs.debug == 'true' uses: mxschmitt/action-tmate@e5c7151931ca95bad1c6f4190c730ecf8c7dde48 # ratchet:mxschmitt/action-tmate@v3 - if: ${{ inputs.debug_enabled }} + - name: Install omnix + if: steps.cache.outputs.should-run == 'true' run: nix --accept-flake-config profile install "github:juspay/omnix" - - name: Summarize flake - run: om show . + - name: Run flake CI + if: steps.cache.outputs.should-run == 'true' + run: om ci run + + - name: Create job result marker + if: success() && steps.cache.outputs.should-run == 'true' && steps.cache.outputs.cache-source == 'none' run: | - om ci run + mkdir -p "${{ steps.cache.outputs.cache-path }}" + echo '{"success":true}' > "${{ steps.cache.outputs.cache-path }}/marker" + + - name: Save execution cache + if: success() && steps.cache.outputs.should-run == 'true' && steps.cache.outputs.cache-source == 'none' + uses: actions/cache/save@5a3ec84eff668545956fd18022155c47e93e2684 # ratchet:actions/cache/save@v4 + with: + path: ${{ steps.cache.outputs.cache-path }} + key: ${{ steps.cache.outputs.cache-key }} test-python: needs: [set-variables] if: ${{ needs.set-variables.outputs.skip_ci != 'true' && needs.set-variables.outputs.skip_tests != 'true' }} concurrency: - group: test-python-${{ matrix.config.python-version }}-${{ matrix.config.package-name }}-${{ github.workflow }}-${{ github.event_name == 'pull_request' && github.event.pull_request.number || github.ref_name }} + group: test-python-${{ matrix.package.name }}-${{ github.workflow }}-${{ github.event_name == 'pull_request' && github.event.pull_request.number || github.ref_name }} cancel-in-progress: true strategy: fail-fast: false matrix: - config: - - python-version: "3.11" - package-name: "python-nix-template" - - python-version: "3.12" - package-name: "python-nix-template" - - python-version: "3.11" - package-name: "pnt-functional" - - python-version: "3.12" - package-name: "pnt-functional" + package: ${{ fromJson(needs.set-variables.outputs.packages) }} uses: ./.github/workflows/python-test.yaml with: - python-version: ${{ matrix.config.python-version }} - package-name: ${{ matrix.config.package-name }} + package-name: ${{ matrix.package.name }} debug_enabled: ${{ needs.set-variables.outputs.debug }} checkout_ref: ${{ needs.set-variables.outputs.checkout_ref }} + force_run: ${{ inputs.force_run && 'true' || 'false' }} secrets: inherit test-release-packages: @@ -245,11 +293,7 @@ jobs: strategy: fail-fast: false matrix: - package: - - name: python-nix-template - path: "packages/python-nix-template" - - name: pnt-functional - path: packages/pnt-functional + package: ${{ fromJson(needs.set-variables.outputs.packages) }} uses: ./.github/workflows/package-release.yaml with: package-path: ${{ matrix.package.path }} @@ -270,8 +314,6 @@ jobs: id-token: write packages: write strategy: - # NOTE: this is only necessary if releases commit to the repository - # max-parallel: 1 matrix: package: - name: python-nix-template From 99086e83d24c577c2bc8865f2ea2d6e096ef1ae3 Mon Sep 17 00:00:00 2001 From: Cameron Smith Date: Mon, 2 Feb 2026 15:55:31 -0500 Subject: [PATCH 044/134] chore(issues): close pnt-dre.4, cached-ci-job and CI redesign complete --- .beads/issues.jsonl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.beads/issues.jsonl b/.beads/issues.jsonl index 72e0aa2..b131010 100644 --- a/.beads/issues.jsonl +++ b/.beads/issues.jsonl @@ -10,5 +10,5 @@ {"id":"pnt-dre.1","title":"Refactor Makefile to bootstrap-only pattern","description":"Restrict Makefile to bootstrap targets only: install-nix, install-direnv, verify, setup-user, check-secrets, clean. Move all other targets to justfile.","status":"closed","priority":2,"issue_type":"task","owner":"cameron.ray.smith@gmail.com","created_at":"2026-01-19T11:54:54.237851-05:00","created_by":"Cameron Smith","updated_at":"2026-02-02T15:39:45.088007-05:00","closed_at":"2026-02-02T15:39:45.088007-05:00","close_reason":"Added verify, setup-user, check-secrets targets aligned with vanixiets. Updated bootstrap output with numbered next-steps. Makefile was already bootstrap-only; no targets removed.","dependencies":[{"issue_id":"pnt-dre.1","depends_on_id":"pnt-dre","type":"parent-child","created_at":"2026-01-19T11:54:54.238477-05:00","created_by":"Cameron Smith"}]} {"id":"pnt-dre.2","title":"Adopt grouped justfile recipe pattern","description":"Reorganize justfile with grouped recipes and section headers following vanixiets pattern: nix, python, conda, docs, secrets, ci/cd groups. Add help comments for each recipe.","status":"closed","priority":2,"issue_type":"task","owner":"cameron.ray.smith@gmail.com","created_at":"2026-01-19T11:54:55.145094-05:00","created_by":"Cameron Smith","updated_at":"2026-02-02T15:42:24.899403-05:00","closed_at":"2026-02-02T15:42:24.899403-05:00","close_reason":"Aligned group naming (conda package→conda, python package→python), fixed Documentation→Docs header, demoted GCP sub-section, corrected type recipe comment, moved helper to EOF.","dependencies":[{"issue_id":"pnt-dre.2","depends_on_id":"pnt-dre","type":"parent-child","created_at":"2026-01-19T11:54:55.145764-05:00","created_by":"Cameron Smith"}]} {"id":"pnt-dre.3","title":"Reorganize scripts/ directory structure","description":"Move scripts into subdirectories: scripts/ci/, scripts/docs/, scripts/sops/. IMPORTANT: scripts/bootstrap.sh must remain at stable path for curl one-liner URL. Update justfile and CI references.","status":"closed","priority":2,"issue_type":"task","owner":"cameron.ray.smith@gmail.com","created_at":"2026-01-19T11:54:55.839371-05:00","created_by":"Cameron Smith","updated_at":"2026-02-02T15:45:23.076616-05:00","closed_at":"2026-02-02T15:45:23.076616-05:00","close_reason":"Created scripts/bootstrap.sh (stable URL for curl one-liner) and scripts/ci/maximize-build-space.sh (canonical version of duplicated CI logic). Workflow inline references deferred to pnt-dre.4 CI redesign due to pre-checkout step ordering. scripts/sops/ and scripts/docs/ skipped — no duplication issues warranting extraction.","dependencies":[{"issue_id":"pnt-dre.3","depends_on_id":"pnt-dre","type":"parent-child","created_at":"2026-01-19T11:54:55.839951-05:00","created_by":"Cameron Smith"}]} -{"id":"pnt-dre.4","title":"Implement cached-ci-job composite action pattern","description":"Add .github/actions/cached-ci-job composite action following typescript-nix-template pattern. Content-addressed caching with hash-sources and force-run support. Update CI to use category-based matrix builds.\n\nPost-federation CI adaptation: the migration from uv workspace to per-package independent locks (pnt-4jg.1) means CI must now discover and iterate packages under packages/. The matrix strategy needs a package axis in addition to the category axis, producing either a {package} x {category} matrix or per-package reusable workflow dispatches. Review how ci.yaml currently enumerates packages and ensure the composite action pattern supports per-package resolution of lock files, dependency caches, and build artifacts.\n\nAcceptance criteria:\n- .github/actions/cached-ci-job composite action implemented\n- Content-addressed caching with hash-sources and force-run support\n- CI matrix discovers packages/ dynamically (not hardcoded)\n- Matrix crosses package x category dimensions\n- Per-package uv.lock files used for cache keys (not root lock)\n- Category-based builds follow typescript-nix-template pattern","status":"open","priority":2,"issue_type":"task","owner":"cameron.ray.smith@gmail.com","created_at":"2026-01-19T11:54:56.79376-05:00","created_by":"Cameron Smith","updated_at":"2026-02-02T14:45:33.154802-05:00","dependencies":[{"issue_id":"pnt-dre.4","depends_on_id":"pnt-dre","type":"parent-child","created_at":"2026-01-19T11:54:56.794334-05:00","created_by":"Cameron Smith"}],"comments":[{"id":2,"issue_id":"pnt-dre.4","author":"Cameron Smith","text":"Minimal CI path fixes applied in d0cab2a as part of pnt-4jg.1 fixups: cache-dependency-glob updated to packages/*/uv.lock, uv sync/lint/test moved into per-package working-directory, ci.yaml path filters updated.\n\nRemaining for pnt-dre.4: replace setup-python/setup-uv actions with nix develop -c just \u003crecipe\u003e pattern, add justfile recipes for per-package sync/test/lint/typecheck, implement cached-ci-job composite action, dynamic package discovery.","created_at":"2026-02-02T20:17:02Z"}]} +{"id":"pnt-dre.4","title":"Implement cached-ci-job composite action pattern","description":"Add .github/actions/cached-ci-job composite action following typescript-nix-template pattern. Content-addressed caching with hash-sources and force-run support. Update CI to use category-based matrix builds.\n\nPost-federation CI adaptation: the migration from uv workspace to per-package independent locks (pnt-4jg.1) means CI must now discover and iterate packages under packages/. The matrix strategy needs a package axis in addition to the category axis, producing either a {package} x {category} matrix or per-package reusable workflow dispatches. Review how ci.yaml currently enumerates packages and ensure the composite action pattern supports per-package resolution of lock files, dependency caches, and build artifacts.\n\nAcceptance criteria:\n- .github/actions/cached-ci-job composite action implemented\n- Content-addressed caching with hash-sources and force-run support\n- CI matrix discovers packages/ dynamically (not hardcoded)\n- Matrix crosses package x category dimensions\n- Per-package uv.lock files used for cache keys (not root lock)\n- Category-based builds follow typescript-nix-template pattern","status":"closed","priority":2,"issue_type":"task","owner":"cameron.ray.smith@gmail.com","created_at":"2026-01-19T11:54:56.79376-05:00","created_by":"Cameron Smith","updated_at":"2026-02-02T15:55:30.748155-05:00","closed_at":"2026-02-02T15:55:30.748155-05:00","close_reason":"Implemented cached-ci-job composite action (ported from typescript-nix-template), per-package CI justfile recipes (ci-sync, ci-lint, ci-test, ci-typecheck, ci-check, list-packages-json), rewrote python-test.yaml to use nix develop -c just \u003crecipe\u003e, added dynamic package discovery and force_run to ci.yaml. All CI steps expressible as nix develop -c just \u003crecipe\u003e.","dependencies":[{"issue_id":"pnt-dre.4","depends_on_id":"pnt-dre","type":"parent-child","created_at":"2026-01-19T11:54:56.794334-05:00","created_by":"Cameron Smith"}],"comments":[{"id":2,"issue_id":"pnt-dre.4","author":"Cameron Smith","text":"Minimal CI path fixes applied in d0cab2a as part of pnt-4jg.1 fixups: cache-dependency-glob updated to packages/*/uv.lock, uv sync/lint/test moved into per-package working-directory, ci.yaml path filters updated.\n\nRemaining for pnt-dre.4: replace setup-python/setup-uv actions with nix develop -c just \u003crecipe\u003e pattern, add justfile recipes for per-package sync/test/lint/typecheck, implement cached-ci-job composite action, dynamic package discovery.","created_at":"2026-02-02T20:17:02Z"}]} {"id":"pnt-dre.5","title":"Add omnix template integration","description":"Configure om.templates in flake with parameter definitions. Add template-verify justfile recipe. Create .github/workflows/template.yaml for CI validation.","status":"open","priority":2,"issue_type":"task","owner":"cameron.ray.smith@gmail.com","created_at":"2026-01-19T11:54:57.668262-05:00","created_by":"Cameron Smith","updated_at":"2026-01-19T11:54:57.668262-05:00","dependencies":[{"issue_id":"pnt-dre.5","depends_on_id":"pnt-dre","type":"parent-child","created_at":"2026-01-19T11:54:57.66888-05:00","created_by":"Cameron Smith"}]} From f9abbf50b3a0adb079160fc1d8c00406947840d0 Mon Sep 17 00:00:00 2001 From: Cameron Smith Date: Mon, 2 Feb 2026 15:56:10 -0500 Subject: [PATCH 045/134] fix(ci): update template workflow path filters for per-package locks Replaces stale !uv.lock with per-package patterns and adds justfile and packages/*/pyproject.toml triggers. --- .github/workflows/template.yaml | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/.github/workflows/template.yaml b/.github/workflows/template.yaml index c784c46..116ccb1 100644 --- a/.github/workflows/template.yaml +++ b/.github/workflows/template.yaml @@ -21,7 +21,9 @@ on: - "!flake.nix" - "!flake.lock" - "!pyproject.toml" - - "!uv.lock" + - "!justfile" + - "!packages/*/uv.lock" + - "!packages/*/pyproject.toml" push: branches: - "main" @@ -32,7 +34,9 @@ on: - "!flake.nix" - "!flake.lock" - "!pyproject.toml" - - "!uv.lock" + - "!justfile" + - "!packages/*/uv.lock" + - "!packages/*/pyproject.toml" defaults: run: From c45dd26b3b8e7f16f032a80062340678c565264e Mon Sep 17 00:00:00 2001 From: Cameron Smith Date: Mon, 2 Feb 2026 15:56:27 -0500 Subject: [PATCH 046/134] chore(issues): close pnt-dre.5 and pnt-dre epic, infrastructure alignment complete --- .beads/issues.jsonl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.beads/issues.jsonl b/.beads/issues.jsonl index b131010..a2fd64e 100644 --- a/.beads/issues.jsonl +++ b/.beads/issues.jsonl @@ -6,9 +6,9 @@ {"id":"pnt-btz.1","title":"Create pnt-cli package scaffold with Rust crates","description":"Create packages/pnt-cli/ with federated structure:\n\nDirectory structure:\n- packages/pnt-cli/pyproject.toml (maturin build-backend, manifest-path binding)\n- packages/pnt-cli/src/pnt_cli/__init__.py (Python wrapper)\n- packages/pnt-cli/crates/Cargo.toml ([workspace] with member crates)\n- packages/pnt-cli/crates/pnt-cli-core/Cargo.toml (pure Rust library)\n- packages/pnt-cli/crates/pnt-cli-py/Cargo.toml (pyo3 bindings, depends on core)\n\npyproject.toml configuration:\n- [build-system] requires maturin\u003e=1.5\n- [tool.maturin] manifest-path = \"crates/pnt-cli-py/Cargo.toml\"\n- [tool.maturin] module-name = \"pnt_cli._native\"\n\nMinimal proof-of-concept: expose a simple function from Rust to Python.\n\nSee: docs/notes/architecture/crane-uv2nix-integration.md\n","status":"open","priority":2,"issue_type":"task","owner":"cameron.ray.smith@gmail.com","created_at":"2026-01-19T11:55:17.885691-05:00","created_by":"Cameron Smith","updated_at":"2026-01-28T14:43:57.882216-05:00","dependencies":[{"issue_id":"pnt-btz.1","depends_on_id":"pnt-btz","type":"parent-child","created_at":"2026-01-19T11:55:17.886287-05:00","created_by":"Cameron Smith"},{"issue_id":"pnt-btz.1","depends_on_id":"pnt-4jg.1","type":"blocks","created_at":"2026-01-19T12:20:18.940008-05:00","created_by":"Cameron Smith"}]} {"id":"pnt-btz.2","title":"Implement crane + uv2nix Nix modules","description":"Create Nix modules implementing the crane + uv2nix integration pattern.\n\nFiles to create:\n- nix/packages/pnt-cli/rust.nix (crane configuration)\n- nix/packages/pnt-cli/default.nix (Python + Rust composition)\n- nix/modules/rust/lib.nix (shared crane utilities, optional)\n\nrust.nix pattern:\n- crane-lib.buildDepsOnly for cargoArtifacts caching\n- commonArgs pattern for derivation hash consistency\n- crane-lib.vendorCargoDeps for maturin's cargo invocation\n- Export cargoArtifacts, cargoVendorDir, clippy, nextest\n\ndefault.nix pattern:\n- Import rust.nix\n- Create overlay injecting cargoVendorDir and CARGO_TARGET_DIR\n- Export overlay and checks for flake composition\n\nUpdate nix/modules/python.nix:\n- Load pnt-cli workspace independently (federated pattern)\n- Compose Rust overlay with uv2nix overlays\n\nSee: docs/notes/architecture/crane-uv2nix-integration.md\n","status":"open","priority":2,"issue_type":"task","owner":"cameron.ray.smith@gmail.com","created_at":"2026-01-19T11:55:18.885252-05:00","created_by":"Cameron Smith","updated_at":"2026-01-28T14:43:58.112357-05:00","dependencies":[{"issue_id":"pnt-btz.2","depends_on_id":"pnt-btz","type":"parent-child","created_at":"2026-01-19T11:55:18.885818-05:00","created_by":"Cameron Smith"},{"issue_id":"pnt-btz.2","depends_on_id":"pnt-btz.1","type":"blocks","created_at":"2026-01-19T12:20:08.210077-05:00","created_by":"Cameron Smith"}]} {"id":"pnt-btz.3","title":"Validate integration and update CI","description":"Validate the full crane + uv2nix + maturin integration and update CI.\n\nValidation checklist:\n- [ ] nix build .#pnt-cli produces working wheel\n- [ ] Python import succeeds: from pnt_cli._native import ...\n- [ ] Rust changes trigger minimal rebuilds (cargoArtifacts cached)\n- [ ] Python-only changes don't rebuild Rust\n- [ ] cargoClippy and cargoNextest checks pass\n\nCI updates (.github/workflows/ci.yaml):\n- Add rust-deps matrix category for cargoArtifacts caching\n- Add rust-checks matrix category for clippy/nextest\n- Ensure proper cache key based on Cargo.lock hash\n- Follow ironstar CI matrix pattern\n\nDocumentation updates:\n- Add usage example to README\n- Document development workflow (uv sync + maturin develop vs nix build)\n- Note editable install limitations\n\nSee: docs/notes/architecture/crane-uv2nix-integration.md\n","status":"open","priority":2,"issue_type":"task","owner":"cameron.ray.smith@gmail.com","created_at":"2026-01-19T11:55:19.746622-05:00","created_by":"Cameron Smith","updated_at":"2026-01-28T14:43:58.351336-05:00","dependencies":[{"issue_id":"pnt-btz.3","depends_on_id":"pnt-btz","type":"parent-child","created_at":"2026-01-19T11:55:19.74722-05:00","created_by":"Cameron Smith"},{"issue_id":"pnt-btz.3","depends_on_id":"pnt-btz.2","type":"blocks","created_at":"2026-01-19T12:20:11.013516-05:00","created_by":"Cameron Smith"}]} -{"id":"pnt-dre","title":"Infrastructure alignment","description":"Align Makefile, justfile, scripts/, and CI with vanixiets and typescript-nix-template patterns. Makefile bootstrap-only, grouped justfile recipes, cached-ci-job CI pattern, omnix template integration.","status":"open","priority":2,"issue_type":"epic","owner":"cameron.ray.smith@gmail.com","created_at":"2026-01-19T11:54:39.841346-05:00","created_by":"Cameron Smith","updated_at":"2026-01-19T11:54:39.841346-05:00"} +{"id":"pnt-dre","title":"Infrastructure alignment","description":"Align Makefile, justfile, scripts/, and CI with vanixiets and typescript-nix-template patterns. Makefile bootstrap-only, grouped justfile recipes, cached-ci-job CI pattern, omnix template integration.","status":"closed","priority":2,"issue_type":"epic","owner":"cameron.ray.smith@gmail.com","created_at":"2026-01-19T11:54:39.841346-05:00","created_by":"Cameron Smith","updated_at":"2026-02-02T15:56:26.823947-05:00","closed_at":"2026-02-02T15:56:26.823947-05:00","close_reason":"All children closed: pnt-dre.1 (Makefile), pnt-dre.2 (justfile), pnt-dre.3 (scripts), pnt-dre.4 (cached-ci-job/CI), pnt-dre.5 (omnix template). Infrastructure alignment complete."} {"id":"pnt-dre.1","title":"Refactor Makefile to bootstrap-only pattern","description":"Restrict Makefile to bootstrap targets only: install-nix, install-direnv, verify, setup-user, check-secrets, clean. Move all other targets to justfile.","status":"closed","priority":2,"issue_type":"task","owner":"cameron.ray.smith@gmail.com","created_at":"2026-01-19T11:54:54.237851-05:00","created_by":"Cameron Smith","updated_at":"2026-02-02T15:39:45.088007-05:00","closed_at":"2026-02-02T15:39:45.088007-05:00","close_reason":"Added verify, setup-user, check-secrets targets aligned with vanixiets. Updated bootstrap output with numbered next-steps. Makefile was already bootstrap-only; no targets removed.","dependencies":[{"issue_id":"pnt-dre.1","depends_on_id":"pnt-dre","type":"parent-child","created_at":"2026-01-19T11:54:54.238477-05:00","created_by":"Cameron Smith"}]} {"id":"pnt-dre.2","title":"Adopt grouped justfile recipe pattern","description":"Reorganize justfile with grouped recipes and section headers following vanixiets pattern: nix, python, conda, docs, secrets, ci/cd groups. Add help comments for each recipe.","status":"closed","priority":2,"issue_type":"task","owner":"cameron.ray.smith@gmail.com","created_at":"2026-01-19T11:54:55.145094-05:00","created_by":"Cameron Smith","updated_at":"2026-02-02T15:42:24.899403-05:00","closed_at":"2026-02-02T15:42:24.899403-05:00","close_reason":"Aligned group naming (conda package→conda, python package→python), fixed Documentation→Docs header, demoted GCP sub-section, corrected type recipe comment, moved helper to EOF.","dependencies":[{"issue_id":"pnt-dre.2","depends_on_id":"pnt-dre","type":"parent-child","created_at":"2026-01-19T11:54:55.145764-05:00","created_by":"Cameron Smith"}]} {"id":"pnt-dre.3","title":"Reorganize scripts/ directory structure","description":"Move scripts into subdirectories: scripts/ci/, scripts/docs/, scripts/sops/. IMPORTANT: scripts/bootstrap.sh must remain at stable path for curl one-liner URL. Update justfile and CI references.","status":"closed","priority":2,"issue_type":"task","owner":"cameron.ray.smith@gmail.com","created_at":"2026-01-19T11:54:55.839371-05:00","created_by":"Cameron Smith","updated_at":"2026-02-02T15:45:23.076616-05:00","closed_at":"2026-02-02T15:45:23.076616-05:00","close_reason":"Created scripts/bootstrap.sh (stable URL for curl one-liner) and scripts/ci/maximize-build-space.sh (canonical version of duplicated CI logic). Workflow inline references deferred to pnt-dre.4 CI redesign due to pre-checkout step ordering. scripts/sops/ and scripts/docs/ skipped — no duplication issues warranting extraction.","dependencies":[{"issue_id":"pnt-dre.3","depends_on_id":"pnt-dre","type":"parent-child","created_at":"2026-01-19T11:54:55.839951-05:00","created_by":"Cameron Smith"}]} {"id":"pnt-dre.4","title":"Implement cached-ci-job composite action pattern","description":"Add .github/actions/cached-ci-job composite action following typescript-nix-template pattern. Content-addressed caching with hash-sources and force-run support. Update CI to use category-based matrix builds.\n\nPost-federation CI adaptation: the migration from uv workspace to per-package independent locks (pnt-4jg.1) means CI must now discover and iterate packages under packages/. The matrix strategy needs a package axis in addition to the category axis, producing either a {package} x {category} matrix or per-package reusable workflow dispatches. Review how ci.yaml currently enumerates packages and ensure the composite action pattern supports per-package resolution of lock files, dependency caches, and build artifacts.\n\nAcceptance criteria:\n- .github/actions/cached-ci-job composite action implemented\n- Content-addressed caching with hash-sources and force-run support\n- CI matrix discovers packages/ dynamically (not hardcoded)\n- Matrix crosses package x category dimensions\n- Per-package uv.lock files used for cache keys (not root lock)\n- Category-based builds follow typescript-nix-template pattern","status":"closed","priority":2,"issue_type":"task","owner":"cameron.ray.smith@gmail.com","created_at":"2026-01-19T11:54:56.79376-05:00","created_by":"Cameron Smith","updated_at":"2026-02-02T15:55:30.748155-05:00","closed_at":"2026-02-02T15:55:30.748155-05:00","close_reason":"Implemented cached-ci-job composite action (ported from typescript-nix-template), per-package CI justfile recipes (ci-sync, ci-lint, ci-test, ci-typecheck, ci-check, list-packages-json), rewrote python-test.yaml to use nix develop -c just \u003crecipe\u003e, added dynamic package discovery and force_run to ci.yaml. All CI steps expressible as nix develop -c just \u003crecipe\u003e.","dependencies":[{"issue_id":"pnt-dre.4","depends_on_id":"pnt-dre","type":"parent-child","created_at":"2026-01-19T11:54:56.794334-05:00","created_by":"Cameron Smith"}],"comments":[{"id":2,"issue_id":"pnt-dre.4","author":"Cameron Smith","text":"Minimal CI path fixes applied in d0cab2a as part of pnt-4jg.1 fixups: cache-dependency-glob updated to packages/*/uv.lock, uv sync/lint/test moved into per-package working-directory, ci.yaml path filters updated.\n\nRemaining for pnt-dre.4: replace setup-python/setup-uv actions with nix develop -c just \u003crecipe\u003e pattern, add justfile recipes for per-package sync/test/lint/typecheck, implement cached-ci-job composite action, dynamic package discovery.","created_at":"2026-02-02T20:17:02Z"}]} -{"id":"pnt-dre.5","title":"Add omnix template integration","description":"Configure om.templates in flake with parameter definitions. Add template-verify justfile recipe. Create .github/workflows/template.yaml for CI validation.","status":"open","priority":2,"issue_type":"task","owner":"cameron.ray.smith@gmail.com","created_at":"2026-01-19T11:54:57.668262-05:00","created_by":"Cameron Smith","updated_at":"2026-01-19T11:54:57.668262-05:00","dependencies":[{"issue_id":"pnt-dre.5","depends_on_id":"pnt-dre","type":"parent-child","created_at":"2026-01-19T11:54:57.66888-05:00","created_by":"Cameron Smith"}]} +{"id":"pnt-dre.5","title":"Add omnix template integration","description":"Configure om.templates in flake with parameter definitions. Add template-verify justfile recipe. Create .github/workflows/template.yaml for CI validation.","status":"closed","priority":2,"issue_type":"task","owner":"cameron.ray.smith@gmail.com","created_at":"2026-01-19T11:54:57.668262-05:00","created_by":"Cameron Smith","updated_at":"2026-02-02T15:56:15.624906-05:00","closed_at":"2026-02-02T15:56:15.624906-05:00","close_reason":"om.templates, template-verify recipe, and template.yaml workflow already existed. Fixed stale path-ignore filters for per-package lock pattern.","dependencies":[{"issue_id":"pnt-dre.5","depends_on_id":"pnt-dre","type":"parent-child","created_at":"2026-01-19T11:54:57.66888-05:00","created_by":"Cameron Smith"}]} From 73cfc63c30aaf4f7916ae114f5424c19fd11f558 Mon Sep 17 00:00:00 2001 From: Cameron Smith Date: Mon, 2 Feb 2026 20:24:15 -0500 Subject: [PATCH 047/134] feat(issues): add setup-nix and nix2container migration tasks --- .beads/issues.jsonl | 1 + 1 file changed, 1 insertion(+) diff --git a/.beads/issues.jsonl b/.beads/issues.jsonl index a2fd64e..f35e52d 100644 --- a/.beads/issues.jsonl +++ b/.beads/issues.jsonl @@ -12,3 +12,4 @@ {"id":"pnt-dre.3","title":"Reorganize scripts/ directory structure","description":"Move scripts into subdirectories: scripts/ci/, scripts/docs/, scripts/sops/. IMPORTANT: scripts/bootstrap.sh must remain at stable path for curl one-liner URL. Update justfile and CI references.","status":"closed","priority":2,"issue_type":"task","owner":"cameron.ray.smith@gmail.com","created_at":"2026-01-19T11:54:55.839371-05:00","created_by":"Cameron Smith","updated_at":"2026-02-02T15:45:23.076616-05:00","closed_at":"2026-02-02T15:45:23.076616-05:00","close_reason":"Created scripts/bootstrap.sh (stable URL for curl one-liner) and scripts/ci/maximize-build-space.sh (canonical version of duplicated CI logic). Workflow inline references deferred to pnt-dre.4 CI redesign due to pre-checkout step ordering. scripts/sops/ and scripts/docs/ skipped — no duplication issues warranting extraction.","dependencies":[{"issue_id":"pnt-dre.3","depends_on_id":"pnt-dre","type":"parent-child","created_at":"2026-01-19T11:54:55.839951-05:00","created_by":"Cameron Smith"}]} {"id":"pnt-dre.4","title":"Implement cached-ci-job composite action pattern","description":"Add .github/actions/cached-ci-job composite action following typescript-nix-template pattern. Content-addressed caching with hash-sources and force-run support. Update CI to use category-based matrix builds.\n\nPost-federation CI adaptation: the migration from uv workspace to per-package independent locks (pnt-4jg.1) means CI must now discover and iterate packages under packages/. The matrix strategy needs a package axis in addition to the category axis, producing either a {package} x {category} matrix or per-package reusable workflow dispatches. Review how ci.yaml currently enumerates packages and ensure the composite action pattern supports per-package resolution of lock files, dependency caches, and build artifacts.\n\nAcceptance criteria:\n- .github/actions/cached-ci-job composite action implemented\n- Content-addressed caching with hash-sources and force-run support\n- CI matrix discovers packages/ dynamically (not hardcoded)\n- Matrix crosses package x category dimensions\n- Per-package uv.lock files used for cache keys (not root lock)\n- Category-based builds follow typescript-nix-template pattern","status":"closed","priority":2,"issue_type":"task","owner":"cameron.ray.smith@gmail.com","created_at":"2026-01-19T11:54:56.79376-05:00","created_by":"Cameron Smith","updated_at":"2026-02-02T15:55:30.748155-05:00","closed_at":"2026-02-02T15:55:30.748155-05:00","close_reason":"Implemented cached-ci-job composite action (ported from typescript-nix-template), per-package CI justfile recipes (ci-sync, ci-lint, ci-test, ci-typecheck, ci-check, list-packages-json), rewrote python-test.yaml to use nix develop -c just \u003crecipe\u003e, added dynamic package discovery and force_run to ci.yaml. All CI steps expressible as nix develop -c just \u003crecipe\u003e.","dependencies":[{"issue_id":"pnt-dre.4","depends_on_id":"pnt-dre","type":"parent-child","created_at":"2026-01-19T11:54:56.794334-05:00","created_by":"Cameron Smith"}],"comments":[{"id":2,"issue_id":"pnt-dre.4","author":"Cameron Smith","text":"Minimal CI path fixes applied in d0cab2a as part of pnt-4jg.1 fixups: cache-dependency-glob updated to packages/*/uv.lock, uv sync/lint/test moved into per-package working-directory, ci.yaml path filters updated.\n\nRemaining for pnt-dre.4: replace setup-python/setup-uv actions with nix develop -c just \u003crecipe\u003e pattern, add justfile recipes for per-package sync/test/lint/typecheck, implement cached-ci-job composite action, dynamic package discovery.","created_at":"2026-02-02T20:17:02Z"}]} {"id":"pnt-dre.5","title":"Add omnix template integration","description":"Configure om.templates in flake with parameter definitions. Add template-verify justfile recipe. Create .github/workflows/template.yaml for CI validation.","status":"closed","priority":2,"issue_type":"task","owner":"cameron.ray.smith@gmail.com","created_at":"2026-01-19T11:54:57.668262-05:00","created_by":"Cameron Smith","updated_at":"2026-02-02T15:56:15.624906-05:00","closed_at":"2026-02-02T15:56:15.624906-05:00","close_reason":"om.templates, template-verify recipe, and template.yaml workflow already existed. Fixed stale path-ignore filters for per-package lock pattern.","dependencies":[{"issue_id":"pnt-dre.5","depends_on_id":"pnt-dre","type":"parent-child","created_at":"2026-01-19T11:54:57.66888-05:00","created_by":"Cameron Smith"}]} +{"id":"pnt-m3t","title":"Adopt setup-nix composite action with nothing-but-nix pattern","description":"Port the vanixiets setup-nix composite action to python-nix-template, replacing inline Nix installation across all workflows.\n\nCurrent state:\n- ci.yaml, python-test.yaml, build-nix-images.yaml each inline DeterminateSystems/nix-installer-action\n- build-nix-images.yaml uses ad-hoc maximize-build-space shell script\n- scripts/ci/maximize-build-space.sh exists but is not wired into workflows\n\nTarget state (matching vanixiets):\n- .github/actions/setup-nix/action.yml composite action\n- Uses wimpysworld/nothing-but-nix for space reclamation (replaces maximize-build-space.sh)\n- Uses cachix/install-nix-action with pinned Nix version\n- Configures build-dir = /nix/build (nothing-but-nix workaround)\n- Integrates magic-nix-cache and cachix setup\n- Hatchet protocol support for configurable space levels\n- All workflows delegate Nix setup to this single action\n\nAcceptance criteria:\n- .github/actions/setup-nix/action.yml implemented (port from vanixiets)\n- ci.yaml nixci job uses setup-nix action\n- python-test.yaml uses setup-nix action\n- build-nix-images.yaml uses setup-nix action (replaces inline maximize-build-space)\n- .github/actions/build-nix-image/ updated (its Nix install steps replaced by setup-nix)\n- scripts/ci/maximize-build-space.sh removed (superseded by nothing-but-nix)\n- setup-python-uv action evaluated for removal (if all Python CI runs via nix develop)\n\nReference: ~/projects/nix-workspace/vanixiets/.github/actions/setup-nix/action.yml","status":"open","priority":2,"issue_type":"task","owner":"cameron.ray.smith@gmail.com","created_at":"2026-02-02T20:24:06.14337-05:00","created_by":"Cameron Smith","updated_at":"2026-02-02T20:24:06.14337-05:00"} From e91dbad0afead9519a3159dd22da7b218b5a8e8f Mon Sep 17 00:00:00 2001 From: Cameron Smith Date: Mon, 2 Feb 2026 20:29:47 -0500 Subject: [PATCH 048/134] chore: add Rust target/ to gitignore --- .gitignore | 3 + packages/pnt-cli/crates/Cargo.lock | 185 ++++++++++++++++++ packages/pnt-cli/crates/Cargo.toml | 17 ++ .../pnt-cli/crates/pnt-cli-core/Cargo.toml | 12 ++ .../pnt-cli/crates/pnt-cli-core/src/lib.rs | 24 +++ packages/pnt-cli/crates/pnt-cli-py/Cargo.toml | 16 ++ packages/pnt-cli/crates/pnt-cli-py/src/lib.rs | 21 ++ 7 files changed, 278 insertions(+) create mode 100644 packages/pnt-cli/crates/Cargo.lock create mode 100644 packages/pnt-cli/crates/Cargo.toml create mode 100644 packages/pnt-cli/crates/pnt-cli-core/Cargo.toml create mode 100644 packages/pnt-cli/crates/pnt-cli-core/src/lib.rs create mode 100644 packages/pnt-cli/crates/pnt-cli-py/Cargo.toml create mode 100644 packages/pnt-cli/crates/pnt-cli-py/src/lib.rs diff --git a/.gitignore b/.gitignore index 9fff26b..1f43abc 100644 --- a/.gitignore +++ b/.gitignore @@ -69,6 +69,9 @@ coverage.xml .uv/ .python-version +# Rust +target/ + # nix result result-* diff --git a/packages/pnt-cli/crates/Cargo.lock b/packages/pnt-cli/crates/Cargo.lock new file mode 100644 index 0000000..cf9d2d2 --- /dev/null +++ b/packages/pnt-cli/crates/Cargo.lock @@ -0,0 +1,185 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 4 + +[[package]] +name = "autocfg" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8" + +[[package]] +name = "cfg-if" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801" + +[[package]] +name = "heck" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" + +[[package]] +name = "indoc" +version = "2.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "79cf5c93f93228cf8efb3ba362535fb11199ac548a09ce117c9b1adc3030d706" +dependencies = [ + "rustversion", +] + +[[package]] +name = "libc" +version = "0.2.180" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bcc35a38544a891a5f7c865aca548a982ccb3b8650a5b06d0fd33a10283c56fc" + +[[package]] +name = "memoffset" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "488016bfae457b036d996092f6cb448677611ce4449e970ceaf42695203f218a" +dependencies = [ + "autocfg", +] + +[[package]] +name = "once_cell" +version = "1.21.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d" + +[[package]] +name = "pnt-cli-core" +version = "0.1.0" + +[[package]] +name = "pnt-cli-py" +version = "0.1.0" +dependencies = [ + "pnt-cli-core", + "pyo3", +] + +[[package]] +name = "portable-atomic" +version = "1.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c33a9471896f1c69cecef8d20cbe2f7accd12527ce60845ff44c153bb2a21b49" + +[[package]] +name = "proc-macro2" +version = "1.0.106" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8fd00f0bb2e90d81d1044c2b32617f68fcb9fa3bb7640c23e9c748e53fb30934" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "pyo3" +version = "0.23.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7778bffd85cf38175ac1f545509665d0b9b92a198ca7941f131f85f7a4f9a872" +dependencies = [ + "cfg-if", + "indoc", + "libc", + "memoffset", + "once_cell", + "portable-atomic", + "pyo3-build-config", + "pyo3-ffi", + "pyo3-macros", + "unindent", +] + +[[package]] +name = "pyo3-build-config" +version = "0.23.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94f6cbe86ef3bf18998d9df6e0f3fc1050a8c5efa409bf712e661a4366e010fb" +dependencies = [ + "once_cell", + "target-lexicon", +] + +[[package]] +name = "pyo3-ffi" +version = "0.23.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e9f1b4c431c0bb1c8fb0a338709859eed0d030ff6daa34368d3b152a63dfdd8d" +dependencies = [ + "libc", + "pyo3-build-config", +] + +[[package]] +name = "pyo3-macros" +version = "0.23.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fbc2201328f63c4710f68abdf653c89d8dbc2858b88c5d88b0ff38a75288a9da" +dependencies = [ + "proc-macro2", + "pyo3-macros-backend", + "quote", + "syn", +] + +[[package]] +name = "pyo3-macros-backend" +version = "0.23.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fca6726ad0f3da9c9de093d6f116a93c1a38e417ed73bf138472cf4064f72028" +dependencies = [ + "heck", + "proc-macro2", + "pyo3-build-config", + "quote", + "syn", +] + +[[package]] +name = "quote" +version = "1.0.44" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "21b2ebcf727b7760c461f091f9f0f539b77b8e87f2fd88131e7f1b433b3cece4" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "rustversion" +version = "1.0.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b39cdef0fa800fc44525c84ccb54a029961a8215f9619753635a9c0d2538d46d" + +[[package]] +name = "syn" +version = "2.0.114" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d4d107df263a3013ef9b1879b0df87d706ff80f65a86ea879bd9c31f9b307c2a" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "target-lexicon" +version = "0.12.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "61c41af27dd6d1e27b1b16b489db798443478cef1f06a660c96db617ba5de3b1" + +[[package]] +name = "unicode-ident" +version = "1.0.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9312f7c4f6ff9069b165498234ce8be658059c6728633667c526e27dc2cf1df5" + +[[package]] +name = "unindent" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7264e107f553ccae879d21fbea1d6724ac785e8c3bfc762137959b5802826ef3" diff --git a/packages/pnt-cli/crates/Cargo.toml b/packages/pnt-cli/crates/Cargo.toml new file mode 100644 index 0000000..ede42fc --- /dev/null +++ b/packages/pnt-cli/crates/Cargo.toml @@ -0,0 +1,17 @@ +[workspace] +resolver = "2" +members = ["pnt-cli-core", "pnt-cli-py"] + +[workspace.package] +version = "0.1.0" +edition = "2024" +license = "Apache-2.0" + +[workspace.lints.rust] +unsafe_code = "forbid" +rust_2018_idioms = { level = "warn", priority = -1 } +unused_qualifications = "warn" + +[workspace.lints.clippy] +panic = "warn" +unwrap_used = "warn" diff --git a/packages/pnt-cli/crates/pnt-cli-core/Cargo.toml b/packages/pnt-cli/crates/pnt-cli-core/Cargo.toml new file mode 100644 index 0000000..6bdbdb1 --- /dev/null +++ b/packages/pnt-cli/crates/pnt-cli-core/Cargo.toml @@ -0,0 +1,12 @@ +[package] +name = "pnt-cli-core" +version.workspace = true +edition.workspace = true +license.workspace = true + +[lib] +name = "pnt_cli_core" +path = "src/lib.rs" + +[lints] +workspace = true diff --git a/packages/pnt-cli/crates/pnt-cli-core/src/lib.rs b/packages/pnt-cli/crates/pnt-cli-core/src/lib.rs new file mode 100644 index 0000000..bec1495 --- /dev/null +++ b/packages/pnt-cli/crates/pnt-cli-core/src/lib.rs @@ -0,0 +1,24 @@ +/// Greet a user by name. +pub fn greet(name: &str) -> String { + format!("Hello, {name}! (from Rust)") +} + +/// Add two unsigned integers. +pub fn add(a: u64, b: u64) -> u64 { + a + b +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_greet() { + assert_eq!(greet("world"), "Hello, world! (from Rust)"); + } + + #[test] + fn test_add() { + assert_eq!(add(2, 3), 5); + } +} diff --git a/packages/pnt-cli/crates/pnt-cli-py/Cargo.toml b/packages/pnt-cli/crates/pnt-cli-py/Cargo.toml new file mode 100644 index 0000000..060ab48 --- /dev/null +++ b/packages/pnt-cli/crates/pnt-cli-py/Cargo.toml @@ -0,0 +1,16 @@ +[package] +name = "pnt-cli-py" +version.workspace = true +edition.workspace = true +license.workspace = true + +[lib] +name = "pnt_cli_native" +crate-type = ["cdylib"] + +[dependencies] +pnt-cli-core = { path = "../pnt-cli-core" } +pyo3 = { version = "0.23", features = ["extension-module"] } + +[lints] +workspace = true diff --git a/packages/pnt-cli/crates/pnt-cli-py/src/lib.rs b/packages/pnt-cli/crates/pnt-cli-py/src/lib.rs new file mode 100644 index 0000000..e0e8165 --- /dev/null +++ b/packages/pnt-cli/crates/pnt-cli-py/src/lib.rs @@ -0,0 +1,21 @@ +use pyo3::prelude::*; + +/// Greet a user by name, returning a string from Rust. +#[pyfunction] +fn greet(name: &str) -> String { + pnt_cli_core::greet(name) +} + +/// Add two unsigned integers. +#[pyfunction] +fn add(a: u64, b: u64) -> u64 { + pnt_cli_core::add(a, b) +} + +/// Native extension module for pnt-cli. +#[pymodule] +fn pnt_cli_native(m: &Bound<'_, PyModule>) -> PyResult<()> { + m.add_function(wrap_pyfunction!(greet, m)?)?; + m.add_function(wrap_pyfunction!(add, m)?)?; + Ok(()) +} From b33f576fbfdb1e550063af35aa46dc86980b8d6e Mon Sep 17 00:00:00 2001 From: Cameron Smith Date: Mon, 2 Feb 2026 20:30:00 -0500 Subject: [PATCH 049/134] feat(pnt-cli): add pyproject.toml with maturin build backend --- packages/pnt-cli/pyproject.toml | 77 +++++++++++++++++++++++++++++++++ 1 file changed, 77 insertions(+) create mode 100644 packages/pnt-cli/pyproject.toml diff --git a/packages/pnt-cli/pyproject.toml b/packages/pnt-cli/pyproject.toml new file mode 100644 index 0000000..2bcbaeb --- /dev/null +++ b/packages/pnt-cli/pyproject.toml @@ -0,0 +1,77 @@ +[project] +authors = [ + { name = "Your Name", email = "your.email@example.com" }, +] +classifiers = [ + "Development Status :: 3 - Alpha", + "License :: OSI Approved :: Apache Software License", + "Operating System :: OS Independent", + "Programming Language :: Python :: 3", + "Programming Language :: Python :: 3.11", + "Programming Language :: Python :: 3.12", + "Programming Language :: Rust", +] +dependencies = [] +description = "CLI package with Rust extension module via pyo3/maturin" +license = { text = "Apache-2.0" } +name = "pnt-cli" +readme = "README.md" +requires-python = ">=3.11,<3.13" +version = "0.1.0" + +[build-system] +build-backend = "maturin" +requires = ["maturin>=1.5,<2.0"] + +[tool.maturin] +features = ["pyo3/extension-module"] +manifest-path = "crates/pnt-cli-py/Cargo.toml" +module-name = "pnt_cli._native" +python-source = "src" + +[tool.uv.sources] +pnt-functional = { path = "../pnt-functional", editable = true } + +[dependency-groups] +dev = [ + { include-group = "lint" }, + { include-group = "test" }, + { include-group = "types" }, +] +lint = [ + "ruff>=0.9.4", +] +test = [ + "pytest>=8.3.4", +] +types = [ + "pyright>=1.1.395", +] + +[tool.uv] +default-groups = ["lint", "test", "types"] + +[tool.pytest.ini_options] +addopts = """ +-rA +--disable-warnings +--durations=0 +""" +log_level = "INFO" +testpaths = [ + "src/pnt_cli/tests", +] + +[tool.ruff] +line-length = 88 +src = ["src"] +target-version = "py311" + +[tool.ruff.lint] +select = [ + "B", # flake8-bugbear + "E", # pycodestyle errors + "F", # pyflakes + "I", # isort + "W", # pycodestyle warnings +] From a3e79c3434aa6a4b8178584fe19236d7cc070864 Mon Sep 17 00:00:00 2001 From: Cameron Smith Date: Mon, 2 Feb 2026 20:30:03 -0500 Subject: [PATCH 050/134] feat(pnt-cli): add Python wrapper, type stubs, and tests for native module --- packages/pnt-cli/src/pnt_cli/__init__.py | 5 +++++ packages/pnt-cli/src/pnt_cli/_native.pyi | 7 +++++++ packages/pnt-cli/src/pnt_cli/py.typed | 0 packages/pnt-cli/src/pnt_cli/tests/__init__.py | 0 packages/pnt-cli/src/pnt_cli/tests/test_native.py | 11 +++++++++++ 5 files changed, 23 insertions(+) create mode 100644 packages/pnt-cli/src/pnt_cli/__init__.py create mode 100644 packages/pnt-cli/src/pnt_cli/_native.pyi create mode 100644 packages/pnt-cli/src/pnt_cli/py.typed create mode 100644 packages/pnt-cli/src/pnt_cli/tests/__init__.py create mode 100644 packages/pnt-cli/src/pnt_cli/tests/test_native.py diff --git a/packages/pnt-cli/src/pnt_cli/__init__.py b/packages/pnt-cli/src/pnt_cli/__init__.py new file mode 100644 index 0000000..0b42bf8 --- /dev/null +++ b/packages/pnt-cli/src/pnt_cli/__init__.py @@ -0,0 +1,5 @@ +"""pnt-cli: CLI package with Rust extension module.""" + +from pnt_cli._native import add, greet + +__all__ = ["add", "greet"] diff --git a/packages/pnt-cli/src/pnt_cli/_native.pyi b/packages/pnt-cli/src/pnt_cli/_native.pyi new file mode 100644 index 0000000..a5ce230 --- /dev/null +++ b/packages/pnt-cli/src/pnt_cli/_native.pyi @@ -0,0 +1,7 @@ +def greet(name: str) -> str: + """Greet a user by name, returning a string from Rust.""" + ... + +def add(a: int, b: int) -> int: + """Add two unsigned integers.""" + ... diff --git a/packages/pnt-cli/src/pnt_cli/py.typed b/packages/pnt-cli/src/pnt_cli/py.typed new file mode 100644 index 0000000..e69de29 diff --git a/packages/pnt-cli/src/pnt_cli/tests/__init__.py b/packages/pnt-cli/src/pnt_cli/tests/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/packages/pnt-cli/src/pnt_cli/tests/test_native.py b/packages/pnt-cli/src/pnt_cli/tests/test_native.py new file mode 100644 index 0000000..7bb07b2 --- /dev/null +++ b/packages/pnt-cli/src/pnt_cli/tests/test_native.py @@ -0,0 +1,11 @@ +from pnt_cli import add, greet + + +def test_greet() -> None: + result = greet("world") + assert result == "Hello, world! (from Rust)" + + +def test_add() -> None: + assert add(2, 3) == 5 + assert add(0, 0) == 0 From 01ebe5f3495114c0f26e1fa39a139702deda247b Mon Sep 17 00:00:00 2001 From: Cameron Smith Date: Mon, 2 Feb 2026 20:30:20 -0500 Subject: [PATCH 051/134] chore(issues): close pnt-btz.1, pnt-cli package scaffold complete --- .beads/issues.jsonl | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.beads/issues.jsonl b/.beads/issues.jsonl index f35e52d..7658b69 100644 --- a/.beads/issues.jsonl +++ b/.beads/issues.jsonl @@ -2,8 +2,9 @@ {"id":"pnt-4jg.1","title":"Remove uv workspace, adopt path dependencies","description":"Remove [tool.uv.workspace] from root pyproject.toml. Each package gets own pyproject.toml with [tool.uv.sources] for sibling references using path sources with editable=true. Follow langchain pattern.","status":"closed","priority":2,"issue_type":"task","owner":"cameron.ray.smith@gmail.com","created_at":"2026-01-19T11:55:07.344057-05:00","created_by":"Cameron Smith","updated_at":"2026-02-02T14:40:02.175394-05:00","closed_at":"2026-02-02T14:40:02.175394-05:00","close_reason":"Implemented in a8a823f. Removed root uv workspace, generated per-package locks, rewrote nix modules to Pattern 3 per-package loading.","dependencies":[{"issue_id":"pnt-4jg.1","depends_on_id":"pnt-4jg","type":"parent-child","created_at":"2026-01-19T11:55:07.344659-05:00","created_by":"Cameron Smith"}],"comments":[{"id":1,"issue_id":"pnt-4jg.1","author":"Cameron Smith","text":"Post-close fixup commits (774ec26):\n- fix(ci): update lock file references for per-package federation (d0cab2a)\n- fixup! merge federated workspace deps: replace // with zipAttrsWith for extras-safe dep merging (7b3e7ae)\n- fixup! load packages independently: document version-conflict invariant in python.nix and architecture doc (36eb8a7, 774ec26)\n\nReview findings addressed: stale CI cache-dependency-glob paths, fragile shallow-merge dep specs, undocumented overlay composition invariant. Full CI redesign (nix develop + justfile symmetry) deferred to pnt-dre.4.","created_at":"2026-02-02T20:17:00Z"}]} {"id":"pnt-4jg.2","title":"Configure pixi feature-based composition","description":"Implement pixi feature/environment pattern: [feature.X.dependencies] + [environments] composition. Single pixi.lock covering all environments. Per-feature task definitions. Target-specific dependencies for platform support.","status":"closed","priority":2,"issue_type":"task","owner":"cameron.ray.smith@gmail.com","created_at":"2026-01-19T11:55:08.085592-05:00","created_by":"Cameron Smith","updated_at":"2026-02-02T15:36:49.459815-05:00","closed_at":"2026-02-02T15:36:49.459815-05:00","close_reason":"Verified pixi feature composition via nix develop -c just \u003crecipe\u003e. Fixed: added missing feature tasks to python-nix-template, delegated justfile conda recipes to pixi task names for correct working directory, moved deprecated build channels to backend.channels.","dependencies":[{"issue_id":"pnt-4jg.2","depends_on_id":"pnt-4jg","type":"parent-child","created_at":"2026-01-19T11:55:08.086155-05:00","created_by":"Cameron Smith"}]} {"id":"pnt-4jg.3","title":"Document package distribution channels","description":"Document which packages support uv/pypi vs pixi/conda distribution. Note dependency graph differences between channels. Update README and package metadata.","status":"closed","priority":2,"issue_type":"task","owner":"cameron.ray.smith@gmail.com","created_at":"2026-01-19T11:55:09.051203-05:00","created_by":"Cameron Smith","updated_at":"2026-02-02T15:37:38.374454-05:00","closed_at":"2026-02-02T15:37:38.374454-05:00","close_reason":"Documented in docs/notes/architecture/package-distribution-channels.md. Both packages support dual-channel (uv/PyPI + pixi/conda-forge) with independent locks. No blocking dependency graph differences between channels.","dependencies":[{"issue_id":"pnt-4jg.3","depends_on_id":"pnt-4jg","type":"parent-child","created_at":"2026-01-19T11:55:09.051857-05:00","created_by":"Cameron Smith"},{"issue_id":"pnt-4jg.3","depends_on_id":"pnt-4jg.1","type":"blocks","created_at":"2026-01-19T12:20:13.557576-05:00","created_by":"Cameron Smith"},{"issue_id":"pnt-4jg.3","depends_on_id":"pnt-4jg.2","type":"blocks","created_at":"2026-01-19T12:20:16.147971-05:00","created_by":"Cameron Smith"}]} +{"id":"pnt-5vr","title":"Migrate container builds from flocken/nixpod to nix2container","description":"Replace the current flocken-based multi-arch container build pipeline with the nix2container pattern used in vanixiets.\n\nCurrent state:\n- nix/modules/containers.nix uses nixpod buildMultiUserNixImage for image construction\n- flocken mkDockerManifest for multi-arch manifest creation and registry push\n- .github/actions/build-nix-image/ uses QEMU for arm64, apt-get skopeo\n- build-nix-images.yaml workflow orchestrates the flocken-based pipeline\n\nTarget state (matching vanixiets):\n- nix2container.buildImage / buildLayer for image construction\n- pkgsCross for cross-compilation (eliminates QEMU dependency)\n- skopeo-nix2container with nix: transport for pushing\n- Custom mkMultiArchManifest (crane-based) for manifest lists\n- containerMatrix flake output for CI matrix generation (pure evaluation)\n- Per-container layer strategy: base layer (bash, coreutils) + app layer\n\nAcceptance criteria:\n- nix2container flake input added (replaces flocken input)\n- nix/modules/containers.nix rewritten with nix2container pattern\n- pkgsCross used for cross-compilation targets\n- lib/mk-multi-arch-manifest.nix ported from vanixiets\n- .github/actions/build-nix-image/ updated (remove QEMU, apt-get skopeo)\n- build-nix-images.yaml updated for nix2container workflow\n- flocken input removed from flake.nix\n- nixpod dependency evaluated (may still be needed for base image features)\n- containerMatrix flake output for CI matrix generation\n\nReference: ~/projects/nix-workspace/vanixiets/modules/containers/default.nix\nReference: ~/projects/nix-workspace/vanixiets/lib/mk-multi-arch-manifest.nix","status":"open","priority":2,"issue_type":"task","owner":"cameron.ray.smith@gmail.com","created_at":"2026-02-02T20:24:12.624117-05:00","created_by":"Cameron Smith","updated_at":"2026-02-02T20:24:12.624117-05:00"} {"id":"pnt-btz","title":"pyo3/Rust extension integration","description":"Add Rust extension module support via maturin + pyo3, demonstrating Nix build integration with crane cargoArtifacts sharing and uv2nix overlay composition.\n\nArchitecture documented in: docs/notes/architecture/crane-uv2nix-integration.md\n\nKey patterns:\n- Per-package Rust workspace (crates/ inside Python package)\n- crane buildDepsOnly for artifact caching\n- uv2nix overlay injection for maturin builds\n- CI matrix with rust-deps/rust-checks/python-wheel categories\n\nReference implementations:\n- ~/projects/rust-workspace/ironstar (crane patterns)\n- ~/projects/planning-workspace/langchain (federated Python)\n","status":"open","priority":2,"issue_type":"epic","owner":"cameron.ray.smith@gmail.com","created_at":"2026-01-19T11:54:41.426256-05:00","created_by":"Cameron Smith","updated_at":"2026-01-28T14:43:57.637638-05:00","dependencies":[{"issue_id":"pnt-btz","depends_on_id":"pnt-dre","type":"blocks","created_at":"2026-01-19T11:55:32.690895-05:00","created_by":"Cameron Smith"},{"issue_id":"pnt-btz","depends_on_id":"pnt-4jg","type":"blocks","created_at":"2026-01-19T11:55:32.812602-05:00","created_by":"Cameron Smith"}]} -{"id":"pnt-btz.1","title":"Create pnt-cli package scaffold with Rust crates","description":"Create packages/pnt-cli/ with federated structure:\n\nDirectory structure:\n- packages/pnt-cli/pyproject.toml (maturin build-backend, manifest-path binding)\n- packages/pnt-cli/src/pnt_cli/__init__.py (Python wrapper)\n- packages/pnt-cli/crates/Cargo.toml ([workspace] with member crates)\n- packages/pnt-cli/crates/pnt-cli-core/Cargo.toml (pure Rust library)\n- packages/pnt-cli/crates/pnt-cli-py/Cargo.toml (pyo3 bindings, depends on core)\n\npyproject.toml configuration:\n- [build-system] requires maturin\u003e=1.5\n- [tool.maturin] manifest-path = \"crates/pnt-cli-py/Cargo.toml\"\n- [tool.maturin] module-name = \"pnt_cli._native\"\n\nMinimal proof-of-concept: expose a simple function from Rust to Python.\n\nSee: docs/notes/architecture/crane-uv2nix-integration.md\n","status":"open","priority":2,"issue_type":"task","owner":"cameron.ray.smith@gmail.com","created_at":"2026-01-19T11:55:17.885691-05:00","created_by":"Cameron Smith","updated_at":"2026-01-28T14:43:57.882216-05:00","dependencies":[{"issue_id":"pnt-btz.1","depends_on_id":"pnt-btz","type":"parent-child","created_at":"2026-01-19T11:55:17.886287-05:00","created_by":"Cameron Smith"},{"issue_id":"pnt-btz.1","depends_on_id":"pnt-4jg.1","type":"blocks","created_at":"2026-01-19T12:20:18.940008-05:00","created_by":"Cameron Smith"}]} +{"id":"pnt-btz.1","title":"Create pnt-cli package scaffold with Rust crates","description":"Create packages/pnt-cli/ with federated structure:\n\nDirectory structure:\n- packages/pnt-cli/pyproject.toml (maturin build-backend, manifest-path binding)\n- packages/pnt-cli/src/pnt_cli/__init__.py (Python wrapper)\n- packages/pnt-cli/crates/Cargo.toml ([workspace] with member crates)\n- packages/pnt-cli/crates/pnt-cli-core/Cargo.toml (pure Rust library)\n- packages/pnt-cli/crates/pnt-cli-py/Cargo.toml (pyo3 bindings, depends on core)\n\npyproject.toml configuration:\n- [build-system] requires maturin\u003e=1.5\n- [tool.maturin] manifest-path = \"crates/pnt-cli-py/Cargo.toml\"\n- [tool.maturin] module-name = \"pnt_cli._native\"\n\nMinimal proof-of-concept: expose a simple function from Rust to Python.\n\nSee: docs/notes/architecture/crane-uv2nix-integration.md\n","status":"closed","priority":2,"issue_type":"task","owner":"cameron.ray.smith@gmail.com","created_at":"2026-01-19T11:55:17.885691-05:00","created_by":"Cameron Smith","updated_at":"2026-02-02T20:30:16.311977-05:00","closed_at":"2026-02-02T20:30:16.311977-05:00","close_reason":"Implemented in a3e79c3. Scaffold verified: cargo check, cargo test (2/2 pass), cargo clippy clean.","dependencies":[{"issue_id":"pnt-btz.1","depends_on_id":"pnt-btz","type":"parent-child","created_at":"2026-01-19T11:55:17.886287-05:00","created_by":"Cameron Smith"},{"issue_id":"pnt-btz.1","depends_on_id":"pnt-4jg.1","type":"blocks","created_at":"2026-01-19T12:20:18.940008-05:00","created_by":"Cameron Smith"}]} {"id":"pnt-btz.2","title":"Implement crane + uv2nix Nix modules","description":"Create Nix modules implementing the crane + uv2nix integration pattern.\n\nFiles to create:\n- nix/packages/pnt-cli/rust.nix (crane configuration)\n- nix/packages/pnt-cli/default.nix (Python + Rust composition)\n- nix/modules/rust/lib.nix (shared crane utilities, optional)\n\nrust.nix pattern:\n- crane-lib.buildDepsOnly for cargoArtifacts caching\n- commonArgs pattern for derivation hash consistency\n- crane-lib.vendorCargoDeps for maturin's cargo invocation\n- Export cargoArtifacts, cargoVendorDir, clippy, nextest\n\ndefault.nix pattern:\n- Import rust.nix\n- Create overlay injecting cargoVendorDir and CARGO_TARGET_DIR\n- Export overlay and checks for flake composition\n\nUpdate nix/modules/python.nix:\n- Load pnt-cli workspace independently (federated pattern)\n- Compose Rust overlay with uv2nix overlays\n\nSee: docs/notes/architecture/crane-uv2nix-integration.md\n","status":"open","priority":2,"issue_type":"task","owner":"cameron.ray.smith@gmail.com","created_at":"2026-01-19T11:55:18.885252-05:00","created_by":"Cameron Smith","updated_at":"2026-01-28T14:43:58.112357-05:00","dependencies":[{"issue_id":"pnt-btz.2","depends_on_id":"pnt-btz","type":"parent-child","created_at":"2026-01-19T11:55:18.885818-05:00","created_by":"Cameron Smith"},{"issue_id":"pnt-btz.2","depends_on_id":"pnt-btz.1","type":"blocks","created_at":"2026-01-19T12:20:08.210077-05:00","created_by":"Cameron Smith"}]} {"id":"pnt-btz.3","title":"Validate integration and update CI","description":"Validate the full crane + uv2nix + maturin integration and update CI.\n\nValidation checklist:\n- [ ] nix build .#pnt-cli produces working wheel\n- [ ] Python import succeeds: from pnt_cli._native import ...\n- [ ] Rust changes trigger minimal rebuilds (cargoArtifacts cached)\n- [ ] Python-only changes don't rebuild Rust\n- [ ] cargoClippy and cargoNextest checks pass\n\nCI updates (.github/workflows/ci.yaml):\n- Add rust-deps matrix category for cargoArtifacts caching\n- Add rust-checks matrix category for clippy/nextest\n- Ensure proper cache key based on Cargo.lock hash\n- Follow ironstar CI matrix pattern\n\nDocumentation updates:\n- Add usage example to README\n- Document development workflow (uv sync + maturin develop vs nix build)\n- Note editable install limitations\n\nSee: docs/notes/architecture/crane-uv2nix-integration.md\n","status":"open","priority":2,"issue_type":"task","owner":"cameron.ray.smith@gmail.com","created_at":"2026-01-19T11:55:19.746622-05:00","created_by":"Cameron Smith","updated_at":"2026-01-28T14:43:58.351336-05:00","dependencies":[{"issue_id":"pnt-btz.3","depends_on_id":"pnt-btz","type":"parent-child","created_at":"2026-01-19T11:55:19.74722-05:00","created_by":"Cameron Smith"},{"issue_id":"pnt-btz.3","depends_on_id":"pnt-btz.2","type":"blocks","created_at":"2026-01-19T12:20:11.013516-05:00","created_by":"Cameron Smith"}]} {"id":"pnt-dre","title":"Infrastructure alignment","description":"Align Makefile, justfile, scripts/, and CI with vanixiets and typescript-nix-template patterns. Makefile bootstrap-only, grouped justfile recipes, cached-ci-job CI pattern, omnix template integration.","status":"closed","priority":2,"issue_type":"epic","owner":"cameron.ray.smith@gmail.com","created_at":"2026-01-19T11:54:39.841346-05:00","created_by":"Cameron Smith","updated_at":"2026-02-02T15:56:26.823947-05:00","closed_at":"2026-02-02T15:56:26.823947-05:00","close_reason":"All children closed: pnt-dre.1 (Makefile), pnt-dre.2 (justfile), pnt-dre.3 (scripts), pnt-dre.4 (cached-ci-job/CI), pnt-dre.5 (omnix template). Infrastructure alignment complete."} From 271aacf5a6628a6be135b5c3008fd501f14c83f5 Mon Sep 17 00:00:00 2001 From: Cameron Smith Date: Mon, 2 Feb 2026 20:31:19 -0500 Subject: [PATCH 052/134] chore(pnt-cli): generate uv.lock for federated package resolution --- packages/pnt-cli/uv.lock | 154 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 154 insertions(+) create mode 100644 packages/pnt-cli/uv.lock diff --git a/packages/pnt-cli/uv.lock b/packages/pnt-cli/uv.lock new file mode 100644 index 0000000..6e660d5 --- /dev/null +++ b/packages/pnt-cli/uv.lock @@ -0,0 +1,154 @@ +version = 1 +revision = 3 +requires-python = ">=3.11, <3.13" + +[[package]] +name = "colorama" +version = "0.4.6" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/d8/53/6f443c9a4a8358a93a6792e2acffb9d9d5cb0a5cfd8802644b7b1c9a02e4/colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44", size = 27697, upload-time = "2022-10-25T02:36:22.414Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/d1/d6/3965ed04c63042e047cb6a3e6ed1a63a35087b6a609aa3a15ed8ac56c221/colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6", size = 25335, upload-time = "2022-10-25T02:36:20.889Z" }, +] + +[[package]] +name = "iniconfig" +version = "2.3.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/72/34/14ca021ce8e5dfedc35312d08ba8bf51fdd999c576889fc2c24cb97f4f10/iniconfig-2.3.0.tar.gz", hash = "sha256:c76315c77db068650d49c5b56314774a7804df16fee4402c1f19d6d15d8c4730", size = 20503, upload-time = "2025-10-18T21:55:43.219Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl", hash = "sha256:f631c04d2c48c52b84d0d0549c99ff3859c98df65b3101406327ecc7d53fbf12", size = 7484, upload-time = "2025-10-18T21:55:41.639Z" }, +] + +[[package]] +name = "nodeenv" +version = "1.10.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/24/bf/d1bda4f6168e0b2e9e5958945e01910052158313224ada5ce1fb2e1113b8/nodeenv-1.10.0.tar.gz", hash = "sha256:996c191ad80897d076bdfba80a41994c2b47c68e224c542b48feba42ba00f8bb", size = 55611, upload-time = "2025-12-20T14:08:54.006Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/88/b2/d0896bdcdc8d28a7fc5717c305f1a861c26e18c05047949fb371034d98bd/nodeenv-1.10.0-py2.py3-none-any.whl", hash = "sha256:5bb13e3eed2923615535339b3c620e76779af4cb4c6a90deccc9e36b274d3827", size = 23438, upload-time = "2025-12-20T14:08:52.782Z" }, +] + +[[package]] +name = "packaging" +version = "26.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/65/ee/299d360cdc32edc7d2cf530f3accf79c4fca01e96ffc950d8a52213bd8e4/packaging-26.0.tar.gz", hash = "sha256:00243ae351a257117b6a241061796684b084ed1c516a08c48a3f7e147a9d80b4", size = 143416, upload-time = "2026-01-21T20:50:39.064Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/b7/b9/c538f279a4e237a006a2c98387d081e9eb060d203d8ed34467cc0f0b9b53/packaging-26.0-py3-none-any.whl", hash = "sha256:b36f1fef9334a5588b4166f8bcd26a14e521f2b55e6b9de3aaa80d3ff7a37529", size = 74366, upload-time = "2026-01-21T20:50:37.788Z" }, +] + +[[package]] +name = "pluggy" +version = "1.6.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/f9/e2/3e91f31a7d2b083fe6ef3fa267035b518369d9511ffab804f839851d2779/pluggy-1.6.0.tar.gz", hash = "sha256:7dcc130b76258d33b90f61b658791dede3486c3e6bfb003ee5c9bfb396dd22f3", size = 69412, upload-time = "2025-05-15T12:30:07.975Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl", hash = "sha256:e920276dd6813095e9377c0bc5566d94c932c33b27a3e3945d8389c374dd4746", size = 20538, upload-time = "2025-05-15T12:30:06.134Z" }, +] + +[[package]] +name = "pnt-cli" +version = "0.1.0" +source = { editable = "." } + +[package.dev-dependencies] +dev = [ + { name = "pyright" }, + { name = "pytest" }, + { name = "ruff" }, +] +lint = [ + { name = "ruff" }, +] +test = [ + { name = "pytest" }, +] +types = [ + { name = "pyright" }, +] + +[package.metadata] + +[package.metadata.requires-dev] +dev = [ + { name = "pyright", specifier = ">=1.1.395" }, + { name = "pytest", specifier = ">=8.3.4" }, + { name = "ruff", specifier = ">=0.9.4" }, +] +lint = [{ name = "ruff", specifier = ">=0.9.4" }] +test = [{ name = "pytest", specifier = ">=8.3.4" }] +types = [{ name = "pyright", specifier = ">=1.1.395" }] + +[[package]] +name = "pygments" +version = "2.19.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/b0/77/a5b8c569bf593b0140bde72ea885a803b82086995367bf2037de0159d924/pygments-2.19.2.tar.gz", hash = "sha256:636cb2477cec7f8952536970bc533bc43743542f70392ae026374600add5b887", size = 4968631, upload-time = "2025-06-21T13:39:12.283Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/c7/21/705964c7812476f378728bdf590ca4b771ec72385c533964653c68e86bdc/pygments-2.19.2-py3-none-any.whl", hash = "sha256:86540386c03d588bb81d44bc3928634ff26449851e99741617ecb9037ee5ec0b", size = 1225217, upload-time = "2025-06-21T13:39:07.939Z" }, +] + +[[package]] +name = "pyright" +version = "1.1.408" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "nodeenv" }, + { name = "typing-extensions" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/74/b2/5db700e52554b8f025faa9c3c624c59f1f6c8841ba81ab97641b54322f16/pyright-1.1.408.tar.gz", hash = "sha256:f28f2321f96852fa50b5829ea492f6adb0e6954568d1caa3f3af3a5f555eb684", size = 4400578, upload-time = "2026-01-08T08:07:38.795Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/0c/82/a2c93e32800940d9573fb28c346772a14778b84ba7524e691b324620ab89/pyright-1.1.408-py3-none-any.whl", hash = "sha256:090b32865f4fdb1e0e6cd82bf5618480d48eecd2eb2e70f960982a3d9a4c17c1", size = 6399144, upload-time = "2026-01-08T08:07:37.082Z" }, +] + +[[package]] +name = "pytest" +version = "9.0.2" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "colorama", marker = "sys_platform == 'win32'" }, + { name = "iniconfig" }, + { name = "packaging" }, + { name = "pluggy" }, + { name = "pygments" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/d1/db/7ef3487e0fb0049ddb5ce41d3a49c235bf9ad299b6a25d5780a89f19230f/pytest-9.0.2.tar.gz", hash = "sha256:75186651a92bd89611d1d9fc20f0b4345fd827c41ccd5c299a868a05d70edf11", size = 1568901, upload-time = "2025-12-06T21:30:51.014Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/3b/ab/b3226f0bd7cdcf710fbede2b3548584366da3b19b5021e74f5bde2a8fa3f/pytest-9.0.2-py3-none-any.whl", hash = "sha256:711ffd45bf766d5264d487b917733b453d917afd2b0ad65223959f59089f875b", size = 374801, upload-time = "2025-12-06T21:30:49.154Z" }, +] + +[[package]] +name = "ruff" +version = "0.14.14" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/2e/06/f71e3a86b2df0dfa2d2f72195941cd09b44f87711cb7fa5193732cb9a5fc/ruff-0.14.14.tar.gz", hash = "sha256:2d0f819c9a90205f3a867dbbd0be083bee9912e170fd7d9704cc8ae45824896b", size = 4515732, upload-time = "2026-01-22T22:30:17.527Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/d2/89/20a12e97bc6b9f9f68343952da08a8099c57237aef953a56b82711d55edd/ruff-0.14.14-py3-none-linux_armv6l.whl", hash = "sha256:7cfe36b56e8489dee8fbc777c61959f60ec0f1f11817e8f2415f429552846aed", size = 10467650, upload-time = "2026-01-22T22:30:08.578Z" }, + { url = "https://files.pythonhosted.org/packages/a3/b1/c5de3fd2d5a831fcae21beda5e3589c0ba67eec8202e992388e4b17a6040/ruff-0.14.14-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:6006a0082336e7920b9573ef8a7f52eec837add1265cc74e04ea8a4368cd704c", size = 10883245, upload-time = "2026-01-22T22:30:04.155Z" }, + { url = "https://files.pythonhosted.org/packages/b8/7c/3c1db59a10e7490f8f6f8559d1db8636cbb13dccebf18686f4e3c9d7c772/ruff-0.14.14-py3-none-macosx_11_0_arm64.whl", hash = "sha256:026c1d25996818f0bf498636686199d9bd0d9d6341c9c2c3b62e2a0198b758de", size = 10231273, upload-time = "2026-01-22T22:30:34.642Z" }, + { url = "https://files.pythonhosted.org/packages/a1/6e/5e0e0d9674be0f8581d1f5e0f0a04761203affce3232c1a1189d0e3b4dad/ruff-0.14.14-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f666445819d31210b71e0a6d1c01e24447a20b85458eea25a25fe8142210ae0e", size = 10585753, upload-time = "2026-01-22T22:30:31.781Z" }, + { url = "https://files.pythonhosted.org/packages/23/09/754ab09f46ff1884d422dc26d59ba18b4e5d355be147721bb2518aa2a014/ruff-0.14.14-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:3c0f18b922c6d2ff9a5e6c3ee16259adc513ca775bcf82c67ebab7cbd9da5bc8", size = 10286052, upload-time = "2026-01-22T22:30:24.827Z" }, + { url = "https://files.pythonhosted.org/packages/c8/cc/e71f88dd2a12afb5f50733851729d6b571a7c3a35bfdb16c3035132675a0/ruff-0.14.14-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1629e67489c2dea43e8658c3dba659edbfd87361624b4040d1df04c9740ae906", size = 11043637, upload-time = "2026-01-22T22:30:13.239Z" }, + { url = "https://files.pythonhosted.org/packages/67/b2/397245026352494497dac935d7f00f1468c03a23a0c5db6ad8fc49ca3fb2/ruff-0.14.14-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:27493a2131ea0f899057d49d303e4292b2cae2bb57253c1ed1f256fbcd1da480", size = 12194761, upload-time = "2026-01-22T22:30:22.542Z" }, + { url = "https://files.pythonhosted.org/packages/5b/06/06ef271459f778323112c51b7587ce85230785cd64e91772034ddb88f200/ruff-0.14.14-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:01ff589aab3f5b539e35db38425da31a57521efd1e4ad1ae08fc34dbe30bd7df", size = 12005701, upload-time = "2026-01-22T22:30:20.499Z" }, + { url = "https://files.pythonhosted.org/packages/41/d6/99364514541cf811ccc5ac44362f88df66373e9fec1b9d1c4cc830593fe7/ruff-0.14.14-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:1cc12d74eef0f29f51775f5b755913eb523546b88e2d733e1d701fe65144e89b", size = 11282455, upload-time = "2026-01-22T22:29:59.679Z" }, + { url = "https://files.pythonhosted.org/packages/ca/71/37daa46f89475f8582b7762ecd2722492df26421714a33e72ccc9a84d7a5/ruff-0.14.14-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bb8481604b7a9e75eff53772496201690ce2687067e038b3cc31aaf16aa0b974", size = 11215882, upload-time = "2026-01-22T22:29:57.032Z" }, + { url = "https://files.pythonhosted.org/packages/2c/10/a31f86169ec91c0705e618443ee74ede0bdd94da0a57b28e72db68b2dbac/ruff-0.14.14-py3-none-manylinux_2_31_riscv64.whl", hash = "sha256:14649acb1cf7b5d2d283ebd2f58d56b75836ed8c6f329664fa91cdea19e76e66", size = 11180549, upload-time = "2026-01-22T22:30:27.175Z" }, + { url = "https://files.pythonhosted.org/packages/fd/1e/c723f20536b5163adf79bdd10c5f093414293cdf567eed9bdb7b83940f3f/ruff-0.14.14-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:e8058d2145566510790eab4e2fad186002e288dec5e0d343a92fe7b0bc1b3e13", size = 10543416, upload-time = "2026-01-22T22:30:01.964Z" }, + { url = "https://files.pythonhosted.org/packages/3e/34/8a84cea7e42c2d94ba5bde1d7a4fae164d6318f13f933d92da6d7c2041ff/ruff-0.14.14-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:e651e977a79e4c758eb807f0481d673a67ffe53cfa92209781dfa3a996cf8412", size = 10285491, upload-time = "2026-01-22T22:30:29.51Z" }, + { url = "https://files.pythonhosted.org/packages/55/ef/b7c5ea0be82518906c978e365e56a77f8de7678c8bb6651ccfbdc178c29f/ruff-0.14.14-py3-none-musllinux_1_2_i686.whl", hash = "sha256:cc8b22da8d9d6fdd844a68ae937e2a0adf9b16514e9a97cc60355e2d4b219fc3", size = 10733525, upload-time = "2026-01-22T22:30:06.499Z" }, + { url = "https://files.pythonhosted.org/packages/6a/5b/aaf1dfbcc53a2811f6cc0a1759de24e4b03e02ba8762daabd9b6bd8c59e3/ruff-0.14.14-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:16bc890fb4cc9781bb05beb5ab4cd51be9e7cb376bf1dd3580512b24eb3fda2b", size = 11315626, upload-time = "2026-01-22T22:30:36.848Z" }, + { url = "https://files.pythonhosted.org/packages/2c/aa/9f89c719c467dfaf8ad799b9bae0df494513fb21d31a6059cb5870e57e74/ruff-0.14.14-py3-none-win32.whl", hash = "sha256:b530c191970b143375b6a68e6f743800b2b786bbcf03a7965b06c4bf04568167", size = 10502442, upload-time = "2026-01-22T22:30:38.93Z" }, + { url = "https://files.pythonhosted.org/packages/87/44/90fa543014c45560cae1fffc63ea059fb3575ee6e1cb654562197e5d16fb/ruff-0.14.14-py3-none-win_amd64.whl", hash = "sha256:3dde1435e6b6fe5b66506c1dff67a421d0b7f6488d466f651c07f4cab3bf20fd", size = 11630486, upload-time = "2026-01-22T22:30:10.852Z" }, + { url = "https://files.pythonhosted.org/packages/9e/6a/40fee331a52339926a92e17ae748827270b288a35ef4a15c9c8f2ec54715/ruff-0.14.14-py3-none-win_arm64.whl", hash = "sha256:56e6981a98b13a32236a72a8da421d7839221fa308b223b9283312312e5ac76c", size = 10920448, upload-time = "2026-01-22T22:30:15.417Z" }, +] + +[[package]] +name = "typing-extensions" +version = "4.15.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/72/94/1a15dd82efb362ac84269196e94cf00f187f7ed21c242792a923cdb1c61f/typing_extensions-4.15.0.tar.gz", hash = "sha256:0cea48d173cc12fa28ecabc3b837ea3cf6f38c6d1136f85cbaaf598984861466", size = 109391, upload-time = "2025-08-25T13:49:26.313Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/18/67/36e9267722cc04a6b9f15c7f3441c2363321a3ea07da7ae0c0707beb2a9c/typing_extensions-4.15.0-py3-none-any.whl", hash = "sha256:f0fa19c6845758ab08074a0cfa8b7aecb71c999ca73d62883bc25cc018c4e548", size = 44614, upload-time = "2025-08-25T13:49:24.86Z" }, +] From cf9f983a762e7263cb19b280728c7a2a4edffb3f Mon Sep 17 00:00:00 2001 From: Cameron Smith Date: Mon, 2 Feb 2026 20:32:37 -0500 Subject: [PATCH 053/134] feat(nix): add crane input for Rust build integration --- flake.lock | 16 ++++++++++++++++ flake.nix | 2 ++ 2 files changed, 18 insertions(+) diff --git a/flake.lock b/flake.lock index 425046e..c70caf8 100644 --- a/flake.lock +++ b/flake.lock @@ -18,6 +18,21 @@ "type": "github" } }, + "crane": { + "locked": { + "lastModified": 1769737823, + "narHash": "sha256-DrBaNpZ+sJ4stXm+0nBX7zqZT9t9P22zbk6m5YhQxS4=", + "owner": "ipetkov", + "repo": "crane", + "rev": "b2f45c3830aa96b7456a4c4bc327d04d7a43e1ba", + "type": "github" + }, + "original": { + "owner": "ipetkov", + "repo": "crane", + "type": "github" + } + }, "flake-parts": { "inputs": { "nixpkgs-lib": [ @@ -277,6 +292,7 @@ }, "root": { "inputs": { + "crane": "crane", "flake-parts": "flake-parts", "flocken": "flocken", "git-hooks": "git-hooks", diff --git a/flake.nix b/flake.nix index 8780821..0f3c28c 100644 --- a/flake.nix +++ b/flake.nix @@ -37,6 +37,8 @@ inputs.flocken.follows = "flocken"; }; + crane.url = "github:ipetkov/crane"; + git-hooks.url = "github:cachix/git-hooks.nix"; git-hooks.flake = false; }; From 073fe08cc178e7494e7336afd5dd3406098c8e12 Mon Sep 17 00:00:00 2001 From: Cameron Smith Date: Mon, 2 Feb 2026 20:32:43 -0500 Subject: [PATCH 054/134] feat(pnt-cli): add crane configuration for Rust extension crates --- nix/packages/pnt-cli/rust.nix | 56 +++++++++++++++++++++++++++++++++++ 1 file changed, 56 insertions(+) create mode 100644 nix/packages/pnt-cli/rust.nix diff --git a/nix/packages/pnt-cli/rust.nix b/nix/packages/pnt-cli/rust.nix new file mode 100644 index 0000000..f9a1f0d --- /dev/null +++ b/nix/packages/pnt-cli/rust.nix @@ -0,0 +1,56 @@ +# Crane configuration for pnt-cli's Rust extension crates. +# +# Follows the commonArgs pattern from ironstar: a single buildDepsOnly call +# creates cargoArtifacts shared by buildPackage, cargoClippy, and cargoNextest. +# PYO3_PYTHON is set explicitly to prevent path-dependent rebuilds. +{ + pkgs, + lib, + crane, + python, +}: +let + crane-lib = crane.mkLib pkgs; + + src = ../../../packages/pnt-cli/crates; + + commonArgs = { + inherit src; + pname = "pnt-cli-rust"; + strictDeps = true; + CARGO_PROFILE = "release"; + env.PYO3_PYTHON = python.interpreter; + nativeBuildInputs = [ + pkgs.pkg-config + python + ]; + buildInputs = lib.optionals pkgs.stdenv.isDarwin [ + pkgs.darwin.apple_sdk.frameworks.SystemConfiguration + ]; + }; + + cargoArtifacts = crane-lib.buildDepsOnly commonArgs; +in +{ + inherit cargoArtifacts; + + cargoVendorDir = crane-lib.vendorCargoDeps { inherit src; }; + + clippy = crane-lib.cargoClippy ( + commonArgs + // { + inherit cargoArtifacts; + cargoClippyExtraArgs = "--all-targets -- --deny warnings"; + } + ); + + nextest = crane-lib.cargoNextest ( + commonArgs + // { + inherit cargoArtifacts; + partitions = 1; + partitionType = "count"; + cargoNextestExtraArgs = "--no-tests=pass"; + } + ); +} From 165d635355ec3dc179615e1995a9ac67df643fce Mon Sep 17 00:00:00 2001 From: Cameron Smith Date: Mon, 2 Feb 2026 20:32:50 -0500 Subject: [PATCH 055/134] feat(pnt-cli): add Python + Rust composition overlay and checks --- nix/packages/pnt-cli/default.nix | 59 ++++++++++++++++++++++++++++++++ 1 file changed, 59 insertions(+) create mode 100644 nix/packages/pnt-cli/default.nix diff --git a/nix/packages/pnt-cli/default.nix b/nix/packages/pnt-cli/default.nix new file mode 100644 index 0000000..d0a807e --- /dev/null +++ b/nix/packages/pnt-cli/default.nix @@ -0,0 +1,59 @@ +# Python + Rust composition for pnt-cli. +# +# Imports rust.nix for crane derivations, then creates a Python package +# overlay that injects cargoVendorDir and CARGO_TARGET_DIR into the +# uv2nix-generated pnt-cli derivation. Exports the overlay and Rust checks +# for flake composition. +{ + pkgs, + lib, + crane, + python, +}: +let + rustPkgs = import ./rust.nix { + inherit + pkgs + lib + crane + python + ; + }; +in +{ + overlay = final: prev: { + pnt-cli = prev.pnt-cli.overrideAttrs (old: { + # Inject pre-vendored Cargo deps (crane's vendoring, not rustPlatform's) + cargoVendorDir = rustPkgs.cargoVendorDir; + + # Reuse crane's cargoArtifacts for incremental builds + preBuild = '' + export CARGO_TARGET_DIR="${rustPkgs.cargoArtifacts}/target" + ''; + + nativeBuildInputs = + (old.nativeBuildInputs or [ ]) + ++ [ + pkgs.cargo + pkgs.rustc + python + ] + ++ final.resolveBuildSystem { + maturin = [ ]; + }; + + buildInputs = + (old.buildInputs or [ ]) + ++ lib.optionals pkgs.stdenv.isDarwin [ + pkgs.darwin.apple_sdk.frameworks.SystemConfiguration + ]; + + env.PYO3_PYTHON = python.interpreter; + }); + }; + + checks = { + pnt-cli-clippy = rustPkgs.clippy; + pnt-cli-nextest = rustPkgs.nextest; + }; +} From 0f15b278fe78d70f6b118a4817c57726a087ff0c Mon Sep 17 00:00:00 2001 From: Cameron Smith Date: Mon, 2 Feb 2026 20:32:54 -0500 Subject: [PATCH 056/134] feat(nix): compose pnt-cli uv2nix and crane overlays in python module --- nix/modules/python.nix | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/nix/modules/python.nix b/nix/modules/python.nix index ec31c15..f0c18d8 100644 --- a/nix/modules/python.nix +++ b/nix/modules/python.nix @@ -40,10 +40,21 @@ }; packageWorkspaces = { + pnt-cli = loadPackage "pnt-cli" ../../packages/pnt-cli; pnt-functional = loadPackage "pnt-functional" ../../packages/pnt-functional; python-nix-template = loadPackage "python-nix-template" ../../packages/python-nix-template; }; + # Per-package Nix modules with optional Rust overlays. + # Packages with Rust extensions get a dedicated module in nix/packages/ + # that encapsulates crane configuration and exports an overlay + checks. + mkPackageModule = + python: + import ../packages/pnt-cli { + inherit pkgs lib python; + crane = inputs.crane; + }; + # Compose per-package uv2nix overlays with shared overrides. # # Invariant: all federated packages must resolve compatible versions for @@ -61,8 +72,11 @@ ( lib.composeManyExtensions [ inputs.pyproject-build-systems.overlays.default + packageWorkspaces.pnt-cli.overlay packageWorkspaces.pnt-functional.overlay packageWorkspaces.python-nix-template.overlay + # Rust integration overlay for pnt-cli (crane + maturin) + (mkPackageModule python).overlay packageOverrides sdistOverrides ] @@ -72,9 +86,17 @@ python: (mkPythonSet python).overrideScope ( lib.composeManyExtensions [ + packageWorkspaces.pnt-cli.editableOverlay packageWorkspaces.pnt-functional.editableOverlay packageWorkspaces.python-nix-template.editableOverlay (final: prev: { + pnt-cli = prev.pnt-cli.overrideAttrs (old: { + nativeBuildInputs = + old.nativeBuildInputs + ++ final.resolveBuildSystem { + editables = [ ]; + }; + }); python-nix-template = prev.python-nix-template.overrideAttrs (old: { nativeBuildInputs = old.nativeBuildInputs @@ -95,8 +117,13 @@ pythonSets = lib.mapAttrs (_: mkPythonSet) pythonVersions; editablePythonSets = lib.mapAttrs (_: mkEditablePythonSet) pythonVersions; + + # Rust checks from per-package modules (using default Python version) + rustChecks = (mkPackageModule pythonVersions.py312).checks; in { + checks = rustChecks; + _module.args = { inherit packageWorkspaces From 4ec289fa7b09f5ce645d63bca874cde5c843d163 Mon Sep 17 00:00:00 2001 From: Cameron Smith Date: Mon, 2 Feb 2026 20:32:58 -0500 Subject: [PATCH 057/134] feat(nix): add Rust tooling to devshell --- nix/modules/devshell.nix | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/nix/modules/devshell.nix b/nix/modules/devshell.nix index 819adfe..db86163 100644 --- a/nix/modules/devshell.nix +++ b/nix/modules/devshell.nix @@ -50,6 +50,12 @@ sops ssh-to-age config.packages.set-git-env + # Rust tooling for pnt-cli pyo3 extension + cargo + rustc + clippy + cargo-nextest + maturin ]; env = { From 64a88f80cb3072632d2c8f6c240dfac77569cc7d Mon Sep 17 00:00:00 2001 From: Cameron Smith Date: Mon, 2 Feb 2026 20:33:41 -0500 Subject: [PATCH 058/134] fix(nix): remove deprecated darwin.apple_sdk framework references --- nix/packages/pnt-cli/default.nix | 6 ------ nix/packages/pnt-cli/rust.nix | 3 --- 2 files changed, 9 deletions(-) diff --git a/nix/packages/pnt-cli/default.nix b/nix/packages/pnt-cli/default.nix index d0a807e..d1cc0b8 100644 --- a/nix/packages/pnt-cli/default.nix +++ b/nix/packages/pnt-cli/default.nix @@ -42,12 +42,6 @@ in maturin = [ ]; }; - buildInputs = - (old.buildInputs or [ ]) - ++ lib.optionals pkgs.stdenv.isDarwin [ - pkgs.darwin.apple_sdk.frameworks.SystemConfiguration - ]; - env.PYO3_PYTHON = python.interpreter; }); }; diff --git a/nix/packages/pnt-cli/rust.nix b/nix/packages/pnt-cli/rust.nix index f9a1f0d..9887f44 100644 --- a/nix/packages/pnt-cli/rust.nix +++ b/nix/packages/pnt-cli/rust.nix @@ -24,9 +24,6 @@ let pkgs.pkg-config python ]; - buildInputs = lib.optionals pkgs.stdenv.isDarwin [ - pkgs.darwin.apple_sdk.frameworks.SystemConfiguration - ]; }; cargoArtifacts = crane-lib.buildDepsOnly commonArgs; From 0ee302fd484dfe5d1ed8599c1726709bf1d43d1a Mon Sep 17 00:00:00 2001 From: Cameron Smith Date: Mon, 2 Feb 2026 20:37:50 -0500 Subject: [PATCH 059/134] fix(pnt-cli): configure cargo vendored deps for offline maturin builds --- nix/packages/pnt-cli/default.nix | 23 +++++++++++++++-------- 1 file changed, 15 insertions(+), 8 deletions(-) diff --git a/nix/packages/pnt-cli/default.nix b/nix/packages/pnt-cli/default.nix index d1cc0b8..d8e8af4 100644 --- a/nix/packages/pnt-cli/default.nix +++ b/nix/packages/pnt-cli/default.nix @@ -23,14 +23,6 @@ in { overlay = final: prev: { pnt-cli = prev.pnt-cli.overrideAttrs (old: { - # Inject pre-vendored Cargo deps (crane's vendoring, not rustPlatform's) - cargoVendorDir = rustPkgs.cargoVendorDir; - - # Reuse crane's cargoArtifacts for incremental builds - preBuild = '' - export CARGO_TARGET_DIR="${rustPkgs.cargoArtifacts}/target" - ''; - nativeBuildInputs = (old.nativeBuildInputs or [ ]) ++ [ @@ -42,6 +34,21 @@ in maturin = [ ]; }; + # Configure cargo to use crane's vendored dependencies (offline build) + # and reuse crane's cargoArtifacts for incremental compilation. + preBuild = '' + mkdir -p .cargo + cat > .cargo/config.toml < Date: Mon, 2 Feb 2026 20:38:40 -0500 Subject: [PATCH 060/134] fix(pnt-cli): use crane's vendor config.toml for source replacement --- nix/packages/pnt-cli/default.nix | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/nix/packages/pnt-cli/default.nix b/nix/packages/pnt-cli/default.nix index d8e8af4..764be15 100644 --- a/nix/packages/pnt-cli/default.nix +++ b/nix/packages/pnt-cli/default.nix @@ -36,16 +36,11 @@ in # Configure cargo to use crane's vendored dependencies (offline build) # and reuse crane's cargoArtifacts for incremental compilation. + # Crane's vendorCargoDeps output includes a config.toml with the correct + # source replacement directives. preBuild = '' mkdir -p .cargo - cat > .cargo/config.toml < Date: Mon, 2 Feb 2026 20:38:56 -0500 Subject: [PATCH 061/134] fix(pnt-cli): disable readme field to avoid maturin build failure --- packages/pnt-cli/pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/pnt-cli/pyproject.toml b/packages/pnt-cli/pyproject.toml index 2bcbaeb..2b6061d 100644 --- a/packages/pnt-cli/pyproject.toml +++ b/packages/pnt-cli/pyproject.toml @@ -15,7 +15,7 @@ dependencies = [] description = "CLI package with Rust extension module via pyo3/maturin" license = { text = "Apache-2.0" } name = "pnt-cli" -readme = "README.md" +readme = false requires-python = ">=3.11,<3.13" version = "0.1.0" From f3ae6d9424402faf5a55c38ba5208a8f26c93821 Mon Sep 17 00:00:00 2001 From: Cameron Smith Date: Mon, 2 Feb 2026 20:39:12 -0500 Subject: [PATCH 062/134] fix(pnt-cli): remove readme field from pyproject.toml --- packages/pnt-cli/pyproject.toml | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/pnt-cli/pyproject.toml b/packages/pnt-cli/pyproject.toml index 2b6061d..02087b5 100644 --- a/packages/pnt-cli/pyproject.toml +++ b/packages/pnt-cli/pyproject.toml @@ -15,7 +15,6 @@ dependencies = [] description = "CLI package with Rust extension module via pyo3/maturin" license = { text = "Apache-2.0" } name = "pnt-cli" -readme = false requires-python = ">=3.11,<3.13" version = "0.1.0" From e399fd5084b43363986317deb0335fcbee30e4dc Mon Sep 17 00:00:00 2001 From: Cameron Smith Date: Mon, 2 Feb 2026 20:39:47 -0500 Subject: [PATCH 063/134] fix(pnt-cli): remove CARGO_TARGET_DIR override for writable maturin builds --- nix/packages/pnt-cli/default.nix | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/nix/packages/pnt-cli/default.nix b/nix/packages/pnt-cli/default.nix index 764be15..74b62c2 100644 --- a/nix/packages/pnt-cli/default.nix +++ b/nix/packages/pnt-cli/default.nix @@ -1,9 +1,10 @@ # Python + Rust composition for pnt-cli. # # Imports rust.nix for crane derivations, then creates a Python package -# overlay that injects cargoVendorDir and CARGO_TARGET_DIR into the -# uv2nix-generated pnt-cli derivation. Exports the overlay and Rust checks -# for flake composition. +# overlay that injects vendored cargo deps into the uv2nix-generated pnt-cli +# derivation. Crane's cargoArtifacts caching applies to the Rust-only check +# derivations (clippy, nextest); the maturin wheel build compiles Rust from +# source within the pyproject.nix derivation using vendored dependencies. { pkgs, lib, @@ -34,14 +35,12 @@ in maturin = [ ]; }; - # Configure cargo to use crane's vendored dependencies (offline build) - # and reuse crane's cargoArtifacts for incremental compilation. - # Crane's vendorCargoDeps output includes a config.toml with the correct - # source replacement directives. + # Configure cargo to use crane's vendored dependencies for offline builds. + # Crane's vendorCargoDeps output includes a config.toml with source + # replacement directives pointing to the vendored crate store paths. preBuild = '' mkdir -p .cargo cp ${rustPkgs.cargoVendorDir}/config.toml .cargo/config.toml - export CARGO_TARGET_DIR="${rustPkgs.cargoArtifacts}/target" ''; env.PYO3_PYTHON = python.interpreter; From 8d8a814ee7859e3d27bb5a3572cc30058aa87b20 Mon Sep 17 00:00:00 2001 From: Cameron Smith Date: Mon, 2 Feb 2026 20:40:43 -0500 Subject: [PATCH 064/134] fix(pnt-cli): set pymodule name to _native for correct PyInit export --- packages/pnt-cli/crates/pnt-cli-py/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/pnt-cli/crates/pnt-cli-py/src/lib.rs b/packages/pnt-cli/crates/pnt-cli-py/src/lib.rs index e0e8165..95aabd1 100644 --- a/packages/pnt-cli/crates/pnt-cli-py/src/lib.rs +++ b/packages/pnt-cli/crates/pnt-cli-py/src/lib.rs @@ -13,7 +13,7 @@ fn add(a: u64, b: u64) -> u64 { } /// Native extension module for pnt-cli. -#[pymodule] +#[pymodule(name = "_native")] fn pnt_cli_native(m: &Bound<'_, PyModule>) -> PyResult<()> { m.add_function(wrap_pyfunction!(greet, m)?)?; m.add_function(wrap_pyfunction!(add, m)?)?; From 875a6dc31e25bee474b34839edab103b6dbbac46 Mon Sep 17 00:00:00 2001 From: Cameron Smith Date: Mon, 2 Feb 2026 20:41:21 -0500 Subject: [PATCH 065/134] chore(issues): close pnt-btz.2, crane + uv2nix Nix modules complete --- .beads/issues.jsonl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.beads/issues.jsonl b/.beads/issues.jsonl index 7658b69..826e668 100644 --- a/.beads/issues.jsonl +++ b/.beads/issues.jsonl @@ -5,7 +5,7 @@ {"id":"pnt-5vr","title":"Migrate container builds from flocken/nixpod to nix2container","description":"Replace the current flocken-based multi-arch container build pipeline with the nix2container pattern used in vanixiets.\n\nCurrent state:\n- nix/modules/containers.nix uses nixpod buildMultiUserNixImage for image construction\n- flocken mkDockerManifest for multi-arch manifest creation and registry push\n- .github/actions/build-nix-image/ uses QEMU for arm64, apt-get skopeo\n- build-nix-images.yaml workflow orchestrates the flocken-based pipeline\n\nTarget state (matching vanixiets):\n- nix2container.buildImage / buildLayer for image construction\n- pkgsCross for cross-compilation (eliminates QEMU dependency)\n- skopeo-nix2container with nix: transport for pushing\n- Custom mkMultiArchManifest (crane-based) for manifest lists\n- containerMatrix flake output for CI matrix generation (pure evaluation)\n- Per-container layer strategy: base layer (bash, coreutils) + app layer\n\nAcceptance criteria:\n- nix2container flake input added (replaces flocken input)\n- nix/modules/containers.nix rewritten with nix2container pattern\n- pkgsCross used for cross-compilation targets\n- lib/mk-multi-arch-manifest.nix ported from vanixiets\n- .github/actions/build-nix-image/ updated (remove QEMU, apt-get skopeo)\n- build-nix-images.yaml updated for nix2container workflow\n- flocken input removed from flake.nix\n- nixpod dependency evaluated (may still be needed for base image features)\n- containerMatrix flake output for CI matrix generation\n\nReference: ~/projects/nix-workspace/vanixiets/modules/containers/default.nix\nReference: ~/projects/nix-workspace/vanixiets/lib/mk-multi-arch-manifest.nix","status":"open","priority":2,"issue_type":"task","owner":"cameron.ray.smith@gmail.com","created_at":"2026-02-02T20:24:12.624117-05:00","created_by":"Cameron Smith","updated_at":"2026-02-02T20:24:12.624117-05:00"} {"id":"pnt-btz","title":"pyo3/Rust extension integration","description":"Add Rust extension module support via maturin + pyo3, demonstrating Nix build integration with crane cargoArtifacts sharing and uv2nix overlay composition.\n\nArchitecture documented in: docs/notes/architecture/crane-uv2nix-integration.md\n\nKey patterns:\n- Per-package Rust workspace (crates/ inside Python package)\n- crane buildDepsOnly for artifact caching\n- uv2nix overlay injection for maturin builds\n- CI matrix with rust-deps/rust-checks/python-wheel categories\n\nReference implementations:\n- ~/projects/rust-workspace/ironstar (crane patterns)\n- ~/projects/planning-workspace/langchain (federated Python)\n","status":"open","priority":2,"issue_type":"epic","owner":"cameron.ray.smith@gmail.com","created_at":"2026-01-19T11:54:41.426256-05:00","created_by":"Cameron Smith","updated_at":"2026-01-28T14:43:57.637638-05:00","dependencies":[{"issue_id":"pnt-btz","depends_on_id":"pnt-dre","type":"blocks","created_at":"2026-01-19T11:55:32.690895-05:00","created_by":"Cameron Smith"},{"issue_id":"pnt-btz","depends_on_id":"pnt-4jg","type":"blocks","created_at":"2026-01-19T11:55:32.812602-05:00","created_by":"Cameron Smith"}]} {"id":"pnt-btz.1","title":"Create pnt-cli package scaffold with Rust crates","description":"Create packages/pnt-cli/ with federated structure:\n\nDirectory structure:\n- packages/pnt-cli/pyproject.toml (maturin build-backend, manifest-path binding)\n- packages/pnt-cli/src/pnt_cli/__init__.py (Python wrapper)\n- packages/pnt-cli/crates/Cargo.toml ([workspace] with member crates)\n- packages/pnt-cli/crates/pnt-cli-core/Cargo.toml (pure Rust library)\n- packages/pnt-cli/crates/pnt-cli-py/Cargo.toml (pyo3 bindings, depends on core)\n\npyproject.toml configuration:\n- [build-system] requires maturin\u003e=1.5\n- [tool.maturin] manifest-path = \"crates/pnt-cli-py/Cargo.toml\"\n- [tool.maturin] module-name = \"pnt_cli._native\"\n\nMinimal proof-of-concept: expose a simple function from Rust to Python.\n\nSee: docs/notes/architecture/crane-uv2nix-integration.md\n","status":"closed","priority":2,"issue_type":"task","owner":"cameron.ray.smith@gmail.com","created_at":"2026-01-19T11:55:17.885691-05:00","created_by":"Cameron Smith","updated_at":"2026-02-02T20:30:16.311977-05:00","closed_at":"2026-02-02T20:30:16.311977-05:00","close_reason":"Implemented in a3e79c3. Scaffold verified: cargo check, cargo test (2/2 pass), cargo clippy clean.","dependencies":[{"issue_id":"pnt-btz.1","depends_on_id":"pnt-btz","type":"parent-child","created_at":"2026-01-19T11:55:17.886287-05:00","created_by":"Cameron Smith"},{"issue_id":"pnt-btz.1","depends_on_id":"pnt-4jg.1","type":"blocks","created_at":"2026-01-19T12:20:18.940008-05:00","created_by":"Cameron Smith"}]} -{"id":"pnt-btz.2","title":"Implement crane + uv2nix Nix modules","description":"Create Nix modules implementing the crane + uv2nix integration pattern.\n\nFiles to create:\n- nix/packages/pnt-cli/rust.nix (crane configuration)\n- nix/packages/pnt-cli/default.nix (Python + Rust composition)\n- nix/modules/rust/lib.nix (shared crane utilities, optional)\n\nrust.nix pattern:\n- crane-lib.buildDepsOnly for cargoArtifacts caching\n- commonArgs pattern for derivation hash consistency\n- crane-lib.vendorCargoDeps for maturin's cargo invocation\n- Export cargoArtifacts, cargoVendorDir, clippy, nextest\n\ndefault.nix pattern:\n- Import rust.nix\n- Create overlay injecting cargoVendorDir and CARGO_TARGET_DIR\n- Export overlay and checks for flake composition\n\nUpdate nix/modules/python.nix:\n- Load pnt-cli workspace independently (federated pattern)\n- Compose Rust overlay with uv2nix overlays\n\nSee: docs/notes/architecture/crane-uv2nix-integration.md\n","status":"open","priority":2,"issue_type":"task","owner":"cameron.ray.smith@gmail.com","created_at":"2026-01-19T11:55:18.885252-05:00","created_by":"Cameron Smith","updated_at":"2026-01-28T14:43:58.112357-05:00","dependencies":[{"issue_id":"pnt-btz.2","depends_on_id":"pnt-btz","type":"parent-child","created_at":"2026-01-19T11:55:18.885818-05:00","created_by":"Cameron Smith"},{"issue_id":"pnt-btz.2","depends_on_id":"pnt-btz.1","type":"blocks","created_at":"2026-01-19T12:20:08.210077-05:00","created_by":"Cameron Smith"}]} +{"id":"pnt-btz.2","title":"Implement crane + uv2nix Nix modules","description":"Create Nix modules implementing the crane + uv2nix integration pattern.\n\nFiles to create:\n- nix/packages/pnt-cli/rust.nix (crane configuration)\n- nix/packages/pnt-cli/default.nix (Python + Rust composition)\n- nix/modules/rust/lib.nix (shared crane utilities, optional)\n\nrust.nix pattern:\n- crane-lib.buildDepsOnly for cargoArtifacts caching\n- commonArgs pattern for derivation hash consistency\n- crane-lib.vendorCargoDeps for maturin's cargo invocation\n- Export cargoArtifacts, cargoVendorDir, clippy, nextest\n\ndefault.nix pattern:\n- Import rust.nix\n- Create overlay injecting cargoVendorDir and CARGO_TARGET_DIR\n- Export overlay and checks for flake composition\n\nUpdate nix/modules/python.nix:\n- Load pnt-cli workspace independently (federated pattern)\n- Compose Rust overlay with uv2nix overlays\n\nSee: docs/notes/architecture/crane-uv2nix-integration.md\n","status":"closed","priority":2,"issue_type":"task","owner":"cameron.ray.smith@gmail.com","created_at":"2026-01-19T11:55:18.885252-05:00","created_by":"Cameron Smith","updated_at":"2026-02-02T20:41:16.274515-05:00","closed_at":"2026-02-02T20:41:16.274515-05:00","close_reason":"Implemented in 8d8a814. Crane checks (clippy, nextest) build. Full maturin wheel builds via nix build .#default. Python import verified: greet('nix') and add(2,3) work end-to-end.","dependencies":[{"issue_id":"pnt-btz.2","depends_on_id":"pnt-btz","type":"parent-child","created_at":"2026-01-19T11:55:18.885818-05:00","created_by":"Cameron Smith"},{"issue_id":"pnt-btz.2","depends_on_id":"pnt-btz.1","type":"blocks","created_at":"2026-01-19T12:20:08.210077-05:00","created_by":"Cameron Smith"}]} {"id":"pnt-btz.3","title":"Validate integration and update CI","description":"Validate the full crane + uv2nix + maturin integration and update CI.\n\nValidation checklist:\n- [ ] nix build .#pnt-cli produces working wheel\n- [ ] Python import succeeds: from pnt_cli._native import ...\n- [ ] Rust changes trigger minimal rebuilds (cargoArtifacts cached)\n- [ ] Python-only changes don't rebuild Rust\n- [ ] cargoClippy and cargoNextest checks pass\n\nCI updates (.github/workflows/ci.yaml):\n- Add rust-deps matrix category for cargoArtifacts caching\n- Add rust-checks matrix category for clippy/nextest\n- Ensure proper cache key based on Cargo.lock hash\n- Follow ironstar CI matrix pattern\n\nDocumentation updates:\n- Add usage example to README\n- Document development workflow (uv sync + maturin develop vs nix build)\n- Note editable install limitations\n\nSee: docs/notes/architecture/crane-uv2nix-integration.md\n","status":"open","priority":2,"issue_type":"task","owner":"cameron.ray.smith@gmail.com","created_at":"2026-01-19T11:55:19.746622-05:00","created_by":"Cameron Smith","updated_at":"2026-01-28T14:43:58.351336-05:00","dependencies":[{"issue_id":"pnt-btz.3","depends_on_id":"pnt-btz","type":"parent-child","created_at":"2026-01-19T11:55:19.74722-05:00","created_by":"Cameron Smith"},{"issue_id":"pnt-btz.3","depends_on_id":"pnt-btz.2","type":"blocks","created_at":"2026-01-19T12:20:11.013516-05:00","created_by":"Cameron Smith"}]} {"id":"pnt-dre","title":"Infrastructure alignment","description":"Align Makefile, justfile, scripts/, and CI with vanixiets and typescript-nix-template patterns. Makefile bootstrap-only, grouped justfile recipes, cached-ci-job CI pattern, omnix template integration.","status":"closed","priority":2,"issue_type":"epic","owner":"cameron.ray.smith@gmail.com","created_at":"2026-01-19T11:54:39.841346-05:00","created_by":"Cameron Smith","updated_at":"2026-02-02T15:56:26.823947-05:00","closed_at":"2026-02-02T15:56:26.823947-05:00","close_reason":"All children closed: pnt-dre.1 (Makefile), pnt-dre.2 (justfile), pnt-dre.3 (scripts), pnt-dre.4 (cached-ci-job/CI), pnt-dre.5 (omnix template). Infrastructure alignment complete."} {"id":"pnt-dre.1","title":"Refactor Makefile to bootstrap-only pattern","description":"Restrict Makefile to bootstrap targets only: install-nix, install-direnv, verify, setup-user, check-secrets, clean. Move all other targets to justfile.","status":"closed","priority":2,"issue_type":"task","owner":"cameron.ray.smith@gmail.com","created_at":"2026-01-19T11:54:54.237851-05:00","created_by":"Cameron Smith","updated_at":"2026-02-02T15:39:45.088007-05:00","closed_at":"2026-02-02T15:39:45.088007-05:00","close_reason":"Added verify, setup-user, check-secrets targets aligned with vanixiets. Updated bootstrap output with numbered next-steps. Makefile was already bootstrap-only; no targets removed.","dependencies":[{"issue_id":"pnt-dre.1","depends_on_id":"pnt-dre","type":"parent-child","created_at":"2026-01-19T11:54:54.238477-05:00","created_by":"Cameron Smith"}]} From 1b7b12eb54cb31366d0386b20b8068831a10b20a Mon Sep 17 00:00:00 2001 From: Cameron Smith Date: Mon, 2 Feb 2026 20:43:43 -0500 Subject: [PATCH 066/134] feat(ci): add Rust justfile recipes, update CI filters and hash-sources --- .github/workflows/ci.yaml | 4 +++- justfile | 28 ++++++++++++++++++++++++++++ nix/modules/python.nix | 12 ++++-------- 3 files changed, 35 insertions(+), 9 deletions(-) diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 803e28a..dd41322 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -34,6 +34,7 @@ on: - "!justfile" - "!packages/*/uv.lock" - "!packages/*/pyproject.toml" + - "!packages/*/crates/**" push: branches: - "main" @@ -47,6 +48,7 @@ on: - "!justfile" - "!packages/*/uv.lock" - "!packages/*/pyproject.toml" + - "!packages/*/crates/**" concurrency: group: ci-${{ github.event.pull_request.number || github.ref }} @@ -213,7 +215,7 @@ jobs: id: cache uses: ./.github/actions/cached-ci-job with: - hash-sources: '**/*.nix flake.lock justfile packages/*/pyproject.toml packages/*/uv.lock' + hash-sources: '**/*.nix flake.lock justfile packages/*/pyproject.toml packages/*/uv.lock packages/*/crates/Cargo.lock' force-run: ${{ inputs.force_run || 'false' }} - name: Install dependencies diff --git a/justfile b/justfile index c0f7e3e..8b296e2 100644 --- a/justfile +++ b/justfile @@ -9,6 +9,7 @@ default: ## Nix ## Python ## Release +## Rust ## Secrets ## Template @@ -377,6 +378,33 @@ uv-type: _ensure-venv check: lint type test @printf "\n\033[92mAll checks passed!\033[0m\n" +## Rust + +# Build Rust crates for a package +[group('rust')] +cargo-build package="pnt-cli": + cd packages/{{package}}/crates && cargo build + +# Run Rust tests via cargo test +[group('rust')] +cargo-test package="pnt-cli": + cd packages/{{package}}/crates && cargo test + +# Run Rust clippy lints +[group('rust')] +cargo-clippy package="pnt-cli": + cd packages/{{package}}/crates && cargo clippy --all-targets -- --deny warnings + +# Run Rust tests via cargo-nextest +[group('rust')] +cargo-nextest package="pnt-cli": + cd packages/{{package}}/crates && cargo nextest run --no-tests=pass + +# Run all Rust checks (clippy, test) +[group('rust')] +cargo-check package="pnt-cli": (cargo-clippy package) (cargo-test package) + @printf "\nAll Rust checks passed for {{package}}.\n" + ## Secrets # Show existing secrets using sops diff --git a/nix/modules/python.nix b/nix/modules/python.nix index f0c18d8..33e53c4 100644 --- a/nix/modules/python.nix +++ b/nix/modules/python.nix @@ -82,21 +82,17 @@ ] ); + # Editable set excludes pnt-cli: maturin packages are incompatible with + # uv2nix's editable overlay (pyprojectFixupEditableHook expects EDITABLE_ROOT + # which maturin's build process does not set). pnt-cli is built as a regular + # wheel in the devshell; use `maturin develop` for iterative Rust development. mkEditablePythonSet = python: (mkPythonSet python).overrideScope ( lib.composeManyExtensions [ - packageWorkspaces.pnt-cli.editableOverlay packageWorkspaces.pnt-functional.editableOverlay packageWorkspaces.python-nix-template.editableOverlay (final: prev: { - pnt-cli = prev.pnt-cli.overrideAttrs (old: { - nativeBuildInputs = - old.nativeBuildInputs - ++ final.resolveBuildSystem { - editables = [ ]; - }; - }); python-nix-template = prev.python-nix-template.overrideAttrs (old: { nativeBuildInputs = old.nativeBuildInputs From 301226cd1e34ac9335f52e592ff0ff699ef7d269 Mon Sep 17 00:00:00 2001 From: Cameron Smith Date: Mon, 2 Feb 2026 20:45:06 -0500 Subject: [PATCH 067/134] chore(issues): close pnt-btz.3 and pnt-btz epic, pyo3 integration complete --- .beads/issues.jsonl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.beads/issues.jsonl b/.beads/issues.jsonl index 826e668..e1e13fe 100644 --- a/.beads/issues.jsonl +++ b/.beads/issues.jsonl @@ -3,10 +3,10 @@ {"id":"pnt-4jg.2","title":"Configure pixi feature-based composition","description":"Implement pixi feature/environment pattern: [feature.X.dependencies] + [environments] composition. Single pixi.lock covering all environments. Per-feature task definitions. Target-specific dependencies for platform support.","status":"closed","priority":2,"issue_type":"task","owner":"cameron.ray.smith@gmail.com","created_at":"2026-01-19T11:55:08.085592-05:00","created_by":"Cameron Smith","updated_at":"2026-02-02T15:36:49.459815-05:00","closed_at":"2026-02-02T15:36:49.459815-05:00","close_reason":"Verified pixi feature composition via nix develop -c just \u003crecipe\u003e. Fixed: added missing feature tasks to python-nix-template, delegated justfile conda recipes to pixi task names for correct working directory, moved deprecated build channels to backend.channels.","dependencies":[{"issue_id":"pnt-4jg.2","depends_on_id":"pnt-4jg","type":"parent-child","created_at":"2026-01-19T11:55:08.086155-05:00","created_by":"Cameron Smith"}]} {"id":"pnt-4jg.3","title":"Document package distribution channels","description":"Document which packages support uv/pypi vs pixi/conda distribution. Note dependency graph differences between channels. Update README and package metadata.","status":"closed","priority":2,"issue_type":"task","owner":"cameron.ray.smith@gmail.com","created_at":"2026-01-19T11:55:09.051203-05:00","created_by":"Cameron Smith","updated_at":"2026-02-02T15:37:38.374454-05:00","closed_at":"2026-02-02T15:37:38.374454-05:00","close_reason":"Documented in docs/notes/architecture/package-distribution-channels.md. Both packages support dual-channel (uv/PyPI + pixi/conda-forge) with independent locks. No blocking dependency graph differences between channels.","dependencies":[{"issue_id":"pnt-4jg.3","depends_on_id":"pnt-4jg","type":"parent-child","created_at":"2026-01-19T11:55:09.051857-05:00","created_by":"Cameron Smith"},{"issue_id":"pnt-4jg.3","depends_on_id":"pnt-4jg.1","type":"blocks","created_at":"2026-01-19T12:20:13.557576-05:00","created_by":"Cameron Smith"},{"issue_id":"pnt-4jg.3","depends_on_id":"pnt-4jg.2","type":"blocks","created_at":"2026-01-19T12:20:16.147971-05:00","created_by":"Cameron Smith"}]} {"id":"pnt-5vr","title":"Migrate container builds from flocken/nixpod to nix2container","description":"Replace the current flocken-based multi-arch container build pipeline with the nix2container pattern used in vanixiets.\n\nCurrent state:\n- nix/modules/containers.nix uses nixpod buildMultiUserNixImage for image construction\n- flocken mkDockerManifest for multi-arch manifest creation and registry push\n- .github/actions/build-nix-image/ uses QEMU for arm64, apt-get skopeo\n- build-nix-images.yaml workflow orchestrates the flocken-based pipeline\n\nTarget state (matching vanixiets):\n- nix2container.buildImage / buildLayer for image construction\n- pkgsCross for cross-compilation (eliminates QEMU dependency)\n- skopeo-nix2container with nix: transport for pushing\n- Custom mkMultiArchManifest (crane-based) for manifest lists\n- containerMatrix flake output for CI matrix generation (pure evaluation)\n- Per-container layer strategy: base layer (bash, coreutils) + app layer\n\nAcceptance criteria:\n- nix2container flake input added (replaces flocken input)\n- nix/modules/containers.nix rewritten with nix2container pattern\n- pkgsCross used for cross-compilation targets\n- lib/mk-multi-arch-manifest.nix ported from vanixiets\n- .github/actions/build-nix-image/ updated (remove QEMU, apt-get skopeo)\n- build-nix-images.yaml updated for nix2container workflow\n- flocken input removed from flake.nix\n- nixpod dependency evaluated (may still be needed for base image features)\n- containerMatrix flake output for CI matrix generation\n\nReference: ~/projects/nix-workspace/vanixiets/modules/containers/default.nix\nReference: ~/projects/nix-workspace/vanixiets/lib/mk-multi-arch-manifest.nix","status":"open","priority":2,"issue_type":"task","owner":"cameron.ray.smith@gmail.com","created_at":"2026-02-02T20:24:12.624117-05:00","created_by":"Cameron Smith","updated_at":"2026-02-02T20:24:12.624117-05:00"} -{"id":"pnt-btz","title":"pyo3/Rust extension integration","description":"Add Rust extension module support via maturin + pyo3, demonstrating Nix build integration with crane cargoArtifacts sharing and uv2nix overlay composition.\n\nArchitecture documented in: docs/notes/architecture/crane-uv2nix-integration.md\n\nKey patterns:\n- Per-package Rust workspace (crates/ inside Python package)\n- crane buildDepsOnly for artifact caching\n- uv2nix overlay injection for maturin builds\n- CI matrix with rust-deps/rust-checks/python-wheel categories\n\nReference implementations:\n- ~/projects/rust-workspace/ironstar (crane patterns)\n- ~/projects/planning-workspace/langchain (federated Python)\n","status":"open","priority":2,"issue_type":"epic","owner":"cameron.ray.smith@gmail.com","created_at":"2026-01-19T11:54:41.426256-05:00","created_by":"Cameron Smith","updated_at":"2026-01-28T14:43:57.637638-05:00","dependencies":[{"issue_id":"pnt-btz","depends_on_id":"pnt-dre","type":"blocks","created_at":"2026-01-19T11:55:32.690895-05:00","created_by":"Cameron Smith"},{"issue_id":"pnt-btz","depends_on_id":"pnt-4jg","type":"blocks","created_at":"2026-01-19T11:55:32.812602-05:00","created_by":"Cameron Smith"}]} +{"id":"pnt-btz","title":"pyo3/Rust extension integration","description":"Add Rust extension module support via maturin + pyo3, demonstrating Nix build integration with crane cargoArtifacts sharing and uv2nix overlay composition.\n\nArchitecture documented in: docs/notes/architecture/crane-uv2nix-integration.md\n\nKey patterns:\n- Per-package Rust workspace (crates/ inside Python package)\n- crane buildDepsOnly for artifact caching\n- uv2nix overlay injection for maturin builds\n- CI matrix with rust-deps/rust-checks/python-wheel categories\n\nReference implementations:\n- ~/projects/rust-workspace/ironstar (crane patterns)\n- ~/projects/planning-workspace/langchain (federated Python)\n","status":"closed","priority":2,"issue_type":"epic","owner":"cameron.ray.smith@gmail.com","created_at":"2026-01-19T11:54:41.426256-05:00","created_by":"Cameron Smith","updated_at":"2026-02-02T20:45:01.187149-05:00","closed_at":"2026-02-02T20:45:01.187149-05:00","close_reason":"All 3 children complete. Crane + uv2nix + maturin integration fully operational.","dependencies":[{"issue_id":"pnt-btz","depends_on_id":"pnt-dre","type":"blocks","created_at":"2026-01-19T11:55:32.690895-05:00","created_by":"Cameron Smith"},{"issue_id":"pnt-btz","depends_on_id":"pnt-4jg","type":"blocks","created_at":"2026-01-19T11:55:32.812602-05:00","created_by":"Cameron Smith"}]} {"id":"pnt-btz.1","title":"Create pnt-cli package scaffold with Rust crates","description":"Create packages/pnt-cli/ with federated structure:\n\nDirectory structure:\n- packages/pnt-cli/pyproject.toml (maturin build-backend, manifest-path binding)\n- packages/pnt-cli/src/pnt_cli/__init__.py (Python wrapper)\n- packages/pnt-cli/crates/Cargo.toml ([workspace] with member crates)\n- packages/pnt-cli/crates/pnt-cli-core/Cargo.toml (pure Rust library)\n- packages/pnt-cli/crates/pnt-cli-py/Cargo.toml (pyo3 bindings, depends on core)\n\npyproject.toml configuration:\n- [build-system] requires maturin\u003e=1.5\n- [tool.maturin] manifest-path = \"crates/pnt-cli-py/Cargo.toml\"\n- [tool.maturin] module-name = \"pnt_cli._native\"\n\nMinimal proof-of-concept: expose a simple function from Rust to Python.\n\nSee: docs/notes/architecture/crane-uv2nix-integration.md\n","status":"closed","priority":2,"issue_type":"task","owner":"cameron.ray.smith@gmail.com","created_at":"2026-01-19T11:55:17.885691-05:00","created_by":"Cameron Smith","updated_at":"2026-02-02T20:30:16.311977-05:00","closed_at":"2026-02-02T20:30:16.311977-05:00","close_reason":"Implemented in a3e79c3. Scaffold verified: cargo check, cargo test (2/2 pass), cargo clippy clean.","dependencies":[{"issue_id":"pnt-btz.1","depends_on_id":"pnt-btz","type":"parent-child","created_at":"2026-01-19T11:55:17.886287-05:00","created_by":"Cameron Smith"},{"issue_id":"pnt-btz.1","depends_on_id":"pnt-4jg.1","type":"blocks","created_at":"2026-01-19T12:20:18.940008-05:00","created_by":"Cameron Smith"}]} {"id":"pnt-btz.2","title":"Implement crane + uv2nix Nix modules","description":"Create Nix modules implementing the crane + uv2nix integration pattern.\n\nFiles to create:\n- nix/packages/pnt-cli/rust.nix (crane configuration)\n- nix/packages/pnt-cli/default.nix (Python + Rust composition)\n- nix/modules/rust/lib.nix (shared crane utilities, optional)\n\nrust.nix pattern:\n- crane-lib.buildDepsOnly for cargoArtifacts caching\n- commonArgs pattern for derivation hash consistency\n- crane-lib.vendorCargoDeps for maturin's cargo invocation\n- Export cargoArtifacts, cargoVendorDir, clippy, nextest\n\ndefault.nix pattern:\n- Import rust.nix\n- Create overlay injecting cargoVendorDir and CARGO_TARGET_DIR\n- Export overlay and checks for flake composition\n\nUpdate nix/modules/python.nix:\n- Load pnt-cli workspace independently (federated pattern)\n- Compose Rust overlay with uv2nix overlays\n\nSee: docs/notes/architecture/crane-uv2nix-integration.md\n","status":"closed","priority":2,"issue_type":"task","owner":"cameron.ray.smith@gmail.com","created_at":"2026-01-19T11:55:18.885252-05:00","created_by":"Cameron Smith","updated_at":"2026-02-02T20:41:16.274515-05:00","closed_at":"2026-02-02T20:41:16.274515-05:00","close_reason":"Implemented in 8d8a814. Crane checks (clippy, nextest) build. Full maturin wheel builds via nix build .#default. Python import verified: greet('nix') and add(2,3) work end-to-end.","dependencies":[{"issue_id":"pnt-btz.2","depends_on_id":"pnt-btz","type":"parent-child","created_at":"2026-01-19T11:55:18.885818-05:00","created_by":"Cameron Smith"},{"issue_id":"pnt-btz.2","depends_on_id":"pnt-btz.1","type":"blocks","created_at":"2026-01-19T12:20:08.210077-05:00","created_by":"Cameron Smith"}]} -{"id":"pnt-btz.3","title":"Validate integration and update CI","description":"Validate the full crane + uv2nix + maturin integration and update CI.\n\nValidation checklist:\n- [ ] nix build .#pnt-cli produces working wheel\n- [ ] Python import succeeds: from pnt_cli._native import ...\n- [ ] Rust changes trigger minimal rebuilds (cargoArtifacts cached)\n- [ ] Python-only changes don't rebuild Rust\n- [ ] cargoClippy and cargoNextest checks pass\n\nCI updates (.github/workflows/ci.yaml):\n- Add rust-deps matrix category for cargoArtifacts caching\n- Add rust-checks matrix category for clippy/nextest\n- Ensure proper cache key based on Cargo.lock hash\n- Follow ironstar CI matrix pattern\n\nDocumentation updates:\n- Add usage example to README\n- Document development workflow (uv sync + maturin develop vs nix build)\n- Note editable install limitations\n\nSee: docs/notes/architecture/crane-uv2nix-integration.md\n","status":"open","priority":2,"issue_type":"task","owner":"cameron.ray.smith@gmail.com","created_at":"2026-01-19T11:55:19.746622-05:00","created_by":"Cameron Smith","updated_at":"2026-01-28T14:43:58.351336-05:00","dependencies":[{"issue_id":"pnt-btz.3","depends_on_id":"pnt-btz","type":"parent-child","created_at":"2026-01-19T11:55:19.74722-05:00","created_by":"Cameron Smith"},{"issue_id":"pnt-btz.3","depends_on_id":"pnt-btz.2","type":"blocks","created_at":"2026-01-19T12:20:11.013516-05:00","created_by":"Cameron Smith"}]} +{"id":"pnt-btz.3","title":"Validate integration and update CI","description":"Validate the full crane + uv2nix + maturin integration and update CI.\n\nValidation checklist:\n- [ ] nix build .#pnt-cli produces working wheel\n- [ ] Python import succeeds: from pnt_cli._native import ...\n- [ ] Rust changes trigger minimal rebuilds (cargoArtifacts cached)\n- [ ] Python-only changes don't rebuild Rust\n- [ ] cargoClippy and cargoNextest checks pass\n\nCI updates (.github/workflows/ci.yaml):\n- Add rust-deps matrix category for cargoArtifacts caching\n- Add rust-checks matrix category for clippy/nextest\n- Ensure proper cache key based on Cargo.lock hash\n- Follow ironstar CI matrix pattern\n\nDocumentation updates:\n- Add usage example to README\n- Document development workflow (uv sync + maturin develop vs nix build)\n- Note editable install limitations\n\nSee: docs/notes/architecture/crane-uv2nix-integration.md\n","status":"closed","priority":2,"issue_type":"task","owner":"cameron.ray.smith@gmail.com","created_at":"2026-01-19T11:55:19.746622-05:00","created_by":"Cameron Smith","updated_at":"2026-02-02T20:44:56.18025-05:00","closed_at":"2026-02-02T20:44:56.18025-05:00","close_reason":"Validated in 1b7b12e. All acceptance criteria pass: nix build produces working wheel, Python import succeeds, clippy/nextest checks pass, justfile recipes work via nix develop -c. CI updated with Rust path filters and hash-sources.","dependencies":[{"issue_id":"pnt-btz.3","depends_on_id":"pnt-btz","type":"parent-child","created_at":"2026-01-19T11:55:19.74722-05:00","created_by":"Cameron Smith"},{"issue_id":"pnt-btz.3","depends_on_id":"pnt-btz.2","type":"blocks","created_at":"2026-01-19T12:20:11.013516-05:00","created_by":"Cameron Smith"}]} {"id":"pnt-dre","title":"Infrastructure alignment","description":"Align Makefile, justfile, scripts/, and CI with vanixiets and typescript-nix-template patterns. Makefile bootstrap-only, grouped justfile recipes, cached-ci-job CI pattern, omnix template integration.","status":"closed","priority":2,"issue_type":"epic","owner":"cameron.ray.smith@gmail.com","created_at":"2026-01-19T11:54:39.841346-05:00","created_by":"Cameron Smith","updated_at":"2026-02-02T15:56:26.823947-05:00","closed_at":"2026-02-02T15:56:26.823947-05:00","close_reason":"All children closed: pnt-dre.1 (Makefile), pnt-dre.2 (justfile), pnt-dre.3 (scripts), pnt-dre.4 (cached-ci-job/CI), pnt-dre.5 (omnix template). Infrastructure alignment complete."} {"id":"pnt-dre.1","title":"Refactor Makefile to bootstrap-only pattern","description":"Restrict Makefile to bootstrap targets only: install-nix, install-direnv, verify, setup-user, check-secrets, clean. Move all other targets to justfile.","status":"closed","priority":2,"issue_type":"task","owner":"cameron.ray.smith@gmail.com","created_at":"2026-01-19T11:54:54.237851-05:00","created_by":"Cameron Smith","updated_at":"2026-02-02T15:39:45.088007-05:00","closed_at":"2026-02-02T15:39:45.088007-05:00","close_reason":"Added verify, setup-user, check-secrets targets aligned with vanixiets. Updated bootstrap output with numbered next-steps. Makefile was already bootstrap-only; no targets removed.","dependencies":[{"issue_id":"pnt-dre.1","depends_on_id":"pnt-dre","type":"parent-child","created_at":"2026-01-19T11:54:54.238477-05:00","created_by":"Cameron Smith"}]} {"id":"pnt-dre.2","title":"Adopt grouped justfile recipe pattern","description":"Reorganize justfile with grouped recipes and section headers following vanixiets pattern: nix, python, conda, docs, secrets, ci/cd groups. Add help comments for each recipe.","status":"closed","priority":2,"issue_type":"task","owner":"cameron.ray.smith@gmail.com","created_at":"2026-01-19T11:54:55.145094-05:00","created_by":"Cameron Smith","updated_at":"2026-02-02T15:42:24.899403-05:00","closed_at":"2026-02-02T15:42:24.899403-05:00","close_reason":"Aligned group naming (conda package→conda, python package→python), fixed Documentation→Docs header, demoted GCP sub-section, corrected type recipe comment, moved helper to EOF.","dependencies":[{"issue_id":"pnt-dre.2","depends_on_id":"pnt-dre","type":"parent-child","created_at":"2026-01-19T11:54:55.145764-05:00","created_by":"Cameron Smith"}]} From d968bedb5fcf8c72f1901473dd81953ecd8556a5 Mon Sep 17 00:00:00 2001 From: Cameron Smith Date: Mon, 2 Feb 2026 20:58:04 -0500 Subject: [PATCH 068/134] docs(architecture): add resolved decisions from pnt-btz implementation Document three implementation decisions that diverged from the original crane-uv2nix integration design: crane config.toml reuse for vendored deps, cargoArtifacts isolation from maturin wheel builds, and editable overlay exclusion for maturin packages. --- .../architecture/crane-uv2nix-integration.md | 50 ++++++++++++++++--- 1 file changed, 42 insertions(+), 8 deletions(-) diff --git a/docs/notes/architecture/crane-uv2nix-integration.md b/docs/notes/architecture/crane-uv2nix-integration.md index 4070c5c..4be1e01 100644 --- a/docs/notes/architecture/crane-uv2nix-integration.md +++ b/docs/notes/architecture/crane-uv2nix-integration.md @@ -134,12 +134,12 @@ in { # Override for this package in the Python package set overlay = final: prev: { pnt-cli = prev.pnt-cli.overrideAttrs (old: { - # Inject pre-vendored Cargo deps (crane's vendoring, not rustPlatform's) - cargoVendorDir = rustPkgs.cargoVendorDir; - - # Reuse crane's cargoArtifacts for incremental builds + # Configure cargo to use crane's vendored dependencies for offline builds. + # Crane's vendorCargoDeps output includes a config.toml with source + # replacement directives pointing to the vendored crate store paths. preBuild = '' - export CARGO_TARGET_DIR="${rustPkgs.cargoArtifacts}/target" + mkdir -p .cargo + cp ${rustPkgs.cargoVendorDir}/config.toml .cargo/config.toml ''; nativeBuildInputs = old.nativeBuildInputs ++ [ @@ -382,6 +382,40 @@ The implementation follows the beads epic dependency chain: - Implements rust.nix and default.nix patterns - Validates full crane + uv2nix + maturin integration +## Resolved decisions + +These decisions emerged during pnt-btz implementation and diverge from or refine the original design above. + +### Crane's config.toml reuse for vendored dependencies + +Maturin needs cargo configured for offline builds using crane's vendored crate store. +Rather than hand-crafting a `.cargo/config.toml` with source replacement directives, the overlay copies crane's `vendorCargoDeps` output config.toml directly. +This works because crane generates deterministic `nix-sources-` source names in its config.toml that correspond to the vendored store paths. +The Pattern 2 overlay above reflects this approach. + +### No CARGO_TARGET_DIR sharing between crane checks and maturin wheel builds + +The original design proposed sharing crane's `cargoArtifacts` with the maturin wheel build via `CARGO_TARGET_DIR`. +In practice the nix store is read-only, so `cargoArtifacts` cannot serve as a writable target directory for maturin's cargo invocation. + +The resolved architecture separates the two build paths: + +- Crane check derivations (`cargoClippy`, `cargoNextest`) inherit `cargoArtifacts` for fast cached feedback on Rust code quality. +- The maturin wheel build within pyproject.nix compiles Rust from source using only `cargoVendorDir` for offline dependency resolution. + +This is a deliberate tradeoff: check caching provides fast CI feedback on the Rust side, while full wheel builds remain hermetic without depending on mutable build artifacts. + +### Editable overlay exclusion for maturin packages + +Maturin packages are incompatible with uv2nix's `pyprojectFixupEditableHook`, which expects `EDITABLE_ROOT` to be set during the build process. +Maturin's build backend does not set this variable. + +The `mkEditablePythonSet` in `nix/modules/python.nix` composes editable overlays only for pure Python packages (`pnt-functional`, `python-nix-template`), excluding `pnt-cli`. +The pnt-cli package is built as a regular wheel in the devshell. + +For iterative Rust development, the workflow is: enter the devshell via `nix develop`, then run `maturin develop --uv` in the package directory. +This rebuilds the native extension in-place without a full Nix rebuild. + ## Open questions ### Cross-package Rust dependencies @@ -402,9 +436,9 @@ Initial recommendation: keep cargoArtifacts per-package for simplicity, optimize ### Editable development workflow -For local development, developers want fast iteration without full Nix rebuilds. -Recommend: use `uv sync` + `maturin develop` outside Nix for iteration, Nix for CI and reproducible builds. -The Nix derivations serve as the source of truth; local development uses native tooling for speed. +Resolved: maturin packages use `maturin develop --uv` within `nix develop` for iterative Rust compilation (see "Editable overlay exclusion" in resolved decisions above). +Pure Python packages use uv2nix editable overlays as designed. +Nix derivations remain the source of truth; local development uses native tooling for speed. ## References From 0945ada5d108692a51e4149c1d83a2bf910c496f Mon Sep 17 00:00:00 2001 From: Cameron Smith Date: Mon, 2 Feb 2026 21:14:31 -0500 Subject: [PATCH 069/134] feat(ci): add setup-nix composite action with nothing-but-nix pattern Port from vanixiets with two additions: extra-conf input for workflow-specific nix configuration and extra-pull-names for cachix additional pull caches. Replaces inline Nix installer across workflows. --- .github/actions/setup-nix/action.yml | 157 +++++++++++++++++++++++++++ 1 file changed, 157 insertions(+) create mode 100644 .github/actions/setup-nix/action.yml diff --git a/.github/actions/setup-nix/action.yml b/.github/actions/setup-nix/action.yml new file mode 100644 index 0000000..5e056a6 --- /dev/null +++ b/.github/actions/setup-nix/action.yml @@ -0,0 +1,157 @@ +name: setup-nix +description: setup nix using nothing-but-nix pattern with space reclamation and magic-nix-cache + +inputs: + installer: + description: | + nix installation strategy: + - 'full' (default): space reclamation + magic-nix-cache + cachix for builds + - 'quick': minimal install for simple tasks (no space reclamation, no caching overhead) + type: string + required: false + default: full + system: + description: nix system to configure (e.g., x86_64-linux, aarch64-darwin) + type: string + required: true + sandbox: + description: enable nix sandbox builds + type: string + default: "true" + extra-conf: + description: additional nix configuration lines (appended to generated config) + type: string + required: false + default: "" + enable-cachix: + description: enable cachix binary cache + type: boolean + default: false + cachix-name: + description: cachix cache name + type: string + required: false + cachix-auth-token: + description: cachix auth token + type: string + required: false + cachix-skip-push: + description: skip pushing to cachix (read-only) + type: boolean + default: false + extra-pull-names: + description: comma-separated list of additional cachix caches to pull from + type: string + required: false + default: "" + nix-version: + description: nix version to install (e.g., 2.32.4, 2.31.2) + type: string + required: false + default: "2.32.4" + hatchet: + description: | + nothing-but-nix hatchet protocol for space reclamation (linux only): + - 'holster' (level 0): ~65GB, preserves Docker + - 'carve' (level 1): ~85GB, preserves Docker + - 'cleave' (level 2, default): ~115GB, removes Docker + - 'rampage' (level 3): ~130GB, removes Docker + type: string + required: false + default: "cleave" + root-safe-haven: + description: | + Space in MB to reserve on root filesystem for non-Nix usage (e.g., Docker overlay). + Only effective with carve/cleave/rampage protocols that expand from root. + type: string + required: false + default: "2048" + mnt-safe-haven: + description: | + Space in MB to reserve on /mnt filesystem. On single-disk runners where /mnt + is on root, this effectively reserves space for Docker overlay storage. + type: string + required: false + default: "4096" + +runs: + using: composite + steps: + - name: reclaim space (linux) + if: runner.os == 'Linux' && inputs.installer == 'full' + uses: wimpysworld/nothing-but-nix@dd6ef566962bfa4656301706035da97ebbe90e9b # main + with: + hatchet-protocol: ${{ inputs.hatchet }} + nix-permission-edict: true + mnt-safe-haven: ${{ inputs.mnt-safe-haven }} + root-safe-haven: ${{ inputs.root-safe-haven }} + + - name: reclaim space (darwin) + if: runner.os == 'macOS' && inputs.installer == 'full' + shell: bash + run: | + echo "::group::disk space (before)" + sudo df -h + echo "::endgroup::" + + echo "::group::disable mds" + sudo mdutil -i off -a || echo "mdutil failed" + sudo launchctl unload -w /System/Library/LaunchDaemons/com.apple.metadata.mds.plist \ + || echo "launchctl unload failed" + echo "::endgroup::" + + echo "Background space expansion started. /nix will grow as space becomes available." + sudo rm -rf \ + /Applications/Xcode_* \ + /Library/Developer/CoreSimulator \ + /Library/Frameworks \ + /Users/runner/.dotnet \ + /Users/runner/.rustup \ + /Users/runner/Library/Android \ + /Users/runner/Library/Caches \ + /Users/runner/Library/Developer/CoreSimulator \ + /Users/runner/hostedtoolcache & + + - name: install nix + uses: cachix/install-nix-action@4e002c8ec80594ecd40e759629461e26c8abed15 # v31 + with: + install_url: https://releases.nixos.org/nix/nix-${{ inputs.nix-version }}/install + extra_nix_config: | + build-dir = /nix/build + sandbox = ${{ inputs.sandbox }} + system = ${{ inputs.system }} + keep-env-derivations = true + keep-outputs = true + ${{ inputs.extra-conf }} + + - name: create build-dir + if: runner.os == 'Linux' + shell: bash + run: sudo mkdir -p /nix/build + + - name: setup magic-nix-cache + if: inputs.installer == 'full' + uses: DeterminateSystems/magic-nix-cache-action@dfe3778ecdeec4fbe981f6e72aeeb2b6427a50e7 # main + with: + use-flakehub: false + diagnostic-endpoint: "" + + - name: setup cachix + if: inputs.enable-cachix == 'true' + uses: cachix/cachix-action@3ba601ff5bbb07c7220846facfa2cd81eeee15a1 # v16 + continue-on-error: true + with: + name: ${{ inputs.cachix-name }} + authToken: ${{ inputs.cachix-auth-token }} + skipPush: ${{ inputs.cachix-skip-push }} + extraPullNames: ${{ inputs.extra-pull-names }} + + - name: post setup-nix + if: runner.os == 'macOS' && inputs.installer == 'full' + uses: srz-zumix/post-run-action@75fdbab2efdc95cf60389ed62d3ef560fdd61953 # v3 + with: + shell: bash -e {0} + post-run: | + echo "::group::disk space (after)" + sudo df -h + echo "::endgroup::" From a594732f493e78116705ac87eb12de87f57b6c02 Mon Sep 17 00:00:00 2001 From: Cameron Smith Date: Mon, 2 Feb 2026 21:14:49 -0500 Subject: [PATCH 070/134] refactor(ci): use setup-nix action in nixci job Replace inline DeterminateSystems/nix-installer-action and cachix/cachix-action with the setup-nix composite action. --- .github/workflows/ci.yaml | 18 +++++++----------- 1 file changed, 7 insertions(+), 11 deletions(-) diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index dd41322..5e7ec5d 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -225,20 +225,16 @@ jobs: sudo apt-get install -yq zstd sudo apt-get clean - - name: Install Nix + - name: Setup Nix if: steps.cache.outputs.should-run == 'true' - uses: DeterminateSystems/nix-installer-action@786fff0690178f1234e4e1fe9b536e94f5433196 # ratchet:DeterminateSystems/nix-installer-action@main + uses: ./.github/actions/setup-nix with: + system: x86_64-linux extra-conf: "system-features = nixos-test benchmark big-parallel kvm" - - - name: Setup remote cache - if: steps.cache.outputs.should-run == 'true' - uses: cachix/cachix-action@be5295a636153b6ad194d3245f78f8e0b78dc704 # ratchet:cachix/cachix-action@master - continue-on-error: true - with: - name: "${{ vars.CACHIX_CACHE_NAME }}" - authToken: "${{ secrets.CACHIX_AUTH_TOKEN }}" - extraPullNames: nix-community,pyproject-nix,sciexp,srid + enable-cachix: true + cachix-name: ${{ vars.CACHIX_CACHE_NAME }} + cachix-auth-token: ${{ secrets.CACHIX_AUTH_TOKEN }} + extra-pull-names: nix-community,pyproject-nix,sciexp,srid - name: Setup tmate debug session if: steps.cache.outputs.should-run == 'true' && needs.set-variables.outputs.debug == 'true' From 5c45f5e75a247f49a5ce52784906ca70f2b7364b Mon Sep 17 00:00:00 2001 From: Cameron Smith Date: Mon, 2 Feb 2026 21:15:02 -0500 Subject: [PATCH 071/134] refactor(ci): use setup-nix action in python-test workflow Replace inline Nix installer and cachix setup with setup-nix composite action for consistent Nix environment configuration. --- .github/workflows/python-test.yaml | 18 +++++++----------- 1 file changed, 7 insertions(+), 11 deletions(-) diff --git a/.github/workflows/python-test.yaml b/.github/workflows/python-test.yaml index 8514301..c37b9eb 100644 --- a/.github/workflows/python-test.yaml +++ b/.github/workflows/python-test.yaml @@ -61,20 +61,16 @@ jobs: hash-sources: 'packages/${{ inputs.package-name }}/**/*.py packages/${{ inputs.package-name }}/pyproject.toml packages/${{ inputs.package-name }}/uv.lock justfile **/*.nix flake.lock' force-run: ${{ inputs.force_run || 'false' }} - - name: Install Nix + - name: Setup Nix if: steps.cache.outputs.should-run == 'true' - uses: DeterminateSystems/nix-installer-action@786fff0690178f1234e4e1fe9b536e94f5433196 # ratchet:DeterminateSystems/nix-installer-action@main + uses: ./.github/actions/setup-nix with: + system: x86_64-linux extra-conf: "system-features = nixos-test benchmark big-parallel kvm" - - - name: Setup remote cache - if: steps.cache.outputs.should-run == 'true' - uses: cachix/cachix-action@be5295a636153b6ad194d3245f78f8e0b78dc704 # ratchet:cachix/cachix-action@master - continue-on-error: true - with: - name: "${{ vars.CACHIX_CACHE_NAME }}" - authToken: "${{ secrets.CACHIX_AUTH_TOKEN }}" - extraPullNames: nix-community,pyproject-nix,sciexp + enable-cachix: true + cachix-name: ${{ vars.CACHIX_CACHE_NAME }} + cachix-auth-token: ${{ secrets.CACHIX_AUTH_TOKEN }} + extra-pull-names: nix-community,pyproject-nix,sciexp - name: Setup tmate debug session if: steps.cache.outputs.should-run == 'true' && inputs.debug_enabled == 'true' From 02c9a9fbee46fcb2dc39cec5c33b50ccb1207d86 Mon Sep 17 00:00:00 2001 From: Cameron Smith Date: Mon, 2 Feb 2026 21:15:25 -0500 Subject: [PATCH 072/134] refactor(ci): use setup-nix action in build-nix-images workflow Replace inline maximize-build-space, Nix installer, and cachix setup with setup-nix composite action. Space reclamation now handled by nothing-but-nix via the setup-nix action's hatchet protocol. --- .github/workflows/build-nix-images.yaml | 50 ++++++++----------------- 1 file changed, 15 insertions(+), 35 deletions(-) diff --git a/.github/workflows/build-nix-images.yaml b/.github/workflows/build-nix-images.yaml index 125a0fb..0d5702c 100644 --- a/.github/workflows/build-nix-images.yaml +++ b/.github/workflows/build-nix-images.yaml @@ -49,20 +49,11 @@ jobs: fail-fast: false steps: - # https://github.com/easimon/maximize-build-space/blob/v10/action.yml#L121-L137 - - name: Maximize build space - run: | - echo "Available storage before removing unused software:" - sudo df -h - echo - sudo rm -rf /usr/local/lib/android - echo "Available storage after removing android:" - sudo df -h - echo - sudo rm -rf /opt/hostedtoolcache/CodeQL - echo "Available storage after removing codeql:" - sudo df -h - echo + - name: Checkout code + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # ratchet:actions/checkout@v4 + with: + ref: ${{ inputs.branch }} + fetch-depth: 0 - name: Install dependencies shell: bash @@ -71,33 +62,22 @@ jobs: sudo apt-get install -yq zstd sudo apt-get clean - - name: Checkout code - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # ratchet:actions/checkout@v4 + - name: Setup Nix + uses: ./.github/actions/setup-nix with: - ref: ${{ inputs.branch }} - fetch-depth: 0 + system: x86_64-linux + extra-conf: | + system-features = nixos-test benchmark big-parallel kvm + extra-platforms = aarch64-linux + enable-cachix: true + cachix-name: ${{ vars.CACHIX_CACHE_NAME }} + cachix-auth-token: ${{ secrets.CACHIX_AUTH_TOKEN }} + extra-pull-names: nix-community,pyproject-nix,sciexp,srid - name: Setup tmate debug session uses: mxschmitt/action-tmate@e5c7151931ca95bad1c6f4190c730ecf8c7dde48 # ratchet:mxschmitt/action-tmate@v3 if: ${{ inputs.debug_enabled == 'true' }} - - name: Install Nix - uses: DeterminateSystems/nix-installer-action@786fff0690178f1234e4e1fe9b536e94f5433196 # ratchet:DeterminateSystems/nix-installer-action@main - with: - extra-conf: "system-features = nixos-test benchmark big-parallel kvm" - # - name: Install Nix - # uses: nixbuild/nix-quick-install-action@v33 - # with: - # nix_conf: "system-features = nixos-test benchmark big-parallel kvm" - - name: Setup remote cache - # TODO: disable continue-on-error https://www.github.com/cachix/cachix-action/issues/200 - uses: cachix/cachix-action@be5295a636153b6ad194d3245f78f8e0b78dc704 # ratchet:cachix/cachix-action@master - continue-on-error: true - with: - name: "${{ vars.CACHIX_CACHE_NAME }}" - authToken: "${{ secrets.CACHIX_AUTH_TOKEN }}" - extraPullNames: nix-community,pyproject-nix,sciexp,srid - - name: Build ${{ matrix.image }} image uses: ./.github/actions/build-nix-image with: From ec27c9aae0943fac75bac90fda04024677eb93c7 Mon Sep 17 00:00:00 2001 From: Cameron Smith Date: Mon, 2 Feb 2026 21:15:50 -0500 Subject: [PATCH 073/134] refactor(ci): remove redundant Nix setup from build-nix-image action Nix installation and cachix configuration are now handled by the parent workflow via setup-nix. Remove duplicate installer and cachix steps along with their input parameters from the composite action. --- .github/actions/build-nix-image/action.yml | 19 ------------------- .github/workflows/build-nix-images.yaml | 2 -- 2 files changed, 21 deletions(-) diff --git a/.github/actions/build-nix-image/action.yml b/.github/actions/build-nix-image/action.yml index d0e3b06..728e5fd 100644 --- a/.github/actions/build-nix-image/action.yml +++ b/.github/actions/build-nix-image/action.yml @@ -16,13 +16,6 @@ inputs: releaseVersion: description: "Release version" required: true - cachixCacheName: - description: "Name of the Cachix cache" - required: true - cachixAuthToken: - description: "Cachix authentication token" - required: true - runs: using: "composite" steps: @@ -38,18 +31,6 @@ runs: sudo apt-get install -yq skopeo sudo apt-get clean - - name: Install Nix - uses: DeterminateSystems/nix-installer-action@786fff0690178f1234e4e1fe9b536e94f5433196 # ratchet:DeterminateSystems/nix-installer-action@main - with: - extra-conf: | - extra-platforms = aarch64-linux - - - name: Setup Remote Nix Cache - uses: cachix/cachix-action@be5295a636153b6ad194d3245f78f8e0b78dc704 # ratchet:cachix/cachix-action@master - with: - name: "${{ inputs.cachixCacheName }}" - authToken: "${{ inputs.cachixAuthToken }}" - - name: Set GitHub CI Slug Variables uses: rlespinasse/github-slug-action@797d68864753cbceedc271349d402da4590e6302 # ratchet:rlespinasse/github-slug-action@v4 with: diff --git a/.github/workflows/build-nix-images.yaml b/.github/workflows/build-nix-images.yaml index 0d5702c..0d832da 100644 --- a/.github/workflows/build-nix-images.yaml +++ b/.github/workflows/build-nix-images.yaml @@ -86,5 +86,3 @@ jobs: imageFQN: "ghcr.io/sciexp/${{ matrix.image }}" nixCommand: "nix run .#${{ matrix.image }}Manifest --impure --accept-flake-config --print-build-logs --show-trace" releaseVersion: "${{ inputs.version }}" - cachixCacheName: ${{ vars.CACHIX_CACHE_NAME }} - cachixAuthToken: ${{ secrets.CACHIX_AUTH_TOKEN }} From 0b1e4facf23016a7791c41b651b834f53978051e Mon Sep 17 00:00:00 2001 From: Cameron Smith Date: Mon, 2 Feb 2026 21:16:08 -0500 Subject: [PATCH 074/134] refactor(ci): remove maximize-build-space script Superseded by nothing-but-nix space reclamation in the setup-nix composite action, which provides configurable hatchet protocols for more effective disk space management on CI runners. --- scripts/ci/maximize-build-space.sh | 17 ----------------- 1 file changed, 17 deletions(-) delete mode 100755 scripts/ci/maximize-build-space.sh diff --git a/scripts/ci/maximize-build-space.sh b/scripts/ci/maximize-build-space.sh deleted file mode 100755 index 8d4256c..0000000 --- a/scripts/ci/maximize-build-space.sh +++ /dev/null @@ -1,17 +0,0 @@ -#!/usr/bin/env bash -# Maximize available disk space on GitHub Actions runners by removing -# unused pre-installed software. Based on: -# https://github.com/easimon/maximize-build-space/blob/v10/action.yml#L121-L137 -set -euo pipefail - -echo "Available storage before removing unused software:" -sudo df -h -echo -sudo rm -rf /usr/local/lib/android -echo "Available storage after removing android:" -sudo df -h -echo -sudo rm -rf /opt/hostedtoolcache/CodeQL -echo "Available storage after removing codeql:" -sudo df -h -echo From 2bde5fee52d5cb818da1a345d5b853e77931f7a2 Mon Sep 17 00:00:00 2001 From: Cameron Smith Date: Mon, 2 Feb 2026 21:16:25 -0500 Subject: [PATCH 075/134] chore(issues): close pnt-m3t, setup-nix composite action complete --- .beads/issues.jsonl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.beads/issues.jsonl b/.beads/issues.jsonl index e1e13fe..d9df866 100644 --- a/.beads/issues.jsonl +++ b/.beads/issues.jsonl @@ -13,4 +13,4 @@ {"id":"pnt-dre.3","title":"Reorganize scripts/ directory structure","description":"Move scripts into subdirectories: scripts/ci/, scripts/docs/, scripts/sops/. IMPORTANT: scripts/bootstrap.sh must remain at stable path for curl one-liner URL. Update justfile and CI references.","status":"closed","priority":2,"issue_type":"task","owner":"cameron.ray.smith@gmail.com","created_at":"2026-01-19T11:54:55.839371-05:00","created_by":"Cameron Smith","updated_at":"2026-02-02T15:45:23.076616-05:00","closed_at":"2026-02-02T15:45:23.076616-05:00","close_reason":"Created scripts/bootstrap.sh (stable URL for curl one-liner) and scripts/ci/maximize-build-space.sh (canonical version of duplicated CI logic). Workflow inline references deferred to pnt-dre.4 CI redesign due to pre-checkout step ordering. scripts/sops/ and scripts/docs/ skipped — no duplication issues warranting extraction.","dependencies":[{"issue_id":"pnt-dre.3","depends_on_id":"pnt-dre","type":"parent-child","created_at":"2026-01-19T11:54:55.839951-05:00","created_by":"Cameron Smith"}]} {"id":"pnt-dre.4","title":"Implement cached-ci-job composite action pattern","description":"Add .github/actions/cached-ci-job composite action following typescript-nix-template pattern. Content-addressed caching with hash-sources and force-run support. Update CI to use category-based matrix builds.\n\nPost-federation CI adaptation: the migration from uv workspace to per-package independent locks (pnt-4jg.1) means CI must now discover and iterate packages under packages/. The matrix strategy needs a package axis in addition to the category axis, producing either a {package} x {category} matrix or per-package reusable workflow dispatches. Review how ci.yaml currently enumerates packages and ensure the composite action pattern supports per-package resolution of lock files, dependency caches, and build artifacts.\n\nAcceptance criteria:\n- .github/actions/cached-ci-job composite action implemented\n- Content-addressed caching with hash-sources and force-run support\n- CI matrix discovers packages/ dynamically (not hardcoded)\n- Matrix crosses package x category dimensions\n- Per-package uv.lock files used for cache keys (not root lock)\n- Category-based builds follow typescript-nix-template pattern","status":"closed","priority":2,"issue_type":"task","owner":"cameron.ray.smith@gmail.com","created_at":"2026-01-19T11:54:56.79376-05:00","created_by":"Cameron Smith","updated_at":"2026-02-02T15:55:30.748155-05:00","closed_at":"2026-02-02T15:55:30.748155-05:00","close_reason":"Implemented cached-ci-job composite action (ported from typescript-nix-template), per-package CI justfile recipes (ci-sync, ci-lint, ci-test, ci-typecheck, ci-check, list-packages-json), rewrote python-test.yaml to use nix develop -c just \u003crecipe\u003e, added dynamic package discovery and force_run to ci.yaml. All CI steps expressible as nix develop -c just \u003crecipe\u003e.","dependencies":[{"issue_id":"pnt-dre.4","depends_on_id":"pnt-dre","type":"parent-child","created_at":"2026-01-19T11:54:56.794334-05:00","created_by":"Cameron Smith"}],"comments":[{"id":2,"issue_id":"pnt-dre.4","author":"Cameron Smith","text":"Minimal CI path fixes applied in d0cab2a as part of pnt-4jg.1 fixups: cache-dependency-glob updated to packages/*/uv.lock, uv sync/lint/test moved into per-package working-directory, ci.yaml path filters updated.\n\nRemaining for pnt-dre.4: replace setup-python/setup-uv actions with nix develop -c just \u003crecipe\u003e pattern, add justfile recipes for per-package sync/test/lint/typecheck, implement cached-ci-job composite action, dynamic package discovery.","created_at":"2026-02-02T20:17:02Z"}]} {"id":"pnt-dre.5","title":"Add omnix template integration","description":"Configure om.templates in flake with parameter definitions. Add template-verify justfile recipe. Create .github/workflows/template.yaml for CI validation.","status":"closed","priority":2,"issue_type":"task","owner":"cameron.ray.smith@gmail.com","created_at":"2026-01-19T11:54:57.668262-05:00","created_by":"Cameron Smith","updated_at":"2026-02-02T15:56:15.624906-05:00","closed_at":"2026-02-02T15:56:15.624906-05:00","close_reason":"om.templates, template-verify recipe, and template.yaml workflow already existed. Fixed stale path-ignore filters for per-package lock pattern.","dependencies":[{"issue_id":"pnt-dre.5","depends_on_id":"pnt-dre","type":"parent-child","created_at":"2026-01-19T11:54:57.66888-05:00","created_by":"Cameron Smith"}]} -{"id":"pnt-m3t","title":"Adopt setup-nix composite action with nothing-but-nix pattern","description":"Port the vanixiets setup-nix composite action to python-nix-template, replacing inline Nix installation across all workflows.\n\nCurrent state:\n- ci.yaml, python-test.yaml, build-nix-images.yaml each inline DeterminateSystems/nix-installer-action\n- build-nix-images.yaml uses ad-hoc maximize-build-space shell script\n- scripts/ci/maximize-build-space.sh exists but is not wired into workflows\n\nTarget state (matching vanixiets):\n- .github/actions/setup-nix/action.yml composite action\n- Uses wimpysworld/nothing-but-nix for space reclamation (replaces maximize-build-space.sh)\n- Uses cachix/install-nix-action with pinned Nix version\n- Configures build-dir = /nix/build (nothing-but-nix workaround)\n- Integrates magic-nix-cache and cachix setup\n- Hatchet protocol support for configurable space levels\n- All workflows delegate Nix setup to this single action\n\nAcceptance criteria:\n- .github/actions/setup-nix/action.yml implemented (port from vanixiets)\n- ci.yaml nixci job uses setup-nix action\n- python-test.yaml uses setup-nix action\n- build-nix-images.yaml uses setup-nix action (replaces inline maximize-build-space)\n- .github/actions/build-nix-image/ updated (its Nix install steps replaced by setup-nix)\n- scripts/ci/maximize-build-space.sh removed (superseded by nothing-but-nix)\n- setup-python-uv action evaluated for removal (if all Python CI runs via nix develop)\n\nReference: ~/projects/nix-workspace/vanixiets/.github/actions/setup-nix/action.yml","status":"open","priority":2,"issue_type":"task","owner":"cameron.ray.smith@gmail.com","created_at":"2026-02-02T20:24:06.14337-05:00","created_by":"Cameron Smith","updated_at":"2026-02-02T20:24:06.14337-05:00"} +{"id":"pnt-m3t","title":"Adopt setup-nix composite action with nothing-but-nix pattern","description":"Port the vanixiets setup-nix composite action to python-nix-template, replacing inline Nix installation across all workflows.\n\nCurrent state:\n- ci.yaml, python-test.yaml, build-nix-images.yaml each inline DeterminateSystems/nix-installer-action\n- build-nix-images.yaml uses ad-hoc maximize-build-space shell script\n- scripts/ci/maximize-build-space.sh exists but is not wired into workflows\n\nTarget state (matching vanixiets):\n- .github/actions/setup-nix/action.yml composite action\n- Uses wimpysworld/nothing-but-nix for space reclamation (replaces maximize-build-space.sh)\n- Uses cachix/install-nix-action with pinned Nix version\n- Configures build-dir = /nix/build (nothing-but-nix workaround)\n- Integrates magic-nix-cache and cachix setup\n- Hatchet protocol support for configurable space levels\n- All workflows delegate Nix setup to this single action\n\nAcceptance criteria:\n- .github/actions/setup-nix/action.yml implemented (port from vanixiets)\n- ci.yaml nixci job uses setup-nix action\n- python-test.yaml uses setup-nix action\n- build-nix-images.yaml uses setup-nix action (replaces inline maximize-build-space)\n- .github/actions/build-nix-image/ updated (its Nix install steps replaced by setup-nix)\n- scripts/ci/maximize-build-space.sh removed (superseded by nothing-but-nix)\n- setup-python-uv action evaluated for removal (if all Python CI runs via nix develop)\n\nReference: ~/projects/nix-workspace/vanixiets/.github/actions/setup-nix/action.yml","status":"closed","priority":2,"issue_type":"task","owner":"cameron.ray.smith@gmail.com","created_at":"2026-02-02T20:24:06.14337-05:00","created_by":"Cameron Smith","updated_at":"2026-02-02T21:16:20.627824-05:00","closed_at":"2026-02-02T21:16:20.627824-05:00","close_reason":"Implemented in 0b1e4fa, setup-nix action ported from vanixiets"} From 3e50f40df6233422449a6cee7c4836d03873cb6d Mon Sep 17 00:00:00 2001 From: Cameron Smith Date: Mon, 2 Feb 2026 21:47:41 -0500 Subject: [PATCH 076/134] refactor(issues): rescope pnt-5vr to production containers, add blocked dev container migration issue --- .beads/issues.jsonl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.beads/issues.jsonl b/.beads/issues.jsonl index d9df866..0c121fb 100644 --- a/.beads/issues.jsonl +++ b/.beads/issues.jsonl @@ -2,7 +2,7 @@ {"id":"pnt-4jg.1","title":"Remove uv workspace, adopt path dependencies","description":"Remove [tool.uv.workspace] from root pyproject.toml. Each package gets own pyproject.toml with [tool.uv.sources] for sibling references using path sources with editable=true. Follow langchain pattern.","status":"closed","priority":2,"issue_type":"task","owner":"cameron.ray.smith@gmail.com","created_at":"2026-01-19T11:55:07.344057-05:00","created_by":"Cameron Smith","updated_at":"2026-02-02T14:40:02.175394-05:00","closed_at":"2026-02-02T14:40:02.175394-05:00","close_reason":"Implemented in a8a823f. Removed root uv workspace, generated per-package locks, rewrote nix modules to Pattern 3 per-package loading.","dependencies":[{"issue_id":"pnt-4jg.1","depends_on_id":"pnt-4jg","type":"parent-child","created_at":"2026-01-19T11:55:07.344659-05:00","created_by":"Cameron Smith"}],"comments":[{"id":1,"issue_id":"pnt-4jg.1","author":"Cameron Smith","text":"Post-close fixup commits (774ec26):\n- fix(ci): update lock file references for per-package federation (d0cab2a)\n- fixup! merge federated workspace deps: replace // with zipAttrsWith for extras-safe dep merging (7b3e7ae)\n- fixup! load packages independently: document version-conflict invariant in python.nix and architecture doc (36eb8a7, 774ec26)\n\nReview findings addressed: stale CI cache-dependency-glob paths, fragile shallow-merge dep specs, undocumented overlay composition invariant. Full CI redesign (nix develop + justfile symmetry) deferred to pnt-dre.4.","created_at":"2026-02-02T20:17:00Z"}]} {"id":"pnt-4jg.2","title":"Configure pixi feature-based composition","description":"Implement pixi feature/environment pattern: [feature.X.dependencies] + [environments] composition. Single pixi.lock covering all environments. Per-feature task definitions. Target-specific dependencies for platform support.","status":"closed","priority":2,"issue_type":"task","owner":"cameron.ray.smith@gmail.com","created_at":"2026-01-19T11:55:08.085592-05:00","created_by":"Cameron Smith","updated_at":"2026-02-02T15:36:49.459815-05:00","closed_at":"2026-02-02T15:36:49.459815-05:00","close_reason":"Verified pixi feature composition via nix develop -c just \u003crecipe\u003e. Fixed: added missing feature tasks to python-nix-template, delegated justfile conda recipes to pixi task names for correct working directory, moved deprecated build channels to backend.channels.","dependencies":[{"issue_id":"pnt-4jg.2","depends_on_id":"pnt-4jg","type":"parent-child","created_at":"2026-01-19T11:55:08.086155-05:00","created_by":"Cameron Smith"}]} {"id":"pnt-4jg.3","title":"Document package distribution channels","description":"Document which packages support uv/pypi vs pixi/conda distribution. Note dependency graph differences between channels. Update README and package metadata.","status":"closed","priority":2,"issue_type":"task","owner":"cameron.ray.smith@gmail.com","created_at":"2026-01-19T11:55:09.051203-05:00","created_by":"Cameron Smith","updated_at":"2026-02-02T15:37:38.374454-05:00","closed_at":"2026-02-02T15:37:38.374454-05:00","close_reason":"Documented in docs/notes/architecture/package-distribution-channels.md. Both packages support dual-channel (uv/PyPI + pixi/conda-forge) with independent locks. No blocking dependency graph differences between channels.","dependencies":[{"issue_id":"pnt-4jg.3","depends_on_id":"pnt-4jg","type":"parent-child","created_at":"2026-01-19T11:55:09.051857-05:00","created_by":"Cameron Smith"},{"issue_id":"pnt-4jg.3","depends_on_id":"pnt-4jg.1","type":"blocks","created_at":"2026-01-19T12:20:13.557576-05:00","created_by":"Cameron Smith"},{"issue_id":"pnt-4jg.3","depends_on_id":"pnt-4jg.2","type":"blocks","created_at":"2026-01-19T12:20:16.147971-05:00","created_by":"Cameron Smith"}]} -{"id":"pnt-5vr","title":"Migrate container builds from flocken/nixpod to nix2container","description":"Replace the current flocken-based multi-arch container build pipeline with the nix2container pattern used in vanixiets.\n\nCurrent state:\n- nix/modules/containers.nix uses nixpod buildMultiUserNixImage for image construction\n- flocken mkDockerManifest for multi-arch manifest creation and registry push\n- .github/actions/build-nix-image/ uses QEMU for arm64, apt-get skopeo\n- build-nix-images.yaml workflow orchestrates the flocken-based pipeline\n\nTarget state (matching vanixiets):\n- nix2container.buildImage / buildLayer for image construction\n- pkgsCross for cross-compilation (eliminates QEMU dependency)\n- skopeo-nix2container with nix: transport for pushing\n- Custom mkMultiArchManifest (crane-based) for manifest lists\n- containerMatrix flake output for CI matrix generation (pure evaluation)\n- Per-container layer strategy: base layer (bash, coreutils) + app layer\n\nAcceptance criteria:\n- nix2container flake input added (replaces flocken input)\n- nix/modules/containers.nix rewritten with nix2container pattern\n- pkgsCross used for cross-compilation targets\n- lib/mk-multi-arch-manifest.nix ported from vanixiets\n- .github/actions/build-nix-image/ updated (remove QEMU, apt-get skopeo)\n- build-nix-images.yaml updated for nix2container workflow\n- flocken input removed from flake.nix\n- nixpod dependency evaluated (may still be needed for base image features)\n- containerMatrix flake output for CI matrix generation\n\nReference: ~/projects/nix-workspace/vanixiets/modules/containers/default.nix\nReference: ~/projects/nix-workspace/vanixiets/lib/mk-multi-arch-manifest.nix","status":"open","priority":2,"issue_type":"task","owner":"cameron.ray.smith@gmail.com","created_at":"2026-02-02T20:24:12.624117-05:00","created_by":"Cameron Smith","updated_at":"2026-02-02T20:24:12.624117-05:00"} +{"id":"pnt-5vr","title":"Migrate container builds from flocken/nixpod to nix2container","description":"Replace the current flocken-based multi-arch container build pipeline with the nix2container pattern used in vanixiets.\n\nCurrent state:\n- nix/modules/containers.nix uses nixpod buildMultiUserNixImage for image construction\n- flocken mkDockerManifest for multi-arch manifest creation and registry push\n- .github/actions/build-nix-image/ uses QEMU for arm64, apt-get skopeo\n- build-nix-images.yaml workflow orchestrates the flocken-based pipeline\n\nTarget state (matching vanixiets):\n- nix2container.buildImage / buildLayer for image construction\n- pkgsCross for cross-compilation (eliminates QEMU dependency)\n- skopeo-nix2container with nix: transport for pushing\n- Custom mkMultiArchManifest (crane-based) for manifest lists\n- containerMatrix flake output for CI matrix generation (pure evaluation)\n- Per-container layer strategy: base layer (bash, coreutils) + app layer\n\nAcceptance criteria:\n- nix2container flake input added (replaces flocken input)\n- nix/modules/containers.nix rewritten with nix2container pattern\n- pkgsCross used for cross-compilation targets\n- lib/mk-multi-arch-manifest.nix ported from vanixiets\n- .github/actions/build-nix-image/ updated (remove QEMU, apt-get skopeo)\n- build-nix-images.yaml updated for nix2container workflow\n- flocken input removed from flake.nix\n- nixpod dependency evaluated (may still be needed for base image features)\n- containerMatrix flake output for CI matrix generation\n\nReference: ~/projects/nix-workspace/vanixiets/modules/containers/default.nix\nReference: ~/projects/nix-workspace/vanixiets/lib/mk-multi-arch-manifest.nix","status":"in_progress","priority":2,"issue_type":"task","owner":"cameron.ray.smith@gmail.com","created_at":"2026-02-02T20:24:12.624117-05:00","created_by":"Cameron Smith","updated_at":"2026-02-02T21:16:34.744617-05:00"} {"id":"pnt-btz","title":"pyo3/Rust extension integration","description":"Add Rust extension module support via maturin + pyo3, demonstrating Nix build integration with crane cargoArtifacts sharing and uv2nix overlay composition.\n\nArchitecture documented in: docs/notes/architecture/crane-uv2nix-integration.md\n\nKey patterns:\n- Per-package Rust workspace (crates/ inside Python package)\n- crane buildDepsOnly for artifact caching\n- uv2nix overlay injection for maturin builds\n- CI matrix with rust-deps/rust-checks/python-wheel categories\n\nReference implementations:\n- ~/projects/rust-workspace/ironstar (crane patterns)\n- ~/projects/planning-workspace/langchain (federated Python)\n","status":"closed","priority":2,"issue_type":"epic","owner":"cameron.ray.smith@gmail.com","created_at":"2026-01-19T11:54:41.426256-05:00","created_by":"Cameron Smith","updated_at":"2026-02-02T20:45:01.187149-05:00","closed_at":"2026-02-02T20:45:01.187149-05:00","close_reason":"All 3 children complete. Crane + uv2nix + maturin integration fully operational.","dependencies":[{"issue_id":"pnt-btz","depends_on_id":"pnt-dre","type":"blocks","created_at":"2026-01-19T11:55:32.690895-05:00","created_by":"Cameron Smith"},{"issue_id":"pnt-btz","depends_on_id":"pnt-4jg","type":"blocks","created_at":"2026-01-19T11:55:32.812602-05:00","created_by":"Cameron Smith"}]} {"id":"pnt-btz.1","title":"Create pnt-cli package scaffold with Rust crates","description":"Create packages/pnt-cli/ with federated structure:\n\nDirectory structure:\n- packages/pnt-cli/pyproject.toml (maturin build-backend, manifest-path binding)\n- packages/pnt-cli/src/pnt_cli/__init__.py (Python wrapper)\n- packages/pnt-cli/crates/Cargo.toml ([workspace] with member crates)\n- packages/pnt-cli/crates/pnt-cli-core/Cargo.toml (pure Rust library)\n- packages/pnt-cli/crates/pnt-cli-py/Cargo.toml (pyo3 bindings, depends on core)\n\npyproject.toml configuration:\n- [build-system] requires maturin\u003e=1.5\n- [tool.maturin] manifest-path = \"crates/pnt-cli-py/Cargo.toml\"\n- [tool.maturin] module-name = \"pnt_cli._native\"\n\nMinimal proof-of-concept: expose a simple function from Rust to Python.\n\nSee: docs/notes/architecture/crane-uv2nix-integration.md\n","status":"closed","priority":2,"issue_type":"task","owner":"cameron.ray.smith@gmail.com","created_at":"2026-01-19T11:55:17.885691-05:00","created_by":"Cameron Smith","updated_at":"2026-02-02T20:30:16.311977-05:00","closed_at":"2026-02-02T20:30:16.311977-05:00","close_reason":"Implemented in a3e79c3. Scaffold verified: cargo check, cargo test (2/2 pass), cargo clippy clean.","dependencies":[{"issue_id":"pnt-btz.1","depends_on_id":"pnt-btz","type":"parent-child","created_at":"2026-01-19T11:55:17.886287-05:00","created_by":"Cameron Smith"},{"issue_id":"pnt-btz.1","depends_on_id":"pnt-4jg.1","type":"blocks","created_at":"2026-01-19T12:20:18.940008-05:00","created_by":"Cameron Smith"}]} {"id":"pnt-btz.2","title":"Implement crane + uv2nix Nix modules","description":"Create Nix modules implementing the crane + uv2nix integration pattern.\n\nFiles to create:\n- nix/packages/pnt-cli/rust.nix (crane configuration)\n- nix/packages/pnt-cli/default.nix (Python + Rust composition)\n- nix/modules/rust/lib.nix (shared crane utilities, optional)\n\nrust.nix pattern:\n- crane-lib.buildDepsOnly for cargoArtifacts caching\n- commonArgs pattern for derivation hash consistency\n- crane-lib.vendorCargoDeps for maturin's cargo invocation\n- Export cargoArtifacts, cargoVendorDir, clippy, nextest\n\ndefault.nix pattern:\n- Import rust.nix\n- Create overlay injecting cargoVendorDir and CARGO_TARGET_DIR\n- Export overlay and checks for flake composition\n\nUpdate nix/modules/python.nix:\n- Load pnt-cli workspace independently (federated pattern)\n- Compose Rust overlay with uv2nix overlays\n\nSee: docs/notes/architecture/crane-uv2nix-integration.md\n","status":"closed","priority":2,"issue_type":"task","owner":"cameron.ray.smith@gmail.com","created_at":"2026-01-19T11:55:18.885252-05:00","created_by":"Cameron Smith","updated_at":"2026-02-02T20:41:16.274515-05:00","closed_at":"2026-02-02T20:41:16.274515-05:00","close_reason":"Implemented in 8d8a814. Crane checks (clippy, nextest) build. Full maturin wheel builds via nix build .#default. Python import verified: greet('nix') and add(2,3) work end-to-end.","dependencies":[{"issue_id":"pnt-btz.2","depends_on_id":"pnt-btz","type":"parent-child","created_at":"2026-01-19T11:55:18.885818-05:00","created_by":"Cameron Smith"},{"issue_id":"pnt-btz.2","depends_on_id":"pnt-btz.1","type":"blocks","created_at":"2026-01-19T12:20:08.210077-05:00","created_by":"Cameron Smith"}]} From 94621bf01904ad2f947375de6f48eb2d4d5376c6 Mon Sep 17 00:00:00 2001 From: Cameron Smith Date: Mon, 2 Feb 2026 21:52:39 -0500 Subject: [PATCH 077/134] chore(issues): rescope pnt-5vr to production containers, create pnt-mgq for dev container migration --- .beads/issues.jsonl | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.beads/issues.jsonl b/.beads/issues.jsonl index 0c121fb..63c1205 100644 --- a/.beads/issues.jsonl +++ b/.beads/issues.jsonl @@ -2,7 +2,7 @@ {"id":"pnt-4jg.1","title":"Remove uv workspace, adopt path dependencies","description":"Remove [tool.uv.workspace] from root pyproject.toml. Each package gets own pyproject.toml with [tool.uv.sources] for sibling references using path sources with editable=true. Follow langchain pattern.","status":"closed","priority":2,"issue_type":"task","owner":"cameron.ray.smith@gmail.com","created_at":"2026-01-19T11:55:07.344057-05:00","created_by":"Cameron Smith","updated_at":"2026-02-02T14:40:02.175394-05:00","closed_at":"2026-02-02T14:40:02.175394-05:00","close_reason":"Implemented in a8a823f. Removed root uv workspace, generated per-package locks, rewrote nix modules to Pattern 3 per-package loading.","dependencies":[{"issue_id":"pnt-4jg.1","depends_on_id":"pnt-4jg","type":"parent-child","created_at":"2026-01-19T11:55:07.344659-05:00","created_by":"Cameron Smith"}],"comments":[{"id":1,"issue_id":"pnt-4jg.1","author":"Cameron Smith","text":"Post-close fixup commits (774ec26):\n- fix(ci): update lock file references for per-package federation (d0cab2a)\n- fixup! merge federated workspace deps: replace // with zipAttrsWith for extras-safe dep merging (7b3e7ae)\n- fixup! load packages independently: document version-conflict invariant in python.nix and architecture doc (36eb8a7, 774ec26)\n\nReview findings addressed: stale CI cache-dependency-glob paths, fragile shallow-merge dep specs, undocumented overlay composition invariant. Full CI redesign (nix develop + justfile symmetry) deferred to pnt-dre.4.","created_at":"2026-02-02T20:17:00Z"}]} {"id":"pnt-4jg.2","title":"Configure pixi feature-based composition","description":"Implement pixi feature/environment pattern: [feature.X.dependencies] + [environments] composition. Single pixi.lock covering all environments. Per-feature task definitions. Target-specific dependencies for platform support.","status":"closed","priority":2,"issue_type":"task","owner":"cameron.ray.smith@gmail.com","created_at":"2026-01-19T11:55:08.085592-05:00","created_by":"Cameron Smith","updated_at":"2026-02-02T15:36:49.459815-05:00","closed_at":"2026-02-02T15:36:49.459815-05:00","close_reason":"Verified pixi feature composition via nix develop -c just \u003crecipe\u003e. Fixed: added missing feature tasks to python-nix-template, delegated justfile conda recipes to pixi task names for correct working directory, moved deprecated build channels to backend.channels.","dependencies":[{"issue_id":"pnt-4jg.2","depends_on_id":"pnt-4jg","type":"parent-child","created_at":"2026-01-19T11:55:08.086155-05:00","created_by":"Cameron Smith"}]} {"id":"pnt-4jg.3","title":"Document package distribution channels","description":"Document which packages support uv/pypi vs pixi/conda distribution. Note dependency graph differences between channels. Update README and package metadata.","status":"closed","priority":2,"issue_type":"task","owner":"cameron.ray.smith@gmail.com","created_at":"2026-01-19T11:55:09.051203-05:00","created_by":"Cameron Smith","updated_at":"2026-02-02T15:37:38.374454-05:00","closed_at":"2026-02-02T15:37:38.374454-05:00","close_reason":"Documented in docs/notes/architecture/package-distribution-channels.md. Both packages support dual-channel (uv/PyPI + pixi/conda-forge) with independent locks. No blocking dependency graph differences between channels.","dependencies":[{"issue_id":"pnt-4jg.3","depends_on_id":"pnt-4jg","type":"parent-child","created_at":"2026-01-19T11:55:09.051857-05:00","created_by":"Cameron Smith"},{"issue_id":"pnt-4jg.3","depends_on_id":"pnt-4jg.1","type":"blocks","created_at":"2026-01-19T12:20:13.557576-05:00","created_by":"Cameron Smith"},{"issue_id":"pnt-4jg.3","depends_on_id":"pnt-4jg.2","type":"blocks","created_at":"2026-01-19T12:20:16.147971-05:00","created_by":"Cameron Smith"}]} -{"id":"pnt-5vr","title":"Migrate container builds from flocken/nixpod to nix2container","description":"Replace the current flocken-based multi-arch container build pipeline with the nix2container pattern used in vanixiets.\n\nCurrent state:\n- nix/modules/containers.nix uses nixpod buildMultiUserNixImage for image construction\n- flocken mkDockerManifest for multi-arch manifest creation and registry push\n- .github/actions/build-nix-image/ uses QEMU for arm64, apt-get skopeo\n- build-nix-images.yaml workflow orchestrates the flocken-based pipeline\n\nTarget state (matching vanixiets):\n- nix2container.buildImage / buildLayer for image construction\n- pkgsCross for cross-compilation (eliminates QEMU dependency)\n- skopeo-nix2container with nix: transport for pushing\n- Custom mkMultiArchManifest (crane-based) for manifest lists\n- containerMatrix flake output for CI matrix generation (pure evaluation)\n- Per-container layer strategy: base layer (bash, coreutils) + app layer\n\nAcceptance criteria:\n- nix2container flake input added (replaces flocken input)\n- nix/modules/containers.nix rewritten with nix2container pattern\n- pkgsCross used for cross-compilation targets\n- lib/mk-multi-arch-manifest.nix ported from vanixiets\n- .github/actions/build-nix-image/ updated (remove QEMU, apt-get skopeo)\n- build-nix-images.yaml updated for nix2container workflow\n- flocken input removed from flake.nix\n- nixpod dependency evaluated (may still be needed for base image features)\n- containerMatrix flake output for CI matrix generation\n\nReference: ~/projects/nix-workspace/vanixiets/modules/containers/default.nix\nReference: ~/projects/nix-workspace/vanixiets/lib/mk-multi-arch-manifest.nix","status":"in_progress","priority":2,"issue_type":"task","owner":"cameron.ray.smith@gmail.com","created_at":"2026-02-02T20:24:12.624117-05:00","created_by":"Cameron Smith","updated_at":"2026-02-02T21:16:34.744617-05:00"} +{"id":"pnt-5vr","title":"Add production containers via nix2container and replace flocken tooling","description":"Add lightweight production/execution container images using nix2container (vanixiets pattern) and replace flocken manifest tooling. This does NOT touch nixpod-based dev containers.\n\nProduction containers (new):\n- nix2container.buildImage for minimal per-package execution images\n- Each user-facing package gets a container with only its runtime closure\n- pkgsCross for cross-compilation (eliminates QEMU dependency)\n- Per-container layer strategy: base layer (bash, coreutils) + app layer\n\nFlocken replacement (affects all containers):\n- crane-based mkMultiArchManifest replacing flocken mkDockerManifest\n- skopeo-nix2container with nix: transport for pushing\n- containerMatrix flake output for CI matrix generation (pure nix evaluation)\n- build-nix-images.yaml updated for nix2container workflow\n\nDoes NOT include:\n- Dev container migration (see pnt-xxx blocked issue)\n- Changes to buildMultiUserNixImage or nixpod integration\n- Existing dev container content or architecture\n\nReference: ~/projects/nix-workspace/vanixiets/modules/containers/default.nix\nReference: ~/projects/nix-workspace/vanixiets/lib/mk-multi-arch-manifest.nix\n\nAcceptance criteria:\n- nix2container flake input added\n- At least one production container defined via nix2container.buildImage\n- pkgsCross used for cross-compilation targets\n- lib/mk-multi-arch-manifest.nix ported from vanixiets\n- containerMatrix flake output for CI matrix generation\n- flocken replaced by crane-based manifests for production containers\n- Existing dev containers still build and work (no regression)","status":"in_progress","priority":2,"issue_type":"task","owner":"cameron.ray.smith@gmail.com","created_at":"2026-02-02T20:24:12.624117-05:00","created_by":"Cameron Smith","updated_at":"2026-02-02T21:47:33.181529-05:00","comments":[{"id":3,"issue_id":"pnt-5vr","author":"Cameron Smith","text":"Checkpoint: session 2026-02-02\n\nDone:\n- Researched vanixiets nix2container patterns (containers/default.nix, mk-multi-arch-manifest.nix, containers.yaml workflow)\n- Researched current pnt container infrastructure (containers.nix, build-nix-image action, build-nix-images workflow)\n- Identified scope mismatch between vanixiets lightweight tool containers and pnt dev containers\n- Rescoped to production containers + flocken replacement only (dev containers deferred to pnt-mgq)\n\nRemaining:\n- Add nix2container flake input\n- Create lib/mk-multi-arch-manifest.nix (port from vanixiets)\n- Define at least one production container via nix2container.buildImage (pnt-cli is the natural candidate)\n- Add pkgsCross targets and containerMatrix flake output\n- Replace flocken manifest tooling for existing dev containers (crane-based manifests)\n- Update build-nix-images.yaml workflow\n- Update build-nix-image composite action (QEMU no longer needed for production containers)\n- Add justfile recipes for container build/push (local/CI symmetry)\n\nContext for next agent:\n- vanixiets reference files are fully analyzed, see subagent outputs in this session\n- setup-nix action is already deployed on this branch stack (pnt-m3t-setup-nix merged into branch)\n- build-nix-image action already had redundant Nix install removed\n- Branch is pnt-5vr-nix2container, branched off pnt-m3t-setup-nix tip\n- Dev containers MUST NOT be touched — only production containers and manifest tooling","created_at":"2026-02-03T02:52:29Z"}]} {"id":"pnt-btz","title":"pyo3/Rust extension integration","description":"Add Rust extension module support via maturin + pyo3, demonstrating Nix build integration with crane cargoArtifacts sharing and uv2nix overlay composition.\n\nArchitecture documented in: docs/notes/architecture/crane-uv2nix-integration.md\n\nKey patterns:\n- Per-package Rust workspace (crates/ inside Python package)\n- crane buildDepsOnly for artifact caching\n- uv2nix overlay injection for maturin builds\n- CI matrix with rust-deps/rust-checks/python-wheel categories\n\nReference implementations:\n- ~/projects/rust-workspace/ironstar (crane patterns)\n- ~/projects/planning-workspace/langchain (federated Python)\n","status":"closed","priority":2,"issue_type":"epic","owner":"cameron.ray.smith@gmail.com","created_at":"2026-01-19T11:54:41.426256-05:00","created_by":"Cameron Smith","updated_at":"2026-02-02T20:45:01.187149-05:00","closed_at":"2026-02-02T20:45:01.187149-05:00","close_reason":"All 3 children complete. Crane + uv2nix + maturin integration fully operational.","dependencies":[{"issue_id":"pnt-btz","depends_on_id":"pnt-dre","type":"blocks","created_at":"2026-01-19T11:55:32.690895-05:00","created_by":"Cameron Smith"},{"issue_id":"pnt-btz","depends_on_id":"pnt-4jg","type":"blocks","created_at":"2026-01-19T11:55:32.812602-05:00","created_by":"Cameron Smith"}]} {"id":"pnt-btz.1","title":"Create pnt-cli package scaffold with Rust crates","description":"Create packages/pnt-cli/ with federated structure:\n\nDirectory structure:\n- packages/pnt-cli/pyproject.toml (maturin build-backend, manifest-path binding)\n- packages/pnt-cli/src/pnt_cli/__init__.py (Python wrapper)\n- packages/pnt-cli/crates/Cargo.toml ([workspace] with member crates)\n- packages/pnt-cli/crates/pnt-cli-core/Cargo.toml (pure Rust library)\n- packages/pnt-cli/crates/pnt-cli-py/Cargo.toml (pyo3 bindings, depends on core)\n\npyproject.toml configuration:\n- [build-system] requires maturin\u003e=1.5\n- [tool.maturin] manifest-path = \"crates/pnt-cli-py/Cargo.toml\"\n- [tool.maturin] module-name = \"pnt_cli._native\"\n\nMinimal proof-of-concept: expose a simple function from Rust to Python.\n\nSee: docs/notes/architecture/crane-uv2nix-integration.md\n","status":"closed","priority":2,"issue_type":"task","owner":"cameron.ray.smith@gmail.com","created_at":"2026-01-19T11:55:17.885691-05:00","created_by":"Cameron Smith","updated_at":"2026-02-02T20:30:16.311977-05:00","closed_at":"2026-02-02T20:30:16.311977-05:00","close_reason":"Implemented in a3e79c3. Scaffold verified: cargo check, cargo test (2/2 pass), cargo clippy clean.","dependencies":[{"issue_id":"pnt-btz.1","depends_on_id":"pnt-btz","type":"parent-child","created_at":"2026-01-19T11:55:17.886287-05:00","created_by":"Cameron Smith"},{"issue_id":"pnt-btz.1","depends_on_id":"pnt-4jg.1","type":"blocks","created_at":"2026-01-19T12:20:18.940008-05:00","created_by":"Cameron Smith"}]} {"id":"pnt-btz.2","title":"Implement crane + uv2nix Nix modules","description":"Create Nix modules implementing the crane + uv2nix integration pattern.\n\nFiles to create:\n- nix/packages/pnt-cli/rust.nix (crane configuration)\n- nix/packages/pnt-cli/default.nix (Python + Rust composition)\n- nix/modules/rust/lib.nix (shared crane utilities, optional)\n\nrust.nix pattern:\n- crane-lib.buildDepsOnly for cargoArtifacts caching\n- commonArgs pattern for derivation hash consistency\n- crane-lib.vendorCargoDeps for maturin's cargo invocation\n- Export cargoArtifacts, cargoVendorDir, clippy, nextest\n\ndefault.nix pattern:\n- Import rust.nix\n- Create overlay injecting cargoVendorDir and CARGO_TARGET_DIR\n- Export overlay and checks for flake composition\n\nUpdate nix/modules/python.nix:\n- Load pnt-cli workspace independently (federated pattern)\n- Compose Rust overlay with uv2nix overlays\n\nSee: docs/notes/architecture/crane-uv2nix-integration.md\n","status":"closed","priority":2,"issue_type":"task","owner":"cameron.ray.smith@gmail.com","created_at":"2026-01-19T11:55:18.885252-05:00","created_by":"Cameron Smith","updated_at":"2026-02-02T20:41:16.274515-05:00","closed_at":"2026-02-02T20:41:16.274515-05:00","close_reason":"Implemented in 8d8a814. Crane checks (clippy, nextest) build. Full maturin wheel builds via nix build .#default. Python import verified: greet('nix') and add(2,3) work end-to-end.","dependencies":[{"issue_id":"pnt-btz.2","depends_on_id":"pnt-btz","type":"parent-child","created_at":"2026-01-19T11:55:18.885818-05:00","created_by":"Cameron Smith"},{"issue_id":"pnt-btz.2","depends_on_id":"pnt-btz.1","type":"blocks","created_at":"2026-01-19T12:20:08.210077-05:00","created_by":"Cameron Smith"}]} @@ -14,3 +14,4 @@ {"id":"pnt-dre.4","title":"Implement cached-ci-job composite action pattern","description":"Add .github/actions/cached-ci-job composite action following typescript-nix-template pattern. Content-addressed caching with hash-sources and force-run support. Update CI to use category-based matrix builds.\n\nPost-federation CI adaptation: the migration from uv workspace to per-package independent locks (pnt-4jg.1) means CI must now discover and iterate packages under packages/. The matrix strategy needs a package axis in addition to the category axis, producing either a {package} x {category} matrix or per-package reusable workflow dispatches. Review how ci.yaml currently enumerates packages and ensure the composite action pattern supports per-package resolution of lock files, dependency caches, and build artifacts.\n\nAcceptance criteria:\n- .github/actions/cached-ci-job composite action implemented\n- Content-addressed caching with hash-sources and force-run support\n- CI matrix discovers packages/ dynamically (not hardcoded)\n- Matrix crosses package x category dimensions\n- Per-package uv.lock files used for cache keys (not root lock)\n- Category-based builds follow typescript-nix-template pattern","status":"closed","priority":2,"issue_type":"task","owner":"cameron.ray.smith@gmail.com","created_at":"2026-01-19T11:54:56.79376-05:00","created_by":"Cameron Smith","updated_at":"2026-02-02T15:55:30.748155-05:00","closed_at":"2026-02-02T15:55:30.748155-05:00","close_reason":"Implemented cached-ci-job composite action (ported from typescript-nix-template), per-package CI justfile recipes (ci-sync, ci-lint, ci-test, ci-typecheck, ci-check, list-packages-json), rewrote python-test.yaml to use nix develop -c just \u003crecipe\u003e, added dynamic package discovery and force_run to ci.yaml. All CI steps expressible as nix develop -c just \u003crecipe\u003e.","dependencies":[{"issue_id":"pnt-dre.4","depends_on_id":"pnt-dre","type":"parent-child","created_at":"2026-01-19T11:54:56.794334-05:00","created_by":"Cameron Smith"}],"comments":[{"id":2,"issue_id":"pnt-dre.4","author":"Cameron Smith","text":"Minimal CI path fixes applied in d0cab2a as part of pnt-4jg.1 fixups: cache-dependency-glob updated to packages/*/uv.lock, uv sync/lint/test moved into per-package working-directory, ci.yaml path filters updated.\n\nRemaining for pnt-dre.4: replace setup-python/setup-uv actions with nix develop -c just \u003crecipe\u003e pattern, add justfile recipes for per-package sync/test/lint/typecheck, implement cached-ci-job composite action, dynamic package discovery.","created_at":"2026-02-02T20:17:02Z"}]} {"id":"pnt-dre.5","title":"Add omnix template integration","description":"Configure om.templates in flake with parameter definitions. Add template-verify justfile recipe. Create .github/workflows/template.yaml for CI validation.","status":"closed","priority":2,"issue_type":"task","owner":"cameron.ray.smith@gmail.com","created_at":"2026-01-19T11:54:57.668262-05:00","created_by":"Cameron Smith","updated_at":"2026-02-02T15:56:15.624906-05:00","closed_at":"2026-02-02T15:56:15.624906-05:00","close_reason":"om.templates, template-verify recipe, and template.yaml workflow already existed. Fixed stale path-ignore filters for per-package lock pattern.","dependencies":[{"issue_id":"pnt-dre.5","depends_on_id":"pnt-dre","type":"parent-child","created_at":"2026-01-19T11:54:57.66888-05:00","created_by":"Cameron Smith"}]} {"id":"pnt-m3t","title":"Adopt setup-nix composite action with nothing-but-nix pattern","description":"Port the vanixiets setup-nix composite action to python-nix-template, replacing inline Nix installation across all workflows.\n\nCurrent state:\n- ci.yaml, python-test.yaml, build-nix-images.yaml each inline DeterminateSystems/nix-installer-action\n- build-nix-images.yaml uses ad-hoc maximize-build-space shell script\n- scripts/ci/maximize-build-space.sh exists but is not wired into workflows\n\nTarget state (matching vanixiets):\n- .github/actions/setup-nix/action.yml composite action\n- Uses wimpysworld/nothing-but-nix for space reclamation (replaces maximize-build-space.sh)\n- Uses cachix/install-nix-action with pinned Nix version\n- Configures build-dir = /nix/build (nothing-but-nix workaround)\n- Integrates magic-nix-cache and cachix setup\n- Hatchet protocol support for configurable space levels\n- All workflows delegate Nix setup to this single action\n\nAcceptance criteria:\n- .github/actions/setup-nix/action.yml implemented (port from vanixiets)\n- ci.yaml nixci job uses setup-nix action\n- python-test.yaml uses setup-nix action\n- build-nix-images.yaml uses setup-nix action (replaces inline maximize-build-space)\n- .github/actions/build-nix-image/ updated (its Nix install steps replaced by setup-nix)\n- scripts/ci/maximize-build-space.sh removed (superseded by nothing-but-nix)\n- setup-python-uv action evaluated for removal (if all Python CI runs via nix develop)\n\nReference: ~/projects/nix-workspace/vanixiets/.github/actions/setup-nix/action.yml","status":"closed","priority":2,"issue_type":"task","owner":"cameron.ray.smith@gmail.com","created_at":"2026-02-02T20:24:06.14337-05:00","created_by":"Cameron Smith","updated_at":"2026-02-02T21:16:20.627824-05:00","closed_at":"2026-02-02T21:16:20.627824-05:00","close_reason":"Implemented in 0b1e4fa, setup-nix action ported from vanixiets"} +{"id":"pnt-mgq","title":"Migrate dev containers to nix2container via upgraded nixpod","description":"Update the dev container builds (containerImage, devcontainerImage) to use nix2container once nixpod itself has completed its nix2container migration.\n\nCurrent state:\n- nix/modules/containers.nix imports buildMultiUserNixImage from nixpod\n- nixpod uses dockerTools.buildLayeredImageWithNixDb internally\n- flocken handles multi-arch manifest creation for dev containers\n- Dev containers include multi-user Nix daemon, home-manager activation, s6-overlay\n\nBlocked on: nixpod completing its nix2container migration (refactor-container-builds branch has research docs with full API mapping and implementation plan)\n\nTarget state:\n- nixpod exports nix2container-based builders (buildMultiUserNixImage rewritten internally)\n- python-nix-template's dev containers consume upgraded nixpod\n- Dev container manifests use crane-based tooling (from pnt-5vr production container work)\n- s6-overlay, home-manager activation, multi-user Nix preserved in container content\n\nAcceptance criteria:\n- Dev containers build using nixpod's nix2container-based API\n- flocken fully removed from flake.nix (production containers handled by pnt-5vr)\n- No regression in dev container functionality (Jupyter, code-server, etc.)\n- Multi-arch publishing works via nix2container transport\n\nReference: ~/projects/nix-workspace/nixpod-home/docs/notes/development/container-build-refactoring.md\nReference: ~/projects/nix-workspace/nixpod-home/containers/nix.nix","status":"open","priority":2,"issue_type":"task","owner":"cameron.ray.smith@gmail.com","created_at":"2026-02-02T21:47:38.830624-05:00","created_by":"Cameron Smith","updated_at":"2026-02-02T21:47:38.830624-05:00"} From b50ac3753c5a3be55e75561ff0ecc01f542f793f Mon Sep 17 00:00:00 2001 From: Cameron Smith Date: Mon, 2 Feb 2026 22:39:08 -0500 Subject: [PATCH 078/134] feat(nix): replace flocken input with nix2container Add nix2container flake input for lightweight production container builds. Remove flocken as direct input and drop the follows directive on nixpod so it brings its own flocken dependency. --- flake.nix | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/flake.nix b/flake.nix index 0f3c28c..6ab3183 100644 --- a/flake.nix +++ b/flake.nix @@ -26,15 +26,14 @@ inputs.nixpkgs.follows = "nixpkgs"; }; - flocken = { - url = "github:mirkolenz/flocken/v2"; + nix2container = { + url = "github:nlewo/nix2container"; inputs.nixpkgs.follows = "nixpkgs"; }; nixpod = { url = "github:cameronraysmith/nixpod/00-lock"; inputs.nixpkgs.follows = "nixpkgs"; inputs.flake-parts.follows = "flake-parts"; - inputs.flocken.follows = "flocken"; }; crane.url = "github:ipetkov/crane"; From 3bdbe64e7ee672db34e938687b795d2d1b7301c7 Mon Sep 17 00:00:00 2001 From: Cameron Smith Date: Mon, 2 Feb 2026 22:39:15 -0500 Subject: [PATCH 079/134] chore(gitignore): allow nix/lib/ through Python lib/ exclusion --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 1f43abc..1f62abf 100644 --- a/.gitignore +++ b/.gitignore @@ -46,6 +46,7 @@ downloads/ eggs/ .eggs/ lib/ +!nix/lib/ lib64/ parts/ sdist/ From 99fe7b860bc7b9f7c02d17b002727936014b4d08 Mon Sep 17 00:00:00 2001 From: Cameron Smith Date: Mon, 2 Feb 2026 22:39:16 -0500 Subject: [PATCH 080/134] feat(nix): add crane-based multi-arch manifest builder Port mk-multi-arch-manifest.nix from vanixiets with mkSourceUri parameter to support both nix2container (nix: transport) and dockerTools (docker-archive: transport) image formats. --- nix/lib/mk-multi-arch-manifest.nix | 148 +++++++++++++++++++++++++++++ 1 file changed, 148 insertions(+) create mode 100644 nix/lib/mk-multi-arch-manifest.nix diff --git a/nix/lib/mk-multi-arch-manifest.nix b/nix/lib/mk-multi-arch-manifest.nix new file mode 100644 index 0000000..52843fc --- /dev/null +++ b/nix/lib/mk-multi-arch-manifest.nix @@ -0,0 +1,148 @@ +# Multi-arch manifest builder using skopeo and crane (manifest lists) +# Single-arch builds auto-detected and skip manifest list creation +# Supports both nix2container (nix: transport) and dockerTools (docker-archive: transport) +{ + lib, + writeShellApplication, + coreutils, + crane, + jq, +}: +{ + images, + name, + registry, + version, + tags ? [ ], + branch ? "main", + skopeo, + mkSourceUri ? (image: "nix:${image}"), +}: +let + # Tags: version first, then explicit tags or "latest" on main branch + parsedTags = [ + version + ] + ++ (if tags != [ ] then tags else (if branch == "main" then [ "latest" ] else [ ])); + isSingleArch = lib.length (lib.attrNames images) == 1; + systemToArch = { + "x86_64-linux" = "amd64"; + "aarch64-linux" = "arm64"; + }; + + # Single-arch: push to primary tag; multi-arch: push with arch suffix, then create manifest list + archImages = lib.mapAttrs' ( + system: image: + let + arch = systemToArch.${system}; + primaryTag = lib.head parsedTags; + in + lib.nameValuePair arch { + inherit system image arch; + tag = if isSingleArch then primaryTag else "${version}-${arch}"; + uri = "${registry.name}/${registry.repo}:${ + if isSingleArch then primaryTag else "${version}-${arch}" + }"; + } + ) images; + + manifestName = "${registry.name}/${registry.repo}:${lib.head parsedTags}"; + repoBase = "${registry.name}/${registry.repo}"; + + skopeoExe = lib.getExe skopeo; + craneExe = lib.getExe crane; + jqExe = lib.getExe jq; + +in +assert lib.assertMsg (images != { }) "At least one image must be provided"; +assert lib.assertMsg (parsedTags != [ ]) "At least one tag must be set"; + +writeShellApplication { + name = "multi-arch-manifest-${name}"; + runtimeInputs = [ + skopeo + crane + jq + coreutils + ]; + + text = '' + function cleanup { + set -x + ${skopeoExe} logout "${registry.name}" || true + ${craneExe} auth logout "${registry.name}" || true + } + trap cleanup EXIT + + set -x + + if [[ ! -f "/etc/containers/policy.json" && ! -f "$HOME/.config/containers/policy.json" ]]; then + mkdir -p "$HOME/.config/containers" + install -Dm444 "${skopeo.policy}/default-policy.json" "$HOME/.config/containers/policy.json" + fi + + set +x + echo "Logging in to ${registry.name}" + ${skopeoExe} login \ + --username "${registry.username}" \ + --password "${registry.password}" \ + "${registry.name}" + ${craneExe} auth login "${registry.name}" \ + --username "${registry.username}" \ + --password "${registry.password}" + set -x + + declare -A PUSHED_DIGESTS + ${lib.concatMapStringsSep "\n" (archImage: '' + echo "Pushing ${archImage.arch} image to ${archImage.uri}" + DIGESTFILE=$(mktemp) + ${skopeoExe} copy \ + --digestfile "$DIGESTFILE" \ + --dest-creds "${registry.username}:${registry.password}" \ + "${mkSourceUri archImage.image}" \ + "docker://${archImage.uri}" + PUSHED_DIGESTS["${archImage.arch}"]=$(cat "$DIGESTFILE") + rm "$DIGESTFILE" + echo "Pushed ${archImage.arch} with digest: ''${PUSHED_DIGESTS["${archImage.arch}"]}" + '') (lib.attrValues archImages)} + + ${lib.optionalString (!isSingleArch) '' + echo "Creating multi-arch manifest list: ${manifestName}" + ${craneExe} index append \ + ${ + lib.concatMapStringsSep " \\\n " ( + archImage: ''-m "${repoBase}@''${PUSHED_DIGESTS["${archImage.arch}"]}"'' + ) (lib.attrValues archImages) + } \ + -t "${manifestName}" + + set +x + echo "Manifest: ${manifestName}" + ${craneExe} manifest "${manifestName}" | ${jqExe} . + echo "Tags: ${toString parsedTags}" + set -x + ''} + + ${lib.concatMapStringsSep "\n" (tag: '' + ${craneExe} tag \ + "${registry.name}/${registry.repo}:${lib.head parsedTags}" \ + "${tag}" + '') (lib.tail parsedTags)} + + set +x + ${ + if isSingleArch then + '' + echo "Successfully pushed single-arch image for ${name}" + '' + else + '' + echo "Successfully pushed multi-arch manifest for ${name}" + '' + } + echo "Available at: ${registry.name}/${registry.repo}:${lib.head parsedTags}" + ${lib.concatMapStringsSep "\n" (tag: '' + echo " Also tagged: ${registry.name}/${registry.repo}:${tag}" + '') (lib.tail parsedTags)} + ''; +} From e18d8d317307db77935385cd8409f127d9c2c111 Mon Sep 17 00:00:00 2001 From: Cameron Smith Date: Mon, 2 Feb 2026 22:43:22 -0500 Subject: [PATCH 081/134] feat(pnt-cli): add minimal CLI entrypoint exercising pyo3 bindings --- packages/pnt-cli/src/pnt_cli/__init__.py | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/packages/pnt-cli/src/pnt_cli/__init__.py b/packages/pnt-cli/src/pnt_cli/__init__.py index 0b42bf8..d27e708 100644 --- a/packages/pnt-cli/src/pnt_cli/__init__.py +++ b/packages/pnt-cli/src/pnt_cli/__init__.py @@ -3,3 +3,16 @@ from pnt_cli._native import add, greet __all__ = ["add", "greet"] + + +def main() -> None: + """CLI entrypoint exercising native pyo3 bindings.""" + import sys + + args = sys.argv[1:] + if args and args[0] == "add" and len(args) == 3: + result = add(int(args[1]), int(args[2])) + print(result) + else: + name = args[0] if args else "world" + print(greet(name)) From 8d52b1a225df8801340086f4542ed43c6420f817 Mon Sep 17 00:00:00 2001 From: Cameron Smith Date: Mon, 2 Feb 2026 22:43:24 -0500 Subject: [PATCH 082/134] feat(pnt-cli): register console_scripts entrypoint in pyproject.toml --- packages/pnt-cli/pyproject.toml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/packages/pnt-cli/pyproject.toml b/packages/pnt-cli/pyproject.toml index 02087b5..27999b1 100644 --- a/packages/pnt-cli/pyproject.toml +++ b/packages/pnt-cli/pyproject.toml @@ -18,6 +18,9 @@ name = "pnt-cli" requires-python = ">=3.11,<3.13" version = "0.1.0" +[project.scripts] +pnt-cli = "pnt_cli:main" + [build-system] build-backend = "maturin" requires = ["maturin>=1.5,<2.0"] From e92e1e5b296fb92b0bba5c62d8db7522dec1b5f3 Mon Sep 17 00:00:00 2001 From: Cameron Smith Date: Mon, 2 Feb 2026 22:48:43 -0500 Subject: [PATCH 083/134] refactor(nix): replace flocken with crane-based manifests, add nix2container production containers Add pnt-cli production container via nix2container.buildImage with 2-layer strategy. Replace flocken manifest tooling with crane-based mkMultiArchManifest for all containers (nix: transport for production, docker-archive: transport for dev). Add containerMatrix flake output for CI matrix generation via pure nix evaluation. --- nix/modules/containers.nix | 257 ++++++++++++++++++++++++++++--------- 1 file changed, 199 insertions(+), 58 deletions(-) diff --git a/nix/modules/containers.nix b/nix/modules/containers.nix index c492e2b..28aaa88 100644 --- a/nix/modules/containers.nix +++ b/nix/modules/containers.nix @@ -1,7 +1,32 @@ { inputs, + lib, ... }: +let + gitHubOrg = "sciexp"; + repoName = "python-nix-template"; + + # Production container definitions (nix2container) + # Add new containers here; containerMatrix auto-discovers them. + productionContainerDefs = { + pnt-cli = { + name = "pnt-cli"; + entrypoint = "pnt-cli"; + description = "pnt-cli with pyo3 native bindings"; + }; + }; + + # Dev container image attribute names for manifest generation + devContainerDefs = { + ${repoName} = { + imageAttr = "containerImage"; + }; + "${repoName}-dev" = { + imageAttr = "devcontainerImage"; + }; + }; +in { perSystem = { @@ -20,6 +45,8 @@ let isLinux = pkgs.stdenv.isLinux; + # --- Python environments --- + defaultPythonVersion = "py312"; defaultPythonSet = pythonSets.${defaultPythonVersion}; defaultEditablePythonSet = editablePythonSets.${defaultPythonVersion}; @@ -41,8 +68,10 @@ ] ) { } packageWorkspaces; - defaultPythonEnv = defaultPythonSet.mkVirtualEnv "python-nix-template-env" defaultDeps; - defaultEditablePythonEnv = defaultEditablePythonSet.mkVirtualEnv "python-nix-template-editable-env" allDeps; + defaultPythonEnv = defaultPythonSet.mkVirtualEnv "${repoName}-env" defaultDeps; + defaultEditablePythonEnv = defaultEditablePythonSet.mkVirtualEnv "${repoName}-editable-env" allDeps; + + # --- Dev container infrastructure (nixpod/dockerTools, unchanged) --- buildMultiUserNixImage = import "${inputs.nixpod.outPath}/containers/nix.nix"; @@ -135,10 +164,85 @@ // extraConfig; }; - gitHubOrg = "sciexp"; - packageName = "python-nix-template"; - version = builtins.getEnv "VERSION"; + # --- Production container infrastructure (nix2container) --- + # Built natively per-system. Cross-compilation via pkgsCross for the + # Python + maturin + Cargo stack is orthogonal and tracked separately. + + nix2container = inputs'.nix2container.packages.nix2container; + skopeo-nix2container = inputs'.nix2container.packages.skopeo-nix2container; + + mkMultiArchManifest = pkgs.callPackage ../lib/mk-multi-arch-manifest.nix { }; + + productionBaseLayer = nix2container.buildLayer { + deps = [ + pkgs.bashInteractive + pkgs.coreutils + pkgs.cacert + ]; + }; + + mkProductionContainer = + { + name, + entrypoint, + pythonEnv ? defaultPythonEnv, + tag ? "latest", + description ? "", + }: + nix2container.buildImage { + inherit name tag; + layers = [ productionBaseLayer ]; + copyToRoot = pkgs.buildEnv { + name = "${name}-root"; + paths = [ + pythonEnv + pkgs.cacert + ]; + pathsToLink = [ + "/bin" + "/lib" + "/etc" + ]; + }; + config = { + entrypoint = [ "${pythonEnv}/bin/${entrypoint}" ]; + Env = [ + "PATH=${pythonEnv}/bin:${pkgs.coreutils}/bin:${pkgs.bashInteractive}/bin" + "SSL_CERT_FILE=${pkgs.cacert}/etc/ssl/certs/ca-bundle.crt" + ]; + Labels = { + "org.opencontainers.image.description" = description; + "org.opencontainers.image.source" = "https://github.com/${gitHubOrg}/${repoName}"; + }; + }; + maxLayers = 2; + }; + + productionContainerPackages = lib.mapAttrs' ( + containerName: def: + lib.nameValuePair "${containerName}ProductionImage" (mkProductionContainer { + inherit (def) name entrypoint description; + }) + ) productionContainerDefs; + # --- Manifest generation (crane-based, replaces flocken) --- + # Env vars (require --impure): VERSION, TAGS, GITHUB_REF_NAME, GITHUB_ACTOR, GITHUB_TOKEN + + getEnvOr = + var: default: + let + val = builtins.getEnv var; + in + if val == "" then default else val; + + getEnvList = + var: + let + val = builtins.getEnv var; + in + if val == "" then [ ] else lib.splitString "," val; + + # Systems to include in multi-arch manifests includedSystems = let envVar = builtins.getEnv "NIX_IMAGE_SYSTEMS"; @@ -150,65 +254,102 @@ ] else builtins.filter (sys: sys != "") (builtins.split " " envVar); - in - { - packages = lib.optionalAttrs isLinux { - containerImage = mkBaseContainer { - name = "python-nix-template"; - pythonPackageEnv = defaultPythonEnv; - }; - devcontainerImage = mkBaseContainer { - name = "python-nix-template-dev"; - pythonPackageEnv = defaultEditablePythonEnv; - extraPkgs = containerDevPackages; - }; - }; + manifestVersion = getEnvOr "VERSION" "0.0.0"; + manifestTags = getEnvList "TAGS"; + manifestBranch = getEnvOr "GITHUB_REF_NAME" "main"; + manifestUsername = getEnvOr "GITHUB_ACTOR" "cameronraysmith"; - legacyPackages = lib.optionalAttrs isLinux { - python-nix-templateManifest = inputs.flocken.legacyPackages.${system}.mkDockerManifest { - inherit version; - github = { - enable = true; - enableRegistry = true; - token = "$GH_TOKEN"; + # Production manifests use nix: transport (skopeo-nix2container) + productionManifestPackages = lib.mapAttrs' ( + containerName: _def: + lib.nameValuePair "${containerName}Manifest" (mkMultiArchManifest { + name = containerName; + images = lib.listToAttrs ( + map (sys: { + name = sys; + value = inputs.self.packages.${sys}."${containerName}ProductionImage"; + }) includedSystems + ); + registry = { + name = "ghcr.io"; + repo = "${gitHubOrg}/${repoName}/${containerName}"; + username = manifestUsername; + password = "$GITHUB_TOKEN"; }; - autoTags.branch = false; - registries = { - "ghcr.io" = { - repo = lib.mkForce "${gitHubOrg}/${packageName}"; - }; + version = manifestVersion; + tags = manifestTags; + branch = manifestBranch; + skopeo = skopeo-nix2container; + }) + ) productionContainerDefs; + + # Dev manifests use docker-archive: transport (regular skopeo) + devManifestPackages = lib.mapAttrs' ( + manifestName: def: + lib.nameValuePair "${manifestName}Manifest" (mkMultiArchManifest { + name = manifestName; + images = lib.listToAttrs ( + map (sys: { + name = sys; + value = inputs.self.packages.${sys}.${def.imageAttr}; + }) includedSystems + ); + registry = { + name = "ghcr.io"; + repo = "${gitHubOrg}/${manifestName}"; + username = manifestUsername; + password = "$GITHUB_TOKEN"; }; - imageFiles = map (sys: inputs.self.packages.${sys}.containerImage) includedSystems; - tags = [ - (builtins.getEnv "GIT_SHA_SHORT") - (builtins.getEnv "GIT_SHA") - (builtins.getEnv "GIT_REF") - "dev" - ]; - }; + version = manifestVersion; + tags = manifestTags; + branch = manifestBranch; + skopeo = pkgs.skopeo; + mkSourceUri = image: "docker-archive:${image}"; + }) + ) devContainerDefs; - python-nix-template-devManifest = inputs.flocken.legacyPackages.${system}.mkDockerManifest { - inherit version; - github = { - enable = true; - enableRegistry = true; - token = "$GH_TOKEN"; + in + { + packages = lib.optionalAttrs isLinux ( + { + # Dev containers (nixpod/dockerTools, unchanged) + containerImage = mkBaseContainer { + name = repoName; + pythonPackageEnv = defaultPythonEnv; }; - autoTags.branch = false; - registries = { - "ghcr.io" = { - repo = lib.mkForce "${gitHubOrg}/${packageName}-dev"; - }; + + devcontainerImage = mkBaseContainer { + name = "${repoName}-dev"; + pythonPackageEnv = defaultEditablePythonEnv; + extraPkgs = containerDevPackages; }; - imageFiles = map (sys: inputs.self.packages.${sys}.devcontainerImage) includedSystems; - tags = [ - (builtins.getEnv "GIT_SHA_SHORT") - (builtins.getEnv "GIT_SHA") - (builtins.getEnv "GIT_REF") - "dev" - ]; - }; - }; + } + // productionContainerPackages + // productionManifestPackages + // devManifestPackages + ); }; + + # CI matrix data (pure evaluation): nix eval .#containerMatrix --json + flake.containerMatrix = { + build = + (lib.mapAttrsToList (containerName: _: { + package = "${containerName}ProductionImage"; + type = "production"; + }) productionContainerDefs) + ++ (lib.mapAttrsToList (_: def: { + package = def.imageAttr; + type = "dev"; + }) devContainerDefs); + manifest = + (lib.mapAttrsToList (containerName: _: { + name = containerName; + type = "production"; + }) productionContainerDefs) + ++ (lib.mapAttrsToList (manifestName: _: { + name = manifestName; + type = "dev"; + }) devContainerDefs); + }; } From 75797f97948da202d113d39812558904268de5c5 Mon Sep 17 00:00:00 2001 From: Cameron Smith Date: Mon, 2 Feb 2026 22:50:10 -0500 Subject: [PATCH 084/134] refactor(justfile): reorganize container recipes with production support Move container recipes from 'nix' group to dedicated 'containers' section. Add production container build/load/push recipes for nix2container pattern. Update dev container recipes to use --no-link --print-out-paths pattern. Add container-matrix recipe for CI integration. Fix image tags to match actual image names (python-nix-template-dev). --- justfile | 75 +++++++++++++++++++++++++++++++++++++++----------------- 1 file changed, 52 insertions(+), 23 deletions(-) diff --git a/justfile b/justfile index 8b296e2..1d7eb2a 100644 --- a/justfile +++ b/justfile @@ -5,6 +5,7 @@ default: # Contents ## CI/CD ## Conda +## Containers ## Docs ## Nix ## Python @@ -271,11 +272,61 @@ conda-type package="python-nix-template": conda-check package="python-nix-template": (conda-lint package) (conda-type package) (conda-test package) @printf "\n\033[92mAll conda checks passed!\033[0m\n" +## Containers + +# Build production container image +[group('containers')] +container-build-production CONTAINER="pnt-cli": + nix build ".#{{CONTAINER}}ProductionImage" -L + +# Load production container to local Docker daemon +[group('containers')] +container-load-production CONTAINER="pnt-cli": + nix run ".#{{CONTAINER}}ProductionImage.copyToDockerDaemon" + +# Push production container manifest (requires registry auth) +[group('containers')] +container-push-production CONTAINER="pnt-cli" VERSION="0.0.0" +TAGS="": + VERSION={{VERSION}} TAGS={{TAGS}} nix run --impure ".#{{CONTAINER}}Manifest" -L + +# Build dev container image +[group('containers')] +container-build-dev: + nix build .#devcontainerImage -L + +# Run dev container with port 8888 exposed +[group('containers')] +container-run-dev: + docker load < $(nix build .#devcontainerImage --no-link --print-out-paths) + docker run -it --rm -p 8888:8888 python-nix-template-dev:latest + +# Build production-deps container image +[group('containers')] +container-build: + nix build .#containerImage -L + +# Run production-deps container with port 8888 exposed +[group('containers')] +container-run: + docker load < $(nix build .#containerImage --no-link --print-out-paths) + docker run -it --rm -p 8888:8888 python-nix-template:latest + +# Push dev container manifests (requires registry auth) +[group('containers')] +container-push-dev VERSION="0.0.0" +TAGS="": + VERSION={{VERSION}} TAGS={{TAGS}} nix run --impure ".#python-nix-templateManifest" -L + VERSION={{VERSION}} TAGS={{TAGS}} nix run --impure ".#python-nix-template-devManifest" -L + +# Display container CI matrix +[group('containers')] +container-matrix: + nix eval .#containerMatrix --json | jq . + ## Nix # Enter the Nix development shell [group('nix')] -dev: +dev: nix develop # Validate the Nix flake configuration @@ -293,28 +344,6 @@ flake-update: ci: om ci -# Build development container image -[group('nix')] -container-build-dev: - nix build .#devcontainerImage - -# Run development container with port 8888 exposed -[group('nix')] -container-run-dev: - docker load < $(nix build .#devcontainerImage --print-out-paths) - docker run -it --rm -p 8888:8888 mypackage-dev:latest - -# Build production container image -[group('nix')] -container-build: - nix build .#containerImage - -# Run production container with port 8888 exposed -[group('nix')] -container-run: - docker load < $(nix build .#containerImage --print-out-paths) - docker run -it --rm -p 8888:8888 mypackage:latest - ## Python # Package commands From 5c1306502eb8f96e4c70f991e9949a6c878e7a01 Mon Sep 17 00:00:00 2001 From: Cameron Smith Date: Mon, 2 Feb 2026 22:52:13 -0500 Subject: [PATCH 085/134] refactor(ci): adopt 3-job container workflow with containerMatrix Replace monolithic container build workflow with discover/build/manifest pattern driven by nix eval .#containerMatrix. Production containers skip QEMU (nix2container), dev containers retain QEMU for cross-compilation. Manifest push uses crane-based tooling with nix: and docker-archive: transport respectively. --- .github/actions/build-nix-image/action.yml | 124 ----------------- .github/workflows/build-nix-images.yaml | 150 ++++++++++++++++----- 2 files changed, 118 insertions(+), 156 deletions(-) delete mode 100644 .github/actions/build-nix-image/action.yml diff --git a/.github/actions/build-nix-image/action.yml b/.github/actions/build-nix-image/action.yml deleted file mode 100644 index 728e5fd..0000000 --- a/.github/actions/build-nix-image/action.yml +++ /dev/null @@ -1,124 +0,0 @@ -name: "Build Nix Docker Image" -description: "Builds a Docker image using Nix" -inputs: - triggerEventName: - description: "The name of the event that triggered the workflow" - required: true - imageName: - description: "Name of the Docker image" - required: true - imageFQN: - description: "Fully Qualified Name of the Docker image" - required: true - nixCommand: - description: "Nix command to build the image" - required: true - releaseVersion: - description: "Release version" - required: true -runs: - using: "composite" - steps: - - name: Setup QEMU - uses: docker/setup-qemu-action@29109295f81e9208d7d86ff1c6c12d2833863392 # v3 - with: - platforms: arm64 - - - name: Install Skopeo - shell: bash - run: | - sudo apt-get update - sudo apt-get install -yq skopeo - sudo apt-get clean - - - name: Set GitHub CI Slug Variables - uses: rlespinasse/github-slug-action@797d68864753cbceedc271349d402da4590e6302 # ratchet:rlespinasse/github-slug-action@v4 - with: - prefix: CI_ - - - name: Set git variables - shell: bash - run: | - echo "GIT_REPO_NAME=$CI_GITHUB_REPOSITORY_NAME_PART" >> $GITHUB_ENV - echo "GIT_REF=$CI_GITHUB_REF_NAME" >> $GITHUB_ENV - if [ "${{ inputs.triggerEventName }}" == "pull_request" ]; then - echo "GIT_SHA=$CI_GITHUB_EVENT_PULL_REQUEST_HEAD_SHA" >> $GITHUB_ENV - echo "GIT_SHA_SHORT=$CI_GITHUB_EVENT_PULL_REQUEST_HEAD_SHA_SHORT" >> $GITHUB_ENV - # elif [ -n "${{ inputs.releaseVersion }}" ]; then - # tag_base="${{ inputs.releaseVersion }}" - # echo "tag_base=$tag_base" - # if [[ $tag_base =~ ^[0-9] ]]; then - # tag="v$tag_base" - # else - # tag="$tag_base" - # fi - - # sha=$(git rev-parse "$tag") - # short_sha=$(git rev-parse --short "$tag") - - # echo "GIT_SHA=$sha" >> $GITHUB_ENV - # echo "GIT_SHA_SHORT=$short_sha" >> $GITHUB_ENV - else - echo "GIT_SHA=$CI_GITHUB_SHA" >> $GITHUB_ENV - echo "GIT_SHA_SHORT=$CI_GITHUB_SHA_SHORT" >> $GITHUB_ENV - fi - - - name: Set nix variables - shell: bash - run: | - echo "NIX_IMAGE_SYSTEMS=x86_64-linux" >> $GITHUB_ENV - - # Toggle this section to enable tmate debug session - # - name: Setup tmate debug session - # uses: mxschmitt/action-tmate@e5c7151931ca95bad1c6f4190c730ecf8c7dde48 # ratchet:mxschmitt/action-tmate@v3 - # env: - # GH_TOKEN: ${{ github.token }} - # VERSION: ${{ inputs.releaseVersion }} - - - name: Build and Push Docker Image - shell: bash - run: | - set -euxo pipefail - - echo "Using Git Repository Name: $GIT_REPO_NAME" - echo "Using Git Reference: $GIT_REF" - echo "Using Git SHA: $GIT_SHA" - echo "Using Git SHA Short: $GIT_SHA_SHORT" - FQN_GIT_SHA="${{ inputs.imageFQN }}:$GIT_SHA" - - echo "Image FQN with Git SHA: $FQN_GIT_SHA" - df -h - - # Check if image exists, - # handle both 404 (manifest unknown) and 403 (forbidden) errors - # which can occur when the image or repository doesn't exist yet - if SKOPEO_OUTPUT=$(skopeo inspect "docker://$FQN_GIT_SHA" 2>&1); then - echo "Image $FQN_GIT_SHA already exists. Skipping build." - else - if echo "$SKOPEO_OUTPUT" | grep -q 'manifest unknown' || \ - echo "$SKOPEO_OUTPUT" | grep -q 'invalid status code from registry 403' || \ - echo "$SKOPEO_OUTPUT" | grep -q 'invalid status code from registry 404'; then - echo "Image $FQN_GIT_SHA does not exist. Building." - nix-channel --update - podman manifest inspect docker.io/library/flocken:latest || true - podman manifest inspect quay.io/flocken:latest || true - ${{ inputs.nixCommand }} - else - echo "Failed to inspect image with error: $SKOPEO_OUTPUT" - exit 1 - fi - fi - - df -h - env: - GH_TOKEN: ${{ github.token }} - VERSION: ${{ inputs.releaseVersion }} - - - name: Check Nix Store usage - shell: bash - run: | - set -euxo pipefail - - df -h - nix store gc --dry-run --debug - df -h diff --git a/.github/workflows/build-nix-images.yaml b/.github/workflows/build-nix-images.yaml index 0d832da..db16245 100644 --- a/.github/workflows/build-nix-images.yaml +++ b/.github/workflows/build-nix-images.yaml @@ -5,54 +5,96 @@ on: inputs: debug_enabled: description: "Run with tmate.io debugging enabled" - required: true + required: false type: boolean default: false version: description: "Version to tag images with" - required: true + required: false type: string - images: - description: "JSON array of images to build" - required: true - type: string - branch: - description: "Branch to checkout" - required: true + default: "" + push: + description: "Push manifests to registry" + required: false + type: boolean + default: false + tags: + description: "Additional tags, comma-separated" + required: false type: string + default: "" workflow_call: inputs: debug_enabled: description: "Run with tmate.io debugging enabled" - required: true - type: string + required: false + type: boolean + default: false version: description: "Version to tag images with" - required: true - type: string - images: - description: "JSON array of images to build" - required: true + required: false type: string - branch: - description: "Branch to checkout" - required: true + default: "" + push: + description: "Push manifests to registry" + required: false + type: boolean + default: false + tags: + description: "Additional tags, comma-separated" + required: false type: string + default: "" + +permissions: + contents: read + packages: write jobs: - build-images: + discover: + runs-on: ubuntu-latest + outputs: + build-matrix: ${{ steps.matrix.outputs.build }} + manifest-matrix: ${{ steps.matrix.outputs.manifest }} + steps: + - name: Checkout code + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # ratchet:actions/checkout@v4 + with: + fetch-depth: 0 + + - name: Setup Nix + uses: ./.github/actions/setup-nix + with: + system: x86_64-linux + enable-cachix: true + cachix-name: ${{ vars.CACHIX_CACHE_NAME }} + cachix-auth-token: ${{ secrets.CACHIX_AUTH_TOKEN }} + extra-pull-names: nix-community,pyproject-nix,sciexp,srid + + - name: Discover container matrix + id: matrix + run: | + echo "Evaluating containerMatrix from flake..." + BUILD=$(nix eval .#containerMatrix.build --json --accept-flake-config) + MANIFEST=$(nix eval .#containerMatrix.manifest --json --accept-flake-config) + echo "Build matrix: $BUILD" + echo "Manifest matrix: $MANIFEST" + echo "build=$BUILD" >> $GITHUB_OUTPUT + echo "manifest=$MANIFEST" >> $GITHUB_OUTPUT + + build: + needs: discover runs-on: ubuntu-latest strategy: - matrix: - image: ${{ fromJson(inputs.images) }} fail-fast: false + matrix: + include: ${{ fromJson(needs.discover.outputs.build-matrix) }} steps: - name: Checkout code uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # ratchet:actions/checkout@v4 with: - ref: ${{ inputs.branch }} fetch-depth: 0 - name: Install dependencies @@ -62,13 +104,19 @@ jobs: sudo apt-get install -yq zstd sudo apt-get clean + - name: Setup QEMU + if: matrix.type == 'dev' + uses: docker/setup-qemu-action@29109295f81e9208d7d86ff1c6c12d2833863392 # ratchet:docker/setup-qemu-action@v3 + with: + platforms: arm64 + - name: Setup Nix uses: ./.github/actions/setup-nix with: system: x86_64-linux extra-conf: | system-features = nixos-test benchmark big-parallel kvm - extra-platforms = aarch64-linux + ${{ matrix.type == 'dev' && 'extra-platforms = aarch64-linux' || '' }} enable-cachix: true cachix-name: ${{ vars.CACHIX_CACHE_NAME }} cachix-auth-token: ${{ secrets.CACHIX_AUTH_TOKEN }} @@ -76,13 +124,51 @@ jobs: - name: Setup tmate debug session uses: mxschmitt/action-tmate@e5c7151931ca95bad1c6f4190c730ecf8c7dde48 # ratchet:mxschmitt/action-tmate@v3 - if: ${{ inputs.debug_enabled == 'true' }} + if: ${{ inputs.debug_enabled == true }} + + - name: Build ${{ matrix.package }} + run: | + echo "Building ${{ matrix.package }} (type: ${{ matrix.type }})" + nix build .#${{ matrix.package }} -L --accept-flake-config + + manifest: + needs: build + if: inputs.push == true + runs-on: ubuntu-latest + strategy: + fail-fast: false + matrix: + include: ${{ fromJson(needs.discover.outputs.manifest-matrix) }} + + steps: + - name: Checkout code + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # ratchet:actions/checkout@v4 + with: + fetch-depth: 0 - - name: Build ${{ matrix.image }} image - uses: ./.github/actions/build-nix-image + - name: Setup Nix + uses: ./.github/actions/setup-nix with: - triggerEventName: "workflow_dispatch" - imageName: "${{ matrix.image }}" - imageFQN: "ghcr.io/sciexp/${{ matrix.image }}" - nixCommand: "nix run .#${{ matrix.image }}Manifest --impure --accept-flake-config --print-build-logs --show-trace" - releaseVersion: "${{ inputs.version }}" + system: x86_64-linux + enable-cachix: true + cachix-name: ${{ vars.CACHIX_CACHE_NAME }} + cachix-auth-token: ${{ secrets.CACHIX_AUTH_TOKEN }} + extra-pull-names: nix-community,pyproject-nix,sciexp,srid + + - name: Login to GitHub Container Registry + run: | + echo "${{ secrets.GITHUB_TOKEN }}" | docker login ghcr.io -u ${{ github.actor }} --password-stdin + + - name: Push ${{ matrix.name }} manifest + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + GITHUB_ACTOR: ${{ github.actor }} + GITHUB_REF_NAME: ${{ github.ref_name }} + VERSION: ${{ inputs.version }} + TAGS: ${{ inputs.tags }} + NIX_IMAGE_SYSTEMS: ${{ matrix.type == 'dev' && 'x86_64-linux' || '' }} + run: | + echo "Pushing manifest for ${{ matrix.name }} (type: ${{ matrix.type }})" + echo "Version: ${VERSION}" + echo "Additional tags: ${TAGS:-none}" + nix run --impure .#${{ matrix.name }}Manifest -L --accept-flake-config From 82a74f5a060731e9490e05fb5078ca5999bb5949 Mon Sep 17 00:00:00 2001 From: Cameron Smith Date: Mon, 2 Feb 2026 22:52:18 -0500 Subject: [PATCH 086/134] refactor(ci): update PR image build to use containerMatrix workflow --- .github/workflows/ci.yaml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 5e7ec5d..7dea222 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -356,8 +356,8 @@ jobs: group: bni-${{ github.workflow }}-${{ github.event_name == 'pull_request' && github.event.pull_request.number || github.ref }} cancel-in-progress: true with: - debug_enabled: ${{ needs.set-variables.outputs.debug }} - version: "" - images: '["python-nix-template", "python-nix-template-dev"]' - branch: ${{ needs.set-variables.outputs.checkout_ref }} + debug_enabled: ${{ needs.set-variables.outputs.debug == 'true' }} + version: ${{ needs.set-variables.outputs.checkout_rev }} + push: false + tags: "" secrets: inherit From 876600eb473923e45e8c0377a30a6d3116b4c364 Mon Sep 17 00:00:00 2001 From: Cameron Smith Date: Mon, 2 Feb 2026 22:52:19 -0500 Subject: [PATCH 087/134] refactor(ci): update release image build to use containerMatrix workflow --- .github/workflows/package-release.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/package-release.yaml b/.github/workflows/package-release.yaml index 79810d4..31231de 100644 --- a/.github/workflows/package-release.yaml +++ b/.github/workflows/package-release.yaml @@ -221,6 +221,6 @@ jobs: with: debug_enabled: ${{ inputs.debug-enabled }} version: ${{ needs.release.outputs.version }} - images: ${{ inputs.images-to-build }} - branch: ${{ inputs.checkout-ref }} + push: true + tags: "" secrets: inherit From cd00d861d53a50087722f67ecdb54718a2947974 Mon Sep 17 00:00:00 2001 From: Cameron Smith Date: Mon, 2 Feb 2026 22:52:26 -0500 Subject: [PATCH 088/134] chore(nix): update flake.lock for nix2container input --- flake.lock | 92 +++++++++++++++++++++--------------------------------- 1 file changed, 36 insertions(+), 56 deletions(-) diff --git a/flake.lock b/flake.lock index c70caf8..4db7ed0 100644 --- a/flake.lock +++ b/flake.lock @@ -53,38 +53,27 @@ "type": "github" } }, - "flake-parts_2": { - "inputs": { - "nixpkgs-lib": "nixpkgs-lib" - }, - "locked": { - "lastModified": 1736143030, - "narHash": "sha256-+hu54pAoLDEZT9pjHlqL9DNzWz0NbUn8NEAHP7PQPzU=", - "owner": "hercules-ci", - "repo": "flake-parts", - "rev": "b905f6fc23a9051a6e1b741e1438dbfc0634c6de", - "type": "github" - }, - "original": { - "owner": "hercules-ci", - "repo": "flake-parts", - "type": "github" - } - }, "flocken": { "inputs": { - "flake-parts": "flake-parts_2", + "flake-parts": [ + "nixpod", + "flake-parts" + ], "nixpkgs": [ + "nixpod", "nixpkgs" ], - "systems": "systems" + "systems": [ + "nixpod", + "systems" + ] }, "locked": { - "lastModified": 1737581094, - "narHash": "sha256-MSjyNy4zENfngnSdXQ6ef/wwACB0jfDyhy0qkI67F9A=", + "lastModified": 1766934152, + "narHash": "sha256-qCfmMX8Q00WehZpOHb7a8/IRg/I7aDnVawpMZPggjxY=", "owner": "mirkolenz", "repo": "flocken", - "rev": "97921a2650cb3de20c2a5ee591b00a6d5099fc40", + "rev": "d42cf9b6febe4ad7ba7d916a293e928af50281b5", "type": "github" }, "original": { @@ -152,6 +141,26 @@ "type": "github" } }, + "nix2container": { + "inputs": { + "nixpkgs": [ + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1767430085, + "narHash": "sha256-SiXJ6xv4pS2MDUqfj0/mmG746cGeJrMQGmoFgHLS25Y=", + "owner": "nlewo", + "repo": "nix2container", + "rev": "66f4b8a47e92aa744ec43acbb5e9185078983909", + "type": "github" + }, + "original": { + "owner": "nlewo", + "repo": "nix2container", + "type": "github" + } + }, "nixos-flake": { "locked": { "lastModified": 1718149389, @@ -184,18 +193,6 @@ "type": "github" } }, - "nixpkgs-lib": { - "locked": { - "lastModified": 1735774519, - "narHash": "sha256-CewEm1o2eVAnoqb6Ml+Qi9Gg/EfNAxbRx1lANGVyoLI=", - "type": "tarball", - "url": "https://github.com/NixOS/nixpkgs/archive/e9b51731911566bbf7e4895475a87fe06961de0b.tar.gz" - }, - "original": { - "type": "tarball", - "url": "https://github.com/NixOS/nixpkgs/archive/e9b51731911566bbf7e4895475a87fe06961de0b.tar.gz" - } - }, "nixpkgs_2": { "locked": { "lastModified": 1756266583, @@ -218,16 +215,14 @@ "flake-parts": [ "flake-parts" ], - "flocken": [ - "flocken" - ], + "flocken": "flocken", "home-manager": "home-manager", "nix-index-database": "nix-index-database", "nixos-flake": "nixos-flake", "nixpkgs": [ "nixpkgs" ], - "systems": "systems_2" + "systems": "systems" }, "locked": { "lastModified": 1758064941, @@ -294,13 +289,13 @@ "inputs": { "crane": "crane", "flake-parts": "flake-parts", - "flocken": "flocken", "git-hooks": "git-hooks", + "nix2container": "nix2container", "nixpkgs": "nixpkgs", "nixpod": "nixpod", "pyproject-build-systems": "pyproject-build-systems", "pyproject-nix": "pyproject-nix", - "systems": "systems_3", + "systems": "systems_2", "uv2nix": "uv2nix" } }, @@ -334,21 +329,6 @@ "type": "github" } }, - "systems_3": { - "locked": { - "lastModified": 1681028828, - "narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=", - "owner": "nix-systems", - "repo": "default", - "rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e", - "type": "github" - }, - "original": { - "owner": "nix-systems", - "repo": "default", - "type": "github" - } - }, "uv2nix": { "inputs": { "nixpkgs": [ From 69594e4c655754924dd2b325e9949bdec41b612e Mon Sep 17 00:00:00 2001 From: Cameron Smith Date: Mon, 2 Feb 2026 22:52:55 -0500 Subject: [PATCH 089/134] chore(issues): update pnt-5vr checkpoint with implementation status --- .beads/issues.jsonl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.beads/issues.jsonl b/.beads/issues.jsonl index 63c1205..5af97e3 100644 --- a/.beads/issues.jsonl +++ b/.beads/issues.jsonl @@ -2,7 +2,7 @@ {"id":"pnt-4jg.1","title":"Remove uv workspace, adopt path dependencies","description":"Remove [tool.uv.workspace] from root pyproject.toml. Each package gets own pyproject.toml with [tool.uv.sources] for sibling references using path sources with editable=true. Follow langchain pattern.","status":"closed","priority":2,"issue_type":"task","owner":"cameron.ray.smith@gmail.com","created_at":"2026-01-19T11:55:07.344057-05:00","created_by":"Cameron Smith","updated_at":"2026-02-02T14:40:02.175394-05:00","closed_at":"2026-02-02T14:40:02.175394-05:00","close_reason":"Implemented in a8a823f. Removed root uv workspace, generated per-package locks, rewrote nix modules to Pattern 3 per-package loading.","dependencies":[{"issue_id":"pnt-4jg.1","depends_on_id":"pnt-4jg","type":"parent-child","created_at":"2026-01-19T11:55:07.344659-05:00","created_by":"Cameron Smith"}],"comments":[{"id":1,"issue_id":"pnt-4jg.1","author":"Cameron Smith","text":"Post-close fixup commits (774ec26):\n- fix(ci): update lock file references for per-package federation (d0cab2a)\n- fixup! merge federated workspace deps: replace // with zipAttrsWith for extras-safe dep merging (7b3e7ae)\n- fixup! load packages independently: document version-conflict invariant in python.nix and architecture doc (36eb8a7, 774ec26)\n\nReview findings addressed: stale CI cache-dependency-glob paths, fragile shallow-merge dep specs, undocumented overlay composition invariant. Full CI redesign (nix develop + justfile symmetry) deferred to pnt-dre.4.","created_at":"2026-02-02T20:17:00Z"}]} {"id":"pnt-4jg.2","title":"Configure pixi feature-based composition","description":"Implement pixi feature/environment pattern: [feature.X.dependencies] + [environments] composition. Single pixi.lock covering all environments. Per-feature task definitions. Target-specific dependencies for platform support.","status":"closed","priority":2,"issue_type":"task","owner":"cameron.ray.smith@gmail.com","created_at":"2026-01-19T11:55:08.085592-05:00","created_by":"Cameron Smith","updated_at":"2026-02-02T15:36:49.459815-05:00","closed_at":"2026-02-02T15:36:49.459815-05:00","close_reason":"Verified pixi feature composition via nix develop -c just \u003crecipe\u003e. Fixed: added missing feature tasks to python-nix-template, delegated justfile conda recipes to pixi task names for correct working directory, moved deprecated build channels to backend.channels.","dependencies":[{"issue_id":"pnt-4jg.2","depends_on_id":"pnt-4jg","type":"parent-child","created_at":"2026-01-19T11:55:08.086155-05:00","created_by":"Cameron Smith"}]} {"id":"pnt-4jg.3","title":"Document package distribution channels","description":"Document which packages support uv/pypi vs pixi/conda distribution. Note dependency graph differences between channels. Update README and package metadata.","status":"closed","priority":2,"issue_type":"task","owner":"cameron.ray.smith@gmail.com","created_at":"2026-01-19T11:55:09.051203-05:00","created_by":"Cameron Smith","updated_at":"2026-02-02T15:37:38.374454-05:00","closed_at":"2026-02-02T15:37:38.374454-05:00","close_reason":"Documented in docs/notes/architecture/package-distribution-channels.md. Both packages support dual-channel (uv/PyPI + pixi/conda-forge) with independent locks. No blocking dependency graph differences between channels.","dependencies":[{"issue_id":"pnt-4jg.3","depends_on_id":"pnt-4jg","type":"parent-child","created_at":"2026-01-19T11:55:09.051857-05:00","created_by":"Cameron Smith"},{"issue_id":"pnt-4jg.3","depends_on_id":"pnt-4jg.1","type":"blocks","created_at":"2026-01-19T12:20:13.557576-05:00","created_by":"Cameron Smith"},{"issue_id":"pnt-4jg.3","depends_on_id":"pnt-4jg.2","type":"blocks","created_at":"2026-01-19T12:20:16.147971-05:00","created_by":"Cameron Smith"}]} -{"id":"pnt-5vr","title":"Add production containers via nix2container and replace flocken tooling","description":"Add lightweight production/execution container images using nix2container (vanixiets pattern) and replace flocken manifest tooling. This does NOT touch nixpod-based dev containers.\n\nProduction containers (new):\n- nix2container.buildImage for minimal per-package execution images\n- Each user-facing package gets a container with only its runtime closure\n- pkgsCross for cross-compilation (eliminates QEMU dependency)\n- Per-container layer strategy: base layer (bash, coreutils) + app layer\n\nFlocken replacement (affects all containers):\n- crane-based mkMultiArchManifest replacing flocken mkDockerManifest\n- skopeo-nix2container with nix: transport for pushing\n- containerMatrix flake output for CI matrix generation (pure nix evaluation)\n- build-nix-images.yaml updated for nix2container workflow\n\nDoes NOT include:\n- Dev container migration (see pnt-xxx blocked issue)\n- Changes to buildMultiUserNixImage or nixpod integration\n- Existing dev container content or architecture\n\nReference: ~/projects/nix-workspace/vanixiets/modules/containers/default.nix\nReference: ~/projects/nix-workspace/vanixiets/lib/mk-multi-arch-manifest.nix\n\nAcceptance criteria:\n- nix2container flake input added\n- At least one production container defined via nix2container.buildImage\n- pkgsCross used for cross-compilation targets\n- lib/mk-multi-arch-manifest.nix ported from vanixiets\n- containerMatrix flake output for CI matrix generation\n- flocken replaced by crane-based manifests for production containers\n- Existing dev containers still build and work (no regression)","status":"in_progress","priority":2,"issue_type":"task","owner":"cameron.ray.smith@gmail.com","created_at":"2026-02-02T20:24:12.624117-05:00","created_by":"Cameron Smith","updated_at":"2026-02-02T21:47:33.181529-05:00","comments":[{"id":3,"issue_id":"pnt-5vr","author":"Cameron Smith","text":"Checkpoint: session 2026-02-02\n\nDone:\n- Researched vanixiets nix2container patterns (containers/default.nix, mk-multi-arch-manifest.nix, containers.yaml workflow)\n- Researched current pnt container infrastructure (containers.nix, build-nix-image action, build-nix-images workflow)\n- Identified scope mismatch between vanixiets lightweight tool containers and pnt dev containers\n- Rescoped to production containers + flocken replacement only (dev containers deferred to pnt-mgq)\n\nRemaining:\n- Add nix2container flake input\n- Create lib/mk-multi-arch-manifest.nix (port from vanixiets)\n- Define at least one production container via nix2container.buildImage (pnt-cli is the natural candidate)\n- Add pkgsCross targets and containerMatrix flake output\n- Replace flocken manifest tooling for existing dev containers (crane-based manifests)\n- Update build-nix-images.yaml workflow\n- Update build-nix-image composite action (QEMU no longer needed for production containers)\n- Add justfile recipes for container build/push (local/CI symmetry)\n\nContext for next agent:\n- vanixiets reference files are fully analyzed, see subagent outputs in this session\n- setup-nix action is already deployed on this branch stack (pnt-m3t-setup-nix merged into branch)\n- build-nix-image action already had redundant Nix install removed\n- Branch is pnt-5vr-nix2container, branched off pnt-m3t-setup-nix tip\n- Dev containers MUST NOT be touched — only production containers and manifest tooling","created_at":"2026-02-03T02:52:29Z"}]} +{"id":"pnt-5vr","title":"Add production containers via nix2container and replace flocken tooling","description":"Add lightweight production/execution container images using nix2container (vanixiets pattern) and replace flocken manifest tooling. This does NOT touch nixpod-based dev containers.\n\nProduction containers (new):\n- nix2container.buildImage for minimal per-package execution images\n- Each user-facing package gets a container with only its runtime closure\n- pkgsCross for cross-compilation (eliminates QEMU dependency)\n- Per-container layer strategy: base layer (bash, coreutils) + app layer\n\nFlocken replacement (affects all containers):\n- crane-based mkMultiArchManifest replacing flocken mkDockerManifest\n- skopeo-nix2container with nix: transport for pushing\n- containerMatrix flake output for CI matrix generation (pure nix evaluation)\n- build-nix-images.yaml updated for nix2container workflow\n\nDoes NOT include:\n- Dev container migration (see pnt-xxx blocked issue)\n- Changes to buildMultiUserNixImage or nixpod integration\n- Existing dev container content or architecture\n\nReference: ~/projects/nix-workspace/vanixiets/modules/containers/default.nix\nReference: ~/projects/nix-workspace/vanixiets/lib/mk-multi-arch-manifest.nix\n\nAcceptance criteria:\n- nix2container flake input added\n- At least one production container defined via nix2container.buildImage\n- pkgsCross used for cross-compilation targets\n- lib/mk-multi-arch-manifest.nix ported from vanixiets\n- containerMatrix flake output for CI matrix generation\n- flocken replaced by crane-based manifests for production containers\n- Existing dev containers still build and work (no regression)","status":"in_progress","priority":2,"issue_type":"task","owner":"cameron.ray.smith@gmail.com","created_at":"2026-02-02T20:24:12.624117-05:00","created_by":"Cameron Smith","updated_at":"2026-02-02T21:47:33.181529-05:00","comments":[{"id":3,"issue_id":"pnt-5vr","author":"Cameron Smith","text":"Checkpoint: session 2026-02-02\n\nDone:\n- Researched vanixiets nix2container patterns (containers/default.nix, mk-multi-arch-manifest.nix, containers.yaml workflow)\n- Researched current pnt container infrastructure (containers.nix, build-nix-image action, build-nix-images workflow)\n- Identified scope mismatch between vanixiets lightweight tool containers and pnt dev containers\n- Rescoped to production containers + flocken replacement only (dev containers deferred to pnt-mgq)\n\nRemaining:\n- Add nix2container flake input\n- Create lib/mk-multi-arch-manifest.nix (port from vanixiets)\n- Define at least one production container via nix2container.buildImage (pnt-cli is the natural candidate)\n- Add pkgsCross targets and containerMatrix flake output\n- Replace flocken manifest tooling for existing dev containers (crane-based manifests)\n- Update build-nix-images.yaml workflow\n- Update build-nix-image composite action (QEMU no longer needed for production containers)\n- Add justfile recipes for container build/push (local/CI symmetry)\n\nContext for next agent:\n- vanixiets reference files are fully analyzed, see subagent outputs in this session\n- setup-nix action is already deployed on this branch stack (pnt-m3t-setup-nix merged into branch)\n- build-nix-image action already had redundant Nix install removed\n- Branch is pnt-5vr-nix2container, branched off pnt-m3t-setup-nix tip\n- Dev containers MUST NOT be touched — only production containers and manifest tooling","created_at":"2026-02-03T02:52:29Z"},{"id":4,"issue_id":"pnt-5vr","author":"Cameron Smith","text":"Checkpoint: session 2026-02-02 (continued)\n\nCompleted:\n- Added nix2container flake input, removed flocken as direct input\n- Created nix/lib/mk-multi-arch-manifest.nix (ported from vanixiets, generalized with mkSourceUri for mixed transport)\n- Added minimal CLI entrypoint to pnt-cli (main() exercising pyo3 greet/add bindings)\n- Defined pnt-cli production container via nix2container.buildImage with 2-layer strategy\n- Replaced flocken manifests with crane-based manifests for all containers (production: nix: transport, dev: docker-archive: transport)\n- Added containerMatrix flake output for CI matrix generation\n- Refactored build-nix-images.yaml to 3-job pattern (discover/build/manifest)\n- Removed obsolete build-nix-image composite action\n- Updated ci.yaml and package-release.yaml callers\n- Added justfile container recipes (build/load/push for production and dev, matrix display)\n\nKnown limitations:\n- Production containers built natively per-system (not pkgsCross) due to Python + maturin + Cargo cross-compilation complexity\n- docker-archive: transport for dev container manifests not yet tested against crane index append (may need validation)\n- Dev containers in CI still limited to x86_64-linux only (NIX_IMAGE_SYSTEMS override)\n\nRemaining for verification:\n- Linux builder needed to test actual container image builds (nix build .#pnt-cliProductionImage)\n- CI workflow run to validate end-to-end (discover -\u003e build -\u003e manifest push)\n- Verify docker-archive: transport works with skopeo + crane manifest list creation","created_at":"2026-02-03T03:52:51Z"}]} {"id":"pnt-btz","title":"pyo3/Rust extension integration","description":"Add Rust extension module support via maturin + pyo3, demonstrating Nix build integration with crane cargoArtifacts sharing and uv2nix overlay composition.\n\nArchitecture documented in: docs/notes/architecture/crane-uv2nix-integration.md\n\nKey patterns:\n- Per-package Rust workspace (crates/ inside Python package)\n- crane buildDepsOnly for artifact caching\n- uv2nix overlay injection for maturin builds\n- CI matrix with rust-deps/rust-checks/python-wheel categories\n\nReference implementations:\n- ~/projects/rust-workspace/ironstar (crane patterns)\n- ~/projects/planning-workspace/langchain (federated Python)\n","status":"closed","priority":2,"issue_type":"epic","owner":"cameron.ray.smith@gmail.com","created_at":"2026-01-19T11:54:41.426256-05:00","created_by":"Cameron Smith","updated_at":"2026-02-02T20:45:01.187149-05:00","closed_at":"2026-02-02T20:45:01.187149-05:00","close_reason":"All 3 children complete. Crane + uv2nix + maturin integration fully operational.","dependencies":[{"issue_id":"pnt-btz","depends_on_id":"pnt-dre","type":"blocks","created_at":"2026-01-19T11:55:32.690895-05:00","created_by":"Cameron Smith"},{"issue_id":"pnt-btz","depends_on_id":"pnt-4jg","type":"blocks","created_at":"2026-01-19T11:55:32.812602-05:00","created_by":"Cameron Smith"}]} {"id":"pnt-btz.1","title":"Create pnt-cli package scaffold with Rust crates","description":"Create packages/pnt-cli/ with federated structure:\n\nDirectory structure:\n- packages/pnt-cli/pyproject.toml (maturin build-backend, manifest-path binding)\n- packages/pnt-cli/src/pnt_cli/__init__.py (Python wrapper)\n- packages/pnt-cli/crates/Cargo.toml ([workspace] with member crates)\n- packages/pnt-cli/crates/pnt-cli-core/Cargo.toml (pure Rust library)\n- packages/pnt-cli/crates/pnt-cli-py/Cargo.toml (pyo3 bindings, depends on core)\n\npyproject.toml configuration:\n- [build-system] requires maturin\u003e=1.5\n- [tool.maturin] manifest-path = \"crates/pnt-cli-py/Cargo.toml\"\n- [tool.maturin] module-name = \"pnt_cli._native\"\n\nMinimal proof-of-concept: expose a simple function from Rust to Python.\n\nSee: docs/notes/architecture/crane-uv2nix-integration.md\n","status":"closed","priority":2,"issue_type":"task","owner":"cameron.ray.smith@gmail.com","created_at":"2026-01-19T11:55:17.885691-05:00","created_by":"Cameron Smith","updated_at":"2026-02-02T20:30:16.311977-05:00","closed_at":"2026-02-02T20:30:16.311977-05:00","close_reason":"Implemented in a3e79c3. Scaffold verified: cargo check, cargo test (2/2 pass), cargo clippy clean.","dependencies":[{"issue_id":"pnt-btz.1","depends_on_id":"pnt-btz","type":"parent-child","created_at":"2026-01-19T11:55:17.886287-05:00","created_by":"Cameron Smith"},{"issue_id":"pnt-btz.1","depends_on_id":"pnt-4jg.1","type":"blocks","created_at":"2026-01-19T12:20:18.940008-05:00","created_by":"Cameron Smith"}]} {"id":"pnt-btz.2","title":"Implement crane + uv2nix Nix modules","description":"Create Nix modules implementing the crane + uv2nix integration pattern.\n\nFiles to create:\n- nix/packages/pnt-cli/rust.nix (crane configuration)\n- nix/packages/pnt-cli/default.nix (Python + Rust composition)\n- nix/modules/rust/lib.nix (shared crane utilities, optional)\n\nrust.nix pattern:\n- crane-lib.buildDepsOnly for cargoArtifacts caching\n- commonArgs pattern for derivation hash consistency\n- crane-lib.vendorCargoDeps for maturin's cargo invocation\n- Export cargoArtifacts, cargoVendorDir, clippy, nextest\n\ndefault.nix pattern:\n- Import rust.nix\n- Create overlay injecting cargoVendorDir and CARGO_TARGET_DIR\n- Export overlay and checks for flake composition\n\nUpdate nix/modules/python.nix:\n- Load pnt-cli workspace independently (federated pattern)\n- Compose Rust overlay with uv2nix overlays\n\nSee: docs/notes/architecture/crane-uv2nix-integration.md\n","status":"closed","priority":2,"issue_type":"task","owner":"cameron.ray.smith@gmail.com","created_at":"2026-01-19T11:55:18.885252-05:00","created_by":"Cameron Smith","updated_at":"2026-02-02T20:41:16.274515-05:00","closed_at":"2026-02-02T20:41:16.274515-05:00","close_reason":"Implemented in 8d8a814. Crane checks (clippy, nextest) build. Full maturin wheel builds via nix build .#default. Python import verified: greet('nix') and add(2,3) work end-to-end.","dependencies":[{"issue_id":"pnt-btz.2","depends_on_id":"pnt-btz","type":"parent-child","created_at":"2026-01-19T11:55:18.885818-05:00","created_by":"Cameron Smith"},{"issue_id":"pnt-btz.2","depends_on_id":"pnt-btz.1","type":"blocks","created_at":"2026-01-19T12:20:08.210077-05:00","created_by":"Cameron Smith"}]} From 4880793dadb388afa68988b71518e84b0fab3db0 Mon Sep 17 00:00:00 2001 From: Cameron Smith Date: Mon, 2 Feb 2026 23:00:34 -0500 Subject: [PATCH 090/134] chore(issues): create pnt-wbq for pkgsCross follow-up discovered from pnt-5vr --- .beads/issues.jsonl | 1 + 1 file changed, 1 insertion(+) diff --git a/.beads/issues.jsonl b/.beads/issues.jsonl index 5af97e3..cfe70da 100644 --- a/.beads/issues.jsonl +++ b/.beads/issues.jsonl @@ -15,3 +15,4 @@ {"id":"pnt-dre.5","title":"Add omnix template integration","description":"Configure om.templates in flake with parameter definitions. Add template-verify justfile recipe. Create .github/workflows/template.yaml for CI validation.","status":"closed","priority":2,"issue_type":"task","owner":"cameron.ray.smith@gmail.com","created_at":"2026-01-19T11:54:57.668262-05:00","created_by":"Cameron Smith","updated_at":"2026-02-02T15:56:15.624906-05:00","closed_at":"2026-02-02T15:56:15.624906-05:00","close_reason":"om.templates, template-verify recipe, and template.yaml workflow already existed. Fixed stale path-ignore filters for per-package lock pattern.","dependencies":[{"issue_id":"pnt-dre.5","depends_on_id":"pnt-dre","type":"parent-child","created_at":"2026-01-19T11:54:57.66888-05:00","created_by":"Cameron Smith"}]} {"id":"pnt-m3t","title":"Adopt setup-nix composite action with nothing-but-nix pattern","description":"Port the vanixiets setup-nix composite action to python-nix-template, replacing inline Nix installation across all workflows.\n\nCurrent state:\n- ci.yaml, python-test.yaml, build-nix-images.yaml each inline DeterminateSystems/nix-installer-action\n- build-nix-images.yaml uses ad-hoc maximize-build-space shell script\n- scripts/ci/maximize-build-space.sh exists but is not wired into workflows\n\nTarget state (matching vanixiets):\n- .github/actions/setup-nix/action.yml composite action\n- Uses wimpysworld/nothing-but-nix for space reclamation (replaces maximize-build-space.sh)\n- Uses cachix/install-nix-action with pinned Nix version\n- Configures build-dir = /nix/build (nothing-but-nix workaround)\n- Integrates magic-nix-cache and cachix setup\n- Hatchet protocol support for configurable space levels\n- All workflows delegate Nix setup to this single action\n\nAcceptance criteria:\n- .github/actions/setup-nix/action.yml implemented (port from vanixiets)\n- ci.yaml nixci job uses setup-nix action\n- python-test.yaml uses setup-nix action\n- build-nix-images.yaml uses setup-nix action (replaces inline maximize-build-space)\n- .github/actions/build-nix-image/ updated (its Nix install steps replaced by setup-nix)\n- scripts/ci/maximize-build-space.sh removed (superseded by nothing-but-nix)\n- setup-python-uv action evaluated for removal (if all Python CI runs via nix develop)\n\nReference: ~/projects/nix-workspace/vanixiets/.github/actions/setup-nix/action.yml","status":"closed","priority":2,"issue_type":"task","owner":"cameron.ray.smith@gmail.com","created_at":"2026-02-02T20:24:06.14337-05:00","created_by":"Cameron Smith","updated_at":"2026-02-02T21:16:20.627824-05:00","closed_at":"2026-02-02T21:16:20.627824-05:00","close_reason":"Implemented in 0b1e4fa, setup-nix action ported from vanixiets"} {"id":"pnt-mgq","title":"Migrate dev containers to nix2container via upgraded nixpod","description":"Update the dev container builds (containerImage, devcontainerImage) to use nix2container once nixpod itself has completed its nix2container migration.\n\nCurrent state:\n- nix/modules/containers.nix imports buildMultiUserNixImage from nixpod\n- nixpod uses dockerTools.buildLayeredImageWithNixDb internally\n- flocken handles multi-arch manifest creation for dev containers\n- Dev containers include multi-user Nix daemon, home-manager activation, s6-overlay\n\nBlocked on: nixpod completing its nix2container migration (refactor-container-builds branch has research docs with full API mapping and implementation plan)\n\nTarget state:\n- nixpod exports nix2container-based builders (buildMultiUserNixImage rewritten internally)\n- python-nix-template's dev containers consume upgraded nixpod\n- Dev container manifests use crane-based tooling (from pnt-5vr production container work)\n- s6-overlay, home-manager activation, multi-user Nix preserved in container content\n\nAcceptance criteria:\n- Dev containers build using nixpod's nix2container-based API\n- flocken fully removed from flake.nix (production containers handled by pnt-5vr)\n- No regression in dev container functionality (Jupyter, code-server, etc.)\n- Multi-arch publishing works via nix2container transport\n\nReference: ~/projects/nix-workspace/nixpod-home/docs/notes/development/container-build-refactoring.md\nReference: ~/projects/nix-workspace/nixpod-home/containers/nix.nix","status":"open","priority":2,"issue_type":"task","owner":"cameron.ray.smith@gmail.com","created_at":"2026-02-02T21:47:38.830624-05:00","created_by":"Cameron Smith","updated_at":"2026-02-02T21:47:38.830624-05:00"} +{"id":"pnt-wbq","title":"Add pkgsCross support for Python/maturin production containers","description":"Enable cross-compilation of production containers via pkgsCross, eliminating the need for per-architecture runners or QEMU emulation.\n\nCurrent state: production containers (nix2container) build natively per-system. On a single x86_64-linux CI runner, only x86_64 images are produced.\n\nTarget state: build both x86_64 and aarch64 production containers from a single x86_64-linux runner using pkgsCross, matching the vanixiets pattern.\n\nChallenge: the Python + maturin + Cargo build pipeline must work under cross-compilation. This requires:\n- Rust cross-compilation toolchain via pkgsCross (generally well-supported)\n- Python headers for target platform\n- maturin building wheels for the target platform\n- uv2nix virtual environment resolution for the target system\n\nThe nix2container infrastructure and containerMatrix are already in place (from pnt-5vr). This issue adds the pkgsCross target definitions and validates the cross-compilation pipeline.\n\nReference: vanixiets uses pkgsCross.gnu64 and pkgsCross.aarch64-multiplatform for simple nixpkgs packages. The Python/Rust case is more complex but the container infrastructure pattern is identical.","status":"open","priority":3,"issue_type":"task","owner":"cameron.ray.smith@gmail.com","created_at":"2026-02-02T23:00:13.965286-05:00","created_by":"Cameron Smith","updated_at":"2026-02-02T23:00:27.262969-05:00","dependencies":[{"issue_id":"pnt-wbq","depends_on_id":"pnt-5vr","type":"discovered-from","created_at":"2026-02-02T23:00:28.588784-05:00","created_by":"Cameron Smith"}]} From 06edd0abfe7e04cd5d3b9a92e00e7b188bb73d37 Mon Sep 17 00:00:00 2001 From: Cameron Smith Date: Mon, 2 Feb 2026 23:18:42 -0500 Subject: [PATCH 091/134] fix(ci): add packages:write permission to test-release-packages job The transitive call chain test-release-packages -> package-release.yaml -> build-nix-images.yaml requires packages:write, which GitHub validates at parse time even for conditionally-skipped jobs. --- .github/workflows/ci.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 7dea222..c1c5866 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -288,6 +288,7 @@ jobs: permissions: contents: write id-token: write + packages: write strategy: fail-fast: false matrix: From 564d8d5681f436b7c983a7633c08073ff5c55e94 Mon Sep 17 00:00:00 2001 From: Cameron Smith Date: Mon, 2 Feb 2026 23:18:50 -0500 Subject: [PATCH 092/134] fix(ci): add discover to manifest job needs for output access The manifest job references needs.discover.outputs.manifest-matrix but only listed build in its needs array. --- .github/workflows/build-nix-images.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build-nix-images.yaml b/.github/workflows/build-nix-images.yaml index db16245..f194c9c 100644 --- a/.github/workflows/build-nix-images.yaml +++ b/.github/workflows/build-nix-images.yaml @@ -132,7 +132,7 @@ jobs: nix build .#${{ matrix.package }} -L --accept-flake-config manifest: - needs: build + needs: [discover, build] if: inputs.push == true runs-on: ubuntu-latest strategy: From 9177ecee4fc38477a24fe289c03fe0c976aa9433 Mon Sep 17 00:00:00 2001 From: Cameron Smith Date: Mon, 2 Feb 2026 23:32:17 -0500 Subject: [PATCH 093/134] fix(template): add project table and workspace to root pyproject.toml The federation migration removed [tool.uv.workspace] and never had a [project] table at root. This causes omnix template init to generate projects where uv lock at root fails with no project to resolve. --- pyproject.toml | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/pyproject.toml b/pyproject.toml index 5f5b963..f5d7fa1 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,3 +1,12 @@ +[project] +description = "A Python project template for Nix using uv2nix and flake-parts" +name = "python-nix-template" +requires-python = ">=3.11,<3.13" +version = "0.0.0" + +[tool.uv.workspace] +members = ["packages/*"] + [tool.pytest.ini_options] addopts = """ -rA From edea99dff232923523de2be452eda94297e08e52 Mon Sep 17 00:00:00 2001 From: Cameron Smith Date: Mon, 2 Feb 2026 23:32:48 -0500 Subject: [PATCH 094/134] refactor(ci): simplify template.yaml with setup-nix action Remove GitGuardian scan and set-variables jobs from template workflow. Use setup-nix composite action instead of inline nix installer and cachix setup. Reduce permissions to contents:read only. --- .github/workflows/template.yaml | 123 ++++---------------------------- 1 file changed, 13 insertions(+), 110 deletions(-) diff --git a/.github/workflows/template.yaml b/.github/workflows/template.yaml index 116ccb1..77925c8 100644 --- a/.github/workflows/template.yaml +++ b/.github/workflows/template.yaml @@ -8,11 +8,6 @@ on: required: true type: boolean default: false - run_build_images: - description: "Run build-images job" - required: false - type: boolean - default: false pull_request: types: [opened, labeled, reopened, synchronize] paths-ignore: @@ -44,126 +39,38 @@ defaults: permissions: contents: read - packages: write - attestations: write - actions: write - id-token: write jobs: - scan: - name: gitguardian - runs-on: ubuntu-latest - steps: - - name: Checkout - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # ratchet:actions/checkout@v4 - with: - fetch-depth: 0 # fetch all history so multiple commits can be scanned - - name: GitGuardian scan - uses: GitGuardian/ggshield-action@455483042671cc73b40d0e753baddffef7309a1f # ratchet:GitGuardian/ggshield-action@v1.37.0 - env: - GITHUB_PUSH_BEFORE_SHA: ${{ github.event.before }} - GITHUB_PUSH_BASE_SHA: ${{ github.event.base }} - GITHUB_PULL_BASE_SHA: ${{ github.event.pull_request.base.sha }} - GITHUB_DEFAULT_BRANCH: ${{ github.event.repository.default_branch }} - GITGUARDIAN_API_KEY: ${{ secrets.GITGUARDIAN_API_KEY }} - - set-variables: - needs: scan - runs-on: ubuntu-latest - outputs: - debug: ${{ steps.set-variables.outputs.debug }} - skip_ci: ${{ steps.set-variables.outputs.skip_ci }} - skip_tests: ${{ steps.set-variables.outputs.skip_tests }} - dry_run_release: ${{ steps.set-variables.outputs.dry_run_release }} - checkout_ref: ${{ steps.set-variables.outputs.checkout_ref }} - checkout_rev: ${{ steps.set-variables.outputs.checkout_rev }} - - steps: - - name: Set action variables - id: set-variables - run: | - DEBUG="false" - SKIP_CI="false" - SKIP_TESTS="false" - DRY_RUN_RELEASE="false" - - if [[ "${{ github.event_name }}" == "workflow_dispatch" ]]; then - DEBUG="${{ inputs.debug_enabled }}" - fi - - if [[ "${{ github.event_name }}" == "pull_request" ]]; then - if ${{ contains(github.event.pull_request.labels.*.name, 'skip-ci') }}; then - SKIP_CI="true" - fi - if ${{ contains(github.event.pull_request.labels.*.name, 'skip-tests') }}; then - SKIP_TESTS="true" - fi - if ${{ contains(github.event.pull_request.labels.*.name, 'actions-debug') }}; then - DEBUG="true" - fi - if ${{ contains(github.event.pull_request.labels.*.name, 'release-dry-run') }}; then - DRY_RUN_RELEASE="true" - fi - CHECKOUT_REF="${{ github.event.pull_request.head.ref }}" - CHECKOUT_REV="${{ github.event.pull_request.head.sha }}" - else - CHECKOUT_REF="${{ github.ref_name }}" - CHECKOUT_REV="${{ github.sha }}" - fi - - echo "DEBUG=$DEBUG" - echo "SKIP_CI=$SKIP_CI" - echo "SKIP_TESTS=$SKIP_TESTS" - echo "CHECKOUT_REF=$CHECKOUT_REF" - echo "CHECKOUT_REV=$CHECKOUT_REV" - - echo "DEBUG=$DEBUG" >> $GITHUB_OUTPUT - echo "SKIP_CI=$SKIP_CI" >> $GITHUB_OUTPUT - echo "SKIP_TESTS=$SKIP_TESTS" >> $GITHUB_OUTPUT - echo "DRY_RUN_RELEASE=$DRY_RUN_RELEASE" >> $GITHUB_OUTPUT - echo "CHECKOUT_REF=$CHECKOUT_REF" >> $GITHUB_OUTPUT - echo "CHECKOUT_REV=$CHECKOUT_REV" >> $GITHUB_OUTPUT - test-omnix-template: - needs: [set-variables] - if: ${{ needs.set-variables.outputs.skip_ci != 'true' }} runs-on: ubuntu-latest concurrency: group: test-omnix-template-${{ github.workflow }}-${{ github.event_name == 'pull_request' && github.event.pull_request.number || github.ref_name }} cancel-in-progress: true steps: - - name: Install dependencies - shell: bash - run: | - sudo apt-get update - sudo apt-get install -yq zstd - sudo apt-get clean - - - name: Install Nix - uses: DeterminateSystems/nix-installer-action@786fff0690178f1234e4e1fe9b536e94f5433196 # ratchet:DeterminateSystems/nix-installer-action@main + - name: Checkout + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # ratchet:actions/checkout@v4 with: - extra-conf: "system-features = nixos-test benchmark big-parallel kvm" + fetch-depth: 0 - - name: Setup remote cache - uses: cachix/cachix-action@be5295a636153b6ad194d3245f78f8e0b78dc704 # ratchet:cachix/cachix-action@master - continue-on-error: true + - name: Setup Nix + uses: ./.github/actions/setup-nix with: - name: "${{ vars.CACHIX_CACHE_NAME }}" - authToken: "${{ secrets.CACHIX_AUTH_TOKEN }}" - extraPullNames: nix-community,pyproject-nix,sciexp,srid + system: x86_64-linux + enable-cachix: true + cachix-name: ${{ vars.CACHIX_CACHE_NAME }} + cachix-auth-token: ${{ secrets.CACHIX_AUTH_TOKEN }} + extra-pull-names: nix-community,pyproject-nix,sciexp,srid - name: Setup tmate debug session uses: mxschmitt/action-tmate@e5c7151931ca95bad1c6f4190c730ecf8c7dde48 # ratchet:mxschmitt/action-tmate@v3 - if: ${{ needs.set-variables.outputs.debug == 'true' }} + if: ${{ inputs.debug_enabled == true }} - name: Install omnix - # If we don't install omnix here, it will just clutter the log of the next step run: nix --accept-flake-config profile install "github:juspay/omnix" - # These tests execute the tl;dr one-liners from the README - name: Test monorepo template initialization run: | - REPO_REF="github:sciexp/python-nix-template/${{ needs.set-variables.outputs.checkout_rev }}" + REPO_REF="github:sciexp/python-nix-template/${{ github.event.pull_request.head.sha || github.sha }}" echo "Using repository reference: $REPO_REF" pwd @@ -189,8 +96,6 @@ jobs: git config --local user.name "Test User" git commit --allow-empty -m "initial commit (empty)" - # This needs to use a global uv (astral-sh/setup-uv) before entering - # the devshell even though uv is included in the devshell nix run github:NixOS/nixpkgs/nixos-unstable#uv -- lock git add . @@ -198,7 +103,7 @@ jobs: - name: Test single-package template initialization run: | - REPO_REF="github:sciexp/python-nix-template/${{ needs.set-variables.outputs.checkout_rev }}" + REPO_REF="github:sciexp/python-nix-template/${{ github.event.pull_request.head.sha || github.sha }}" echo "Using repository reference: $REPO_REF" pwd @@ -224,8 +129,6 @@ jobs: git config --local user.name "Test User" git commit --allow-empty -m "initial commit (empty)" - # This needs to use a global uv (astral-sh/setup-uv) before entering - # the devshell even though uv is included in the devshell nix run github:NixOS/nixpkgs/nixos-unstable#uv -- lock git add . From 089d50d4d1ff03d5c1d1aef8ba5ced41cc2b8e24 Mon Sep 17 00:00:00 2001 From: Cameron Smith Date: Mon, 2 Feb 2026 23:34:36 -0500 Subject: [PATCH 095/134] feat(ci): add ci-build-category.sh for matrix builds Port category-based build script from typescript-nix-template. Supports packages, checks, and devshells categories with per-system discovery via nix eval and individual attribute builds. --- scripts/ci/ci-build-category.sh | 177 ++++++++++++++++++++++++++++++++ 1 file changed, 177 insertions(+) create mode 100755 scripts/ci/ci-build-category.sh diff --git a/scripts/ci/ci-build-category.sh b/scripts/ci/ci-build-category.sh new file mode 100755 index 0000000..26601e9 --- /dev/null +++ b/scripts/ci/ci-build-category.sh @@ -0,0 +1,177 @@ +#!/usr/bin/env bash +set -euo pipefail + +# ============================================================================ +# CI Category Builder +# ============================================================================ +# Build specific categories of flake outputs for GitHub Actions matrix jobs. +# Designed to minimize disk space usage per job by building subsets of outputs. +# +# Usage: +# ci-build-category.sh +# +# Arguments: +# system - Target system (x86_64-linux, aarch64-linux, aarch64-darwin) +# category - Output category to build (lowercase): +# - packages: all packages for system +# - checks: checks only +# - devshells: devshells only (maps to devShells flake attr) +# +# Examples: +# ci-build-category.sh x86_64-linux packages +# ci-build-category.sh x86_64-linux checks +# ci-build-category.sh x86_64-linux devshells +# ============================================================================ + +# ============================================================================ +# Argument parsing +# ============================================================================ + +if [ $# -lt 2 ]; then + echo "usage: $0 " + echo "" + echo "system: x86_64-linux, aarch64-linux, aarch64-darwin" + echo "category: packages, checks, devshells" + exit 1 +fi + +SYSTEM="$1" +CATEGORY="$2" + +# ============================================================================ +# Validation +# ============================================================================ + +case "$SYSTEM" in + x86_64-linux|aarch64-linux|aarch64-darwin) + ;; + *) + echo "error: unsupported system '$SYSTEM'" + echo "supported: x86_64-linux, aarch64-linux, aarch64-darwin" + exit 1 + ;; +esac + +case "$CATEGORY" in + packages|checks|devshells) + ;; + *) + echo "error: unknown category '$CATEGORY'" + echo "valid: packages, checks, devshells" + exit 1 + ;; +esac + +# Map lowercase category arg to the flake attribute name +map_flake_attr() { + case "$1" in + packages) echo "packages" ;; + checks) echo "checks" ;; + devshells) echo "devShells" ;; + esac +} + +FLAKE_ATTR=$(map_flake_attr "$CATEGORY") + +# ============================================================================ +# Helper functions +# ============================================================================ + +print_header() { + local title="$1" + echo "" + echo "---" + echo "$title" + echo "---" +} + +print_step() { + local step="$1" + echo "" + echo "step: $step" +} + +report_disk_usage() { + echo "" + echo "disk usage:" + df -h / | tail -1 +} + +# ============================================================================ +# Generic build function +# ============================================================================ + +build_category() { + local system="$1" + local flake_attr="$2" + local label="$3" + + print_header "building $label for $system" + + print_step "discovering $label" + local attrs + attrs=$(nix eval ".#${flake_attr}.${system}" --apply 'builtins.attrNames' --json 2>/dev/null | jq -r '.[]' || echo "") + + if [ -z "$attrs" ]; then + echo "no $label found for $system" + return 0 + fi + + local count + count=$(echo "$attrs" | wc -l | tr -d ' ') + echo "found $count $label" + + print_step "building $label" + local failed=0 + while read -r attr; do + if [ -n "$attr" ]; then + echo "" + echo "building ${flake_attr}.${system}.${attr}" + if ! nix build ".#${flake_attr}.${system}.${attr}" -L --no-link --accept-flake-config; then + echo "failed to build ${flake_attr}.${system}.${attr}" + failed=$((failed + 1)) + fi + fi + done <<< "$attrs" + + if [ $failed -gt 0 ]; then + echo "" + echo "failed to build $failed $label" + return 1 + fi + + echo "" + echo "successfully built $count $label" +} + +# ============================================================================ +# Main execution +# ============================================================================ + +echo "system: $SYSTEM" +echo "category: $CATEGORY (flake attr: $FLAKE_ATTR)" + +START_TIME=$(date +%s) +echo "start time: $(date)" +report_disk_usage + +build_category "$SYSTEM" "$FLAKE_ATTR" "$CATEGORY" +BUILD_STATUS=$? + +END_TIME=$(date +%s) +DURATION=$((END_TIME - START_TIME)) + +print_header "build summary" +echo "" +echo "category: $CATEGORY" +echo "duration: ${DURATION}s" +report_disk_usage +echo "" + +if [ $BUILD_STATUS -eq 0 ]; then + echo "status: success" + exit 0 +else + echo "status: failed" + exit 1 +fi From 80ad72efbd9ff4aff97a093d980a07423d52c555 Mon Sep 17 00:00:00 2001 From: Cameron Smith Date: Mon, 2 Feb 2026 23:34:45 -0500 Subject: [PATCH 096/134] feat(ci): add justfile recipes for CI matrix, secrets scan, and release Add ci-build-category, scan-secrets, scan-staged recipes to CI/CD group. Add preview-version and release-package recipes to release group for semantic-release via nix develop. --- justfile | 38 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) diff --git a/justfile b/justfile index 1d7eb2a..5e4b511 100644 --- a/justfile +++ b/justfile @@ -16,6 +16,21 @@ default: ## CI/CD +# Build a category of nix flake outputs for CI matrix +[group('CI/CD')] +ci-build-category system category: + bash scripts/ci/ci-build-category.sh {{system}} {{category}} + +# Scan repository for hardcoded secrets +[group('CI/CD')] +scan-secrets: + gitleaks detect --verbose --redact + +# Scan staged files for hardcoded secrets (pre-commit) +[group('CI/CD')] +scan-staged: + gitleaks protect --staged --verbose --redact + # Set gcloud context [group('CI/CD')] gcloud-context: @@ -700,6 +715,29 @@ test-release-direct: test-package-release package-name="python-nix-template" branch="main": yarn workspace {{package-name}} test-release -b {{branch}} +# Preview release version for a package (dry-run semantic-release) +[group('release')] +preview-version base-branch package-path: + #!/usr/bin/env bash + set -euo pipefail + PACKAGE_NAME=$(basename "{{package-path}}") + yarn workspace "$PACKAGE_NAME" install + unset GITHUB_ACTIONS + yarn workspace "$PACKAGE_NAME" test-release -b "{{base-branch}}" + +# Run semantic-release for a package +[group('release')] +release-package package-name dry-run="false": + #!/usr/bin/env bash + set -euo pipefail + yarn workspace {{package-name}} install + if [ "{{dry-run}}" = "true" ]; then + unset GITHUB_ACTIONS + yarn workspace {{package-name}} test-release -b "${GITHUB_REF_NAME:-main}" + else + yarn workspace {{package-name}} release + fi + ## Docs # Add quartodoc extension From c8edf750729b237961291a024dca9a9a72e7b327 Mon Sep 17 00:00:00 2001 From: Cameron Smith Date: Mon, 2 Feb 2026 23:38:24 -0500 Subject: [PATCH 097/134] refactor(ci): replace omnix with category-based nix matrix architecture Replace monolithic nixci/om-ci-run job with 3-entry category matrix (packages, checks, devshells) using ci-build-category.sh. Replace GitGuardian with gitleaks via nix run. Add flake-validation and bootstrap-verification jobs. Add preview-release-version job for PRs. Reduce top-level permissions to contents:read with per-job overrides. --- .github/workflows/ci.yaml | 353 ++++++++++++++++++++++++++++++-------- 1 file changed, 282 insertions(+), 71 deletions(-) diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index c1c5866..ed60261 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -60,14 +60,13 @@ defaults: permissions: contents: read - packages: write - attestations: write - actions: write - id-token: write jobs: - scan: - name: gitguardian + # --------------------------------------------------------------------------- + # job 1: secrets-scan + # scans repository for secrets — security-critical, no caching + # --------------------------------------------------------------------------- + secrets-scan: runs-on: ubuntu-latest steps: - name: Checkout @@ -75,37 +74,20 @@ jobs: with: fetch-depth: 0 - - name: Check execution cache - id: cache - uses: ./.github/actions/cached-ci-job + - name: Setup Nix + uses: ./.github/actions/setup-nix with: - force-run: ${{ inputs.force_run || 'false' }} - - - name: GitGuardian scan - if: steps.cache.outputs.should-run == 'true' - uses: GitGuardian/ggshield-action@455483042671cc73b40d0e753baddffef7309a1f # ratchet:GitGuardian/ggshield-action@v1.37.0 - env: - GITHUB_PUSH_BEFORE_SHA: ${{ github.event.before }} - GITHUB_PUSH_BASE_SHA: ${{ github.event.base }} - GITHUB_PULL_BASE_SHA: ${{ github.event.pull_request.base.sha }} - GITHUB_DEFAULT_BRANCH: ${{ github.event.repository.default_branch }} - GITGUARDIAN_API_KEY: ${{ secrets.GITGUARDIAN_API_KEY }} - - - name: Create job result marker - if: success() && steps.cache.outputs.should-run == 'true' && steps.cache.outputs.cache-source == 'none' - run: | - mkdir -p "${{ steps.cache.outputs.cache-path }}" - echo '{"success":true}' > "${{ steps.cache.outputs.cache-path }}/marker" + system: x86_64-linux - - name: Save execution cache - if: success() && steps.cache.outputs.should-run == 'true' && steps.cache.outputs.cache-source == 'none' - uses: actions/cache/save@5a3ec84eff668545956fd18022155c47e93e2684 # ratchet:actions/cache/save@v4 - with: - path: ${{ steps.cache.outputs.cache-path }} - key: ${{ steps.cache.outputs.cache-key }} + - name: Scan for secrets + run: nix run nixpkgs#gitleaks -- detect --verbose --redact + # --------------------------------------------------------------------------- + # job 2: set-variables + # computes CI variables, discovers packages, determines routing + # --------------------------------------------------------------------------- set-variables: - needs: scan + needs: secrets-scan runs-on: ubuntu-latest outputs: debug: ${{ steps.set-variables.outputs.debug }} @@ -116,6 +98,7 @@ jobs: checkout_rev: ${{ steps.set-variables.outputs.checkout_rev }} has_docs: ${{ steps.check-docs.outputs.has_docs }} packages: ${{ steps.discover-packages.outputs.packages }} + force_ci: ${{ steps.set-variables.outputs.force_ci }} steps: - name: Checkout for discovery @@ -143,9 +126,13 @@ jobs: SKIP_CI="false" SKIP_TESTS="false" DRY_RUN_RELEASE="false" + FORCE_CI="false" if [[ "${{ github.event_name }}" == "workflow_dispatch" ]]; then DEBUG="${{ inputs.debug_enabled }}" + if [[ "${{ inputs.force_run }}" == "true" ]]; then + FORCE_CI="true" + fi fi if [[ "${{ github.event_name }}" == "pull_request" ]]; then @@ -161,6 +148,9 @@ jobs: if ${{ contains(github.event.pull_request.labels.*.name, 'release-dry-run') }}; then DRY_RUN_RELEASE="true" fi + if ${{ contains(github.event.pull_request.labels.*.name, 'force-ci') }}; then + FORCE_CI="true" + fi CHECKOUT_REF="${{ github.event.pull_request.head.ref }}" CHECKOUT_REV="${{ github.event.pull_request.head.sha }}" else @@ -174,6 +164,7 @@ jobs: echo "dry_run_release=$DRY_RUN_RELEASE" >> $GITHUB_OUTPUT echo "checkout_ref=$CHECKOUT_REF" >> $GITHUB_OUTPUT echo "checkout_rev=$CHECKOUT_REV" >> $GITHUB_OUTPUT + echo "force_ci=$FORCE_CI" >> $GITHUB_OUTPUT - name: Discover packages id: discover-packages @@ -186,67 +177,195 @@ jobs: echo "packages=$PACKAGES" >> $GITHUB_OUTPUT echo "Discovered packages: $PACKAGES" - preview-docs: - needs: set-variables - if: ${{ needs.set-variables.outputs.has_docs == 'true' && needs.set-variables.outputs.skip_ci != 'true' && ( contains(github.event.pull_request.labels.*.name, 'docs-preview') || (github.event_name == 'workflow_dispatch' && inputs.run_docs_preview) ) }} - uses: ./.github/workflows/deploy-docs.yaml - permissions: - contents: read - deployments: write - concurrency: - group: docs-preview-${{ github.workflow }}-${{ github.event_name == 'pull_request' && github.event.pull_request.number || github.ref_name }}-${{ github.sha }} - cancel-in-progress: true - with: - debug_enabled: ${{ needs.set-variables.outputs.debug }} - branch: ${{ needs.set-variables.outputs.checkout_ref }} - secrets: inherit + # --------------------------------------------------------------------------- + # job 3: flake-validation + # validates flake structure, justfile recipes, nix flake check + # --------------------------------------------------------------------------- + flake-validation: + needs: [secrets-scan, set-variables] + runs-on: ubuntu-latest + if: ${{ needs.set-variables.outputs.skip_ci != 'true' }} + steps: + - name: Checkout + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # ratchet:actions/checkout@v4 + + - name: Check execution cache + id: cache + uses: ./.github/actions/cached-ci-job + with: + hash-sources: '**/*.nix flake.lock justfile' + force-run: ${{ needs.set-variables.outputs.force_ci }} - nixci: + - name: Setup Nix + if: steps.cache.outputs.should-run == 'true' + uses: ./.github/actions/setup-nix + with: + system: x86_64-linux + enable-cachix: true + cachix-name: ${{ vars.CACHIX_CACHE_NAME }} + cachix-auth-token: ${{ secrets.CACHIX_AUTH_TOKEN }} + + - name: Verify justfile recipes + if: steps.cache.outputs.should-run == 'true' + run: | + JUST_RECIPES=$(nix develop --accept-flake-config -c just --summary) + echo "Available recipes (summary):" + echo "$JUST_RECIPES" | tr ' ' '\n' | head -20 + echo "... (and more)" + + echo "" + echo "Verifying core recipes..." + for recipe in check lint; do + if echo "$JUST_RECIPES" | grep -qw "$recipe"; then + echo " $recipe recipe found" + else + echo " $recipe recipe not found" + exit 1 + fi + done + + - name: Validate flake + if: steps.cache.outputs.should-run == 'true' + run: nix develop --accept-flake-config -c just flake-check + + - name: Create job result marker + if: success() && steps.cache.outputs.should-run == 'true' && steps.cache.outputs.cache-source == 'none' + run: | + mkdir -p "${{ steps.cache.outputs.cache-path }}" + echo '{"success":true}' > "${{ steps.cache.outputs.cache-path }}/marker" + + - name: Save execution cache + if: success() && steps.cache.outputs.should-run == 'true' && steps.cache.outputs.cache-source == 'none' + uses: actions/cache/save@5a3ec84eff668545956fd18022155c47e93e2684 # ratchet:actions/cache/save@v4 + with: + path: ${{ steps.cache.outputs.cache-path }} + key: ${{ steps.cache.outputs.cache-key }} + + # --------------------------------------------------------------------------- + # job 4: bootstrap-verification + # validates bootstrap.sh and Makefile workflow on clean ubuntu + # --------------------------------------------------------------------------- + bootstrap-verification: + needs: [secrets-scan, set-variables] runs-on: ubuntu-latest - needs: set-variables if: ${{ needs.set-variables.outputs.skip_ci != 'true' }} - concurrency: - group: nixci-${{ github.workflow }}-${{ github.event_name == 'pull_request' && github.event.pull_request.number || github.ref_name }} - cancel-in-progress: true steps: - - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # ratchet:actions/checkout@v4 + - name: Checkout + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # ratchet:actions/checkout@v4 - name: Check execution cache id: cache uses: ./.github/actions/cached-ci-job with: - hash-sources: '**/*.nix flake.lock justfile packages/*/pyproject.toml packages/*/uv.lock packages/*/crates/Cargo.lock' - force-run: ${{ inputs.force_run || 'false' }} + hash-sources: 'Makefile .envrc .github/actions/setup-nix/action.yml' + force-run: ${{ needs.set-variables.outputs.force_ci }} + + - name: Run make bootstrap + if: steps.cache.outputs.should-run == 'true' + run: make bootstrap + + - name: Verify nix installed + if: steps.cache.outputs.should-run == 'true' + run: | + if ! command -v nix &> /dev/null; then + echo "nix not found in PATH" + exit 1 + fi + echo "nix found at: $(command -v nix)" + nix --version + + - name: Verify direnv configured + if: steps.cache.outputs.should-run == 'true' + run: | + if ! command -v direnv &> /dev/null; then + echo "direnv not found in PATH" + exit 1 + fi + echo "direnv found at: $(command -v direnv)" + + - name: Run make verify + if: steps.cache.outputs.should-run == 'true' + run: make verify - - name: Install dependencies + - name: Run make setup-user if: steps.cache.outputs.should-run == 'true' + run: make setup-user + + - name: Verify age key exists + if: steps.cache.outputs.should-run == 'true' + run: | + if [ ! -f ~/.config/sops/age/keys.txt ]; then + echo "age key not generated" + exit 1 + fi + echo "age key generated successfully" + + - name: Create job result marker + if: success() && steps.cache.outputs.should-run == 'true' && steps.cache.outputs.cache-source == 'none' run: | - sudo apt-get update - sudo apt-get install -yq zstd - sudo apt-get clean + mkdir -p "${{ steps.cache.outputs.cache-path }}" + echo '{"success":true}' > "${{ steps.cache.outputs.cache-path }}/marker" + + - name: Save execution cache + if: success() && steps.cache.outputs.should-run == 'true' && steps.cache.outputs.cache-source == 'none' + uses: actions/cache/save@5a3ec84eff668545956fd18022155c47e93e2684 # ratchet:actions/cache/save@v4 + with: + path: ${{ steps.cache.outputs.cache-path }} + key: ${{ steps.cache.outputs.cache-key }} + + # --------------------------------------------------------------------------- + # job 5: nix + # category-based matrix build for flake outputs (packages, checks, devshells) + # --------------------------------------------------------------------------- + nix: + needs: [secrets-scan, set-variables] + runs-on: ${{ matrix.runner }} + if: ${{ needs.set-variables.outputs.skip_ci != 'true' }} + strategy: + fail-fast: false + matrix: + include: + - system: x86_64-linux + runner: ubuntu-latest + category: packages + - system: x86_64-linux + runner: ubuntu-latest + category: checks + - system: x86_64-linux + runner: ubuntu-latest + category: devshells + steps: + - name: Checkout + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # ratchet:actions/checkout@v4 + + - name: Check execution cache + id: cache + uses: ./.github/actions/cached-ci-job + with: + check-name: nix-${{ matrix.category }} + hash-sources: '**/*.nix flake.lock justfile packages/*/pyproject.toml packages/*/uv.lock packages/*/crates/Cargo.lock' + force-run: ${{ needs.set-variables.outputs.force_ci }} - name: Setup Nix if: steps.cache.outputs.should-run == 'true' uses: ./.github/actions/setup-nix with: - system: x86_64-linux + system: ${{ matrix.system }} extra-conf: "system-features = nixos-test benchmark big-parallel kvm" enable-cachix: true cachix-name: ${{ vars.CACHIX_CACHE_NAME }} cachix-auth-token: ${{ secrets.CACHIX_AUTH_TOKEN }} extra-pull-names: nix-community,pyproject-nix,sciexp,srid - - name: Setup tmate debug session - if: steps.cache.outputs.should-run == 'true' && needs.set-variables.outputs.debug == 'true' - uses: mxschmitt/action-tmate@e5c7151931ca95bad1c6f4190c730ecf8c7dde48 # ratchet:mxschmitt/action-tmate@v3 - - - name: Install omnix + - name: Build ${{ matrix.category }} if: steps.cache.outputs.should-run == 'true' - run: nix --accept-flake-config profile install "github:juspay/omnix" + run: | + echo "Building ${{ matrix.category }} for ${{ matrix.system }}" + nix develop --accept-flake-config -c just ci-build-category "${{ matrix.system }}" "${{ matrix.category }}" - - name: Run flake CI - if: steps.cache.outputs.should-run == 'true' - run: om ci run + - name: Report disk usage + if: always() + run: df -h - name: Create job result marker if: success() && steps.cache.outputs.should-run == 'true' && steps.cache.outputs.cache-source == 'none' @@ -261,6 +380,10 @@ jobs: path: ${{ steps.cache.outputs.cache-path }} key: ${{ steps.cache.outputs.cache-key }} + # --------------------------------------------------------------------------- + # job 6: test-python + # per-package python test matrix + # --------------------------------------------------------------------------- test-python: needs: [set-variables] if: ${{ needs.set-variables.outputs.skip_ci != 'true' && needs.set-variables.outputs.skip_tests != 'true' }} @@ -279,6 +402,82 @@ jobs: force_run: ${{ inputs.force_run && 'true' || 'false' }} secrets: inherit + # --------------------------------------------------------------------------- + # job 7: preview-release-version + # preview semantic-release version for each package (PR only) + # --------------------------------------------------------------------------- + preview-release-version: + needs: [set-variables] + if: ${{ github.event_name == 'pull_request' }} + strategy: + fail-fast: false + matrix: + package: ${{ fromJson(needs.set-variables.outputs.packages) }} + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # ratchet:actions/checkout@v4 + with: + ref: ${{ needs.set-variables.outputs.checkout_ref }} + fetch-depth: 0 + + - name: Check execution cache + id: cache + uses: ./.github/actions/cached-ci-job + with: + check-name: preview-release-version-${{ matrix.package.name }} + force-run: ${{ needs.set-variables.outputs.force_ci }} + + - name: Setup Nix + if: steps.cache.outputs.should-run == 'true' + uses: ./.github/actions/setup-nix + with: + system: x86_64-linux + enable-cachix: true + cachix-name: ${{ vars.CACHIX_CACHE_NAME }} + cachix-auth-token: ${{ secrets.CACHIX_AUTH_TOKEN }} + + - name: Preview version for ${{ matrix.package.name }} + if: steps.cache.outputs.should-run == 'true' + run: | + nix develop --accept-flake-config -c just preview-version main ${{ matrix.package.path }} + + - name: Create job result marker + if: success() && steps.cache.outputs.should-run == 'true' && steps.cache.outputs.cache-source == 'none' + run: | + mkdir -p "${{ steps.cache.outputs.cache-path }}" + echo '{"success":true}' > "${{ steps.cache.outputs.cache-path }}/marker" + + - name: Save execution cache + if: success() && steps.cache.outputs.should-run == 'true' && steps.cache.outputs.cache-source == 'none' + uses: actions/cache/save@5a3ec84eff668545956fd18022155c47e93e2684 # ratchet:actions/cache/save@v4 + with: + path: ${{ steps.cache.outputs.cache-path }} + key: ${{ steps.cache.outputs.cache-key }} + + # --------------------------------------------------------------------------- + # job 8: preview-docs + # deploy docs to preview environment (PR only) + # --------------------------------------------------------------------------- + preview-docs: + needs: set-variables + if: ${{ needs.set-variables.outputs.has_docs == 'true' && needs.set-variables.outputs.skip_ci != 'true' && ( contains(github.event.pull_request.labels.*.name, 'docs-preview') || (github.event_name == 'workflow_dispatch' && inputs.run_docs_preview) ) }} + uses: ./.github/workflows/deploy-docs.yaml + permissions: + contents: read + deployments: write + concurrency: + group: docs-preview-${{ github.workflow }}-${{ github.event_name == 'pull_request' && github.event.pull_request.number || github.ref_name }}-${{ github.sha }} + cancel-in-progress: true + with: + debug_enabled: ${{ needs.set-variables.outputs.debug }} + branch: ${{ needs.set-variables.outputs.checkout_ref }} + secrets: inherit + + # --------------------------------------------------------------------------- + # job 9: test-release-packages + # dry-run release for each package (PR only) + # --------------------------------------------------------------------------- test-release-packages: needs: [set-variables, test-python] if: ${{ github.event_name == 'pull_request' }} @@ -302,8 +501,12 @@ jobs: checkout-ref: ${{ needs.set-variables.outputs.checkout_ref }} secrets: inherit + # --------------------------------------------------------------------------- + # job 10: release-packages + # production release on push to main/beta + # --------------------------------------------------------------------------- release-packages: - needs: [test-python, nixci] + needs: [set-variables, test-python, nix] if: ${{ github.repository_owner == 'sciexp' && (github.event_name == 'push' || github.event_name == 'workflow_dispatch') && (github.ref == 'refs/heads/main' || github.ref == 'refs/heads/beta') }} concurrency: group: release-${{ matrix.package.name }}-${{ github.workflow }}-${{ github.ref_name }} @@ -334,8 +537,12 @@ jobs: images-to-build: ${{ matrix.package.images }} secrets: inherit + # --------------------------------------------------------------------------- + # job 11: deploy-docs + # production docs deployment on push to main/beta + # --------------------------------------------------------------------------- deploy-docs: - needs: [set-variables, test-python, nixci] + needs: [set-variables, test-python, nix] if: ${{ needs.set-variables.outputs.has_docs == 'true' && github.repository_owner == 'sciexp' && (github.event_name == 'push' || github.event_name == 'workflow_dispatch') && (github.ref == 'refs/heads/main' || github.ref == 'refs/heads/beta') }} uses: ./.github/workflows/deploy-docs.yaml permissions: @@ -349,6 +556,10 @@ jobs: branch: ${{ github.ref_name }} secrets: inherit + # --------------------------------------------------------------------------- + # job 12: build-pr-images + # build container images for PR validation + # --------------------------------------------------------------------------- build-pr-images: needs: [set-variables] if: ${{ needs.set-variables.outputs.skip_ci != 'true' && ( contains(github.event.pull_request.labels.*.name, 'build-images') || (github.event_name == 'workflow_dispatch' && inputs.run_build_images) ) }} From adf66e37e6f5217c522fb814ce22f38ae57798f2 Mon Sep 17 00:00:00 2001 From: Cameron Smith Date: Mon, 2 Feb 2026 23:39:01 -0500 Subject: [PATCH 098/134] refactor(ci): replace standalone tool installs with nix develop in package-release Remove astral-sh/setup-uv and threeal/setup-yarn-action, use setup-nix composite action instead. Wrap yarn and uv commands with nix develop. Add cached-ci-job support with dry-run-only cache persistence per ADR-0016. Fix artifact upload path for per-package working directory. --- .github/workflows/package-release.yaml | 94 +++++++++++++++----------- 1 file changed, 55 insertions(+), 39 deletions(-) diff --git a/.github/workflows/package-release.yaml b/.github/workflows/package-release.yaml index 31231de..96fda44 100644 --- a/.github/workflows/package-release.yaml +++ b/.github/workflows/package-release.yaml @@ -44,6 +44,11 @@ on: required: false type: string default: "[]" + force-run: + description: "Force execution even if already successful" + required: false + type: boolean + default: false workflow_call: inputs: @@ -88,6 +93,11 @@ on: required: false type: string default: "[]" + force-run: + description: "Force execution even if already successful" + required: false + type: string + default: "false" outputs: artifact-name: @@ -103,6 +113,10 @@ on: description: "Git tag created for the release" value: ${{ jobs.release.outputs.tag }} +defaults: + run: + shell: bash + jobs: release: runs-on: ubuntu-latest @@ -121,41 +135,38 @@ jobs: ref: ${{ inputs.checkout-ref }} persist-credentials: false - - name: Install uv - uses: astral-sh/setup-uv@f94ec6bedd8674c4426838e6b50417d36b6ab231 # ratchet:astral-sh/setup-uv@v5 + # Production releases intentionally DO NOT save cache results. + # This ensures fresh builds for all production deployments per ADR-0016. + - name: Check execution cache + id: cache + uses: ./.github/actions/cached-ci-job with: - python-version: "3.12" - enable-cache: true - cache-dependency-glob: "packages/*/uv.lock" - version: "0.6.8" + check-name: ${{ inputs.package-name }}-release + hash-sources: 'packages/${{ inputs.package-name }}/**/* yarn.lock justfile .github/actions/setup-nix/action.yml .github/workflows/package-release.yaml' + force-run: ${{ inputs.force-run }} - - name: Setup Yarn - uses: threeal/setup-yarn-action@ec8c075e62bc497968de40011c2b766f5e8f1ac5 # ratchet:threeal/setup-yarn-action@v2.0.0 + - name: Setup Nix + if: steps.cache.outputs.should-run == 'true' + uses: ./.github/actions/setup-nix with: - version: "4.6.0" - cache: true - - - name: Install npm dependencies - if: ${{ inputs.release-dry-run == 'true' }} - run: | - yarn workspace ${{ inputs.package-name }} install - git log --oneline --branches --tags + installer: quick + system: x86_64-linux - - name: Test semantic-release - if: ${{ inputs.release-dry-run == 'true' }} + - name: Test semantic-release (dry-run) + if: steps.cache.outputs.should-run == 'true' && inputs.release-dry-run == 'true' env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} run: | - unset GITHUB_ACTIONS - yarn workspace ${{ inputs.package-name }} test-release -b ${{ inputs.checkout-ref }} + nix develop --accept-flake-config -c just release-package ${{ inputs.package-name }} true - name: Run semantic-release id: semantic-release + if: steps.cache.outputs.should-run == 'true' && inputs.release-dry-run != 'true' uses: cycjimmy/semantic-release-action@b1b432f13acb7768e0c8efdec416d363a57546f2 # ratchet:cycjimmy/semantic-release-action@v4 with: working_directory: ${{ inputs.package-path }} - dry_run: ${{ inputs.release-dry-run == 'true' }} + dry_run: false semantic_version: 24 extra_plugins: | @semantic-release/changelog @@ -163,56 +174,61 @@ jobs: semantic-release-major-tag semantic-release-monorepo conventional-changelog-conventionalcommits - ci: ${{ inputs.release-dry-run == 'false' }} + ci: true env: GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - GITHUB_ACTIONS: ${{ inputs.release-dry-run == 'false' }} - name: Set outputs id: set-outputs + if: steps.cache.outputs.should-run == 'true' run: | ARTIFACT_NAME="${{ inputs.package-name }}-${{ github.run_id }}" echo "artifact-name=$ARTIFACT_NAME" >> $GITHUB_OUTPUT - # Log release information if [ "${{ steps.semantic-release.outputs.new_release_published }}" == "true" ]; then - echo "📦 Package ${{ inputs.package-name }} released version ${{ steps.semantic-release.outputs.new_release_version }}" - echo "🏷️ Tag: ${{ steps.semantic-release.outputs.new_release_git_tag }}" + echo "Package ${{ inputs.package-name }} released version ${{ steps.semantic-release.outputs.new_release_version }}" + echo "Tag: ${{ steps.semantic-release.outputs.new_release_git_tag }}" else - echo "ℹ️ No release needed for ${{ inputs.package-name }}" + echo "No release needed for ${{ inputs.package-name }}" fi - name: Build package - if: ${{ steps.semantic-release.outputs.new_release_published == 'true' || inputs.release-dry-run == 'true' }} + if: steps.cache.outputs.should-run == 'true' && (steps.semantic-release.outputs.new_release_published == 'true' || inputs.release-dry-run == 'true') working-directory: ${{ inputs.package-path }} run: | - uv build + nix develop --accept-flake-config -c uv build - name: Setup tmate debug session uses: mxschmitt/action-tmate@e5c7151931ca95bad1c6f4190c730ecf8c7dde48 # ratchet:mxschmitt/action-tmate@v3 if: ${{ inputs.debug-enabled }} - name: Upload artifacts - if: ${{ steps.semantic-release.outputs.new_release_published == 'true' || inputs.release-dry-run == 'true' }} + if: steps.cache.outputs.should-run == 'true' && (steps.semantic-release.outputs.new_release_published == 'true' || inputs.release-dry-run == 'true') uses: actions/upload-artifact@4cec3d8aa04e39d1a68397de0c4cd6fb9dce8ec1 # ratchet:actions/upload-artifact@v4 with: name: ${{ steps.set-outputs.outputs.artifact-name }} - path: dist + path: ${{ inputs.package-path }}/dist - name: Publish to PyPI - if: ${{ steps.semantic-release.outputs.new_release_published == 'true' && inputs.release-dry-run != 'true' }} - # uses: pypa/gh-action-pypi-publish@76f52bc884231f62b9a034ebfe128415bbaabdfc # ratchet:pypa/gh-action-pypi-publish@release/v1 + if: steps.cache.outputs.should-run == 'true' && steps.semantic-release.outputs.new_release_published == 'true' && inputs.release-dry-run != 'true' continue-on-error: true - run: uv publish + run: nix develop --accept-flake-config -c uv publish env: UV_PUBLISH_TOKEN: ${{ secrets.UV_PUBLISH_TOKEN }} - # with: - # packages-dir: dist - - name: Minimize uv cache - run: uv cache prune --ci - if: always() + - name: Create job result marker + if: success() && steps.cache.outputs.should-run == 'true' && inputs.release-dry-run == 'true' && steps.cache.outputs.cache-source == 'none' + run: | + mkdir -p "${{ steps.cache.outputs.cache-path }}" + echo '{"success":true}' > "${{ steps.cache.outputs.cache-path }}/marker" + + - name: Save execution cache + if: success() && steps.cache.outputs.should-run == 'true' && inputs.release-dry-run == 'true' && steps.cache.outputs.cache-source == 'none' + uses: actions/cache/save@5a3ec84eff668545956fd18022155c47e93e2684 # ratchet:actions/cache/save@v4 + with: + path: ${{ steps.cache.outputs.cache-path }} + key: ${{ steps.cache.outputs.cache-key }} build-images: needs: [release] From 00d4a141971c21802339ee09cf6e20a8b3ec8cce Mon Sep 17 00:00:00 2001 From: Cameron Smith Date: Mon, 2 Feb 2026 23:40:33 -0500 Subject: [PATCH 099/134] feat(nix): add gitleaks to devshell for local/CI secrets scanning parity --- nix/modules/devshell.nix | 1 + 1 file changed, 1 insertion(+) diff --git a/nix/modules/devshell.nix b/nix/modules/devshell.nix index db86163..8a57594 100644 --- a/nix/modules/devshell.nix +++ b/nix/modules/devshell.nix @@ -47,6 +47,7 @@ yarn-berry virtualenv age + gitleaks sops ssh-to-age config.packages.set-git-env From ab6f2659e6bd876f3f26c24308dbaa98334d2a06 Mon Sep 17 00:00:00 2001 From: Cameron Smith Date: Mon, 2 Feb 2026 23:40:40 -0500 Subject: [PATCH 100/134] fix(ci): use nix develop for secrets-scan to maintain local/CI parity Gitleaks is now in the devshell, so use nix develop -c just scan-secrets instead of nix run nixpkgs#gitleaks directly. This ensures the same command works locally and in CI. --- .github/workflows/ci.yaml | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index ed60261..db3081e 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -78,9 +78,13 @@ jobs: uses: ./.github/actions/setup-nix with: system: x86_64-linux + enable-cachix: true + cachix-name: ${{ vars.CACHIX_CACHE_NAME }} + cachix-auth-token: ${{ secrets.CACHIX_AUTH_TOKEN }} + extra-pull-names: nix-community,pyproject-nix,sciexp,srid - name: Scan for secrets - run: nix run nixpkgs#gitleaks -- detect --verbose --redact + run: nix develop --accept-flake-config -c just scan-secrets # --------------------------------------------------------------------------- # job 2: set-variables From 4bc84a396f466b299b0a1fd734e20183e05de711 Mon Sep 17 00:00:00 2001 From: Cameron Smith Date: Mon, 2 Feb 2026 23:43:39 -0500 Subject: [PATCH 101/134] fix(ci): add packages:write permission to build-pr-images job The build-pr-images job calls build-nix-images.yaml which declares packages:write at the workflow level. With ci.yaml top-level permissions reduced to contents:read, the caller must explicitly provide packages:write. --- .github/workflows/ci.yaml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index db3081e..111e55f 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -567,6 +567,9 @@ jobs: build-pr-images: needs: [set-variables] if: ${{ needs.set-variables.outputs.skip_ci != 'true' && ( contains(github.event.pull_request.labels.*.name, 'build-images') || (github.event_name == 'workflow_dispatch' && inputs.run_build_images) ) }} + permissions: + contents: read + packages: write uses: ./.github/workflows/build-nix-images.yaml concurrency: group: bni-${{ github.workflow }}-${{ github.event_name == 'pull_request' && github.event.pull_request.number || github.ref }} From 68dbf3373fdc6930ef37fcc39306bf2113309043 Mon Sep 17 00:00:00 2001 From: Cameron Smith Date: Mon, 2 Feb 2026 23:45:09 -0500 Subject: [PATCH 102/134] chore(issues): update pnt-5vr checkpoint with CI refactoring status --- .beads/issues.jsonl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.beads/issues.jsonl b/.beads/issues.jsonl index cfe70da..a3464ae 100644 --- a/.beads/issues.jsonl +++ b/.beads/issues.jsonl @@ -2,7 +2,7 @@ {"id":"pnt-4jg.1","title":"Remove uv workspace, adopt path dependencies","description":"Remove [tool.uv.workspace] from root pyproject.toml. Each package gets own pyproject.toml with [tool.uv.sources] for sibling references using path sources with editable=true. Follow langchain pattern.","status":"closed","priority":2,"issue_type":"task","owner":"cameron.ray.smith@gmail.com","created_at":"2026-01-19T11:55:07.344057-05:00","created_by":"Cameron Smith","updated_at":"2026-02-02T14:40:02.175394-05:00","closed_at":"2026-02-02T14:40:02.175394-05:00","close_reason":"Implemented in a8a823f. Removed root uv workspace, generated per-package locks, rewrote nix modules to Pattern 3 per-package loading.","dependencies":[{"issue_id":"pnt-4jg.1","depends_on_id":"pnt-4jg","type":"parent-child","created_at":"2026-01-19T11:55:07.344659-05:00","created_by":"Cameron Smith"}],"comments":[{"id":1,"issue_id":"pnt-4jg.1","author":"Cameron Smith","text":"Post-close fixup commits (774ec26):\n- fix(ci): update lock file references for per-package federation (d0cab2a)\n- fixup! merge federated workspace deps: replace // with zipAttrsWith for extras-safe dep merging (7b3e7ae)\n- fixup! load packages independently: document version-conflict invariant in python.nix and architecture doc (36eb8a7, 774ec26)\n\nReview findings addressed: stale CI cache-dependency-glob paths, fragile shallow-merge dep specs, undocumented overlay composition invariant. Full CI redesign (nix develop + justfile symmetry) deferred to pnt-dre.4.","created_at":"2026-02-02T20:17:00Z"}]} {"id":"pnt-4jg.2","title":"Configure pixi feature-based composition","description":"Implement pixi feature/environment pattern: [feature.X.dependencies] + [environments] composition. Single pixi.lock covering all environments. Per-feature task definitions. Target-specific dependencies for platform support.","status":"closed","priority":2,"issue_type":"task","owner":"cameron.ray.smith@gmail.com","created_at":"2026-01-19T11:55:08.085592-05:00","created_by":"Cameron Smith","updated_at":"2026-02-02T15:36:49.459815-05:00","closed_at":"2026-02-02T15:36:49.459815-05:00","close_reason":"Verified pixi feature composition via nix develop -c just \u003crecipe\u003e. Fixed: added missing feature tasks to python-nix-template, delegated justfile conda recipes to pixi task names for correct working directory, moved deprecated build channels to backend.channels.","dependencies":[{"issue_id":"pnt-4jg.2","depends_on_id":"pnt-4jg","type":"parent-child","created_at":"2026-01-19T11:55:08.086155-05:00","created_by":"Cameron Smith"}]} {"id":"pnt-4jg.3","title":"Document package distribution channels","description":"Document which packages support uv/pypi vs pixi/conda distribution. Note dependency graph differences between channels. Update README and package metadata.","status":"closed","priority":2,"issue_type":"task","owner":"cameron.ray.smith@gmail.com","created_at":"2026-01-19T11:55:09.051203-05:00","created_by":"Cameron Smith","updated_at":"2026-02-02T15:37:38.374454-05:00","closed_at":"2026-02-02T15:37:38.374454-05:00","close_reason":"Documented in docs/notes/architecture/package-distribution-channels.md. Both packages support dual-channel (uv/PyPI + pixi/conda-forge) with independent locks. No blocking dependency graph differences between channels.","dependencies":[{"issue_id":"pnt-4jg.3","depends_on_id":"pnt-4jg","type":"parent-child","created_at":"2026-01-19T11:55:09.051857-05:00","created_by":"Cameron Smith"},{"issue_id":"pnt-4jg.3","depends_on_id":"pnt-4jg.1","type":"blocks","created_at":"2026-01-19T12:20:13.557576-05:00","created_by":"Cameron Smith"},{"issue_id":"pnt-4jg.3","depends_on_id":"pnt-4jg.2","type":"blocks","created_at":"2026-01-19T12:20:16.147971-05:00","created_by":"Cameron Smith"}]} -{"id":"pnt-5vr","title":"Add production containers via nix2container and replace flocken tooling","description":"Add lightweight production/execution container images using nix2container (vanixiets pattern) and replace flocken manifest tooling. This does NOT touch nixpod-based dev containers.\n\nProduction containers (new):\n- nix2container.buildImage for minimal per-package execution images\n- Each user-facing package gets a container with only its runtime closure\n- pkgsCross for cross-compilation (eliminates QEMU dependency)\n- Per-container layer strategy: base layer (bash, coreutils) + app layer\n\nFlocken replacement (affects all containers):\n- crane-based mkMultiArchManifest replacing flocken mkDockerManifest\n- skopeo-nix2container with nix: transport for pushing\n- containerMatrix flake output for CI matrix generation (pure nix evaluation)\n- build-nix-images.yaml updated for nix2container workflow\n\nDoes NOT include:\n- Dev container migration (see pnt-xxx blocked issue)\n- Changes to buildMultiUserNixImage or nixpod integration\n- Existing dev container content or architecture\n\nReference: ~/projects/nix-workspace/vanixiets/modules/containers/default.nix\nReference: ~/projects/nix-workspace/vanixiets/lib/mk-multi-arch-manifest.nix\n\nAcceptance criteria:\n- nix2container flake input added\n- At least one production container defined via nix2container.buildImage\n- pkgsCross used for cross-compilation targets\n- lib/mk-multi-arch-manifest.nix ported from vanixiets\n- containerMatrix flake output for CI matrix generation\n- flocken replaced by crane-based manifests for production containers\n- Existing dev containers still build and work (no regression)","status":"in_progress","priority":2,"issue_type":"task","owner":"cameron.ray.smith@gmail.com","created_at":"2026-02-02T20:24:12.624117-05:00","created_by":"Cameron Smith","updated_at":"2026-02-02T21:47:33.181529-05:00","comments":[{"id":3,"issue_id":"pnt-5vr","author":"Cameron Smith","text":"Checkpoint: session 2026-02-02\n\nDone:\n- Researched vanixiets nix2container patterns (containers/default.nix, mk-multi-arch-manifest.nix, containers.yaml workflow)\n- Researched current pnt container infrastructure (containers.nix, build-nix-image action, build-nix-images workflow)\n- Identified scope mismatch between vanixiets lightweight tool containers and pnt dev containers\n- Rescoped to production containers + flocken replacement only (dev containers deferred to pnt-mgq)\n\nRemaining:\n- Add nix2container flake input\n- Create lib/mk-multi-arch-manifest.nix (port from vanixiets)\n- Define at least one production container via nix2container.buildImage (pnt-cli is the natural candidate)\n- Add pkgsCross targets and containerMatrix flake output\n- Replace flocken manifest tooling for existing dev containers (crane-based manifests)\n- Update build-nix-images.yaml workflow\n- Update build-nix-image composite action (QEMU no longer needed for production containers)\n- Add justfile recipes for container build/push (local/CI symmetry)\n\nContext for next agent:\n- vanixiets reference files are fully analyzed, see subagent outputs in this session\n- setup-nix action is already deployed on this branch stack (pnt-m3t-setup-nix merged into branch)\n- build-nix-image action already had redundant Nix install removed\n- Branch is pnt-5vr-nix2container, branched off pnt-m3t-setup-nix tip\n- Dev containers MUST NOT be touched — only production containers and manifest tooling","created_at":"2026-02-03T02:52:29Z"},{"id":4,"issue_id":"pnt-5vr","author":"Cameron Smith","text":"Checkpoint: session 2026-02-02 (continued)\n\nCompleted:\n- Added nix2container flake input, removed flocken as direct input\n- Created nix/lib/mk-multi-arch-manifest.nix (ported from vanixiets, generalized with mkSourceUri for mixed transport)\n- Added minimal CLI entrypoint to pnt-cli (main() exercising pyo3 greet/add bindings)\n- Defined pnt-cli production container via nix2container.buildImage with 2-layer strategy\n- Replaced flocken manifests with crane-based manifests for all containers (production: nix: transport, dev: docker-archive: transport)\n- Added containerMatrix flake output for CI matrix generation\n- Refactored build-nix-images.yaml to 3-job pattern (discover/build/manifest)\n- Removed obsolete build-nix-image composite action\n- Updated ci.yaml and package-release.yaml callers\n- Added justfile container recipes (build/load/push for production and dev, matrix display)\n\nKnown limitations:\n- Production containers built natively per-system (not pkgsCross) due to Python + maturin + Cargo cross-compilation complexity\n- docker-archive: transport for dev container manifests not yet tested against crane index append (may need validation)\n- Dev containers in CI still limited to x86_64-linux only (NIX_IMAGE_SYSTEMS override)\n\nRemaining for verification:\n- Linux builder needed to test actual container image builds (nix build .#pnt-cliProductionImage)\n- CI workflow run to validate end-to-end (discover -\u003e build -\u003e manifest push)\n- Verify docker-archive: transport works with skopeo + crane manifest list creation","created_at":"2026-02-03T03:52:51Z"}]} +{"id":"pnt-5vr","title":"Add production containers via nix2container and replace flocken tooling","description":"Add lightweight production/execution container images using nix2container (vanixiets pattern) and replace flocken manifest tooling. This does NOT touch nixpod-based dev containers.\n\nProduction containers (new):\n- nix2container.buildImage for minimal per-package execution images\n- Each user-facing package gets a container with only its runtime closure\n- pkgsCross for cross-compilation (eliminates QEMU dependency)\n- Per-container layer strategy: base layer (bash, coreutils) + app layer\n\nFlocken replacement (affects all containers):\n- crane-based mkMultiArchManifest replacing flocken mkDockerManifest\n- skopeo-nix2container with nix: transport for pushing\n- containerMatrix flake output for CI matrix generation (pure nix evaluation)\n- build-nix-images.yaml updated for nix2container workflow\n\nDoes NOT include:\n- Dev container migration (see pnt-xxx blocked issue)\n- Changes to buildMultiUserNixImage or nixpod integration\n- Existing dev container content or architecture\n\nReference: ~/projects/nix-workspace/vanixiets/modules/containers/default.nix\nReference: ~/projects/nix-workspace/vanixiets/lib/mk-multi-arch-manifest.nix\n\nAcceptance criteria:\n- nix2container flake input added\n- At least one production container defined via nix2container.buildImage\n- pkgsCross used for cross-compilation targets\n- lib/mk-multi-arch-manifest.nix ported from vanixiets\n- containerMatrix flake output for CI matrix generation\n- flocken replaced by crane-based manifests for production containers\n- Existing dev containers still build and work (no regression)","status":"in_progress","priority":2,"issue_type":"task","owner":"cameron.ray.smith@gmail.com","created_at":"2026-02-02T20:24:12.624117-05:00","created_by":"Cameron Smith","updated_at":"2026-02-02T21:47:33.181529-05:00","comments":[{"id":3,"issue_id":"pnt-5vr","author":"Cameron Smith","text":"Checkpoint: session 2026-02-02\n\nDone:\n- Researched vanixiets nix2container patterns (containers/default.nix, mk-multi-arch-manifest.nix, containers.yaml workflow)\n- Researched current pnt container infrastructure (containers.nix, build-nix-image action, build-nix-images workflow)\n- Identified scope mismatch between vanixiets lightweight tool containers and pnt dev containers\n- Rescoped to production containers + flocken replacement only (dev containers deferred to pnt-mgq)\n\nRemaining:\n- Add nix2container flake input\n- Create lib/mk-multi-arch-manifest.nix (port from vanixiets)\n- Define at least one production container via nix2container.buildImage (pnt-cli is the natural candidate)\n- Add pkgsCross targets and containerMatrix flake output\n- Replace flocken manifest tooling for existing dev containers (crane-based manifests)\n- Update build-nix-images.yaml workflow\n- Update build-nix-image composite action (QEMU no longer needed for production containers)\n- Add justfile recipes for container build/push (local/CI symmetry)\n\nContext for next agent:\n- vanixiets reference files are fully analyzed, see subagent outputs in this session\n- setup-nix action is already deployed on this branch stack (pnt-m3t-setup-nix merged into branch)\n- build-nix-image action already had redundant Nix install removed\n- Branch is pnt-5vr-nix2container, branched off pnt-m3t-setup-nix tip\n- Dev containers MUST NOT be touched — only production containers and manifest tooling","created_at":"2026-02-03T02:52:29Z"},{"id":4,"issue_id":"pnt-5vr","author":"Cameron Smith","text":"Checkpoint: session 2026-02-02 (continued)\n\nCompleted:\n- Added nix2container flake input, removed flocken as direct input\n- Created nix/lib/mk-multi-arch-manifest.nix (ported from vanixiets, generalized with mkSourceUri for mixed transport)\n- Added minimal CLI entrypoint to pnt-cli (main() exercising pyo3 greet/add bindings)\n- Defined pnt-cli production container via nix2container.buildImage with 2-layer strategy\n- Replaced flocken manifests with crane-based manifests for all containers (production: nix: transport, dev: docker-archive: transport)\n- Added containerMatrix flake output for CI matrix generation\n- Refactored build-nix-images.yaml to 3-job pattern (discover/build/manifest)\n- Removed obsolete build-nix-image composite action\n- Updated ci.yaml and package-release.yaml callers\n- Added justfile container recipes (build/load/push for production and dev, matrix display)\n\nKnown limitations:\n- Production containers built natively per-system (not pkgsCross) due to Python + maturin + Cargo cross-compilation complexity\n- docker-archive: transport for dev container manifests not yet tested against crane index append (may need validation)\n- Dev containers in CI still limited to x86_64-linux only (NIX_IMAGE_SYSTEMS override)\n\nRemaining for verification:\n- Linux builder needed to test actual container image builds (nix build .#pnt-cliProductionImage)\n- CI workflow run to validate end-to-end (discover -\u003e build -\u003e manifest push)\n- Verify docker-archive: transport works with skopeo + crane manifest list creation","created_at":"2026-02-03T03:52:51Z"},{"id":5,"issue_id":"pnt-5vr","author":"Cameron Smith","text":"Checkpoint: session 2026-02-02 (CI refactoring)\n\nDone:\n- Fixed template test failure: added [project] and [tool.uv.workspace] to root pyproject.toml\n- Simplified template.yaml: replaced GitGuardian with setup-nix action, removed scan/set-variables jobs\n- Created scripts/ci/ci-build-category.sh for category-based matrix builds\n- Added justfile recipes: ci-build-category, scan-secrets, scan-staged, preview-version, release-package\n- Added gitleaks to devshell for local/CI parity\n- Refactored ci.yaml: replaced omnix/nixci with 3-entry category matrix (packages, checks, devshells), replaced GitGuardian with gitleaks via nix develop, added flake-validation and bootstrap-verification jobs, added preview-release-version job, reduced top-level permissions to contents:read\n- Refactored package-release.yaml: replaced setup-uv and setup-yarn actions with nix develop via setup-nix, added cached-ci-job support, fixed artifact upload path\n- Fixed permissions chain: build-nix-images.yaml needs packages:write from callers, added to build-pr-images and test-release-packages\n\nRemaining:\n- CI run verification: latest push (4bc84a3) should resolve startup_failure from permissions chain. Need to verify CI passes end-to-end.\n- Iterative fixes: if nix category builds or test-release-packages fail at runtime, diagnose from logs and fix\n- Close pnt-5vr once CI confirmed working\n- Container workflow 3-job pattern (discover -\u003e build -\u003e manifest) not yet tested in CI\n\nContext for next agent:\n- Branch is pnt-5vr-nix2container with PR #44\n- The CI architecture now matches vanixiets/typescript-nix-template patterns\n- Three parallel startup_failures were caused by permissions chain issues (build-nix-images.yaml declares packages:write at workflow level, GitHub validates entire call chain at parse time)\n- run 21617100530 was from an intermediate push before the full refactoring landed\n- The secrets-scan job uses nix develop -c just scan-secrets (gitleaks is in devshell)\n- The nix job uses a static 3-entry matrix calling just ci-build-category\n- package-release.yaml now uses nix develop for all tool access (yarn, uv)\n- To check CI: gh run list --workflow \"CI/CD\" --limit 3 --repo sciexp/python-nix-template\n- To download logs: gh api \"repos/sciexp/python-nix-template/actions/runs/\u003cid\u003e/logs\" \u003e logs.zip","created_at":"2026-02-03T04:45:03Z"}]} {"id":"pnt-btz","title":"pyo3/Rust extension integration","description":"Add Rust extension module support via maturin + pyo3, demonstrating Nix build integration with crane cargoArtifacts sharing and uv2nix overlay composition.\n\nArchitecture documented in: docs/notes/architecture/crane-uv2nix-integration.md\n\nKey patterns:\n- Per-package Rust workspace (crates/ inside Python package)\n- crane buildDepsOnly for artifact caching\n- uv2nix overlay injection for maturin builds\n- CI matrix with rust-deps/rust-checks/python-wheel categories\n\nReference implementations:\n- ~/projects/rust-workspace/ironstar (crane patterns)\n- ~/projects/planning-workspace/langchain (federated Python)\n","status":"closed","priority":2,"issue_type":"epic","owner":"cameron.ray.smith@gmail.com","created_at":"2026-01-19T11:54:41.426256-05:00","created_by":"Cameron Smith","updated_at":"2026-02-02T20:45:01.187149-05:00","closed_at":"2026-02-02T20:45:01.187149-05:00","close_reason":"All 3 children complete. Crane + uv2nix + maturin integration fully operational.","dependencies":[{"issue_id":"pnt-btz","depends_on_id":"pnt-dre","type":"blocks","created_at":"2026-01-19T11:55:32.690895-05:00","created_by":"Cameron Smith"},{"issue_id":"pnt-btz","depends_on_id":"pnt-4jg","type":"blocks","created_at":"2026-01-19T11:55:32.812602-05:00","created_by":"Cameron Smith"}]} {"id":"pnt-btz.1","title":"Create pnt-cli package scaffold with Rust crates","description":"Create packages/pnt-cli/ with federated structure:\n\nDirectory structure:\n- packages/pnt-cli/pyproject.toml (maturin build-backend, manifest-path binding)\n- packages/pnt-cli/src/pnt_cli/__init__.py (Python wrapper)\n- packages/pnt-cli/crates/Cargo.toml ([workspace] with member crates)\n- packages/pnt-cli/crates/pnt-cli-core/Cargo.toml (pure Rust library)\n- packages/pnt-cli/crates/pnt-cli-py/Cargo.toml (pyo3 bindings, depends on core)\n\npyproject.toml configuration:\n- [build-system] requires maturin\u003e=1.5\n- [tool.maturin] manifest-path = \"crates/pnt-cli-py/Cargo.toml\"\n- [tool.maturin] module-name = \"pnt_cli._native\"\n\nMinimal proof-of-concept: expose a simple function from Rust to Python.\n\nSee: docs/notes/architecture/crane-uv2nix-integration.md\n","status":"closed","priority":2,"issue_type":"task","owner":"cameron.ray.smith@gmail.com","created_at":"2026-01-19T11:55:17.885691-05:00","created_by":"Cameron Smith","updated_at":"2026-02-02T20:30:16.311977-05:00","closed_at":"2026-02-02T20:30:16.311977-05:00","close_reason":"Implemented in a3e79c3. Scaffold verified: cargo check, cargo test (2/2 pass), cargo clippy clean.","dependencies":[{"issue_id":"pnt-btz.1","depends_on_id":"pnt-btz","type":"parent-child","created_at":"2026-01-19T11:55:17.886287-05:00","created_by":"Cameron Smith"},{"issue_id":"pnt-btz.1","depends_on_id":"pnt-4jg.1","type":"blocks","created_at":"2026-01-19T12:20:18.940008-05:00","created_by":"Cameron Smith"}]} {"id":"pnt-btz.2","title":"Implement crane + uv2nix Nix modules","description":"Create Nix modules implementing the crane + uv2nix integration pattern.\n\nFiles to create:\n- nix/packages/pnt-cli/rust.nix (crane configuration)\n- nix/packages/pnt-cli/default.nix (Python + Rust composition)\n- nix/modules/rust/lib.nix (shared crane utilities, optional)\n\nrust.nix pattern:\n- crane-lib.buildDepsOnly for cargoArtifacts caching\n- commonArgs pattern for derivation hash consistency\n- crane-lib.vendorCargoDeps for maturin's cargo invocation\n- Export cargoArtifacts, cargoVendorDir, clippy, nextest\n\ndefault.nix pattern:\n- Import rust.nix\n- Create overlay injecting cargoVendorDir and CARGO_TARGET_DIR\n- Export overlay and checks for flake composition\n\nUpdate nix/modules/python.nix:\n- Load pnt-cli workspace independently (federated pattern)\n- Compose Rust overlay with uv2nix overlays\n\nSee: docs/notes/architecture/crane-uv2nix-integration.md\n","status":"closed","priority":2,"issue_type":"task","owner":"cameron.ray.smith@gmail.com","created_at":"2026-01-19T11:55:18.885252-05:00","created_by":"Cameron Smith","updated_at":"2026-02-02T20:41:16.274515-05:00","closed_at":"2026-02-02T20:41:16.274515-05:00","close_reason":"Implemented in 8d8a814. Crane checks (clippy, nextest) build. Full maturin wheel builds via nix build .#default. Python import verified: greet('nix') and add(2,3) work end-to-end.","dependencies":[{"issue_id":"pnt-btz.2","depends_on_id":"pnt-btz","type":"parent-child","created_at":"2026-01-19T11:55:18.885818-05:00","created_by":"Cameron Smith"},{"issue_id":"pnt-btz.2","depends_on_id":"pnt-btz.1","type":"blocks","created_at":"2026-01-19T12:20:08.210077-05:00","created_by":"Cameron Smith"}]} From 567df4c8e7a3a7536fc8f7ff748223d4df8244bf Mon Sep 17 00:00:00 2001 From: Cameron Smith Date: Tue, 3 Feb 2026 00:03:13 -0500 Subject: [PATCH 103/134] fix(ci): add --no-confirm to Nix installer for non-interactive CI --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index c84196a..9ba6057 100644 --- a/Makefile +++ b/Makefile @@ -71,7 +71,7 @@ install-nix: ## Install Nix using the Determinate Systems installer @if command -v nix >/dev/null 2>&1; then \ echo "Nix is already installed."; \ else \ - curl --proto '=https' --tlsv1.2 -sSf -L https://install.determinate.systems/nix | sh -s -- install; \ + curl --proto '=https' --tlsv1.2 -sSf -L https://install.determinate.systems/nix | sh -s -- install --no-confirm; \ fi .PHONY: install-direnv From 349bff6fa1ad643c3356cdd74d5ca4dc007e0bbc Mon Sep 17 00:00:00 2001 From: Cameron Smith Date: Tue, 3 Feb 2026 00:04:47 -0500 Subject: [PATCH 104/134] fix(ci): replace nix flake check with system-specific validation The full nix flake check evaluates all systems including aarch64-linux, which fails on x86_64-linux CI runners due to IFD in nixpod container dependencies (catppuccin-starship). System-specific evaluation and build of checks avoids this cross-system issue. --- justfile | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/justfile b/justfile index 5e4b511..0bb0b1b 100644 --- a/justfile +++ b/justfile @@ -344,10 +344,18 @@ container-matrix: dev: nix develop -# Validate the Nix flake configuration +# Validate the Nix flake configuration for the current system [group('nix')] flake-check: - nix flake check + #!/usr/bin/env bash + set -euo pipefail + SYSTEM=$(nix eval --impure --raw --expr builtins.currentSystem) + echo "Validating flake for $SYSTEM..." + nix flake metadata + echo "Evaluating checks for $SYSTEM..." + nix eval ".#checks.$SYSTEM" --apply builtins.attrNames --json + echo "Building checks for $SYSTEM..." + nix build ".#checks.$SYSTEM" --no-link -L # Update all flake inputs to their latest versions [group('nix')] From e6d1404fe0d6ec4d8a60c759e16a877306574393 Mon Sep 17 00:00:00 2001 From: Cameron Smith Date: Tue, 3 Feb 2026 00:05:08 -0500 Subject: [PATCH 105/134] fix(ci): exclude multi-arch manifest packages from category builds Manifest packages reference packages from other systems (e.g. aarch64-linux on x86_64-linux runners) and cannot be built in single-system CI jobs. The dedicated build-nix-images workflow handles manifest creation with proper multi-arch infrastructure. --- scripts/ci/ci-build-category.sh | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/scripts/ci/ci-build-category.sh b/scripts/ci/ci-build-category.sh index 26601e9..b7d6bbc 100755 --- a/scripts/ci/ci-build-category.sh +++ b/scripts/ci/ci-build-category.sh @@ -112,6 +112,13 @@ build_category() { local attrs attrs=$(nix eval ".#${flake_attr}.${system}" --apply 'builtins.attrNames' --json 2>/dev/null | jq -r '.[]' || echo "") + # Exclude multi-arch manifest packages from single-system CI builds. + # Manifests reference packages from other systems and are built by + # the dedicated build-nix-images workflow instead. + if [ "$flake_attr" = "packages" ]; then + attrs=$(echo "$attrs" | grep -v 'Manifest$' || echo "") + fi + if [ -z "$attrs" ]; then echo "no $label found for $system" return 0 From 34be403ab234aa6222957daaf6492fa3c3faae37 Mon Sep 17 00:00:00 2001 From: Cameron Smith Date: Tue, 3 Feb 2026 00:05:21 -0500 Subject: [PATCH 106/134] fix(ci): rename root workspace project to avoid uv name collision The root pyproject.toml and packages/python-nix-template both used the name python-nix-template, causing uv to error with "Two workspace members are both named" during ci-sync in test-python jobs. --- pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index f5d7fa1..73a2e8c 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] description = "A Python project template for Nix using uv2nix and flake-parts" -name = "python-nix-template" +name = "python-nix-template-workspace" requires-python = ">=3.11,<3.13" version = "0.0.0" From 22853ee989a0f85ff9fbcfac23cff2b13d4997c3 Mon Sep 17 00:00:00 2001 From: Cameron Smith Date: Tue, 3 Feb 2026 00:05:41 -0500 Subject: [PATCH 107/134] feat(pnt-cli): add package.json for yarn workspace and semantic-release The preview-release-version CI job discovers all packages and runs yarn workspace commands, which requires a package.json in each package directory. --- packages/pnt-cli/package.json | 92 +++++++++++++++++++++++++++++++++++ 1 file changed, 92 insertions(+) create mode 100644 packages/pnt-cli/package.json diff --git a/packages/pnt-cli/package.json b/packages/pnt-cli/package.json new file mode 100644 index 0000000..5c2ab70 --- /dev/null +++ b/packages/pnt-cli/package.json @@ -0,0 +1,92 @@ +{ + "description": "pnt-cli with pyo3 native bindings", + "devDependencies": { + "@semantic-release/changelog": "^6.0.3", + "@semantic-release/git": "^10.0.1", + "@semantic-release/github": "^11.0.1", + "conventional-changelog-conventionalcommits": "^8.0.0", + "cross-env": "^7.0.3", + "semantic-release": "^24.2.3", + "semantic-release-major-tag": "^0.3.2", + "semantic-release-monorepo": "^8.0.2" + }, + "engines": { + "node": ">=18" + }, + "license": "MIT", + "name": "pnt-cli", + "packageManager": "yarn@4.6.0", + "private": true, + "release": { + "branches": [ + { + "name": "main" + }, + { + "name": "beta", + "prerelease": true + } + ], + "extends": "semantic-release-monorepo", + "npmPublish": false, + "plugins": [ + [ + "@semantic-release/commit-analyzer", + { + "parserOpts": { + "noteKeywords": [ + "BREAKING CHANGE", + "BREAKING-CHANGE" + ] + }, + "preset": "conventionalcommits" + } + ], + [ + "@semantic-release/release-notes-generator", + { + "parserOpts": { + "noteKeywords": [ + "BREAKING CHANGE", + "BREAKING-CHANGE", + "NOTABLE CHANGE", + "NOTABLE-CHANGE" + ] + }, + "preset": "conventionalcommits" + } + ], + [ + "@semantic-release/changelog", + { + "changelogTitle": "# Changelog" + } + ], + [ + "@semantic-release/github", + { + "addReleases": "bottom", + "failComment": false, + "successComment": false + } + ], + [ + "semantic-release-major-tag", + { + "customTags": [ + "v${major}", + "v${major}.${minor}" + ] + } + ] + ] + }, + "repository": { + "type": "git", + "url": "https://github.com/sciexp/python-nix-template.git" + }, + "scripts": { + "test-release": "semantic-release --dry-run --no-ci" + }, + "version": "0.0.0-development" +} From 66b21da16745be2c277e8bd909df3d92e26768fe Mon Sep 17 00:00:00 2001 From: Cameron Smith Date: Tue, 3 Feb 2026 00:17:19 -0500 Subject: [PATCH 108/134] chore: update yarn.lock with pnt-cli workspace entry --- yarn.lock | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/yarn.lock b/yarn.lock index a84cb60..865a0c8 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3538,6 +3538,21 @@ __metadata: languageName: node linkType: hard +"pnt-cli@workspace:packages/pnt-cli": + version: 0.0.0-use.local + resolution: "pnt-cli@workspace:packages/pnt-cli" + dependencies: + "@semantic-release/changelog": "npm:^6.0.3" + "@semantic-release/git": "npm:^10.0.1" + "@semantic-release/github": "npm:^11.0.1" + conventional-changelog-conventionalcommits: "npm:^8.0.0" + cross-env: "npm:^7.0.3" + semantic-release: "npm:^24.2.3" + semantic-release-major-tag: "npm:^0.3.2" + semantic-release-monorepo: "npm:^8.0.2" + languageName: unknown + linkType: soft + "pnt-functional@workspace:packages/pnt-functional": version: 0.0.0-use.local resolution: "pnt-functional@workspace:packages/pnt-functional" From 53e24456063e5e1d4dec5b8139e98e11b33184a3 Mon Sep 17 00:00:00 2001 From: Cameron Smith Date: Tue, 3 Feb 2026 00:17:34 -0500 Subject: [PATCH 109/134] fix(ci): iterate over check attributes in flake-check recipe The checks flake output is an attribute set, not a single derivation. Build each check individually to avoid nix build type mismatch. --- justfile | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/justfile b/justfile index 0bb0b1b..81fbd19 100644 --- a/justfile +++ b/justfile @@ -355,7 +355,10 @@ flake-check: echo "Evaluating checks for $SYSTEM..." nix eval ".#checks.$SYSTEM" --apply builtins.attrNames --json echo "Building checks for $SYSTEM..." - nix build ".#checks.$SYSTEM" --no-link -L + for check in $(nix eval ".#checks.$SYSTEM" --apply builtins.attrNames --json | jq -r '.[]'); do + echo "Building check: $check" + nix build ".#checks.$SYSTEM.$check" --no-link -L + done # Update all flake inputs to their latest versions [group('nix')] From c760bd13ea9d40d6f7bc28621ac85a9a5ca1a8a4 Mon Sep 17 00:00:00 2001 From: Cameron Smith Date: Tue, 3 Feb 2026 00:25:00 -0500 Subject: [PATCH 110/134] fix(ci): use main branch for semantic-release dry-run validation The dry-run was using GITHUB_REF_NAME which resolves to the PR branch, not a configured release branch. Semantic-release rejects branches not in its branches config, causing ERELEASEBRANCHES errors on PR branches. --- justfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/justfile b/justfile index 81fbd19..3aabf28 100644 --- a/justfile +++ b/justfile @@ -744,7 +744,7 @@ release-package package-name dry-run="false": yarn workspace {{package-name}} install if [ "{{dry-run}}" = "true" ]; then unset GITHUB_ACTIONS - yarn workspace {{package-name}} test-release -b "${GITHUB_REF_NAME:-main}" + yarn workspace {{package-name}} test-release -b main else yarn workspace {{package-name}} release fi From 223b0cd6b76b5c9ebcb1fb6ef6dbe3f8140fe75b Mon Sep 17 00:00:00 2001 From: Cameron Smith Date: Tue, 3 Feb 2026 00:32:37 -0500 Subject: [PATCH 111/134] chore(issues): close pnt-5vr after CI verification --- .beads/issues.jsonl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.beads/issues.jsonl b/.beads/issues.jsonl index a3464ae..f8df89b 100644 --- a/.beads/issues.jsonl +++ b/.beads/issues.jsonl @@ -2,7 +2,7 @@ {"id":"pnt-4jg.1","title":"Remove uv workspace, adopt path dependencies","description":"Remove [tool.uv.workspace] from root pyproject.toml. Each package gets own pyproject.toml with [tool.uv.sources] for sibling references using path sources with editable=true. Follow langchain pattern.","status":"closed","priority":2,"issue_type":"task","owner":"cameron.ray.smith@gmail.com","created_at":"2026-01-19T11:55:07.344057-05:00","created_by":"Cameron Smith","updated_at":"2026-02-02T14:40:02.175394-05:00","closed_at":"2026-02-02T14:40:02.175394-05:00","close_reason":"Implemented in a8a823f. Removed root uv workspace, generated per-package locks, rewrote nix modules to Pattern 3 per-package loading.","dependencies":[{"issue_id":"pnt-4jg.1","depends_on_id":"pnt-4jg","type":"parent-child","created_at":"2026-01-19T11:55:07.344659-05:00","created_by":"Cameron Smith"}],"comments":[{"id":1,"issue_id":"pnt-4jg.1","author":"Cameron Smith","text":"Post-close fixup commits (774ec26):\n- fix(ci): update lock file references for per-package federation (d0cab2a)\n- fixup! merge federated workspace deps: replace // with zipAttrsWith for extras-safe dep merging (7b3e7ae)\n- fixup! load packages independently: document version-conflict invariant in python.nix and architecture doc (36eb8a7, 774ec26)\n\nReview findings addressed: stale CI cache-dependency-glob paths, fragile shallow-merge dep specs, undocumented overlay composition invariant. Full CI redesign (nix develop + justfile symmetry) deferred to pnt-dre.4.","created_at":"2026-02-02T20:17:00Z"}]} {"id":"pnt-4jg.2","title":"Configure pixi feature-based composition","description":"Implement pixi feature/environment pattern: [feature.X.dependencies] + [environments] composition. Single pixi.lock covering all environments. Per-feature task definitions. Target-specific dependencies for platform support.","status":"closed","priority":2,"issue_type":"task","owner":"cameron.ray.smith@gmail.com","created_at":"2026-01-19T11:55:08.085592-05:00","created_by":"Cameron Smith","updated_at":"2026-02-02T15:36:49.459815-05:00","closed_at":"2026-02-02T15:36:49.459815-05:00","close_reason":"Verified pixi feature composition via nix develop -c just \u003crecipe\u003e. Fixed: added missing feature tasks to python-nix-template, delegated justfile conda recipes to pixi task names for correct working directory, moved deprecated build channels to backend.channels.","dependencies":[{"issue_id":"pnt-4jg.2","depends_on_id":"pnt-4jg","type":"parent-child","created_at":"2026-01-19T11:55:08.086155-05:00","created_by":"Cameron Smith"}]} {"id":"pnt-4jg.3","title":"Document package distribution channels","description":"Document which packages support uv/pypi vs pixi/conda distribution. Note dependency graph differences between channels. Update README and package metadata.","status":"closed","priority":2,"issue_type":"task","owner":"cameron.ray.smith@gmail.com","created_at":"2026-01-19T11:55:09.051203-05:00","created_by":"Cameron Smith","updated_at":"2026-02-02T15:37:38.374454-05:00","closed_at":"2026-02-02T15:37:38.374454-05:00","close_reason":"Documented in docs/notes/architecture/package-distribution-channels.md. Both packages support dual-channel (uv/PyPI + pixi/conda-forge) with independent locks. No blocking dependency graph differences between channels.","dependencies":[{"issue_id":"pnt-4jg.3","depends_on_id":"pnt-4jg","type":"parent-child","created_at":"2026-01-19T11:55:09.051857-05:00","created_by":"Cameron Smith"},{"issue_id":"pnt-4jg.3","depends_on_id":"pnt-4jg.1","type":"blocks","created_at":"2026-01-19T12:20:13.557576-05:00","created_by":"Cameron Smith"},{"issue_id":"pnt-4jg.3","depends_on_id":"pnt-4jg.2","type":"blocks","created_at":"2026-01-19T12:20:16.147971-05:00","created_by":"Cameron Smith"}]} -{"id":"pnt-5vr","title":"Add production containers via nix2container and replace flocken tooling","description":"Add lightweight production/execution container images using nix2container (vanixiets pattern) and replace flocken manifest tooling. This does NOT touch nixpod-based dev containers.\n\nProduction containers (new):\n- nix2container.buildImage for minimal per-package execution images\n- Each user-facing package gets a container with only its runtime closure\n- pkgsCross for cross-compilation (eliminates QEMU dependency)\n- Per-container layer strategy: base layer (bash, coreutils) + app layer\n\nFlocken replacement (affects all containers):\n- crane-based mkMultiArchManifest replacing flocken mkDockerManifest\n- skopeo-nix2container with nix: transport for pushing\n- containerMatrix flake output for CI matrix generation (pure nix evaluation)\n- build-nix-images.yaml updated for nix2container workflow\n\nDoes NOT include:\n- Dev container migration (see pnt-xxx blocked issue)\n- Changes to buildMultiUserNixImage or nixpod integration\n- Existing dev container content or architecture\n\nReference: ~/projects/nix-workspace/vanixiets/modules/containers/default.nix\nReference: ~/projects/nix-workspace/vanixiets/lib/mk-multi-arch-manifest.nix\n\nAcceptance criteria:\n- nix2container flake input added\n- At least one production container defined via nix2container.buildImage\n- pkgsCross used for cross-compilation targets\n- lib/mk-multi-arch-manifest.nix ported from vanixiets\n- containerMatrix flake output for CI matrix generation\n- flocken replaced by crane-based manifests for production containers\n- Existing dev containers still build and work (no regression)","status":"in_progress","priority":2,"issue_type":"task","owner":"cameron.ray.smith@gmail.com","created_at":"2026-02-02T20:24:12.624117-05:00","created_by":"Cameron Smith","updated_at":"2026-02-02T21:47:33.181529-05:00","comments":[{"id":3,"issue_id":"pnt-5vr","author":"Cameron Smith","text":"Checkpoint: session 2026-02-02\n\nDone:\n- Researched vanixiets nix2container patterns (containers/default.nix, mk-multi-arch-manifest.nix, containers.yaml workflow)\n- Researched current pnt container infrastructure (containers.nix, build-nix-image action, build-nix-images workflow)\n- Identified scope mismatch between vanixiets lightweight tool containers and pnt dev containers\n- Rescoped to production containers + flocken replacement only (dev containers deferred to pnt-mgq)\n\nRemaining:\n- Add nix2container flake input\n- Create lib/mk-multi-arch-manifest.nix (port from vanixiets)\n- Define at least one production container via nix2container.buildImage (pnt-cli is the natural candidate)\n- Add pkgsCross targets and containerMatrix flake output\n- Replace flocken manifest tooling for existing dev containers (crane-based manifests)\n- Update build-nix-images.yaml workflow\n- Update build-nix-image composite action (QEMU no longer needed for production containers)\n- Add justfile recipes for container build/push (local/CI symmetry)\n\nContext for next agent:\n- vanixiets reference files are fully analyzed, see subagent outputs in this session\n- setup-nix action is already deployed on this branch stack (pnt-m3t-setup-nix merged into branch)\n- build-nix-image action already had redundant Nix install removed\n- Branch is pnt-5vr-nix2container, branched off pnt-m3t-setup-nix tip\n- Dev containers MUST NOT be touched — only production containers and manifest tooling","created_at":"2026-02-03T02:52:29Z"},{"id":4,"issue_id":"pnt-5vr","author":"Cameron Smith","text":"Checkpoint: session 2026-02-02 (continued)\n\nCompleted:\n- Added nix2container flake input, removed flocken as direct input\n- Created nix/lib/mk-multi-arch-manifest.nix (ported from vanixiets, generalized with mkSourceUri for mixed transport)\n- Added minimal CLI entrypoint to pnt-cli (main() exercising pyo3 greet/add bindings)\n- Defined pnt-cli production container via nix2container.buildImage with 2-layer strategy\n- Replaced flocken manifests with crane-based manifests for all containers (production: nix: transport, dev: docker-archive: transport)\n- Added containerMatrix flake output for CI matrix generation\n- Refactored build-nix-images.yaml to 3-job pattern (discover/build/manifest)\n- Removed obsolete build-nix-image composite action\n- Updated ci.yaml and package-release.yaml callers\n- Added justfile container recipes (build/load/push for production and dev, matrix display)\n\nKnown limitations:\n- Production containers built natively per-system (not pkgsCross) due to Python + maturin + Cargo cross-compilation complexity\n- docker-archive: transport for dev container manifests not yet tested against crane index append (may need validation)\n- Dev containers in CI still limited to x86_64-linux only (NIX_IMAGE_SYSTEMS override)\n\nRemaining for verification:\n- Linux builder needed to test actual container image builds (nix build .#pnt-cliProductionImage)\n- CI workflow run to validate end-to-end (discover -\u003e build -\u003e manifest push)\n- Verify docker-archive: transport works with skopeo + crane manifest list creation","created_at":"2026-02-03T03:52:51Z"},{"id":5,"issue_id":"pnt-5vr","author":"Cameron Smith","text":"Checkpoint: session 2026-02-02 (CI refactoring)\n\nDone:\n- Fixed template test failure: added [project] and [tool.uv.workspace] to root pyproject.toml\n- Simplified template.yaml: replaced GitGuardian with setup-nix action, removed scan/set-variables jobs\n- Created scripts/ci/ci-build-category.sh for category-based matrix builds\n- Added justfile recipes: ci-build-category, scan-secrets, scan-staged, preview-version, release-package\n- Added gitleaks to devshell for local/CI parity\n- Refactored ci.yaml: replaced omnix/nixci with 3-entry category matrix (packages, checks, devshells), replaced GitGuardian with gitleaks via nix develop, added flake-validation and bootstrap-verification jobs, added preview-release-version job, reduced top-level permissions to contents:read\n- Refactored package-release.yaml: replaced setup-uv and setup-yarn actions with nix develop via setup-nix, added cached-ci-job support, fixed artifact upload path\n- Fixed permissions chain: build-nix-images.yaml needs packages:write from callers, added to build-pr-images and test-release-packages\n\nRemaining:\n- CI run verification: latest push (4bc84a3) should resolve startup_failure from permissions chain. Need to verify CI passes end-to-end.\n- Iterative fixes: if nix category builds or test-release-packages fail at runtime, diagnose from logs and fix\n- Close pnt-5vr once CI confirmed working\n- Container workflow 3-job pattern (discover -\u003e build -\u003e manifest) not yet tested in CI\n\nContext for next agent:\n- Branch is pnt-5vr-nix2container with PR #44\n- The CI architecture now matches vanixiets/typescript-nix-template patterns\n- Three parallel startup_failures were caused by permissions chain issues (build-nix-images.yaml declares packages:write at workflow level, GitHub validates entire call chain at parse time)\n- run 21617100530 was from an intermediate push before the full refactoring landed\n- The secrets-scan job uses nix develop -c just scan-secrets (gitleaks is in devshell)\n- The nix job uses a static 3-entry matrix calling just ci-build-category\n- package-release.yaml now uses nix develop for all tool access (yarn, uv)\n- To check CI: gh run list --workflow \"CI/CD\" --limit 3 --repo sciexp/python-nix-template\n- To download logs: gh api \"repos/sciexp/python-nix-template/actions/runs/\u003cid\u003e/logs\" \u003e logs.zip","created_at":"2026-02-03T04:45:03Z"}]} +{"id":"pnt-5vr","title":"Add production containers via nix2container and replace flocken tooling","description":"Add lightweight production/execution container images using nix2container (vanixiets pattern) and replace flocken manifest tooling. This does NOT touch nixpod-based dev containers.\n\nProduction containers (new):\n- nix2container.buildImage for minimal per-package execution images\n- Each user-facing package gets a container with only its runtime closure\n- pkgsCross for cross-compilation (eliminates QEMU dependency)\n- Per-container layer strategy: base layer (bash, coreutils) + app layer\n\nFlocken replacement (affects all containers):\n- crane-based mkMultiArchManifest replacing flocken mkDockerManifest\n- skopeo-nix2container with nix: transport for pushing\n- containerMatrix flake output for CI matrix generation (pure nix evaluation)\n- build-nix-images.yaml updated for nix2container workflow\n\nDoes NOT include:\n- Dev container migration (see pnt-xxx blocked issue)\n- Changes to buildMultiUserNixImage or nixpod integration\n- Existing dev container content or architecture\n\nReference: ~/projects/nix-workspace/vanixiets/modules/containers/default.nix\nReference: ~/projects/nix-workspace/vanixiets/lib/mk-multi-arch-manifest.nix\n\nAcceptance criteria:\n- nix2container flake input added\n- At least one production container defined via nix2container.buildImage\n- pkgsCross used for cross-compilation targets\n- lib/mk-multi-arch-manifest.nix ported from vanixiets\n- containerMatrix flake output for CI matrix generation\n- flocken replaced by crane-based manifests for production containers\n- Existing dev containers still build and work (no regression)","status":"closed","priority":2,"issue_type":"task","owner":"cameron.ray.smith@gmail.com","created_at":"2026-02-02T20:24:12.624117-05:00","created_by":"Cameron Smith","updated_at":"2026-02-03T00:32:32.102656-05:00","closed_at":"2026-02-03T00:32:32.102656-05:00","close_reason":"Implemented in c760bd1. PR #44.","comments":[{"id":3,"issue_id":"pnt-5vr","author":"Cameron Smith","text":"Checkpoint: session 2026-02-02\n\nDone:\n- Researched vanixiets nix2container patterns (containers/default.nix, mk-multi-arch-manifest.nix, containers.yaml workflow)\n- Researched current pnt container infrastructure (containers.nix, build-nix-image action, build-nix-images workflow)\n- Identified scope mismatch between vanixiets lightweight tool containers and pnt dev containers\n- Rescoped to production containers + flocken replacement only (dev containers deferred to pnt-mgq)\n\nRemaining:\n- Add nix2container flake input\n- Create lib/mk-multi-arch-manifest.nix (port from vanixiets)\n- Define at least one production container via nix2container.buildImage (pnt-cli is the natural candidate)\n- Add pkgsCross targets and containerMatrix flake output\n- Replace flocken manifest tooling for existing dev containers (crane-based manifests)\n- Update build-nix-images.yaml workflow\n- Update build-nix-image composite action (QEMU no longer needed for production containers)\n- Add justfile recipes for container build/push (local/CI symmetry)\n\nContext for next agent:\n- vanixiets reference files are fully analyzed, see subagent outputs in this session\n- setup-nix action is already deployed on this branch stack (pnt-m3t-setup-nix merged into branch)\n- build-nix-image action already had redundant Nix install removed\n- Branch is pnt-5vr-nix2container, branched off pnt-m3t-setup-nix tip\n- Dev containers MUST NOT be touched — only production containers and manifest tooling","created_at":"2026-02-03T02:52:29Z"},{"id":4,"issue_id":"pnt-5vr","author":"Cameron Smith","text":"Checkpoint: session 2026-02-02 (continued)\n\nCompleted:\n- Added nix2container flake input, removed flocken as direct input\n- Created nix/lib/mk-multi-arch-manifest.nix (ported from vanixiets, generalized with mkSourceUri for mixed transport)\n- Added minimal CLI entrypoint to pnt-cli (main() exercising pyo3 greet/add bindings)\n- Defined pnt-cli production container via nix2container.buildImage with 2-layer strategy\n- Replaced flocken manifests with crane-based manifests for all containers (production: nix: transport, dev: docker-archive: transport)\n- Added containerMatrix flake output for CI matrix generation\n- Refactored build-nix-images.yaml to 3-job pattern (discover/build/manifest)\n- Removed obsolete build-nix-image composite action\n- Updated ci.yaml and package-release.yaml callers\n- Added justfile container recipes (build/load/push for production and dev, matrix display)\n\nKnown limitations:\n- Production containers built natively per-system (not pkgsCross) due to Python + maturin + Cargo cross-compilation complexity\n- docker-archive: transport for dev container manifests not yet tested against crane index append (may need validation)\n- Dev containers in CI still limited to x86_64-linux only (NIX_IMAGE_SYSTEMS override)\n\nRemaining for verification:\n- Linux builder needed to test actual container image builds (nix build .#pnt-cliProductionImage)\n- CI workflow run to validate end-to-end (discover -\u003e build -\u003e manifest push)\n- Verify docker-archive: transport works with skopeo + crane manifest list creation","created_at":"2026-02-03T03:52:51Z"},{"id":5,"issue_id":"pnt-5vr","author":"Cameron Smith","text":"Checkpoint: session 2026-02-02 (CI refactoring)\n\nDone:\n- Fixed template test failure: added [project] and [tool.uv.workspace] to root pyproject.toml\n- Simplified template.yaml: replaced GitGuardian with setup-nix action, removed scan/set-variables jobs\n- Created scripts/ci/ci-build-category.sh for category-based matrix builds\n- Added justfile recipes: ci-build-category, scan-secrets, scan-staged, preview-version, release-package\n- Added gitleaks to devshell for local/CI parity\n- Refactored ci.yaml: replaced omnix/nixci with 3-entry category matrix (packages, checks, devshells), replaced GitGuardian with gitleaks via nix develop, added flake-validation and bootstrap-verification jobs, added preview-release-version job, reduced top-level permissions to contents:read\n- Refactored package-release.yaml: replaced setup-uv and setup-yarn actions with nix develop via setup-nix, added cached-ci-job support, fixed artifact upload path\n- Fixed permissions chain: build-nix-images.yaml needs packages:write from callers, added to build-pr-images and test-release-packages\n\nRemaining:\n- CI run verification: latest push (4bc84a3) should resolve startup_failure from permissions chain. Need to verify CI passes end-to-end.\n- Iterative fixes: if nix category builds or test-release-packages fail at runtime, diagnose from logs and fix\n- Close pnt-5vr once CI confirmed working\n- Container workflow 3-job pattern (discover -\u003e build -\u003e manifest) not yet tested in CI\n\nContext for next agent:\n- Branch is pnt-5vr-nix2container with PR #44\n- The CI architecture now matches vanixiets/typescript-nix-template patterns\n- Three parallel startup_failures were caused by permissions chain issues (build-nix-images.yaml declares packages:write at workflow level, GitHub validates entire call chain at parse time)\n- run 21617100530 was from an intermediate push before the full refactoring landed\n- The secrets-scan job uses nix develop -c just scan-secrets (gitleaks is in devshell)\n- The nix job uses a static 3-entry matrix calling just ci-build-category\n- package-release.yaml now uses nix develop for all tool access (yarn, uv)\n- To check CI: gh run list --workflow \"CI/CD\" --limit 3 --repo sciexp/python-nix-template\n- To download logs: gh api \"repos/sciexp/python-nix-template/actions/runs/\u003cid\u003e/logs\" \u003e logs.zip","created_at":"2026-02-03T04:45:03Z"}]} {"id":"pnt-btz","title":"pyo3/Rust extension integration","description":"Add Rust extension module support via maturin + pyo3, demonstrating Nix build integration with crane cargoArtifacts sharing and uv2nix overlay composition.\n\nArchitecture documented in: docs/notes/architecture/crane-uv2nix-integration.md\n\nKey patterns:\n- Per-package Rust workspace (crates/ inside Python package)\n- crane buildDepsOnly for artifact caching\n- uv2nix overlay injection for maturin builds\n- CI matrix with rust-deps/rust-checks/python-wheel categories\n\nReference implementations:\n- ~/projects/rust-workspace/ironstar (crane patterns)\n- ~/projects/planning-workspace/langchain (federated Python)\n","status":"closed","priority":2,"issue_type":"epic","owner":"cameron.ray.smith@gmail.com","created_at":"2026-01-19T11:54:41.426256-05:00","created_by":"Cameron Smith","updated_at":"2026-02-02T20:45:01.187149-05:00","closed_at":"2026-02-02T20:45:01.187149-05:00","close_reason":"All 3 children complete. Crane + uv2nix + maturin integration fully operational.","dependencies":[{"issue_id":"pnt-btz","depends_on_id":"pnt-dre","type":"blocks","created_at":"2026-01-19T11:55:32.690895-05:00","created_by":"Cameron Smith"},{"issue_id":"pnt-btz","depends_on_id":"pnt-4jg","type":"blocks","created_at":"2026-01-19T11:55:32.812602-05:00","created_by":"Cameron Smith"}]} {"id":"pnt-btz.1","title":"Create pnt-cli package scaffold with Rust crates","description":"Create packages/pnt-cli/ with federated structure:\n\nDirectory structure:\n- packages/pnt-cli/pyproject.toml (maturin build-backend, manifest-path binding)\n- packages/pnt-cli/src/pnt_cli/__init__.py (Python wrapper)\n- packages/pnt-cli/crates/Cargo.toml ([workspace] with member crates)\n- packages/pnt-cli/crates/pnt-cli-core/Cargo.toml (pure Rust library)\n- packages/pnt-cli/crates/pnt-cli-py/Cargo.toml (pyo3 bindings, depends on core)\n\npyproject.toml configuration:\n- [build-system] requires maturin\u003e=1.5\n- [tool.maturin] manifest-path = \"crates/pnt-cli-py/Cargo.toml\"\n- [tool.maturin] module-name = \"pnt_cli._native\"\n\nMinimal proof-of-concept: expose a simple function from Rust to Python.\n\nSee: docs/notes/architecture/crane-uv2nix-integration.md\n","status":"closed","priority":2,"issue_type":"task","owner":"cameron.ray.smith@gmail.com","created_at":"2026-01-19T11:55:17.885691-05:00","created_by":"Cameron Smith","updated_at":"2026-02-02T20:30:16.311977-05:00","closed_at":"2026-02-02T20:30:16.311977-05:00","close_reason":"Implemented in a3e79c3. Scaffold verified: cargo check, cargo test (2/2 pass), cargo clippy clean.","dependencies":[{"issue_id":"pnt-btz.1","depends_on_id":"pnt-btz","type":"parent-child","created_at":"2026-01-19T11:55:17.886287-05:00","created_by":"Cameron Smith"},{"issue_id":"pnt-btz.1","depends_on_id":"pnt-4jg.1","type":"blocks","created_at":"2026-01-19T12:20:18.940008-05:00","created_by":"Cameron Smith"}]} {"id":"pnt-btz.2","title":"Implement crane + uv2nix Nix modules","description":"Create Nix modules implementing the crane + uv2nix integration pattern.\n\nFiles to create:\n- nix/packages/pnt-cli/rust.nix (crane configuration)\n- nix/packages/pnt-cli/default.nix (Python + Rust composition)\n- nix/modules/rust/lib.nix (shared crane utilities, optional)\n\nrust.nix pattern:\n- crane-lib.buildDepsOnly for cargoArtifacts caching\n- commonArgs pattern for derivation hash consistency\n- crane-lib.vendorCargoDeps for maturin's cargo invocation\n- Export cargoArtifacts, cargoVendorDir, clippy, nextest\n\ndefault.nix pattern:\n- Import rust.nix\n- Create overlay injecting cargoVendorDir and CARGO_TARGET_DIR\n- Export overlay and checks for flake composition\n\nUpdate nix/modules/python.nix:\n- Load pnt-cli workspace independently (federated pattern)\n- Compose Rust overlay with uv2nix overlays\n\nSee: docs/notes/architecture/crane-uv2nix-integration.md\n","status":"closed","priority":2,"issue_type":"task","owner":"cameron.ray.smith@gmail.com","created_at":"2026-01-19T11:55:18.885252-05:00","created_by":"Cameron Smith","updated_at":"2026-02-02T20:41:16.274515-05:00","closed_at":"2026-02-02T20:41:16.274515-05:00","close_reason":"Implemented in 8d8a814. Crane checks (clippy, nextest) build. Full maturin wheel builds via nix build .#default. Python import verified: greet('nix') and add(2,3) work end-to-end.","dependencies":[{"issue_id":"pnt-btz.2","depends_on_id":"pnt-btz","type":"parent-child","created_at":"2026-01-19T11:55:18.885818-05:00","created_by":"Cameron Smith"},{"issue_id":"pnt-btz.2","depends_on_id":"pnt-btz.1","type":"blocks","created_at":"2026-01-19T12:20:08.210077-05:00","created_by":"Cameron Smith"}]} From 4e110a6ba2465cf16ed65cf868486ecc79c95e1b Mon Sep 17 00:00:00 2001 From: Cameron Smith Date: Tue, 3 Feb 2026 09:25:13 -0500 Subject: [PATCH 112/134] refactor(bootstrap): adopt vanixiets Makefile with NixOS community nix-installer Replace Determinate Systems installer with pinned NixOS community nix-installer (v2.33.0) matching vanixiets conventions. Adds platform detection, retry logic, trusted-users config, bootstrap-prep-darwin target, and nix-based direnv install. Restores pnt-specific devShell tool list in verify target and secrets/shared.yaml existence guard. --- Makefile | 202 +++++++++++++++++++++++++++++++++++++++++-------------- 1 file changed, 153 insertions(+), 49 deletions(-) diff --git a/Makefile b/Makefile index 9ba6057..053beb2 100644 --- a/Makefile +++ b/Makefile @@ -3,13 +3,13 @@ # tl;dr: # # 1. Run 'make bootstrap' to install nix and direnv -# 2. Run 'make verify' to check the installation -# 3. Run 'make setup-user' to generate sops-nix age key +# 2. Run 'make verify' to check your installation +# 3. Run 'make setup-user' to generate age keys for secrets (first time only) # 4. Run 'nix develop' to enter the development environment -# 5. Use 'just ...' to run tasks +# 5. Use 'just ...' to run configuration tasks # -# This Makefile handles bootstrap only. After this is complete, -# see the justfile for development and configuration tasks. +# This Makefile helps bootstrap a development environment with nix and direnv. +# After bootstrap is complete, see the justfile for managing configurations. .DEFAULT_GOAL := help @@ -48,39 +48,113 @@ help-targets: ## eval "$(make help-targets HELP_TARGETS_PATTERN=bootstrap | sed ##@ bootstrap #------- +.PHONY: bootstrap-prep-darwin +bootstrap-prep-darwin: ## Install darwin prerequisites (Xcode CLI tools + Homebrew) before 'make bootstrap' + @printf "Installing darwin prerequisites...\n\n" + @printf "Step 1: Xcode Command Line Tools\n" + @if xcode-select -p &>/dev/null; then \ + printf " ● Xcode CLI tools already installed\n"; \ + else \ + printf " Installing Xcode CLI tools (this will open a dialog)...\n"; \ + xcode-select --install; \ + printf " ⏳ Wait for installation to complete, then re-run this target\n"; \ + exit 1; \ + fi + @printf "\nStep 2: Homebrew\n" + @if command -v brew &>/dev/null; then \ + printf " ● Homebrew already installed\n"; \ + else \ + printf " Installing Homebrew...\n"; \ + /bin/bash -c "$$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"; \ + fi + @printf "\n● Darwin prerequisites complete!\n" + @printf "Next: Run 'make bootstrap' to install Nix\n" + .PHONY: bootstrap bootstrap: ## Main bootstrap target that runs all necessary setup steps bootstrap: install-nix install-direnv - @printf "\nBootstrap of nix and direnv complete!\n\n" - @printf "Next steps:\n\n" - @printf " 1. Start a new shell session\n" - @printf " 2. Run 'make verify' to check the installation\n" - @printf " 3. Run 'make setup-user' to generate your age key for secrets\n" - @printf " 4. Run 'nix develop' to enter the development environment\n" - @printf " 5. Use 'just ...' to run tasks\n" - @printf "\n" - @printf "To auto-activate the dev environment on directory entry:\n" - @printf " - see https://direnv.net/docs/hook.html to add direnv to your shell\n" - @printf " - start a new shell session\n" - @printf " - 'cd' out and back into the project directory\n" - @printf " - allow direnv by running 'direnv allow'\n" + @printf "\n● Bootstrap of nix and direnv complete!\n\n" + @printf "Next steps:\n" + @echo "1. Start a new shell session (to load nix in PATH)" + @echo "2. Run 'make verify' to check your installation" + @echo "3. Run 'make setup-user' to generate age keys (first time setup)" + @echo "4. Run 'nix develop' to enter the development environment" + @echo "" + @printf "Optional: Auto-activate development environment with direnv\n" + @echo " - See https://direnv.net/docs/hook.html to add direnv to your shell" + @echo " - Start a new shell session" + @echo " - cd out and back into the project directory" + @echo " - Run 'direnv allow' to activate" + @echo "" + @printf "For detailed documentation, see docs/new-user-host.md\n" .PHONY: install-nix -install-nix: ## Install Nix using the Determinate Systems installer +# Download platform-specific binary directly from GitHub Releases. +# This bypasses both the Fastly CDN (HTTP 618 errors) and the shell wrapper +# (which has template placeholders that aren't filled in for raw source files). +# To update version, change NIX_INSTALLER_VERSION below. +# Note: versioning jumped from 0.27.0 to 3.11.3, then back to 2.33.0 when +# NixOS/nix-installer removed the 3.x tags (repo renamed from experimental-nix-installer). +# https://github.com/NixOS/nix-installer/releases +# +# The nix-installer 2.33.0 defaults include settings equivalent to: +# --extra-conf "experimental-features = nix-command flakes" +# --extra-conf "auto-optimise-store = true" +# --extra-conf "always-allow-substitutes = true" +# --extra-conf "max-jobs = auto" +# --extra-conf "extra-nix-path = nixpkgs=flake:nixpkgs" +# --extra-conf "bash-prompt-prefix = (nix:\$name)\\040" +# +# We add trusted-users to allow flake-specified substituters and public keys: +# --extra-conf "trusted-users = root @admin @wheel" +# This enables accepting flake nixConfig without prompts or warnings. +# +# If using the upstream nix installer (https://nixos.org/download/) which lacks +# these defaults, add the --extra-conf flags above to the install command. +NIX_INSTALLER_VERSION := 2.33.0 +install-nix: ## Install Nix using the NixOS community installer @echo "Installing Nix..." @if command -v nix >/dev/null 2>&1; then \ echo "Nix is already installed."; \ else \ - curl --proto '=https' --tlsv1.2 -sSf -L https://install.determinate.systems/nix | sh -s -- install --no-confirm; \ + case "$$(uname -s)-$$(uname -m)" in \ + Linux-x86_64) PLATFORM="x86_64-linux" ;; \ + Linux-aarch64) PLATFORM="aarch64-linux" ;; \ + Darwin-x86_64) PLATFORM="x86_64-darwin" ;; \ + Darwin-arm64) PLATFORM="aarch64-darwin" ;; \ + *) echo "Unsupported platform: $$(uname -s)-$$(uname -m)"; exit 1 ;; \ + esac; \ + INSTALLER_URL="https://github.com/NixOS/nix-installer/releases/download/$(NIX_INSTALLER_VERSION)/nix-installer-$$PLATFORM"; \ + echo "Platform: $$PLATFORM"; \ + echo "Downloading from: $$INSTALLER_URL"; \ + max_attempts=3; \ + attempt=1; \ + while [ $$attempt -le $$max_attempts ]; do \ + echo "Attempt $$attempt of $$max_attempts..."; \ + if curl --proto '=https' --tlsv1.2 -sSf -L --retry 3 --retry-delay 5 \ + "$$INSTALLER_URL" -o /tmp/nix-installer && chmod +x /tmp/nix-installer; then \ + /tmp/nix-installer install --no-confirm \ + --extra-conf "trusted-users = root @admin @wheel" && break; \ + fi; \ + attempt=$$((attempt + 1)); \ + if [ $$attempt -le $$max_attempts ]; then \ + echo "Download or install failed, waiting 10 seconds before retry..."; \ + sleep 10; \ + fi; \ + done; \ + if [ $$attempt -gt $$max_attempts ]; then \ + echo "Failed to install nix after $$max_attempts attempts"; \ + exit 1; \ + fi; \ fi .PHONY: install-direnv -install-direnv: ## Install direnv using the official installation script +install-direnv: ## Install direnv (requires nix to be installed first) @echo "Installing direnv..." @if command -v direnv >/dev/null 2>&1; then \ echo "direnv is already installed."; \ else \ - curl -sfL https://direnv.net/install.sh | bash; \ + . /nix/var/nix/profiles/default/etc/profile.d/nix-daemon.sh && nix profile install nixpkgs#direnv; \ fi @echo "" @echo "See https://direnv.net/docs/hook.html if you would like to add direnv to your shell" @@ -94,69 +168,101 @@ verify: ## Verify nix installation and environment setup @printf "\nVerifying installation...\n\n" @printf "Checking nix installation: " @if command -v nix >/dev/null 2>&1; then \ - printf "found at %s\n" "$$(command -v nix)"; \ + printf "● nix found at %s\n" "$$(command -v nix)"; \ nix --version; \ else \ - printf "not found\n"; \ + printf "⊘ nix not found\n"; \ printf "Run 'make install-nix' to install nix\n"; \ exit 1; \ fi @printf "\nChecking nix flakes support: " @if nix flake --help >/dev/null 2>&1; then \ - printf "enabled\n"; \ + printf "● flakes enabled\n"; \ else \ - printf "not enabled\n"; \ + printf "⊘ flakes not enabled\n"; \ exit 1; \ fi @printf "\nChecking direnv installation: " @if command -v direnv >/dev/null 2>&1; then \ - printf "found\n"; \ + printf "● direnv found\n"; \ else \ - printf "not found (optional but recommended)\n"; \ + printf "⚠️ direnv not found (optional but recommended)\n"; \ printf "Run 'make install-direnv' to install\n"; \ fi @printf "\nChecking flake validity: " @if nix flake metadata . >/dev/null 2>&1; then \ - printf "valid\n"; \ + printf "● flake is valid\n"; \ else \ - printf "flake has errors\n"; \ + printf "⊘ flake has errors\n"; \ exit 1; \ fi @printf "\nChecking required tools in devShell: " @if nix develop --command bash -c 'command -v just && command -v python && command -v uv && command -v pixi && command -v ruff' >/dev/null 2>&1; then \ - printf "just, python, uv, pixi, ruff available\n"; \ + printf "● just, python, uv, pixi, ruff available\n"; \ else \ - printf "some tools missing from devShell\n"; \ + printf "⊘ some tools missing from devShell\n"; \ exit 1; \ fi - @printf "\nAll verification checks passed.\n\n" + @printf "\n/etc/nix/nix.conf:\n" + @printf "==================\n" + @cat /etc/nix/nix.conf 2>/dev/null || printf "(file not found)\n" + @printf "==================\n" + @if [ -f /etc/nix/nix.custom.conf ]; then \ + printf "\n/etc/nix/nix.custom.conf:\n"; \ + printf "==================\n"; \ + cat /etc/nix/nix.custom.conf; \ + printf "==================\n"; \ + fi + @printf "\n● All verification checks passed!\n\n" #------- ##@ setup #------- .PHONY: setup-user -setup-user: ## Generate age key for sops-nix secrets - @if [ -f "$$HOME/.config/sops/age/keys.txt" ]; then \ - printf "Age key already exists at $$HOME/.config/sops/age/keys.txt\n"; \ - printf "Public key: "; \ - grep 'public key:' "$$HOME/.config/sops/age/keys.txt" | awk '{print $$NF}'; \ +setup-user: ## Generate age key for sops-nix secrets (first time user setup) + @printf "\nGenerating age key for secrets management...\n\n" + @. /nix/var/nix/profiles/default/etc/profile.d/nix-daemon.sh && \ + if [ -f ~/.config/sops/age/keys.txt ]; then \ + printf "⚠️ Age key already exists at ~/.config/sops/age/keys.txt\n"; \ + printf "To regenerate, manually delete the file first\n"; \ + printf "\nYour public key is:\n"; \ + nix shell nixpkgs#age -c age-keygen -y ~/.config/sops/age/keys.txt 2>/dev/null || printf "Error reading existing key\n"; \ else \ - mkdir -p "$$HOME/.config/sops/age"; \ - nix develop --command age-keygen -o "$$HOME/.config/sops/age/keys.txt" 2>&1 | tee /dev/stderr; \ - printf "\nAge key generated. Share the public key above with the team.\n"; \ + mkdir -p ~/.config/sops/age; \ + nix shell nixpkgs#age -c age-keygen -o ~/.config/sops/age/keys.txt; \ + chmod 600 ~/.config/sops/age/keys.txt; \ + printf "\n● Age key generated successfully!\n\n"; \ + printf "Your public key is:\n"; \ + nix shell nixpkgs#age -c age-keygen -y ~/.config/sops/age/keys.txt; \ + printf "\n⚠️ IMPORTANT: Back up your private key to Bitwarden!\n"; \ + printf "1. Copy the content of ~/.config/sops/age/keys.txt\n"; \ + printf "2. Store in Bitwarden as secure note: 'age-key-'\n"; \ + printf "3. Send your PUBLIC key (shown above) to the admin\n"; \ + printf "\nSee docs/new-user-host.md for complete setup instructions\n"; \ fi .PHONY: check-secrets -check-secrets: ## Verify you can decrypt shared secrets - @if [ ! -f "$$HOME/.config/sops/age/keys.txt" ]; then \ - printf "No age key found. Run 'make setup-user' first.\n"; \ +check-secrets: ## Check if you can decrypt shared secrets (requires age key and admin setup) + @printf "\nChecking secrets access...\n\n" + @if [ ! -f ~/.config/sops/age/keys.txt ]; then \ + printf "⊘ No age key found. Run 'make setup-user' first\n"; \ exit 1; \ fi @if [ -f secrets/shared.yaml ]; then \ - nix develop --command sops -d secrets/shared.yaml > /dev/null 2>&1 && \ - printf "Secrets decryption verified.\n" || \ - (printf "Cannot decrypt secrets. Your age key may not be registered.\n"; exit 1); \ + if nix develop --command sops -d secrets/shared.yaml >/dev/null 2>&1; then \ + printf "● Successfully decrypted shared secrets!\n"; \ + printf "You have proper access to the secrets system\n"; \ + else \ + printf "⊘ Cannot decrypt shared secrets\n"; \ + printf "Possible reasons:\n"; \ + printf "1. Admin hasn't added your key to .sops.yaml yet\n"; \ + printf "2. Admin hasn't run 'sops updatekeys' after adding you\n"; \ + printf "3. Your age key is incorrect\n"; \ + printf "\nSend your public key to admin:\n"; \ + age-keygen -y ~/.config/sops/age/keys.txt; \ + exit 1; \ + fi; \ else \ printf "No secrets/shared.yaml found. Secrets not yet configured for this project.\n"; \ fi @@ -169,5 +275,3 @@ check-secrets: ## Verify you can decrypt shared secrets clean: ## Clean any temporary files or build artifacts @echo "Cleaning up..." @rm -rf result result-* - @find . -type d -name "__pycache__" -exec rm -rf {} + - @find . -type f -name "*.pyc" -delete From a70a8c0044f213ec7aeb0f3a968f4b140bc1e952 Mon Sep 17 00:00:00 2001 From: Cameron Smith Date: Tue, 3 Feb 2026 09:25:19 -0500 Subject: [PATCH 113/134] refactor(bootstrap): align bootstrap.sh with Makefile nix-installer change Switch from Determinate Systems installer to NixOS community nix-installer (v2.33.0) and from curl-based direnv to nix profile install, maintaining manual sync parity with Makefile. --- scripts/bootstrap.sh | 22 ++++++++++++++++++---- 1 file changed, 18 insertions(+), 4 deletions(-) diff --git a/scripts/bootstrap.sh b/scripts/bootstrap.sh index 83a2c40..8029027 100755 --- a/scripts/bootstrap.sh +++ b/scripts/bootstrap.sh @@ -18,8 +18,22 @@ if command -v nix >/dev/null 2>&1; then echo "Nix is already installed." nix --version else - echo "Installing Nix via Determinate Systems installer..." - curl --proto '=https' --tlsv1.2 -sSf -L https://install.determinate.systems/nix | sh -s -- install + echo "Installing Nix via NixOS community installer..." + NIX_INSTALLER_VERSION="2.33.0" + case "$(uname -s)-$(uname -m)" in + Linux-x86_64) PLATFORM="x86_64-linux" ;; + Linux-aarch64) PLATFORM="aarch64-linux" ;; + Darwin-x86_64) PLATFORM="x86_64-darwin" ;; + Darwin-arm64) PLATFORM="aarch64-darwin" ;; + *) echo "Unsupported platform: $(uname -s)-$(uname -m)"; exit 1 ;; + esac + INSTALLER_URL="https://github.com/NixOS/nix-installer/releases/download/${NIX_INSTALLER_VERSION}/nix-installer-${PLATFORM}" + echo "Platform: ${PLATFORM}" + echo "Downloading from: ${INSTALLER_URL}" + curl --proto '=https' --tlsv1.2 -sSf -L --retry 3 --retry-delay 5 \ + "${INSTALLER_URL}" -o /tmp/nix-installer && chmod +x /tmp/nix-installer + /tmp/nix-installer install --no-confirm \ + --extra-conf "trusted-users = root @admin @wheel" fi echo @@ -28,8 +42,8 @@ echo "Checking direnv installation..." if command -v direnv >/dev/null 2>&1; then echo "direnv is already installed." else - echo "Installing direnv..." - curl -sfL https://direnv.net/install.sh | bash + echo "Installing direnv via nix..." + . /nix/var/nix/profiles/default/etc/profile.d/nix-daemon.sh && nix profile install nixpkgs#direnv fi echo From d74cb85e86fcab6a07ee2054cf30457853082741 Mon Sep 17 00:00:00 2001 From: Cameron Smith Date: Tue, 3 Feb 2026 09:25:23 -0500 Subject: [PATCH 114/134] fix: add missing trailing newline to pnt-functional package.json --- packages/pnt-functional/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/pnt-functional/package.json b/packages/pnt-functional/package.json index c08834d..466ba65 100644 --- a/packages/pnt-functional/package.json +++ b/packages/pnt-functional/package.json @@ -89,4 +89,4 @@ "test-release": "semantic-release --dry-run --no-ci" }, "version": "0.0.0-development" -} \ No newline at end of file +} From fb7244a124e7a10fac19f0d8ade625ae3a9c7d8b Mon Sep 17 00:00:00 2001 From: Cameron Smith Date: Tue, 3 Feb 2026 09:25:24 -0500 Subject: [PATCH 115/134] fix: add missing trailing newline to python-nix-template package.json --- packages/python-nix-template/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/python-nix-template/package.json b/packages/python-nix-template/package.json index 3ab66fb..970da82 100644 --- a/packages/python-nix-template/package.json +++ b/packages/python-nix-template/package.json @@ -89,4 +89,4 @@ "test-release": "semantic-release --dry-run --no-ci" }, "version": "0.0.0-development" -} \ No newline at end of file +} From 35c2e15db72fc03395a4ba5e27820a4ca529dc4a Mon Sep 17 00:00:00 2001 From: Cameron Smith Date: Tue, 3 Feb 2026 09:27:38 -0500 Subject: [PATCH 116/134] fix(bootstrap): use curl-based direnv install in bootstrap.sh The standalone bootstrap script runs before a new shell session, so nix may not be in PATH yet. The curl-based install is nix-independent and more resilient for the pre-clone one-liner use case. --- scripts/bootstrap.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/scripts/bootstrap.sh b/scripts/bootstrap.sh index 8029027..f34854c 100755 --- a/scripts/bootstrap.sh +++ b/scripts/bootstrap.sh @@ -42,8 +42,8 @@ echo "Checking direnv installation..." if command -v direnv >/dev/null 2>&1; then echo "direnv is already installed." else - echo "Installing direnv via nix..." - . /nix/var/nix/profiles/default/etc/profile.d/nix-daemon.sh && nix profile install nixpkgs#direnv + echo "Installing direnv..." + curl -sfL https://direnv.net/install.sh | bash fi echo From cf9a286707288f5b31cf0ba1f8813cb00bcfd92c Mon Sep 17 00:00:00 2001 From: Cameron Smith Date: Tue, 3 Feb 2026 10:10:28 -0500 Subject: [PATCH 117/134] feat(beads): add nix architecture modernization epic with migration and template tasks --- .beads/issues.jsonl | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.beads/issues.jsonl b/.beads/issues.jsonl index f8df89b..dacbfdd 100644 --- a/.beads/issues.jsonl +++ b/.beads/issues.jsonl @@ -13,6 +13,9 @@ {"id":"pnt-dre.3","title":"Reorganize scripts/ directory structure","description":"Move scripts into subdirectories: scripts/ci/, scripts/docs/, scripts/sops/. IMPORTANT: scripts/bootstrap.sh must remain at stable path for curl one-liner URL. Update justfile and CI references.","status":"closed","priority":2,"issue_type":"task","owner":"cameron.ray.smith@gmail.com","created_at":"2026-01-19T11:54:55.839371-05:00","created_by":"Cameron Smith","updated_at":"2026-02-02T15:45:23.076616-05:00","closed_at":"2026-02-02T15:45:23.076616-05:00","close_reason":"Created scripts/bootstrap.sh (stable URL for curl one-liner) and scripts/ci/maximize-build-space.sh (canonical version of duplicated CI logic). Workflow inline references deferred to pnt-dre.4 CI redesign due to pre-checkout step ordering. scripts/sops/ and scripts/docs/ skipped — no duplication issues warranting extraction.","dependencies":[{"issue_id":"pnt-dre.3","depends_on_id":"pnt-dre","type":"parent-child","created_at":"2026-01-19T11:54:55.839951-05:00","created_by":"Cameron Smith"}]} {"id":"pnt-dre.4","title":"Implement cached-ci-job composite action pattern","description":"Add .github/actions/cached-ci-job composite action following typescript-nix-template pattern. Content-addressed caching with hash-sources and force-run support. Update CI to use category-based matrix builds.\n\nPost-federation CI adaptation: the migration from uv workspace to per-package independent locks (pnt-4jg.1) means CI must now discover and iterate packages under packages/. The matrix strategy needs a package axis in addition to the category axis, producing either a {package} x {category} matrix or per-package reusable workflow dispatches. Review how ci.yaml currently enumerates packages and ensure the composite action pattern supports per-package resolution of lock files, dependency caches, and build artifacts.\n\nAcceptance criteria:\n- .github/actions/cached-ci-job composite action implemented\n- Content-addressed caching with hash-sources and force-run support\n- CI matrix discovers packages/ dynamically (not hardcoded)\n- Matrix crosses package x category dimensions\n- Per-package uv.lock files used for cache keys (not root lock)\n- Category-based builds follow typescript-nix-template pattern","status":"closed","priority":2,"issue_type":"task","owner":"cameron.ray.smith@gmail.com","created_at":"2026-01-19T11:54:56.79376-05:00","created_by":"Cameron Smith","updated_at":"2026-02-02T15:55:30.748155-05:00","closed_at":"2026-02-02T15:55:30.748155-05:00","close_reason":"Implemented cached-ci-job composite action (ported from typescript-nix-template), per-package CI justfile recipes (ci-sync, ci-lint, ci-test, ci-typecheck, ci-check, list-packages-json), rewrote python-test.yaml to use nix develop -c just \u003crecipe\u003e, added dynamic package discovery and force_run to ci.yaml. All CI steps expressible as nix develop -c just \u003crecipe\u003e.","dependencies":[{"issue_id":"pnt-dre.4","depends_on_id":"pnt-dre","type":"parent-child","created_at":"2026-01-19T11:54:56.794334-05:00","created_by":"Cameron Smith"}],"comments":[{"id":2,"issue_id":"pnt-dre.4","author":"Cameron Smith","text":"Minimal CI path fixes applied in d0cab2a as part of pnt-4jg.1 fixups: cache-dependency-glob updated to packages/*/uv.lock, uv sync/lint/test moved into per-package working-directory, ci.yaml path filters updated.\n\nRemaining for pnt-dre.4: replace setup-python/setup-uv actions with nix develop -c just \u003crecipe\u003e pattern, add justfile recipes for per-package sync/test/lint/typecheck, implement cached-ci-job composite action, dynamic package discovery.","created_at":"2026-02-02T20:17:02Z"}]} {"id":"pnt-dre.5","title":"Add omnix template integration","description":"Configure om.templates in flake with parameter definitions. Add template-verify justfile recipe. Create .github/workflows/template.yaml for CI validation.","status":"closed","priority":2,"issue_type":"task","owner":"cameron.ray.smith@gmail.com","created_at":"2026-01-19T11:54:57.668262-05:00","created_by":"Cameron Smith","updated_at":"2026-02-02T15:56:15.624906-05:00","closed_at":"2026-02-02T15:56:15.624906-05:00","close_reason":"om.templates, template-verify recipe, and template.yaml workflow already existed. Fixed stale path-ignore filters for per-package lock pattern.","dependencies":[{"issue_id":"pnt-dre.5","depends_on_id":"pnt-dre","type":"parent-child","created_at":"2026-01-19T11:54:57.66888-05:00","created_by":"Cameron Smith"}]} +{"id":"pnt-edl","title":"Modernize nix module architecture and template validation","description":"Migrate python-nix-template to dendritic flake-parts architecture (import-tree) matching vanixiets, ironstar, and typescript-nix-template conventions. Fix template.yaml workflow to properly validate instantiated templates including PyO3/maturin extensions.\n\nMotivation: Current nix/modules/ uses hand-rolled readDir discovery instead of import-tree. Template CI test (test-omnix-template) fails because it runs nix develop -c pytest which cannot load PyO3 _native extension (maturin packages are excluded from editableOverlay by design). Both issues block PR #44 from being fully validated.\n\nReference implementations:\n- vanixiets: modules/ with import-tree, 200+ auto-discovered modules\n- ironstar: modules/ with import-tree, crane for Rust builds\n- typescript-nix-template: modules/ with import-tree, two-variant template testing\n\nSequencing: Migration first (structural), then template workflow fix (validation). Template test depends on knowing the final module layout.","status":"open","priority":2,"issue_type":"epic","owner":"cameron.ray.smith@gmail.com","created_at":"2026-02-03T10:09:57.390595-05:00","created_by":"Cameron Smith","updated_at":"2026-02-03T10:09:57.390595-05:00"} +{"id":"pnt-j6f","title":"Migrate to dendritic flake-parts with import-tree","description":"Restructure nix module architecture to match reference implementations (vanixiets, ironstar, typescript-nix-template).\n\nChanges required:\n- Add import-tree as flake input (github:vic/import-tree or equivalent)\n- Move nix/modules/*.nix to modules/*.nix (top-level)\n- Replace readDir-based discovery in flake.nix with: flake-parts.lib.mkFlake { inherit inputs; } (inputs.import-tree ./modules)\n- Add systems.nix module (extract system list from flake.nix)\n- Add flake-parts.nix module (external module imports like nix-unit)\n- Keep nix/packages/pnt-cli/ and nix/lib/ as non-module utilities (imported explicitly by python.nix)\n- Update all relative paths in modules that reference nix/packages/ or nix/lib/ (now one level up)\n- containers.nix is 355 lines — evaluate splitting into containers/dev.nix and containers/production.nix\n- Update template.nix conditional paths to reflect new module locations\n- Verify nix flake check passes after restructure\n- Update .github/workflows/ path filters if they reference nix/modules/\n\nKey architectural decisions:\n- Modules communicate through _module.args (python.nix exports) and config namespace (pre-commit.devShell)\n- import-tree auto-discovers all .nix files in modules/ tree\n- No manual imports list in flake.nix — adding a file to modules/ auto-includes it\n- nix/packages/ stays as explicit utility imports (not auto-discovered modules)","status":"open","priority":2,"issue_type":"task","owner":"cameron.ray.smith@gmail.com","created_at":"2026-02-03T10:10:03.187287-05:00","created_by":"Cameron Smith","updated_at":"2026-02-03T10:10:03.187287-05:00","dependencies":[{"issue_id":"pnt-j6f","depends_on_id":"pnt-edl","type":"child-of","created_at":"2026-02-03T10:10:17.67297-05:00","created_by":"Cameron Smith"}]} +{"id":"pnt-m1w","title":"Fix template.yaml workflow for proper PyO3 and multi-variant validation","description":"Align template.yaml with typescript-nix-template patterns and fix the test-omnix-template job that currently fails with ModuleNotFoundError for pnt_cli._native and pnt_functional.\n\nRoot cause: The current test runs nix develop -c pytest on instantiated template, but:\n- pnt-cli PyO3 _native extension is excluded from editableOverlay (maturin incompatible)\n- pnt-functional is not on PYTHONPATH in nix develop without editable overlay\n- This fails both in CI and locally — it is a fundamental workflow gap\n\nFix approach (align with typescript-nix-template):\n- Replace nix develop -c pytest with nix flake check --accept-flake-config\n- nix flake check exercises all Nix builds including maturin wheel, validating PyO3 integration\n- Add set-variables job (debug flags, skip-ci, checkout details)\n- Test TWO variants matching monorepo-package boolean parameter:\n 1. Full monorepo (monorepo-package=true): includes pnt-functional + pnt-cli\n 2. Single package (monorepo-package=false): main package only\n- Fix cachix reference: instantiated template tries pnt-mono.cachix.org which 401s (expected for fresh project, but should be parameterized or removed)\n- Consider adding lightweight smoke test after flake check: nix develop -c python -c 'import pnt_mono'\n- Add cached-ci-job composite action if available in .github/actions/\n\nReference: typescript-nix-template .github/workflows/template.yaml tests full and minimal variants with git init, bun install, nix flake check sequence.","status":"open","priority":2,"issue_type":"task","owner":"cameron.ray.smith@gmail.com","created_at":"2026-02-03T10:10:08.916223-05:00","created_by":"Cameron Smith","updated_at":"2026-02-03T10:10:08.916223-05:00","dependencies":[{"issue_id":"pnt-m1w","depends_on_id":"pnt-edl","type":"child-of","created_at":"2026-02-03T10:10:17.838035-05:00","created_by":"Cameron Smith"},{"issue_id":"pnt-m1w","depends_on_id":"pnt-j6f","type":"blocked-by","created_at":"2026-02-03T10:10:18.005313-05:00","created_by":"Cameron Smith"}]} {"id":"pnt-m3t","title":"Adopt setup-nix composite action with nothing-but-nix pattern","description":"Port the vanixiets setup-nix composite action to python-nix-template, replacing inline Nix installation across all workflows.\n\nCurrent state:\n- ci.yaml, python-test.yaml, build-nix-images.yaml each inline DeterminateSystems/nix-installer-action\n- build-nix-images.yaml uses ad-hoc maximize-build-space shell script\n- scripts/ci/maximize-build-space.sh exists but is not wired into workflows\n\nTarget state (matching vanixiets):\n- .github/actions/setup-nix/action.yml composite action\n- Uses wimpysworld/nothing-but-nix for space reclamation (replaces maximize-build-space.sh)\n- Uses cachix/install-nix-action with pinned Nix version\n- Configures build-dir = /nix/build (nothing-but-nix workaround)\n- Integrates magic-nix-cache and cachix setup\n- Hatchet protocol support for configurable space levels\n- All workflows delegate Nix setup to this single action\n\nAcceptance criteria:\n- .github/actions/setup-nix/action.yml implemented (port from vanixiets)\n- ci.yaml nixci job uses setup-nix action\n- python-test.yaml uses setup-nix action\n- build-nix-images.yaml uses setup-nix action (replaces inline maximize-build-space)\n- .github/actions/build-nix-image/ updated (its Nix install steps replaced by setup-nix)\n- scripts/ci/maximize-build-space.sh removed (superseded by nothing-but-nix)\n- setup-python-uv action evaluated for removal (if all Python CI runs via nix develop)\n\nReference: ~/projects/nix-workspace/vanixiets/.github/actions/setup-nix/action.yml","status":"closed","priority":2,"issue_type":"task","owner":"cameron.ray.smith@gmail.com","created_at":"2026-02-02T20:24:06.14337-05:00","created_by":"Cameron Smith","updated_at":"2026-02-02T21:16:20.627824-05:00","closed_at":"2026-02-02T21:16:20.627824-05:00","close_reason":"Implemented in 0b1e4fa, setup-nix action ported from vanixiets"} {"id":"pnt-mgq","title":"Migrate dev containers to nix2container via upgraded nixpod","description":"Update the dev container builds (containerImage, devcontainerImage) to use nix2container once nixpod itself has completed its nix2container migration.\n\nCurrent state:\n- nix/modules/containers.nix imports buildMultiUserNixImage from nixpod\n- nixpod uses dockerTools.buildLayeredImageWithNixDb internally\n- flocken handles multi-arch manifest creation for dev containers\n- Dev containers include multi-user Nix daemon, home-manager activation, s6-overlay\n\nBlocked on: nixpod completing its nix2container migration (refactor-container-builds branch has research docs with full API mapping and implementation plan)\n\nTarget state:\n- nixpod exports nix2container-based builders (buildMultiUserNixImage rewritten internally)\n- python-nix-template's dev containers consume upgraded nixpod\n- Dev container manifests use crane-based tooling (from pnt-5vr production container work)\n- s6-overlay, home-manager activation, multi-user Nix preserved in container content\n\nAcceptance criteria:\n- Dev containers build using nixpod's nix2container-based API\n- flocken fully removed from flake.nix (production containers handled by pnt-5vr)\n- No regression in dev container functionality (Jupyter, code-server, etc.)\n- Multi-arch publishing works via nix2container transport\n\nReference: ~/projects/nix-workspace/nixpod-home/docs/notes/development/container-build-refactoring.md\nReference: ~/projects/nix-workspace/nixpod-home/containers/nix.nix","status":"open","priority":2,"issue_type":"task","owner":"cameron.ray.smith@gmail.com","created_at":"2026-02-02T21:47:38.830624-05:00","created_by":"Cameron Smith","updated_at":"2026-02-02T21:47:38.830624-05:00"} {"id":"pnt-wbq","title":"Add pkgsCross support for Python/maturin production containers","description":"Enable cross-compilation of production containers via pkgsCross, eliminating the need for per-architecture runners or QEMU emulation.\n\nCurrent state: production containers (nix2container) build natively per-system. On a single x86_64-linux CI runner, only x86_64 images are produced.\n\nTarget state: build both x86_64 and aarch64 production containers from a single x86_64-linux runner using pkgsCross, matching the vanixiets pattern.\n\nChallenge: the Python + maturin + Cargo build pipeline must work under cross-compilation. This requires:\n- Rust cross-compilation toolchain via pkgsCross (generally well-supported)\n- Python headers for target platform\n- maturin building wheels for the target platform\n- uv2nix virtual environment resolution for the target system\n\nThe nix2container infrastructure and containerMatrix are already in place (from pnt-5vr). This issue adds the pkgsCross target definitions and validates the cross-compilation pipeline.\n\nReference: vanixiets uses pkgsCross.gnu64 and pkgsCross.aarch64-multiplatform for simple nixpkgs packages. The Python/Rust case is more complex but the container infrastructure pattern is identical.","status":"open","priority":3,"issue_type":"task","owner":"cameron.ray.smith@gmail.com","created_at":"2026-02-02T23:00:13.965286-05:00","created_by":"Cameron Smith","updated_at":"2026-02-02T23:00:27.262969-05:00","dependencies":[{"issue_id":"pnt-wbq","depends_on_id":"pnt-5vr","type":"discovered-from","created_at":"2026-02-02T23:00:28.588784-05:00","created_by":"Cameron Smith"}]} From 8296d94f11656eced95ac2c8e5e277de6fc397ca Mon Sep 17 00:00:00 2001 From: Cameron Smith Date: Tue, 3 Feb 2026 10:20:32 -0500 Subject: [PATCH 118/134] feat(beads): add PyO3 test strategy investigation task to nix modernization epic --- .beads/issues.jsonl | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.beads/issues.jsonl b/.beads/issues.jsonl index dacbfdd..3d3e7c7 100644 --- a/.beads/issues.jsonl +++ b/.beads/issues.jsonl @@ -1,3 +1,4 @@ +{"id":"pnt-3qp","title":"Investigate and validate optimal test strategy for PyO3 + Python hybrid packages","description":"The current devShell excludes pnt-cli from uv2nix editableOverlay because maturin packages are incompatible with pyprojectFixupEditableHook (expects EDITABLE_ROOT which maturin does not set). This means nix develop -c pytest cannot import pnt_cli._native, failing both locally and in CI.\n\nThis task requires investigation and experimentation to determine the optimal testing strategy for packages containing both Python and Rust code via PyO3 extension modules, using maturin as the build backend and crane for Rust build artifact caching.\n\nQuestions to answer through experimentation:\n\n1. Can we install pnt-cli non-editable in the devShell virtualenv (pre-built wheel via Nix) so pytest can import _native? What are the trade-offs for developer iteration speed?\n\n2. What is the correct split between cargo nextest (pure Rust unit tests in crates/) and pytest (Python integration tests that exercise the PyO3 bindings)? Should these be separate CI jobs or a unified test recipe?\n\n3. Can maturin develop be integrated into the devShell shellHook or a just recipe to build the extension in-place for iterative development? How does this interact with the uv2nix virtualenv?\n\n4. How do the reference implementations handle this?\n - ~/projects/nix-workspace/uv2nix — upstream patterns for maturin/PyO3 packages\n - ~/projects/nix-workspace/pyproject.nix — Python project tooling for Nix\n - ~/projects/nix-workspace/nix-cargo-crane — crane patterns for Rust builds\n - ~/projects/rust-workspace/ironstar — crane devShell integration (Rust-only but relevant caching patterns)\n\n5. For the template test (omnix init + validate): should instantiated templates use nix flake check (builds everything through Nix including maturin wheel), nix develop -c uv run pytest (uv builds the wheel), or a combination?\n\n6. Does the nix build path (nix flake check / nix build) already exercise both Rust compilation (via crane cargoArtifacts) and Python tests (via pytest in check phase)? If so, it may be sufficient for CI validation without needing devShell-based testing.\n\nAcceptance criteria:\n- Document the chosen test strategy with rationale\n- Validate that both cargo nextest (Rust unit tests) and pytest (Python integration tests) pass\n- Validate the strategy works both locally (nix develop) and in CI (template instantiation test)\n- Update devshell.nix, justfile, and template.yaml as needed to implement the chosen strategy\n- Ensure crane artifact caching is preserved (no unnecessary Rust rebuilds)","status":"open","priority":2,"issue_type":"task","owner":"cameron.ray.smith@gmail.com","created_at":"2026-02-03T10:20:11.038346-05:00","created_by":"Cameron Smith","updated_at":"2026-02-03T10:20:11.038346-05:00","dependencies":[{"issue_id":"pnt-3qp","depends_on_id":"pnt-edl","type":"child-of","created_at":"2026-02-03T10:20:20.918483-05:00","created_by":"Cameron Smith"},{"issue_id":"pnt-3qp","depends_on_id":"pnt-j6f","type":"blocked-by","created_at":"2026-02-03T10:20:21.103095-05:00","created_by":"Cameron Smith"}]} {"id":"pnt-4jg","title":"Dependency model migration","description":"Migrate from single-lock uv workspace to independent-lock multi-package pattern following langchain/langgraph approach. Include pixi feature-based composition for conda ecosystem parity.","status":"closed","priority":2,"issue_type":"epic","owner":"cameron.ray.smith@gmail.com","created_at":"2026-01-19T11:54:40.744055-05:00","created_by":"Cameron Smith","updated_at":"2026-02-02T15:37:43.167289-05:00","closed_at":"2026-02-02T15:37:43.167289-05:00","close_reason":"All children closed: pnt-4jg.1 (uv workspace removal), pnt-4jg.2 (pixi feature composition), pnt-4jg.3 (distribution channel docs). Dependency model migration complete."} {"id":"pnt-4jg.1","title":"Remove uv workspace, adopt path dependencies","description":"Remove [tool.uv.workspace] from root pyproject.toml. Each package gets own pyproject.toml with [tool.uv.sources] for sibling references using path sources with editable=true. Follow langchain pattern.","status":"closed","priority":2,"issue_type":"task","owner":"cameron.ray.smith@gmail.com","created_at":"2026-01-19T11:55:07.344057-05:00","created_by":"Cameron Smith","updated_at":"2026-02-02T14:40:02.175394-05:00","closed_at":"2026-02-02T14:40:02.175394-05:00","close_reason":"Implemented in a8a823f. Removed root uv workspace, generated per-package locks, rewrote nix modules to Pattern 3 per-package loading.","dependencies":[{"issue_id":"pnt-4jg.1","depends_on_id":"pnt-4jg","type":"parent-child","created_at":"2026-01-19T11:55:07.344659-05:00","created_by":"Cameron Smith"}],"comments":[{"id":1,"issue_id":"pnt-4jg.1","author":"Cameron Smith","text":"Post-close fixup commits (774ec26):\n- fix(ci): update lock file references for per-package federation (d0cab2a)\n- fixup! merge federated workspace deps: replace // with zipAttrsWith for extras-safe dep merging (7b3e7ae)\n- fixup! load packages independently: document version-conflict invariant in python.nix and architecture doc (36eb8a7, 774ec26)\n\nReview findings addressed: stale CI cache-dependency-glob paths, fragile shallow-merge dep specs, undocumented overlay composition invariant. Full CI redesign (nix develop + justfile symmetry) deferred to pnt-dre.4.","created_at":"2026-02-02T20:17:00Z"}]} {"id":"pnt-4jg.2","title":"Configure pixi feature-based composition","description":"Implement pixi feature/environment pattern: [feature.X.dependencies] + [environments] composition. Single pixi.lock covering all environments. Per-feature task definitions. Target-specific dependencies for platform support.","status":"closed","priority":2,"issue_type":"task","owner":"cameron.ray.smith@gmail.com","created_at":"2026-01-19T11:55:08.085592-05:00","created_by":"Cameron Smith","updated_at":"2026-02-02T15:36:49.459815-05:00","closed_at":"2026-02-02T15:36:49.459815-05:00","close_reason":"Verified pixi feature composition via nix develop -c just \u003crecipe\u003e. Fixed: added missing feature tasks to python-nix-template, delegated justfile conda recipes to pixi task names for correct working directory, moved deprecated build channels to backend.channels.","dependencies":[{"issue_id":"pnt-4jg.2","depends_on_id":"pnt-4jg","type":"parent-child","created_at":"2026-01-19T11:55:08.086155-05:00","created_by":"Cameron Smith"}]} @@ -15,7 +16,7 @@ {"id":"pnt-dre.5","title":"Add omnix template integration","description":"Configure om.templates in flake with parameter definitions. Add template-verify justfile recipe. Create .github/workflows/template.yaml for CI validation.","status":"closed","priority":2,"issue_type":"task","owner":"cameron.ray.smith@gmail.com","created_at":"2026-01-19T11:54:57.668262-05:00","created_by":"Cameron Smith","updated_at":"2026-02-02T15:56:15.624906-05:00","closed_at":"2026-02-02T15:56:15.624906-05:00","close_reason":"om.templates, template-verify recipe, and template.yaml workflow already existed. Fixed stale path-ignore filters for per-package lock pattern.","dependencies":[{"issue_id":"pnt-dre.5","depends_on_id":"pnt-dre","type":"parent-child","created_at":"2026-01-19T11:54:57.66888-05:00","created_by":"Cameron Smith"}]} {"id":"pnt-edl","title":"Modernize nix module architecture and template validation","description":"Migrate python-nix-template to dendritic flake-parts architecture (import-tree) matching vanixiets, ironstar, and typescript-nix-template conventions. Fix template.yaml workflow to properly validate instantiated templates including PyO3/maturin extensions.\n\nMotivation: Current nix/modules/ uses hand-rolled readDir discovery instead of import-tree. Template CI test (test-omnix-template) fails because it runs nix develop -c pytest which cannot load PyO3 _native extension (maturin packages are excluded from editableOverlay by design). Both issues block PR #44 from being fully validated.\n\nReference implementations:\n- vanixiets: modules/ with import-tree, 200+ auto-discovered modules\n- ironstar: modules/ with import-tree, crane for Rust builds\n- typescript-nix-template: modules/ with import-tree, two-variant template testing\n\nSequencing: Migration first (structural), then template workflow fix (validation). Template test depends on knowing the final module layout.","status":"open","priority":2,"issue_type":"epic","owner":"cameron.ray.smith@gmail.com","created_at":"2026-02-03T10:09:57.390595-05:00","created_by":"Cameron Smith","updated_at":"2026-02-03T10:09:57.390595-05:00"} {"id":"pnt-j6f","title":"Migrate to dendritic flake-parts with import-tree","description":"Restructure nix module architecture to match reference implementations (vanixiets, ironstar, typescript-nix-template).\n\nChanges required:\n- Add import-tree as flake input (github:vic/import-tree or equivalent)\n- Move nix/modules/*.nix to modules/*.nix (top-level)\n- Replace readDir-based discovery in flake.nix with: flake-parts.lib.mkFlake { inherit inputs; } (inputs.import-tree ./modules)\n- Add systems.nix module (extract system list from flake.nix)\n- Add flake-parts.nix module (external module imports like nix-unit)\n- Keep nix/packages/pnt-cli/ and nix/lib/ as non-module utilities (imported explicitly by python.nix)\n- Update all relative paths in modules that reference nix/packages/ or nix/lib/ (now one level up)\n- containers.nix is 355 lines — evaluate splitting into containers/dev.nix and containers/production.nix\n- Update template.nix conditional paths to reflect new module locations\n- Verify nix flake check passes after restructure\n- Update .github/workflows/ path filters if they reference nix/modules/\n\nKey architectural decisions:\n- Modules communicate through _module.args (python.nix exports) and config namespace (pre-commit.devShell)\n- import-tree auto-discovers all .nix files in modules/ tree\n- No manual imports list in flake.nix — adding a file to modules/ auto-includes it\n- nix/packages/ stays as explicit utility imports (not auto-discovered modules)","status":"open","priority":2,"issue_type":"task","owner":"cameron.ray.smith@gmail.com","created_at":"2026-02-03T10:10:03.187287-05:00","created_by":"Cameron Smith","updated_at":"2026-02-03T10:10:03.187287-05:00","dependencies":[{"issue_id":"pnt-j6f","depends_on_id":"pnt-edl","type":"child-of","created_at":"2026-02-03T10:10:17.67297-05:00","created_by":"Cameron Smith"}]} -{"id":"pnt-m1w","title":"Fix template.yaml workflow for proper PyO3 and multi-variant validation","description":"Align template.yaml with typescript-nix-template patterns and fix the test-omnix-template job that currently fails with ModuleNotFoundError for pnt_cli._native and pnt_functional.\n\nRoot cause: The current test runs nix develop -c pytest on instantiated template, but:\n- pnt-cli PyO3 _native extension is excluded from editableOverlay (maturin incompatible)\n- pnt-functional is not on PYTHONPATH in nix develop without editable overlay\n- This fails both in CI and locally — it is a fundamental workflow gap\n\nFix approach (align with typescript-nix-template):\n- Replace nix develop -c pytest with nix flake check --accept-flake-config\n- nix flake check exercises all Nix builds including maturin wheel, validating PyO3 integration\n- Add set-variables job (debug flags, skip-ci, checkout details)\n- Test TWO variants matching monorepo-package boolean parameter:\n 1. Full monorepo (monorepo-package=true): includes pnt-functional + pnt-cli\n 2. Single package (monorepo-package=false): main package only\n- Fix cachix reference: instantiated template tries pnt-mono.cachix.org which 401s (expected for fresh project, but should be parameterized or removed)\n- Consider adding lightweight smoke test after flake check: nix develop -c python -c 'import pnt_mono'\n- Add cached-ci-job composite action if available in .github/actions/\n\nReference: typescript-nix-template .github/workflows/template.yaml tests full and minimal variants with git init, bun install, nix flake check sequence.","status":"open","priority":2,"issue_type":"task","owner":"cameron.ray.smith@gmail.com","created_at":"2026-02-03T10:10:08.916223-05:00","created_by":"Cameron Smith","updated_at":"2026-02-03T10:10:08.916223-05:00","dependencies":[{"issue_id":"pnt-m1w","depends_on_id":"pnt-edl","type":"child-of","created_at":"2026-02-03T10:10:17.838035-05:00","created_by":"Cameron Smith"},{"issue_id":"pnt-m1w","depends_on_id":"pnt-j6f","type":"blocked-by","created_at":"2026-02-03T10:10:18.005313-05:00","created_by":"Cameron Smith"}]} +{"id":"pnt-m1w","title":"Fix template.yaml workflow for proper PyO3 and multi-variant validation","description":"Align template.yaml with typescript-nix-template patterns and fix the test-omnix-template job that currently fails with ModuleNotFoundError for pnt_cli._native and pnt_functional.\n\nRoot cause: The current test runs nix develop -c pytest on instantiated template, but:\n- pnt-cli PyO3 _native extension is excluded from editableOverlay (maturin incompatible)\n- pnt-functional is not on PYTHONPATH in nix develop without editable overlay\n- This fails both in CI and locally — it is a fundamental workflow gap\n\nFix approach (align with typescript-nix-template):\n- Replace nix develop -c pytest with nix flake check --accept-flake-config\n- nix flake check exercises all Nix builds including maturin wheel, validating PyO3 integration\n- Add set-variables job (debug flags, skip-ci, checkout details)\n- Test TWO variants matching monorepo-package boolean parameter:\n 1. Full monorepo (monorepo-package=true): includes pnt-functional + pnt-cli\n 2. Single package (monorepo-package=false): main package only\n- Fix cachix reference: instantiated template tries pnt-mono.cachix.org which 401s (expected for fresh project, but should be parameterized or removed)\n- Consider adding lightweight smoke test after flake check: nix develop -c python -c 'import pnt_mono'\n- Add cached-ci-job composite action if available in .github/actions/\n\nReference: typescript-nix-template .github/workflows/template.yaml tests full and minimal variants with git init, bun install, nix flake check sequence.","status":"open","priority":2,"issue_type":"task","owner":"cameron.ray.smith@gmail.com","created_at":"2026-02-03T10:10:08.916223-05:00","created_by":"Cameron Smith","updated_at":"2026-02-03T10:10:08.916223-05:00","dependencies":[{"issue_id":"pnt-m1w","depends_on_id":"pnt-edl","type":"child-of","created_at":"2026-02-03T10:10:17.838035-05:00","created_by":"Cameron Smith"},{"issue_id":"pnt-m1w","depends_on_id":"pnt-j6f","type":"blocked-by","created_at":"2026-02-03T10:10:18.005313-05:00","created_by":"Cameron Smith"},{"issue_id":"pnt-m1w","depends_on_id":"pnt-3qp","type":"blocked-by","created_at":"2026-02-03T10:20:21.254918-05:00","created_by":"Cameron Smith"}]} {"id":"pnt-m3t","title":"Adopt setup-nix composite action with nothing-but-nix pattern","description":"Port the vanixiets setup-nix composite action to python-nix-template, replacing inline Nix installation across all workflows.\n\nCurrent state:\n- ci.yaml, python-test.yaml, build-nix-images.yaml each inline DeterminateSystems/nix-installer-action\n- build-nix-images.yaml uses ad-hoc maximize-build-space shell script\n- scripts/ci/maximize-build-space.sh exists but is not wired into workflows\n\nTarget state (matching vanixiets):\n- .github/actions/setup-nix/action.yml composite action\n- Uses wimpysworld/nothing-but-nix for space reclamation (replaces maximize-build-space.sh)\n- Uses cachix/install-nix-action with pinned Nix version\n- Configures build-dir = /nix/build (nothing-but-nix workaround)\n- Integrates magic-nix-cache and cachix setup\n- Hatchet protocol support for configurable space levels\n- All workflows delegate Nix setup to this single action\n\nAcceptance criteria:\n- .github/actions/setup-nix/action.yml implemented (port from vanixiets)\n- ci.yaml nixci job uses setup-nix action\n- python-test.yaml uses setup-nix action\n- build-nix-images.yaml uses setup-nix action (replaces inline maximize-build-space)\n- .github/actions/build-nix-image/ updated (its Nix install steps replaced by setup-nix)\n- scripts/ci/maximize-build-space.sh removed (superseded by nothing-but-nix)\n- setup-python-uv action evaluated for removal (if all Python CI runs via nix develop)\n\nReference: ~/projects/nix-workspace/vanixiets/.github/actions/setup-nix/action.yml","status":"closed","priority":2,"issue_type":"task","owner":"cameron.ray.smith@gmail.com","created_at":"2026-02-02T20:24:06.14337-05:00","created_by":"Cameron Smith","updated_at":"2026-02-02T21:16:20.627824-05:00","closed_at":"2026-02-02T21:16:20.627824-05:00","close_reason":"Implemented in 0b1e4fa, setup-nix action ported from vanixiets"} {"id":"pnt-mgq","title":"Migrate dev containers to nix2container via upgraded nixpod","description":"Update the dev container builds (containerImage, devcontainerImage) to use nix2container once nixpod itself has completed its nix2container migration.\n\nCurrent state:\n- nix/modules/containers.nix imports buildMultiUserNixImage from nixpod\n- nixpod uses dockerTools.buildLayeredImageWithNixDb internally\n- flocken handles multi-arch manifest creation for dev containers\n- Dev containers include multi-user Nix daemon, home-manager activation, s6-overlay\n\nBlocked on: nixpod completing its nix2container migration (refactor-container-builds branch has research docs with full API mapping and implementation plan)\n\nTarget state:\n- nixpod exports nix2container-based builders (buildMultiUserNixImage rewritten internally)\n- python-nix-template's dev containers consume upgraded nixpod\n- Dev container manifests use crane-based tooling (from pnt-5vr production container work)\n- s6-overlay, home-manager activation, multi-user Nix preserved in container content\n\nAcceptance criteria:\n- Dev containers build using nixpod's nix2container-based API\n- flocken fully removed from flake.nix (production containers handled by pnt-5vr)\n- No regression in dev container functionality (Jupyter, code-server, etc.)\n- Multi-arch publishing works via nix2container transport\n\nReference: ~/projects/nix-workspace/nixpod-home/docs/notes/development/container-build-refactoring.md\nReference: ~/projects/nix-workspace/nixpod-home/containers/nix.nix","status":"open","priority":2,"issue_type":"task","owner":"cameron.ray.smith@gmail.com","created_at":"2026-02-02T21:47:38.830624-05:00","created_by":"Cameron Smith","updated_at":"2026-02-02T21:47:38.830624-05:00"} {"id":"pnt-wbq","title":"Add pkgsCross support for Python/maturin production containers","description":"Enable cross-compilation of production containers via pkgsCross, eliminating the need for per-architecture runners or QEMU emulation.\n\nCurrent state: production containers (nix2container) build natively per-system. On a single x86_64-linux CI runner, only x86_64 images are produced.\n\nTarget state: build both x86_64 and aarch64 production containers from a single x86_64-linux runner using pkgsCross, matching the vanixiets pattern.\n\nChallenge: the Python + maturin + Cargo build pipeline must work under cross-compilation. This requires:\n- Rust cross-compilation toolchain via pkgsCross (generally well-supported)\n- Python headers for target platform\n- maturin building wheels for the target platform\n- uv2nix virtual environment resolution for the target system\n\nThe nix2container infrastructure and containerMatrix are already in place (from pnt-5vr). This issue adds the pkgsCross target definitions and validates the cross-compilation pipeline.\n\nReference: vanixiets uses pkgsCross.gnu64 and pkgsCross.aarch64-multiplatform for simple nixpkgs packages. The Python/Rust case is more complex but the container infrastructure pattern is identical.","status":"open","priority":3,"issue_type":"task","owner":"cameron.ray.smith@gmail.com","created_at":"2026-02-02T23:00:13.965286-05:00","created_by":"Cameron Smith","updated_at":"2026-02-02T23:00:27.262969-05:00","dependencies":[{"issue_id":"pnt-wbq","depends_on_id":"pnt-5vr","type":"discovered-from","created_at":"2026-02-02T23:00:28.588784-05:00","created_by":"Cameron Smith"}]} From 5899fd587dd9c3f066a177297d2d9dae218c6231 Mon Sep 17 00:00:00 2001 From: Cameron Smith Date: Tue, 3 Feb 2026 10:29:21 -0500 Subject: [PATCH 119/134] feat(nix): add import-tree input to flake.nix --- flake.nix | 2 ++ 1 file changed, 2 insertions(+) diff --git a/flake.nix b/flake.nix index 6ab3183..59dbff5 100644 --- a/flake.nix +++ b/flake.nix @@ -38,6 +38,8 @@ crane.url = "github:ipetkov/crane"; + import-tree.url = "github:vic/import-tree"; + git-hooks.url = "github:cachix/git-hooks.nix"; git-hooks.flake = false; }; From c7fa278a07e4c28d59642d9d76fa6f18390ee5e3 Mon Sep 17 00:00:00 2001 From: Cameron Smith Date: Tue, 3 Feb 2026 10:29:28 -0500 Subject: [PATCH 120/134] feat(nix): add modules/systems.nix for system configuration --- modules/systems.nix | 8 ++++++++ 1 file changed, 8 insertions(+) create mode 100644 modules/systems.nix diff --git a/modules/systems.nix b/modules/systems.nix new file mode 100644 index 0000000..8669711 --- /dev/null +++ b/modules/systems.nix @@ -0,0 +1,8 @@ +{ + systems = [ + "x86_64-linux" + "aarch64-linux" + "aarch64-darwin" + "x86_64-darwin" + ]; +} From f10d85d5ea9880e3d8931587038547c41d5da2e2 Mon Sep 17 00:00:00 2001 From: Cameron Smith Date: Tue, 3 Feb 2026 10:29:33 -0500 Subject: [PATCH 121/134] feat(nix): add modules/flake-parts.nix placeholder --- modules/flake-parts.nix | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 modules/flake-parts.nix diff --git a/modules/flake-parts.nix b/modules/flake-parts.nix new file mode 100644 index 0000000..182900a --- /dev/null +++ b/modules/flake-parts.nix @@ -0,0 +1,5 @@ +{ ... }: +{ + # External flake-parts module imports. + # git-hooks is imported in pre-commit.nix. +} From 6fd8daf16700289d77dd6d1302daa431743d1efa Mon Sep 17 00:00:00 2001 From: Cameron Smith Date: Tue, 3 Feb 2026 10:29:38 -0500 Subject: [PATCH 122/134] refactor(nix): move devshell.nix to modules/ --- modules/devshell.nix | 90 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 90 insertions(+) create mode 100644 modules/devshell.nix diff --git a/modules/devshell.nix b/modules/devshell.nix new file mode 100644 index 0000000..8a57594 --- /dev/null +++ b/modules/devshell.nix @@ -0,0 +1,90 @@ +{ + inputs, + ... +}: +{ + perSystem = + { + config, + self', + pkgs, + lib, + packageWorkspaces, + editablePythonSets, + pythonVersions, + ... + }: + let + # Merge deps from all independent package workspaces, unioning extras lists + # for shared dependency names rather than silently dropping via // + allDeps = lib.foldlAttrs ( + acc: _: pkg: + lib.zipAttrsWith (_: values: lib.unique (lib.flatten values)) [ + acc + pkg.workspace.deps.all + ] + ) { } packageWorkspaces; + + mkDevShell = + { + name, + pythonVersion, + }: + let + python = pythonVersions.${pythonVersion}; + pythonEnv = editablePythonSets.${pythonVersion}; + virtualenv = pythonEnv.mkVirtualEnv "${name}-dev-env" allDeps; + in + pkgs.mkShell { + inherit name; + inputsFrom = [ config.pre-commit.devShell ]; + packages = with pkgs; [ + just + pixi + quarto + teller + uv + yarn-berry + virtualenv + age + gitleaks + sops + ssh-to-age + config.packages.set-git-env + # Rust tooling for pnt-cli pyo3 extension + cargo + rustc + clippy + cargo-nextest + maturin + ]; + + env = { + UV_NO_SYNC = "1"; + UV_PYTHON = "${virtualenv}/bin/python"; + UV_PYTHON_DOWNLOADS = "never"; + }; + + shellHook = '' + unset PYTHONPATH + export REPO_ROOT=$(git rev-parse --show-toplevel) + set-git-env + ''; + }; + in + { + devShells = rec { + pythonNixTemplate311 = mkDevShell { + name = "python-nix-template-3.11"; + pythonVersion = "py311"; + }; + + pythonNixTemplate312 = mkDevShell { + name = "python-nix-template-3.12"; + pythonVersion = "py312"; + }; + + default = pythonNixTemplate312; + }; + }; +} From 0afa2614db2d5d7f508148d35bcab32058e17c9e Mon Sep 17 00:00:00 2001 From: Cameron Smith Date: Tue, 3 Feb 2026 10:29:41 -0500 Subject: [PATCH 123/134] refactor(nix): move git-env.nix to modules/ --- modules/git-env.nix | 64 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 64 insertions(+) create mode 100644 modules/git-env.nix diff --git a/modules/git-env.nix b/modules/git-env.nix new file mode 100644 index 0000000..68e5377 --- /dev/null +++ b/modules/git-env.nix @@ -0,0 +1,64 @@ +{ + inputs, + lib, + config, + pkgs, + ... +}: + +{ + perSystem = + { system, pkgs, ... }: + { + packages.set-git-env = pkgs.writeShellApplication { + name = "set-git-env"; + runtimeInputs = with pkgs; [ + git + coreutils + gnused + gnugrep + ]; + text = '' + #!/usr/bin/env bash + + set -euo pipefail + + update_or_append() { + local var_name=$1 + local var_value=$2 + local file=".env" + + # Create .env file if it doesn't exist + if [ ! -f "$file" ]; then + touch "$file" + fi + + if [ -s "$file" ] && [ "$(tail -c1 "$file"; echo x)" != $'\nx' ]; then + echo >> "$file" + fi + + if grep -q "^$var_name=" "$file"; then + # Use sed with backup extension for compatibility + sed -i.bak "s/^$var_name=.*/$var_name=$var_value/" "$file" + # Remove backup file + rm -f "$file.bak" + else + echo "$var_name=$var_value" >> "$file" + fi + } + + GIT_REPO_NAME=$(basename -s .git "$(git config --get remote.origin.url 2>/dev/null || echo "unknown-repo")") + update_or_append "GIT_REPO_NAME" "$GIT_REPO_NAME" + + GIT_REF=$(git symbolic-ref -q --short HEAD 2>/dev/null || git rev-parse HEAD 2>/dev/null || echo "unknown-ref") + update_or_append "GIT_REF" "$GIT_REF" + + GIT_SHA=$(git rev-parse HEAD 2>/dev/null || echo "unknown-sha") + update_or_append "GIT_SHA" "$GIT_SHA" + + GIT_SHA_SHORT=$(git rev-parse --short HEAD 2>/dev/null || echo "unknown") + update_or_append "GIT_SHA_SHORT" "$GIT_SHA_SHORT" + ''; + }; + }; +} From ff52f3b332aaafab1d2078d615329e51a2841451 Mon Sep 17 00:00:00 2001 From: Cameron Smith Date: Tue, 3 Feb 2026 10:29:42 -0500 Subject: [PATCH 124/134] refactor(nix): move overrides.nix to modules/ --- modules/overrides.nix | 60 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 60 insertions(+) create mode 100644 modules/overrides.nix diff --git a/modules/overrides.nix b/modules/overrides.nix new file mode 100644 index 0000000..e3dd66e --- /dev/null +++ b/modules/overrides.nix @@ -0,0 +1,60 @@ +{ + inputs, + ... +}: +{ + perSystem = + { + config, + self', + pkgs, + lib, + ... + }: + let + # Function to create package-specific overrides + mkPackageOverrides = + { pkgs }: + final: prev: { + # Example overrides for specific packages + # numpy = prev.numpy.overrideAttrs (old: { + # buildInputs = (old.buildInputs or []) ++ [ pkgs.openblas ]; + # }); + + # Example of fixing a package that needs specific build system dependencies + # tensorflow = prev.tensorflow.overrideAttrs (old: { + # nativeBuildInputs = (old.nativeBuildInputs or []) ++ [ + # (final.resolveBuildSystem { + # setuptools = []; + # wheel = []; + # numpy = []; + # }) + # ]; + # }); + }; + + # Function to create sdist-specific overrides + mkSdistOverrides = + { pkgs }: + final: prev: { + # Example overrides for source distributions + # pyzmq = prev.pyzmq.overrideAttrs (old: { + # buildInputs = (old.buildInputs or []) ++ [ pkgs.zeromq ]; + # nativeBuildInputs = (old.nativeBuildInputs or []) ++ [ + # (final.resolveBuildSystem { + # cmake = []; + # ninja = []; + # packaging = []; + # }) + # ]; + # }); + }; + in + { + # Expose the override functions for use in other modules + _module.args = { + packageOverrides = mkPackageOverrides { inherit pkgs; }; + sdistOverrides = mkSdistOverrides { inherit pkgs; }; + }; + }; +} From ad5c6bc58de5344aa8f45889d7cacb1dcf8e8ca4 Mon Sep 17 00:00:00 2001 From: Cameron Smith Date: Tue, 3 Feb 2026 10:29:42 -0500 Subject: [PATCH 125/134] refactor(nix): move packages.nix to modules/ --- modules/packages.nix | 41 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 41 insertions(+) create mode 100644 modules/packages.nix diff --git a/modules/packages.nix b/modules/packages.nix new file mode 100644 index 0000000..56c4143 --- /dev/null +++ b/modules/packages.nix @@ -0,0 +1,41 @@ +{ + inputs, + ... +}: +{ + perSystem = + { + config, + self', + pkgs, + lib, + packageWorkspaces, + pythonSets, + editablePythonSets, + pythonVersions, + ... + }: + let + # Merge deps from all independent package workspaces, unioning extras lists + # for shared dependency names rather than silently dropping via // + mergeWorkspaceDeps = + selector: + lib.foldlAttrs ( + acc: _: pkg: + lib.zipAttrsWith (_: values: lib.unique (lib.flatten values)) [ + acc + (selector pkg.workspace.deps) + ] + ) { } packageWorkspaces; + + defaultDeps = mergeWorkspaceDeps (deps: deps.default); + in + { + packages = rec { + pythonNixTemplate311 = pythonSets.py311.mkVirtualEnv "python-nix-template-3.11" defaultDeps; + pythonNixTemplate312 = pythonSets.py312.mkVirtualEnv "python-nix-template-3.12" defaultDeps; + + default = pythonNixTemplate312; + }; + }; +} From 9c673084e611a1922dc553c31c473a1246cd1781 Mon Sep 17 00:00:00 2001 From: Cameron Smith Date: Tue, 3 Feb 2026 10:29:43 -0500 Subject: [PATCH 126/134] refactor(nix): move pre-commit.nix to modules/ --- modules/pre-commit.nix | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) create mode 100644 modules/pre-commit.nix diff --git a/modules/pre-commit.nix b/modules/pre-commit.nix new file mode 100644 index 0000000..352abaf --- /dev/null +++ b/modules/pre-commit.nix @@ -0,0 +1,24 @@ +{ inputs, ... }: +{ + imports = [ + (inputs.git-hooks + /flake-module.nix) + ]; + perSystem = + { + config, + self', + pkgs, + lib, + ... + }: + { + pre-commit.settings = { + hooks = { + nixfmt-rfc-style.enable = true; + ruff.enable = true; + ruff-format.enable = true; + taplo.enable = true; + }; + }; + }; +} From 36396255163370988f9f4bdc0ce59cf4f4b52afc Mon Sep 17 00:00:00 2001 From: Cameron Smith Date: Tue, 3 Feb 2026 10:29:43 -0500 Subject: [PATCH 127/134] refactor(nix): move template-rename.nix to modules/ --- modules/template-rename.nix | 97 +++++++++++++++++++++++++++++++++++++ 1 file changed, 97 insertions(+) create mode 100644 modules/template-rename.nix diff --git a/modules/template-rename.nix b/modules/template-rename.nix new file mode 100644 index 0000000..6af3217 --- /dev/null +++ b/modules/template-rename.nix @@ -0,0 +1,97 @@ +{ + inputs, + lib, + config, + pkgs, + ... +}: + +{ + perSystem = + { system, pkgs, ... }: + { + packages.fix-template-names = pkgs.writeShellApplication { + name = "fix-template-names"; + runtimeInputs = with pkgs; [ + coreutils + gnused + gnugrep + findutils + file + ]; + text = '' + #!/usr/bin/env bash + + set -euo pipefail + + # Colors for output + GREEN='\033[0;32m' + YELLOW='\033[1;33m' + RED='\033[0;31m' + NC='\033[0m' # No Color + + # Get the current directory name as default new name + DEFAULT_NEW_NAME=$(basename "$(pwd)") + # Convert to underscore version + DEFAULT_NEW_UNDERSCORE=$(echo "$DEFAULT_NEW_NAME" | tr '-' '_') + + # Check for required arguments + if [ $# -lt 1 ]; then + echo -e "''${RED}Error: Missing required argument.''${NC}" + echo "Usage: fix-template-names OLD_NAME [NEW_NAME]" + echo "OLD_NAME: The original template name to be replaced" + echo "NEW_NAME: The new name to use (optional, defaults to current directory name: $DEFAULT_NEW_NAME)" + exit 1 + fi + + # Set old name from first argument + OLD_NAME="$1" + # Convert to underscore version + OLD_UNDERSCORE=$(echo "$OLD_NAME" | tr '-' '_') + + # Use second command line argument if provided, otherwise use defaults + if [ $# -eq 2 ]; then + NEW_NAME="$2" + # Convert to underscore version + NEW_UNDERSCORE=$(echo "$NEW_NAME" | tr '-' '_') + else + NEW_NAME="$DEFAULT_NEW_NAME" + NEW_UNDERSCORE="$DEFAULT_NEW_UNDERSCORE" + fi + + echo -e "''${YELLOW}Starting replacement of template names...''${NC}" + echo -e "''${YELLOW}Replacing $OLD_NAME with $NEW_NAME''${NC}" + echo -e "''${YELLOW}Replacing $OLD_UNDERSCORE with $NEW_UNDERSCORE''${NC}" + + # Find all text files in the project (excluding .git, node_modules, and other common directories to ignore) + # and replace the strings in-place + find . -type f \ + -not -path "*/\.*" \ + -not -path "*/node_modules/*" \ + -not -path "*/venv/*" \ + -not -path "*/build/*" \ + -not -path "*/dist/*" \ + -not -path "*/\__pycache__/*" \ + -exec grep -l "$OLD_NAME\|$OLD_UNDERSCORE" {} \; | while read -r file; do + echo "Processing: $file" + + # Check if file is binary + if file "$file" | grep -q "binary"; then + echo " Skipping binary file" + continue + fi + + # Make replacements + sed -i.bak "s/$OLD_NAME/$NEW_NAME/g" "$file" + sed -i.bak "s/$OLD_UNDERSCORE/$NEW_UNDERSCORE/g" "$file" + + # Remove backup files + rm -f "''${file}.bak" + done + + echo -e "''${GREEN}Replacement complete!''${NC}" + echo -e "''${YELLOW}Note: You may need to rebuild or reinstall your package after these changes.''${NC}" + ''; + }; + }; +} From 5fc4cef8e4116ca72d4ac5358607be38317227ab Mon Sep 17 00:00:00 2001 From: Cameron Smith Date: Tue, 3 Feb 2026 10:30:09 -0500 Subject: [PATCH 128/134] refactor(nix): move python.nix to modules/ and update paths --- modules/python.nix | 133 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 133 insertions(+) create mode 100644 modules/python.nix diff --git a/modules/python.nix b/modules/python.nix new file mode 100644 index 0000000..da85eef --- /dev/null +++ b/modules/python.nix @@ -0,0 +1,133 @@ +{ + inputs, + ... +}: +{ + perSystem = + { + config, + self', + pkgs, + lib, + packageOverrides ? (_: _: { }), + sdistOverrides ? (_: _: { }), + ... + }: + let + pythonVersions = { + py311 = pkgs.python311; + py312 = pkgs.python312; + }; + + # Load each Python package independently (no root workspace). + # Each package directory contains its own pyproject.toml and uv.lock, + # resolved independently following the LangChain federation model. + loadPackage = + name: path: + let + workspace = inputs.uv2nix.lib.workspace.loadWorkspace { + workspaceRoot = path; + }; + in + { + inherit workspace; + overlay = workspace.mkPyprojectOverlay { + sourcePreference = "wheel"; + }; + editableOverlay = workspace.mkEditablePyprojectOverlay { + root = "$REPO_ROOT"; + }; + }; + + packageWorkspaces = { + pnt-cli = loadPackage "pnt-cli" ../packages/pnt-cli; + pnt-functional = loadPackage "pnt-functional" ../packages/pnt-functional; + python-nix-template = loadPackage "python-nix-template" ../packages/python-nix-template; + }; + + # Per-package Nix modules with optional Rust overlays. + # Packages with Rust extensions get a dedicated module in nix/packages/ + # that encapsulates crane configuration and exports an overlay + checks. + mkPackageModule = + python: + import ../nix/packages/pnt-cli { + inherit pkgs lib python; + crane = inputs.crane; + }; + + # Compose per-package uv2nix overlays with shared overrides. + # + # Invariant: all federated packages must resolve compatible versions for + # shared dependencies. Per-package uv2nix overlays are composed sequentially + # into a single package set — if two packages resolve different versions of + # the same dependency, the later overlay silently wins. Enforce version + # alignment across packages by running: + # uv lock --check + # in each package directory after updating any shared dependency. + mkPythonSet = + python: + (pkgs.callPackage inputs.pyproject-nix.build.packages { + inherit python; + }).overrideScope + ( + lib.composeManyExtensions [ + inputs.pyproject-build-systems.overlays.default + packageWorkspaces.pnt-cli.overlay + packageWorkspaces.pnt-functional.overlay + packageWorkspaces.python-nix-template.overlay + # Rust integration overlay for pnt-cli (crane + maturin) + (mkPackageModule python).overlay + packageOverrides + sdistOverrides + ] + ); + + # Editable set excludes pnt-cli: maturin packages are incompatible with + # uv2nix's editable overlay (pyprojectFixupEditableHook expects EDITABLE_ROOT + # which maturin's build process does not set). pnt-cli is built as a regular + # wheel in the devshell; use `maturin develop` for iterative Rust development. + mkEditablePythonSet = + python: + (mkPythonSet python).overrideScope ( + lib.composeManyExtensions [ + packageWorkspaces.pnt-functional.editableOverlay + packageWorkspaces.python-nix-template.editableOverlay + (final: prev: { + python-nix-template = prev.python-nix-template.overrideAttrs (old: { + nativeBuildInputs = + old.nativeBuildInputs + ++ final.resolveBuildSystem { + editables = [ ]; + }; + }); + pnt-functional = prev.pnt-functional.overrideAttrs (old: { + nativeBuildInputs = + old.nativeBuildInputs + ++ final.resolveBuildSystem { + editables = [ ]; + }; + }); + }) + ] + ); + + pythonSets = lib.mapAttrs (_: mkPythonSet) pythonVersions; + editablePythonSets = lib.mapAttrs (_: mkEditablePythonSet) pythonVersions; + + # Rust checks from per-package modules (using default Python version) + rustChecks = (mkPackageModule pythonVersions.py312).checks; + in + { + checks = rustChecks; + + _module.args = { + inherit + packageWorkspaces + pythonSets + editablePythonSets + pythonVersions + ; + defaultPython = pythonVersions.py312; + }; + }; +} From fe88810a4a79e21c0d68da74d0865533cd3dc48c Mon Sep 17 00:00:00 2001 From: Cameron Smith Date: Tue, 3 Feb 2026 10:30:20 -0500 Subject: [PATCH 129/134] refactor(nix): move containers.nix to modules/ and update paths --- modules/containers.nix | 355 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 355 insertions(+) create mode 100644 modules/containers.nix diff --git a/modules/containers.nix b/modules/containers.nix new file mode 100644 index 0000000..7c5429c --- /dev/null +++ b/modules/containers.nix @@ -0,0 +1,355 @@ +{ + inputs, + lib, + ... +}: +let + gitHubOrg = "sciexp"; + repoName = "python-nix-template"; + + # Production container definitions (nix2container) + # Add new containers here; containerMatrix auto-discovers them. + productionContainerDefs = { + pnt-cli = { + name = "pnt-cli"; + entrypoint = "pnt-cli"; + description = "pnt-cli with pyo3 native bindings"; + }; + }; + + # Dev container image attribute names for manifest generation + devContainerDefs = { + ${repoName} = { + imageAttr = "containerImage"; + }; + "${repoName}-dev" = { + imageAttr = "devcontainerImage"; + }; + }; +in +{ + perSystem = + { + config, + self', + inputs', + pkgs, + lib, + system, + packageWorkspaces, + pythonSets, + editablePythonSets, + pythonVersions, + ... + }: + let + isLinux = pkgs.stdenv.isLinux; + + # --- Python environments --- + + defaultPythonVersion = "py312"; + defaultPythonSet = pythonSets.${defaultPythonVersion}; + defaultEditablePythonSet = editablePythonSets.${defaultPythonVersion}; + + # Merge deps from all independent package workspaces, unioning extras lists + # for shared dependency names rather than silently dropping via // + defaultDeps = lib.foldlAttrs ( + acc: _: pkg: + lib.zipAttrsWith (_: values: lib.unique (lib.flatten values)) [ + acc + pkg.workspace.deps.default + ] + ) { } packageWorkspaces; + allDeps = lib.foldlAttrs ( + acc: _: pkg: + lib.zipAttrsWith (_: values: lib.unique (lib.flatten values)) [ + acc + pkg.workspace.deps.all + ] + ) { } packageWorkspaces; + + defaultPythonEnv = defaultPythonSet.mkVirtualEnv "${repoName}-env" defaultDeps; + defaultEditablePythonEnv = defaultEditablePythonSet.mkVirtualEnv "${repoName}-editable-env" allDeps; + + # --- Dev container infrastructure (nixpod/dockerTools, unchanged) --- + + buildMultiUserNixImage = import "${inputs.nixpod.outPath}/containers/nix.nix"; + + containerUsername = "jovyan"; + containerUserInfo = { + uid = 1000; + gid = 0; + uname = containerUsername; + gname = "wheel"; + }; + + containerSysPackages = with pkgs; [ + bashInteractive + cacert + coreutils + direnv + gnutar + gzip + less + nix + procps + sudo + zsh + ]; + + containerDevPackages = with pkgs; [ + git + helix + lazygit + neovim + starship + ]; + + mkBaseContainer = + { + name, + tag ? "latest", + pythonPackageEnv, + extraContents ? [ ], + extraPkgs ? [ ], + extraEnv ? [ ], + extraConfig ? { }, + }: + buildMultiUserNixImage { + inherit pkgs name tag; + storeOwner = containerUserInfo; + maxLayers = 121; + fromImage = inputs'.nixpod.packages.sudoImage; + compressor = "zstd"; + + extraPkgs = containerSysPackages ++ extraPkgs ++ [ pythonPackageEnv ]; + extraContents = [ + inputs'.nixpod.legacyPackages.homeConfigurations.${containerUsername}.activationPackage + ] + ++ extraContents; + + extraFakeRootCommands = '' + chown -R ${containerUsername}:wheel /nix + ''; + + nixConf = { + allowed-users = [ "*" ]; + experimental-features = [ + "nix-command" + "flakes" + ]; + max-jobs = [ "auto" ]; + sandbox = "false"; + trusted-users = [ + "root" + "${containerUsername}" + "runner" + ]; + }; + + extraEnv = [ + "NB_USER=${containerUsername}" + "NB_UID=1000" + "NB_PREFIX=/" + "LD_LIBRARY_PATH=${pythonPackageEnv}/lib:/usr/local/nvidia/lib64" + "NVIDIA_DRIVER_CAPABILITIES='compute,utility'" + "NVIDIA_VISIBLE_DEVICES=all" + "QUARTO_PYTHON=${pythonPackageEnv}/bin/python" + ] + ++ extraEnv; + + extraConfig = { + ExposedPorts."8888/tcp" = { }; + } + // extraConfig; + }; + + # --- Production container infrastructure (nix2container) --- + # Built natively per-system. Cross-compilation via pkgsCross for the + # Python + maturin + Cargo stack is orthogonal and tracked separately. + + nix2container = inputs'.nix2container.packages.nix2container; + skopeo-nix2container = inputs'.nix2container.packages.skopeo-nix2container; + + mkMultiArchManifest = pkgs.callPackage ../nix/lib/mk-multi-arch-manifest.nix { }; + + productionBaseLayer = nix2container.buildLayer { + deps = [ + pkgs.bashInteractive + pkgs.coreutils + pkgs.cacert + ]; + }; + + mkProductionContainer = + { + name, + entrypoint, + pythonEnv ? defaultPythonEnv, + tag ? "latest", + description ? "", + }: + nix2container.buildImage { + inherit name tag; + layers = [ productionBaseLayer ]; + copyToRoot = pkgs.buildEnv { + name = "${name}-root"; + paths = [ + pythonEnv + pkgs.cacert + ]; + pathsToLink = [ + "/bin" + "/lib" + "/etc" + ]; + }; + config = { + entrypoint = [ "${pythonEnv}/bin/${entrypoint}" ]; + Env = [ + "PATH=${pythonEnv}/bin:${pkgs.coreutils}/bin:${pkgs.bashInteractive}/bin" + "SSL_CERT_FILE=${pkgs.cacert}/etc/ssl/certs/ca-bundle.crt" + ]; + Labels = { + "org.opencontainers.image.description" = description; + "org.opencontainers.image.source" = "https://github.com/${gitHubOrg}/${repoName}"; + }; + }; + maxLayers = 2; + }; + + productionContainerPackages = lib.mapAttrs' ( + containerName: def: + lib.nameValuePair "${containerName}ProductionImage" (mkProductionContainer { + inherit (def) name entrypoint description; + }) + ) productionContainerDefs; + + # --- Manifest generation (crane-based, replaces flocken) --- + # Env vars (require --impure): VERSION, TAGS, GITHUB_REF_NAME, GITHUB_ACTOR, GITHUB_TOKEN + + getEnvOr = + var: default: + let + val = builtins.getEnv var; + in + if val == "" then default else val; + + getEnvList = + var: + let + val = builtins.getEnv var; + in + if val == "" then [ ] else lib.splitString "," val; + + # Systems to include in multi-arch manifests + includedSystems = + let + envVar = builtins.getEnv "NIX_IMAGE_SYSTEMS"; + in + if envVar == "" then + [ + "x86_64-linux" + "aarch64-linux" + ] + else + builtins.filter (sys: sys != "") (builtins.split " " envVar); + + manifestVersion = getEnvOr "VERSION" "0.0.0"; + manifestTags = getEnvList "TAGS"; + manifestBranch = getEnvOr "GITHUB_REF_NAME" "main"; + manifestUsername = getEnvOr "GITHUB_ACTOR" "cameronraysmith"; + + # Production manifests use nix: transport (skopeo-nix2container) + productionManifestPackages = lib.mapAttrs' ( + containerName: _def: + lib.nameValuePair "${containerName}Manifest" (mkMultiArchManifest { + name = containerName; + images = lib.listToAttrs ( + map (sys: { + name = sys; + value = inputs.self.packages.${sys}."${containerName}ProductionImage"; + }) includedSystems + ); + registry = { + name = "ghcr.io"; + repo = "${gitHubOrg}/${repoName}/${containerName}"; + username = manifestUsername; + password = "$GITHUB_TOKEN"; + }; + version = manifestVersion; + tags = manifestTags; + branch = manifestBranch; + skopeo = skopeo-nix2container; + }) + ) productionContainerDefs; + + # Dev manifests use docker-archive: transport (regular skopeo) + devManifestPackages = lib.mapAttrs' ( + manifestName: def: + lib.nameValuePair "${manifestName}Manifest" (mkMultiArchManifest { + name = manifestName; + images = lib.listToAttrs ( + map (sys: { + name = sys; + value = inputs.self.packages.${sys}.${def.imageAttr}; + }) includedSystems + ); + registry = { + name = "ghcr.io"; + repo = "${gitHubOrg}/${manifestName}"; + username = manifestUsername; + password = "$GITHUB_TOKEN"; + }; + version = manifestVersion; + tags = manifestTags; + branch = manifestBranch; + skopeo = pkgs.skopeo; + mkSourceUri = image: "docker-archive:${image}"; + }) + ) devContainerDefs; + + in + { + packages = lib.optionalAttrs isLinux ( + { + # Dev containers (nixpod/dockerTools, unchanged) + containerImage = mkBaseContainer { + name = repoName; + pythonPackageEnv = defaultPythonEnv; + }; + + devcontainerImage = mkBaseContainer { + name = "${repoName}-dev"; + pythonPackageEnv = defaultEditablePythonEnv; + extraPkgs = containerDevPackages; + }; + } + // productionContainerPackages + // productionManifestPackages + // devManifestPackages + ); + }; + + # CI matrix data (pure evaluation): nix eval .#containerMatrix --json + flake.containerMatrix = { + build = + (lib.mapAttrsToList (containerName: _: { + package = "${containerName}ProductionImage"; + type = "production"; + }) productionContainerDefs) + ++ (lib.mapAttrsToList (_: def: { + package = def.imageAttr; + type = "dev"; + }) devContainerDefs); + manifest = + (lib.mapAttrsToList (containerName: _: { + name = containerName; + type = "production"; + }) productionContainerDefs) + ++ (lib.mapAttrsToList (manifestName: _: { + name = manifestName; + type = "dev"; + }) devContainerDefs); + }; +} From ac19f6c436d4e57319341f3aa431162d44f2656d Mon Sep 17 00:00:00 2001 From: Cameron Smith Date: Tue, 3 Feb 2026 10:30:31 -0500 Subject: [PATCH 130/134] refactor(nix): move template.nix to modules/ and update paths --- modules/template.nix | 148 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 148 insertions(+) create mode 100644 modules/template.nix diff --git a/modules/template.nix b/modules/template.nix new file mode 100644 index 0000000..670d480 --- /dev/null +++ b/modules/template.nix @@ -0,0 +1,148 @@ +{ inputs, ... }: + +{ + flake = rec { + templates.default = { + description = "A Python project template for Nix using uv2nix and flake-parts"; + path = builtins.path { path = inputs.self; }; + welcomeText = '' + Welcome to the python-nix-template! + + NOTE: If you're reusing a preexisting directory for PROJECT_DIRECTORY you + may need to run `direnv revoke $PROJECT_DIRECTORY` to unload the environment + before proceeding. + + Otherwise, don't forget to `cd` into your new project directory. + + If you do not have nix and direnv installed, check + + ```bash + make -n bootstrap + ``` + + and rerun without the `-n` if you are comfortable with the commands. Otherwise, + manually install the nix package manager and direnv. + + In order to recognize the `flake.nix` and associated files, create a git + repository, stage the files, and run `direnv allow` to load the environment. + You might need to run `direnv revoke` first if you're reusing a directory + where you have previously run `direnv allow`. + + You can copy and paste + + ```bash + git init && git commit --allow-empty -m "initial commit (empty)" && git add . && direnv allow + ``` + + or, if you prefer, run the commands manually to verify or modify them + + ```bash + ❯ git init + Initialized empty Git repository in ... + + ❯ git commit --allow-empty -m "initial commit (empty)" + [main (root-commit) bba59e7] initial commit (empty) + + ❯ git add . + + ❯ direnv allow + ``` + + You should then be able to run `pytest` to verify the project is working. + See the README for more information. + ''; + }; + + # https://omnix.page/om/init.html#spec + om.templates.python-nix-template = { + template = templates.default; + params = [ + { + name = "package-name-kebab-case"; + description = "Name of the Python package (kebab-case)"; + placeholder = "python-nix-template"; + } + { + name = "package-name-snake-case"; + description = "Name of the Python package (snake_case)"; + placeholder = "python_nix_template"; + } + { + name = "monorepo-package"; + description = "Include the functional programming monorepo package in the project"; + paths = [ "packages/pnt-functional" ]; + value = false; + } + { + name = "git-org"; + description = "GitHub organization or user name"; + placeholder = "sciexp"; + } + { + name = "author"; + description = "Author name"; + placeholder = "Your Name"; + } + { + name = "author-email"; + description = "Author email"; + placeholder = "your.email@example.com"; + } + { + name = "project-description"; + description = "Project description for documentation"; + placeholder = "A Python project template for Nix using uv2nix and flake-parts"; + } + { + name = "vscode"; + description = "Include the VSCode settings folder (./.vscode)"; + paths = [ ".vscode" ]; + value = true; + } + { + name = "github-ci"; + description = "Include GitHub Actions workflow configuration"; + paths = [ ".github" ]; + value = true; + } + { + name = "docs"; + description = "Include documentation site infrastructure (MkDocs + Cloudflare deployment)"; + paths = [ + "docs" + ".github/workflows/deploy-docs.yaml" + ]; + value = true; + } + { + name = "nix-template"; + description = "Keep the flake template in the project"; + paths = [ + "**/template.nix" + ".github/workflows/template.yaml" + ]; + value = false; + } + ]; + tests = { + default = { + params = { + package-name = "awesome-package"; + author = "John Doe"; + author-email = "john@example.com"; + }; + asserts = { + source = { + "pyproject.toml" = true; + "flake.nix" = true; + ".github/workflows/ci.yaml" = true; + ".vscode" = true; + "modules/template.nix" = false; + }; + packages.default = { }; + }; + }; + }; + }; + }; +} From 8ba4a869c222078ee4ce3ecc15452d382b58ee74 Mon Sep 17 00:00:00 2001 From: Cameron Smith Date: Tue, 3 Feb 2026 10:30:36 -0500 Subject: [PATCH 131/134] refactor(nix): remove empty nix/modules/ directory --- nix/modules/containers.nix | 355 -------------------------------- nix/modules/devshell.nix | 90 -------- nix/modules/git-env.nix | 64 ------ nix/modules/overrides.nix | 60 ------ nix/modules/packages.nix | 41 ---- nix/modules/pre-commit.nix | 24 --- nix/modules/python.nix | 133 ------------ nix/modules/template-rename.nix | 97 --------- nix/modules/template.nix | 148 ------------- 9 files changed, 1012 deletions(-) delete mode 100644 nix/modules/containers.nix delete mode 100644 nix/modules/devshell.nix delete mode 100644 nix/modules/git-env.nix delete mode 100644 nix/modules/overrides.nix delete mode 100644 nix/modules/packages.nix delete mode 100644 nix/modules/pre-commit.nix delete mode 100644 nix/modules/python.nix delete mode 100644 nix/modules/template-rename.nix delete mode 100644 nix/modules/template.nix diff --git a/nix/modules/containers.nix b/nix/modules/containers.nix deleted file mode 100644 index 28aaa88..0000000 --- a/nix/modules/containers.nix +++ /dev/null @@ -1,355 +0,0 @@ -{ - inputs, - lib, - ... -}: -let - gitHubOrg = "sciexp"; - repoName = "python-nix-template"; - - # Production container definitions (nix2container) - # Add new containers here; containerMatrix auto-discovers them. - productionContainerDefs = { - pnt-cli = { - name = "pnt-cli"; - entrypoint = "pnt-cli"; - description = "pnt-cli with pyo3 native bindings"; - }; - }; - - # Dev container image attribute names for manifest generation - devContainerDefs = { - ${repoName} = { - imageAttr = "containerImage"; - }; - "${repoName}-dev" = { - imageAttr = "devcontainerImage"; - }; - }; -in -{ - perSystem = - { - config, - self', - inputs', - pkgs, - lib, - system, - packageWorkspaces, - pythonSets, - editablePythonSets, - pythonVersions, - ... - }: - let - isLinux = pkgs.stdenv.isLinux; - - # --- Python environments --- - - defaultPythonVersion = "py312"; - defaultPythonSet = pythonSets.${defaultPythonVersion}; - defaultEditablePythonSet = editablePythonSets.${defaultPythonVersion}; - - # Merge deps from all independent package workspaces, unioning extras lists - # for shared dependency names rather than silently dropping via // - defaultDeps = lib.foldlAttrs ( - acc: _: pkg: - lib.zipAttrsWith (_: values: lib.unique (lib.flatten values)) [ - acc - pkg.workspace.deps.default - ] - ) { } packageWorkspaces; - allDeps = lib.foldlAttrs ( - acc: _: pkg: - lib.zipAttrsWith (_: values: lib.unique (lib.flatten values)) [ - acc - pkg.workspace.deps.all - ] - ) { } packageWorkspaces; - - defaultPythonEnv = defaultPythonSet.mkVirtualEnv "${repoName}-env" defaultDeps; - defaultEditablePythonEnv = defaultEditablePythonSet.mkVirtualEnv "${repoName}-editable-env" allDeps; - - # --- Dev container infrastructure (nixpod/dockerTools, unchanged) --- - - buildMultiUserNixImage = import "${inputs.nixpod.outPath}/containers/nix.nix"; - - containerUsername = "jovyan"; - containerUserInfo = { - uid = 1000; - gid = 0; - uname = containerUsername; - gname = "wheel"; - }; - - containerSysPackages = with pkgs; [ - bashInteractive - cacert - coreutils - direnv - gnutar - gzip - less - nix - procps - sudo - zsh - ]; - - containerDevPackages = with pkgs; [ - git - helix - lazygit - neovim - starship - ]; - - mkBaseContainer = - { - name, - tag ? "latest", - pythonPackageEnv, - extraContents ? [ ], - extraPkgs ? [ ], - extraEnv ? [ ], - extraConfig ? { }, - }: - buildMultiUserNixImage { - inherit pkgs name tag; - storeOwner = containerUserInfo; - maxLayers = 121; - fromImage = inputs'.nixpod.packages.sudoImage; - compressor = "zstd"; - - extraPkgs = containerSysPackages ++ extraPkgs ++ [ pythonPackageEnv ]; - extraContents = [ - inputs'.nixpod.legacyPackages.homeConfigurations.${containerUsername}.activationPackage - ] - ++ extraContents; - - extraFakeRootCommands = '' - chown -R ${containerUsername}:wheel /nix - ''; - - nixConf = { - allowed-users = [ "*" ]; - experimental-features = [ - "nix-command" - "flakes" - ]; - max-jobs = [ "auto" ]; - sandbox = "false"; - trusted-users = [ - "root" - "${containerUsername}" - "runner" - ]; - }; - - extraEnv = [ - "NB_USER=${containerUsername}" - "NB_UID=1000" - "NB_PREFIX=/" - "LD_LIBRARY_PATH=${pythonPackageEnv}/lib:/usr/local/nvidia/lib64" - "NVIDIA_DRIVER_CAPABILITIES='compute,utility'" - "NVIDIA_VISIBLE_DEVICES=all" - "QUARTO_PYTHON=${pythonPackageEnv}/bin/python" - ] - ++ extraEnv; - - extraConfig = { - ExposedPorts."8888/tcp" = { }; - } - // extraConfig; - }; - - # --- Production container infrastructure (nix2container) --- - # Built natively per-system. Cross-compilation via pkgsCross for the - # Python + maturin + Cargo stack is orthogonal and tracked separately. - - nix2container = inputs'.nix2container.packages.nix2container; - skopeo-nix2container = inputs'.nix2container.packages.skopeo-nix2container; - - mkMultiArchManifest = pkgs.callPackage ../lib/mk-multi-arch-manifest.nix { }; - - productionBaseLayer = nix2container.buildLayer { - deps = [ - pkgs.bashInteractive - pkgs.coreutils - pkgs.cacert - ]; - }; - - mkProductionContainer = - { - name, - entrypoint, - pythonEnv ? defaultPythonEnv, - tag ? "latest", - description ? "", - }: - nix2container.buildImage { - inherit name tag; - layers = [ productionBaseLayer ]; - copyToRoot = pkgs.buildEnv { - name = "${name}-root"; - paths = [ - pythonEnv - pkgs.cacert - ]; - pathsToLink = [ - "/bin" - "/lib" - "/etc" - ]; - }; - config = { - entrypoint = [ "${pythonEnv}/bin/${entrypoint}" ]; - Env = [ - "PATH=${pythonEnv}/bin:${pkgs.coreutils}/bin:${pkgs.bashInteractive}/bin" - "SSL_CERT_FILE=${pkgs.cacert}/etc/ssl/certs/ca-bundle.crt" - ]; - Labels = { - "org.opencontainers.image.description" = description; - "org.opencontainers.image.source" = "https://github.com/${gitHubOrg}/${repoName}"; - }; - }; - maxLayers = 2; - }; - - productionContainerPackages = lib.mapAttrs' ( - containerName: def: - lib.nameValuePair "${containerName}ProductionImage" (mkProductionContainer { - inherit (def) name entrypoint description; - }) - ) productionContainerDefs; - - # --- Manifest generation (crane-based, replaces flocken) --- - # Env vars (require --impure): VERSION, TAGS, GITHUB_REF_NAME, GITHUB_ACTOR, GITHUB_TOKEN - - getEnvOr = - var: default: - let - val = builtins.getEnv var; - in - if val == "" then default else val; - - getEnvList = - var: - let - val = builtins.getEnv var; - in - if val == "" then [ ] else lib.splitString "," val; - - # Systems to include in multi-arch manifests - includedSystems = - let - envVar = builtins.getEnv "NIX_IMAGE_SYSTEMS"; - in - if envVar == "" then - [ - "x86_64-linux" - "aarch64-linux" - ] - else - builtins.filter (sys: sys != "") (builtins.split " " envVar); - - manifestVersion = getEnvOr "VERSION" "0.0.0"; - manifestTags = getEnvList "TAGS"; - manifestBranch = getEnvOr "GITHUB_REF_NAME" "main"; - manifestUsername = getEnvOr "GITHUB_ACTOR" "cameronraysmith"; - - # Production manifests use nix: transport (skopeo-nix2container) - productionManifestPackages = lib.mapAttrs' ( - containerName: _def: - lib.nameValuePair "${containerName}Manifest" (mkMultiArchManifest { - name = containerName; - images = lib.listToAttrs ( - map (sys: { - name = sys; - value = inputs.self.packages.${sys}."${containerName}ProductionImage"; - }) includedSystems - ); - registry = { - name = "ghcr.io"; - repo = "${gitHubOrg}/${repoName}/${containerName}"; - username = manifestUsername; - password = "$GITHUB_TOKEN"; - }; - version = manifestVersion; - tags = manifestTags; - branch = manifestBranch; - skopeo = skopeo-nix2container; - }) - ) productionContainerDefs; - - # Dev manifests use docker-archive: transport (regular skopeo) - devManifestPackages = lib.mapAttrs' ( - manifestName: def: - lib.nameValuePair "${manifestName}Manifest" (mkMultiArchManifest { - name = manifestName; - images = lib.listToAttrs ( - map (sys: { - name = sys; - value = inputs.self.packages.${sys}.${def.imageAttr}; - }) includedSystems - ); - registry = { - name = "ghcr.io"; - repo = "${gitHubOrg}/${manifestName}"; - username = manifestUsername; - password = "$GITHUB_TOKEN"; - }; - version = manifestVersion; - tags = manifestTags; - branch = manifestBranch; - skopeo = pkgs.skopeo; - mkSourceUri = image: "docker-archive:${image}"; - }) - ) devContainerDefs; - - in - { - packages = lib.optionalAttrs isLinux ( - { - # Dev containers (nixpod/dockerTools, unchanged) - containerImage = mkBaseContainer { - name = repoName; - pythonPackageEnv = defaultPythonEnv; - }; - - devcontainerImage = mkBaseContainer { - name = "${repoName}-dev"; - pythonPackageEnv = defaultEditablePythonEnv; - extraPkgs = containerDevPackages; - }; - } - // productionContainerPackages - // productionManifestPackages - // devManifestPackages - ); - }; - - # CI matrix data (pure evaluation): nix eval .#containerMatrix --json - flake.containerMatrix = { - build = - (lib.mapAttrsToList (containerName: _: { - package = "${containerName}ProductionImage"; - type = "production"; - }) productionContainerDefs) - ++ (lib.mapAttrsToList (_: def: { - package = def.imageAttr; - type = "dev"; - }) devContainerDefs); - manifest = - (lib.mapAttrsToList (containerName: _: { - name = containerName; - type = "production"; - }) productionContainerDefs) - ++ (lib.mapAttrsToList (manifestName: _: { - name = manifestName; - type = "dev"; - }) devContainerDefs); - }; -} diff --git a/nix/modules/devshell.nix b/nix/modules/devshell.nix deleted file mode 100644 index 8a57594..0000000 --- a/nix/modules/devshell.nix +++ /dev/null @@ -1,90 +0,0 @@ -{ - inputs, - ... -}: -{ - perSystem = - { - config, - self', - pkgs, - lib, - packageWorkspaces, - editablePythonSets, - pythonVersions, - ... - }: - let - # Merge deps from all independent package workspaces, unioning extras lists - # for shared dependency names rather than silently dropping via // - allDeps = lib.foldlAttrs ( - acc: _: pkg: - lib.zipAttrsWith (_: values: lib.unique (lib.flatten values)) [ - acc - pkg.workspace.deps.all - ] - ) { } packageWorkspaces; - - mkDevShell = - { - name, - pythonVersion, - }: - let - python = pythonVersions.${pythonVersion}; - pythonEnv = editablePythonSets.${pythonVersion}; - virtualenv = pythonEnv.mkVirtualEnv "${name}-dev-env" allDeps; - in - pkgs.mkShell { - inherit name; - inputsFrom = [ config.pre-commit.devShell ]; - packages = with pkgs; [ - just - pixi - quarto - teller - uv - yarn-berry - virtualenv - age - gitleaks - sops - ssh-to-age - config.packages.set-git-env - # Rust tooling for pnt-cli pyo3 extension - cargo - rustc - clippy - cargo-nextest - maturin - ]; - - env = { - UV_NO_SYNC = "1"; - UV_PYTHON = "${virtualenv}/bin/python"; - UV_PYTHON_DOWNLOADS = "never"; - }; - - shellHook = '' - unset PYTHONPATH - export REPO_ROOT=$(git rev-parse --show-toplevel) - set-git-env - ''; - }; - in - { - devShells = rec { - pythonNixTemplate311 = mkDevShell { - name = "python-nix-template-3.11"; - pythonVersion = "py311"; - }; - - pythonNixTemplate312 = mkDevShell { - name = "python-nix-template-3.12"; - pythonVersion = "py312"; - }; - - default = pythonNixTemplate312; - }; - }; -} diff --git a/nix/modules/git-env.nix b/nix/modules/git-env.nix deleted file mode 100644 index 68e5377..0000000 --- a/nix/modules/git-env.nix +++ /dev/null @@ -1,64 +0,0 @@ -{ - inputs, - lib, - config, - pkgs, - ... -}: - -{ - perSystem = - { system, pkgs, ... }: - { - packages.set-git-env = pkgs.writeShellApplication { - name = "set-git-env"; - runtimeInputs = with pkgs; [ - git - coreutils - gnused - gnugrep - ]; - text = '' - #!/usr/bin/env bash - - set -euo pipefail - - update_or_append() { - local var_name=$1 - local var_value=$2 - local file=".env" - - # Create .env file if it doesn't exist - if [ ! -f "$file" ]; then - touch "$file" - fi - - if [ -s "$file" ] && [ "$(tail -c1 "$file"; echo x)" != $'\nx' ]; then - echo >> "$file" - fi - - if grep -q "^$var_name=" "$file"; then - # Use sed with backup extension for compatibility - sed -i.bak "s/^$var_name=.*/$var_name=$var_value/" "$file" - # Remove backup file - rm -f "$file.bak" - else - echo "$var_name=$var_value" >> "$file" - fi - } - - GIT_REPO_NAME=$(basename -s .git "$(git config --get remote.origin.url 2>/dev/null || echo "unknown-repo")") - update_or_append "GIT_REPO_NAME" "$GIT_REPO_NAME" - - GIT_REF=$(git symbolic-ref -q --short HEAD 2>/dev/null || git rev-parse HEAD 2>/dev/null || echo "unknown-ref") - update_or_append "GIT_REF" "$GIT_REF" - - GIT_SHA=$(git rev-parse HEAD 2>/dev/null || echo "unknown-sha") - update_or_append "GIT_SHA" "$GIT_SHA" - - GIT_SHA_SHORT=$(git rev-parse --short HEAD 2>/dev/null || echo "unknown") - update_or_append "GIT_SHA_SHORT" "$GIT_SHA_SHORT" - ''; - }; - }; -} diff --git a/nix/modules/overrides.nix b/nix/modules/overrides.nix deleted file mode 100644 index e3dd66e..0000000 --- a/nix/modules/overrides.nix +++ /dev/null @@ -1,60 +0,0 @@ -{ - inputs, - ... -}: -{ - perSystem = - { - config, - self', - pkgs, - lib, - ... - }: - let - # Function to create package-specific overrides - mkPackageOverrides = - { pkgs }: - final: prev: { - # Example overrides for specific packages - # numpy = prev.numpy.overrideAttrs (old: { - # buildInputs = (old.buildInputs or []) ++ [ pkgs.openblas ]; - # }); - - # Example of fixing a package that needs specific build system dependencies - # tensorflow = prev.tensorflow.overrideAttrs (old: { - # nativeBuildInputs = (old.nativeBuildInputs or []) ++ [ - # (final.resolveBuildSystem { - # setuptools = []; - # wheel = []; - # numpy = []; - # }) - # ]; - # }); - }; - - # Function to create sdist-specific overrides - mkSdistOverrides = - { pkgs }: - final: prev: { - # Example overrides for source distributions - # pyzmq = prev.pyzmq.overrideAttrs (old: { - # buildInputs = (old.buildInputs or []) ++ [ pkgs.zeromq ]; - # nativeBuildInputs = (old.nativeBuildInputs or []) ++ [ - # (final.resolveBuildSystem { - # cmake = []; - # ninja = []; - # packaging = []; - # }) - # ]; - # }); - }; - in - { - # Expose the override functions for use in other modules - _module.args = { - packageOverrides = mkPackageOverrides { inherit pkgs; }; - sdistOverrides = mkSdistOverrides { inherit pkgs; }; - }; - }; -} diff --git a/nix/modules/packages.nix b/nix/modules/packages.nix deleted file mode 100644 index 56c4143..0000000 --- a/nix/modules/packages.nix +++ /dev/null @@ -1,41 +0,0 @@ -{ - inputs, - ... -}: -{ - perSystem = - { - config, - self', - pkgs, - lib, - packageWorkspaces, - pythonSets, - editablePythonSets, - pythonVersions, - ... - }: - let - # Merge deps from all independent package workspaces, unioning extras lists - # for shared dependency names rather than silently dropping via // - mergeWorkspaceDeps = - selector: - lib.foldlAttrs ( - acc: _: pkg: - lib.zipAttrsWith (_: values: lib.unique (lib.flatten values)) [ - acc - (selector pkg.workspace.deps) - ] - ) { } packageWorkspaces; - - defaultDeps = mergeWorkspaceDeps (deps: deps.default); - in - { - packages = rec { - pythonNixTemplate311 = pythonSets.py311.mkVirtualEnv "python-nix-template-3.11" defaultDeps; - pythonNixTemplate312 = pythonSets.py312.mkVirtualEnv "python-nix-template-3.12" defaultDeps; - - default = pythonNixTemplate312; - }; - }; -} diff --git a/nix/modules/pre-commit.nix b/nix/modules/pre-commit.nix deleted file mode 100644 index 352abaf..0000000 --- a/nix/modules/pre-commit.nix +++ /dev/null @@ -1,24 +0,0 @@ -{ inputs, ... }: -{ - imports = [ - (inputs.git-hooks + /flake-module.nix) - ]; - perSystem = - { - config, - self', - pkgs, - lib, - ... - }: - { - pre-commit.settings = { - hooks = { - nixfmt-rfc-style.enable = true; - ruff.enable = true; - ruff-format.enable = true; - taplo.enable = true; - }; - }; - }; -} diff --git a/nix/modules/python.nix b/nix/modules/python.nix deleted file mode 100644 index 33e53c4..0000000 --- a/nix/modules/python.nix +++ /dev/null @@ -1,133 +0,0 @@ -{ - inputs, - ... -}: -{ - perSystem = - { - config, - self', - pkgs, - lib, - packageOverrides ? (_: _: { }), - sdistOverrides ? (_: _: { }), - ... - }: - let - pythonVersions = { - py311 = pkgs.python311; - py312 = pkgs.python312; - }; - - # Load each Python package independently (no root workspace). - # Each package directory contains its own pyproject.toml and uv.lock, - # resolved independently following the LangChain federation model. - loadPackage = - name: path: - let - workspace = inputs.uv2nix.lib.workspace.loadWorkspace { - workspaceRoot = path; - }; - in - { - inherit workspace; - overlay = workspace.mkPyprojectOverlay { - sourcePreference = "wheel"; - }; - editableOverlay = workspace.mkEditablePyprojectOverlay { - root = "$REPO_ROOT"; - }; - }; - - packageWorkspaces = { - pnt-cli = loadPackage "pnt-cli" ../../packages/pnt-cli; - pnt-functional = loadPackage "pnt-functional" ../../packages/pnt-functional; - python-nix-template = loadPackage "python-nix-template" ../../packages/python-nix-template; - }; - - # Per-package Nix modules with optional Rust overlays. - # Packages with Rust extensions get a dedicated module in nix/packages/ - # that encapsulates crane configuration and exports an overlay + checks. - mkPackageModule = - python: - import ../packages/pnt-cli { - inherit pkgs lib python; - crane = inputs.crane; - }; - - # Compose per-package uv2nix overlays with shared overrides. - # - # Invariant: all federated packages must resolve compatible versions for - # shared dependencies. Per-package uv2nix overlays are composed sequentially - # into a single package set — if two packages resolve different versions of - # the same dependency, the later overlay silently wins. Enforce version - # alignment across packages by running: - # uv lock --check - # in each package directory after updating any shared dependency. - mkPythonSet = - python: - (pkgs.callPackage inputs.pyproject-nix.build.packages { - inherit python; - }).overrideScope - ( - lib.composeManyExtensions [ - inputs.pyproject-build-systems.overlays.default - packageWorkspaces.pnt-cli.overlay - packageWorkspaces.pnt-functional.overlay - packageWorkspaces.python-nix-template.overlay - # Rust integration overlay for pnt-cli (crane + maturin) - (mkPackageModule python).overlay - packageOverrides - sdistOverrides - ] - ); - - # Editable set excludes pnt-cli: maturin packages are incompatible with - # uv2nix's editable overlay (pyprojectFixupEditableHook expects EDITABLE_ROOT - # which maturin's build process does not set). pnt-cli is built as a regular - # wheel in the devshell; use `maturin develop` for iterative Rust development. - mkEditablePythonSet = - python: - (mkPythonSet python).overrideScope ( - lib.composeManyExtensions [ - packageWorkspaces.pnt-functional.editableOverlay - packageWorkspaces.python-nix-template.editableOverlay - (final: prev: { - python-nix-template = prev.python-nix-template.overrideAttrs (old: { - nativeBuildInputs = - old.nativeBuildInputs - ++ final.resolveBuildSystem { - editables = [ ]; - }; - }); - pnt-functional = prev.pnt-functional.overrideAttrs (old: { - nativeBuildInputs = - old.nativeBuildInputs - ++ final.resolveBuildSystem { - editables = [ ]; - }; - }); - }) - ] - ); - - pythonSets = lib.mapAttrs (_: mkPythonSet) pythonVersions; - editablePythonSets = lib.mapAttrs (_: mkEditablePythonSet) pythonVersions; - - # Rust checks from per-package modules (using default Python version) - rustChecks = (mkPackageModule pythonVersions.py312).checks; - in - { - checks = rustChecks; - - _module.args = { - inherit - packageWorkspaces - pythonSets - editablePythonSets - pythonVersions - ; - defaultPython = pythonVersions.py312; - }; - }; -} diff --git a/nix/modules/template-rename.nix b/nix/modules/template-rename.nix deleted file mode 100644 index 6af3217..0000000 --- a/nix/modules/template-rename.nix +++ /dev/null @@ -1,97 +0,0 @@ -{ - inputs, - lib, - config, - pkgs, - ... -}: - -{ - perSystem = - { system, pkgs, ... }: - { - packages.fix-template-names = pkgs.writeShellApplication { - name = "fix-template-names"; - runtimeInputs = with pkgs; [ - coreutils - gnused - gnugrep - findutils - file - ]; - text = '' - #!/usr/bin/env bash - - set -euo pipefail - - # Colors for output - GREEN='\033[0;32m' - YELLOW='\033[1;33m' - RED='\033[0;31m' - NC='\033[0m' # No Color - - # Get the current directory name as default new name - DEFAULT_NEW_NAME=$(basename "$(pwd)") - # Convert to underscore version - DEFAULT_NEW_UNDERSCORE=$(echo "$DEFAULT_NEW_NAME" | tr '-' '_') - - # Check for required arguments - if [ $# -lt 1 ]; then - echo -e "''${RED}Error: Missing required argument.''${NC}" - echo "Usage: fix-template-names OLD_NAME [NEW_NAME]" - echo "OLD_NAME: The original template name to be replaced" - echo "NEW_NAME: The new name to use (optional, defaults to current directory name: $DEFAULT_NEW_NAME)" - exit 1 - fi - - # Set old name from first argument - OLD_NAME="$1" - # Convert to underscore version - OLD_UNDERSCORE=$(echo "$OLD_NAME" | tr '-' '_') - - # Use second command line argument if provided, otherwise use defaults - if [ $# -eq 2 ]; then - NEW_NAME="$2" - # Convert to underscore version - NEW_UNDERSCORE=$(echo "$NEW_NAME" | tr '-' '_') - else - NEW_NAME="$DEFAULT_NEW_NAME" - NEW_UNDERSCORE="$DEFAULT_NEW_UNDERSCORE" - fi - - echo -e "''${YELLOW}Starting replacement of template names...''${NC}" - echo -e "''${YELLOW}Replacing $OLD_NAME with $NEW_NAME''${NC}" - echo -e "''${YELLOW}Replacing $OLD_UNDERSCORE with $NEW_UNDERSCORE''${NC}" - - # Find all text files in the project (excluding .git, node_modules, and other common directories to ignore) - # and replace the strings in-place - find . -type f \ - -not -path "*/\.*" \ - -not -path "*/node_modules/*" \ - -not -path "*/venv/*" \ - -not -path "*/build/*" \ - -not -path "*/dist/*" \ - -not -path "*/\__pycache__/*" \ - -exec grep -l "$OLD_NAME\|$OLD_UNDERSCORE" {} \; | while read -r file; do - echo "Processing: $file" - - # Check if file is binary - if file "$file" | grep -q "binary"; then - echo " Skipping binary file" - continue - fi - - # Make replacements - sed -i.bak "s/$OLD_NAME/$NEW_NAME/g" "$file" - sed -i.bak "s/$OLD_UNDERSCORE/$NEW_UNDERSCORE/g" "$file" - - # Remove backup files - rm -f "''${file}.bak" - done - - echo -e "''${GREEN}Replacement complete!''${NC}" - echo -e "''${YELLOW}Note: You may need to rebuild or reinstall your package after these changes.''${NC}" - ''; - }; - }; -} diff --git a/nix/modules/template.nix b/nix/modules/template.nix deleted file mode 100644 index f1caa33..0000000 --- a/nix/modules/template.nix +++ /dev/null @@ -1,148 +0,0 @@ -{ inputs, ... }: - -{ - flake = rec { - templates.default = { - description = "A Python project template for Nix using uv2nix and flake-parts"; - path = builtins.path { path = inputs.self; }; - welcomeText = '' - Welcome to the python-nix-template! - - NOTE: If you're reusing a preexisting directory for PROJECT_DIRECTORY you - may need to run `direnv revoke $PROJECT_DIRECTORY` to unload the environment - before proceeding. - - Otherwise, don't forget to `cd` into your new project directory. - - If you do not have nix and direnv installed, check - - ```bash - make -n bootstrap - ``` - - and rerun without the `-n` if you are comfortable with the commands. Otherwise, - manually install the nix package manager and direnv. - - In order to recognize the `flake.nix` and associated files, create a git - repository, stage the files, and run `direnv allow` to load the environment. - You might need to run `direnv revoke` first if you're reusing a directory - where you have previously run `direnv allow`. - - You can copy and paste - - ```bash - git init && git commit --allow-empty -m "initial commit (empty)" && git add . && direnv allow - ``` - - or, if you prefer, run the commands manually to verify or modify them - - ```bash - ❯ git init - Initialized empty Git repository in ... - - ❯ git commit --allow-empty -m "initial commit (empty)" - [main (root-commit) bba59e7] initial commit (empty) - - ❯ git add . - - ❯ direnv allow - ``` - - You should then be able to run `pytest` to verify the project is working. - See the README for more information. - ''; - }; - - # https://omnix.page/om/init.html#spec - om.templates.python-nix-template = { - template = templates.default; - params = [ - { - name = "package-name-kebab-case"; - description = "Name of the Python package (kebab-case)"; - placeholder = "python-nix-template"; - } - { - name = "package-name-snake-case"; - description = "Name of the Python package (snake_case)"; - placeholder = "python_nix_template"; - } - { - name = "monorepo-package"; - description = "Include the functional programming monorepo package in the project"; - paths = [ "packages/pnt-functional" ]; - value = false; - } - { - name = "git-org"; - description = "GitHub organization or user name"; - placeholder = "sciexp"; - } - { - name = "author"; - description = "Author name"; - placeholder = "Your Name"; - } - { - name = "author-email"; - description = "Author email"; - placeholder = "your.email@example.com"; - } - { - name = "project-description"; - description = "Project description for documentation"; - placeholder = "A Python project template for Nix using uv2nix and flake-parts"; - } - { - name = "vscode"; - description = "Include the VSCode settings folder (./.vscode)"; - paths = [ ".vscode" ]; - value = true; - } - { - name = "github-ci"; - description = "Include GitHub Actions workflow configuration"; - paths = [ ".github" ]; - value = true; - } - { - name = "docs"; - description = "Include documentation site infrastructure (MkDocs + Cloudflare deployment)"; - paths = [ - "docs" - ".github/workflows/deploy-docs.yaml" - ]; - value = true; - } - { - name = "nix-template"; - description = "Keep the flake template in the project"; - paths = [ - "**/template.nix" - ".github/workflows/template.yaml" - ]; - value = false; - } - ]; - tests = { - default = { - params = { - package-name = "awesome-package"; - author = "John Doe"; - author-email = "john@example.com"; - }; - asserts = { - source = { - "pyproject.toml" = true; - "flake.nix" = true; - ".github/workflows/ci.yaml" = true; - ".vscode" = true; - "nix/modules/template.nix" = false; - }; - packages.default = { }; - }; - }; - }; - }; - }; -} From 8cc8df2a682ae94266ac3e4f4d1bc8b97d3d8265 Mon Sep 17 00:00:00 2001 From: Cameron Smith Date: Tue, 3 Feb 2026 10:30:53 -0500 Subject: [PATCH 132/134] refactor(nix): replace readDir with import-tree for module discovery --- flake.nix | 17 ++--------------- 1 file changed, 2 insertions(+), 15 deletions(-) diff --git a/flake.nix b/flake.nix index 59dbff5..75278cb 100644 --- a/flake.nix +++ b/flake.nix @@ -58,19 +58,6 @@ }; outputs = - inputs@{ - self, - flake-parts, - nixpkgs, - ... - }: - flake-parts.lib.mkFlake { inherit inputs; } { - # https://github.com/NixOS/nixpkgs/blob/24.05/lib/systems/flake-systems.nix - # systems = nixpkgs.lib.systems.flakeExposed; # tiered list of feasible systems - # https://github.com/nix-systems/default # plausible systems - # systems = [ "aarch64-darwin" "aarch64-linux" "x86_64-darwin" "x86_64-linux" ]; - systems = import inputs.systems; - - imports = with builtins; map (fn: ./nix/modules/${fn}) (attrNames (readDir ./nix/modules)); - }; + inputs@{ flake-parts, ... }: + flake-parts.lib.mkFlake { inherit inputs; } (inputs.import-tree ./modules); } From 25fcac8b85631ba3684b46061a701a8b48e5c96c Mon Sep 17 00:00:00 2001 From: Cameron Smith Date: Tue, 3 Feb 2026 10:31:45 -0500 Subject: [PATCH 133/134] chore(beads): close pnt-j6f after dendritic migration --- .beads/issues.jsonl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.beads/issues.jsonl b/.beads/issues.jsonl index 3d3e7c7..ce26644 100644 --- a/.beads/issues.jsonl +++ b/.beads/issues.jsonl @@ -15,7 +15,7 @@ {"id":"pnt-dre.4","title":"Implement cached-ci-job composite action pattern","description":"Add .github/actions/cached-ci-job composite action following typescript-nix-template pattern. Content-addressed caching with hash-sources and force-run support. Update CI to use category-based matrix builds.\n\nPost-federation CI adaptation: the migration from uv workspace to per-package independent locks (pnt-4jg.1) means CI must now discover and iterate packages under packages/. The matrix strategy needs a package axis in addition to the category axis, producing either a {package} x {category} matrix or per-package reusable workflow dispatches. Review how ci.yaml currently enumerates packages and ensure the composite action pattern supports per-package resolution of lock files, dependency caches, and build artifacts.\n\nAcceptance criteria:\n- .github/actions/cached-ci-job composite action implemented\n- Content-addressed caching with hash-sources and force-run support\n- CI matrix discovers packages/ dynamically (not hardcoded)\n- Matrix crosses package x category dimensions\n- Per-package uv.lock files used for cache keys (not root lock)\n- Category-based builds follow typescript-nix-template pattern","status":"closed","priority":2,"issue_type":"task","owner":"cameron.ray.smith@gmail.com","created_at":"2026-01-19T11:54:56.79376-05:00","created_by":"Cameron Smith","updated_at":"2026-02-02T15:55:30.748155-05:00","closed_at":"2026-02-02T15:55:30.748155-05:00","close_reason":"Implemented cached-ci-job composite action (ported from typescript-nix-template), per-package CI justfile recipes (ci-sync, ci-lint, ci-test, ci-typecheck, ci-check, list-packages-json), rewrote python-test.yaml to use nix develop -c just \u003crecipe\u003e, added dynamic package discovery and force_run to ci.yaml. All CI steps expressible as nix develop -c just \u003crecipe\u003e.","dependencies":[{"issue_id":"pnt-dre.4","depends_on_id":"pnt-dre","type":"parent-child","created_at":"2026-01-19T11:54:56.794334-05:00","created_by":"Cameron Smith"}],"comments":[{"id":2,"issue_id":"pnt-dre.4","author":"Cameron Smith","text":"Minimal CI path fixes applied in d0cab2a as part of pnt-4jg.1 fixups: cache-dependency-glob updated to packages/*/uv.lock, uv sync/lint/test moved into per-package working-directory, ci.yaml path filters updated.\n\nRemaining for pnt-dre.4: replace setup-python/setup-uv actions with nix develop -c just \u003crecipe\u003e pattern, add justfile recipes for per-package sync/test/lint/typecheck, implement cached-ci-job composite action, dynamic package discovery.","created_at":"2026-02-02T20:17:02Z"}]} {"id":"pnt-dre.5","title":"Add omnix template integration","description":"Configure om.templates in flake with parameter definitions. Add template-verify justfile recipe. Create .github/workflows/template.yaml for CI validation.","status":"closed","priority":2,"issue_type":"task","owner":"cameron.ray.smith@gmail.com","created_at":"2026-01-19T11:54:57.668262-05:00","created_by":"Cameron Smith","updated_at":"2026-02-02T15:56:15.624906-05:00","closed_at":"2026-02-02T15:56:15.624906-05:00","close_reason":"om.templates, template-verify recipe, and template.yaml workflow already existed. Fixed stale path-ignore filters for per-package lock pattern.","dependencies":[{"issue_id":"pnt-dre.5","depends_on_id":"pnt-dre","type":"parent-child","created_at":"2026-01-19T11:54:57.66888-05:00","created_by":"Cameron Smith"}]} {"id":"pnt-edl","title":"Modernize nix module architecture and template validation","description":"Migrate python-nix-template to dendritic flake-parts architecture (import-tree) matching vanixiets, ironstar, and typescript-nix-template conventions. Fix template.yaml workflow to properly validate instantiated templates including PyO3/maturin extensions.\n\nMotivation: Current nix/modules/ uses hand-rolled readDir discovery instead of import-tree. Template CI test (test-omnix-template) fails because it runs nix develop -c pytest which cannot load PyO3 _native extension (maturin packages are excluded from editableOverlay by design). Both issues block PR #44 from being fully validated.\n\nReference implementations:\n- vanixiets: modules/ with import-tree, 200+ auto-discovered modules\n- ironstar: modules/ with import-tree, crane for Rust builds\n- typescript-nix-template: modules/ with import-tree, two-variant template testing\n\nSequencing: Migration first (structural), then template workflow fix (validation). Template test depends on knowing the final module layout.","status":"open","priority":2,"issue_type":"epic","owner":"cameron.ray.smith@gmail.com","created_at":"2026-02-03T10:09:57.390595-05:00","created_by":"Cameron Smith","updated_at":"2026-02-03T10:09:57.390595-05:00"} -{"id":"pnt-j6f","title":"Migrate to dendritic flake-parts with import-tree","description":"Restructure nix module architecture to match reference implementations (vanixiets, ironstar, typescript-nix-template).\n\nChanges required:\n- Add import-tree as flake input (github:vic/import-tree or equivalent)\n- Move nix/modules/*.nix to modules/*.nix (top-level)\n- Replace readDir-based discovery in flake.nix with: flake-parts.lib.mkFlake { inherit inputs; } (inputs.import-tree ./modules)\n- Add systems.nix module (extract system list from flake.nix)\n- Add flake-parts.nix module (external module imports like nix-unit)\n- Keep nix/packages/pnt-cli/ and nix/lib/ as non-module utilities (imported explicitly by python.nix)\n- Update all relative paths in modules that reference nix/packages/ or nix/lib/ (now one level up)\n- containers.nix is 355 lines — evaluate splitting into containers/dev.nix and containers/production.nix\n- Update template.nix conditional paths to reflect new module locations\n- Verify nix flake check passes after restructure\n- Update .github/workflows/ path filters if they reference nix/modules/\n\nKey architectural decisions:\n- Modules communicate through _module.args (python.nix exports) and config namespace (pre-commit.devShell)\n- import-tree auto-discovers all .nix files in modules/ tree\n- No manual imports list in flake.nix — adding a file to modules/ auto-includes it\n- nix/packages/ stays as explicit utility imports (not auto-discovered modules)","status":"open","priority":2,"issue_type":"task","owner":"cameron.ray.smith@gmail.com","created_at":"2026-02-03T10:10:03.187287-05:00","created_by":"Cameron Smith","updated_at":"2026-02-03T10:10:03.187287-05:00","dependencies":[{"issue_id":"pnt-j6f","depends_on_id":"pnt-edl","type":"child-of","created_at":"2026-02-03T10:10:17.67297-05:00","created_by":"Cameron Smith"}]} +{"id":"pnt-j6f","title":"Migrate to dendritic flake-parts with import-tree","description":"Restructure nix module architecture to match reference implementations (vanixiets, ironstar, typescript-nix-template).\n\nChanges required:\n- Add import-tree as flake input (github:vic/import-tree or equivalent)\n- Move nix/modules/*.nix to modules/*.nix (top-level)\n- Replace readDir-based discovery in flake.nix with: flake-parts.lib.mkFlake { inherit inputs; } (inputs.import-tree ./modules)\n- Add systems.nix module (extract system list from flake.nix)\n- Add flake-parts.nix module (external module imports like nix-unit)\n- Keep nix/packages/pnt-cli/ and nix/lib/ as non-module utilities (imported explicitly by python.nix)\n- Update all relative paths in modules that reference nix/packages/ or nix/lib/ (now one level up)\n- containers.nix is 355 lines — evaluate splitting into containers/dev.nix and containers/production.nix\n- Update template.nix conditional paths to reflect new module locations\n- Verify nix flake check passes after restructure\n- Update .github/workflows/ path filters if they reference nix/modules/\n\nKey architectural decisions:\n- Modules communicate through _module.args (python.nix exports) and config namespace (pre-commit.devShell)\n- import-tree auto-discovers all .nix files in modules/ tree\n- No manual imports list in flake.nix — adding a file to modules/ auto-includes it\n- nix/packages/ stays as explicit utility imports (not auto-discovered modules)","status":"in_progress","priority":2,"issue_type":"task","owner":"cameron.ray.smith@gmail.com","created_at":"2026-02-03T10:10:03.187287-05:00","created_by":"Cameron Smith","updated_at":"2026-02-03T10:26:41.701696-05:00","dependencies":[{"issue_id":"pnt-j6f","depends_on_id":"pnt-edl","type":"child-of","created_at":"2026-02-03T10:10:17.67297-05:00","created_by":"Cameron Smith"}]} {"id":"pnt-m1w","title":"Fix template.yaml workflow for proper PyO3 and multi-variant validation","description":"Align template.yaml with typescript-nix-template patterns and fix the test-omnix-template job that currently fails with ModuleNotFoundError for pnt_cli._native and pnt_functional.\n\nRoot cause: The current test runs nix develop -c pytest on instantiated template, but:\n- pnt-cli PyO3 _native extension is excluded from editableOverlay (maturin incompatible)\n- pnt-functional is not on PYTHONPATH in nix develop without editable overlay\n- This fails both in CI and locally — it is a fundamental workflow gap\n\nFix approach (align with typescript-nix-template):\n- Replace nix develop -c pytest with nix flake check --accept-flake-config\n- nix flake check exercises all Nix builds including maturin wheel, validating PyO3 integration\n- Add set-variables job (debug flags, skip-ci, checkout details)\n- Test TWO variants matching monorepo-package boolean parameter:\n 1. Full monorepo (monorepo-package=true): includes pnt-functional + pnt-cli\n 2. Single package (monorepo-package=false): main package only\n- Fix cachix reference: instantiated template tries pnt-mono.cachix.org which 401s (expected for fresh project, but should be parameterized or removed)\n- Consider adding lightweight smoke test after flake check: nix develop -c python -c 'import pnt_mono'\n- Add cached-ci-job composite action if available in .github/actions/\n\nReference: typescript-nix-template .github/workflows/template.yaml tests full and minimal variants with git init, bun install, nix flake check sequence.","status":"open","priority":2,"issue_type":"task","owner":"cameron.ray.smith@gmail.com","created_at":"2026-02-03T10:10:08.916223-05:00","created_by":"Cameron Smith","updated_at":"2026-02-03T10:10:08.916223-05:00","dependencies":[{"issue_id":"pnt-m1w","depends_on_id":"pnt-edl","type":"child-of","created_at":"2026-02-03T10:10:17.838035-05:00","created_by":"Cameron Smith"},{"issue_id":"pnt-m1w","depends_on_id":"pnt-j6f","type":"blocked-by","created_at":"2026-02-03T10:10:18.005313-05:00","created_by":"Cameron Smith"},{"issue_id":"pnt-m1w","depends_on_id":"pnt-3qp","type":"blocked-by","created_at":"2026-02-03T10:20:21.254918-05:00","created_by":"Cameron Smith"}]} {"id":"pnt-m3t","title":"Adopt setup-nix composite action with nothing-but-nix pattern","description":"Port the vanixiets setup-nix composite action to python-nix-template, replacing inline Nix installation across all workflows.\n\nCurrent state:\n- ci.yaml, python-test.yaml, build-nix-images.yaml each inline DeterminateSystems/nix-installer-action\n- build-nix-images.yaml uses ad-hoc maximize-build-space shell script\n- scripts/ci/maximize-build-space.sh exists but is not wired into workflows\n\nTarget state (matching vanixiets):\n- .github/actions/setup-nix/action.yml composite action\n- Uses wimpysworld/nothing-but-nix for space reclamation (replaces maximize-build-space.sh)\n- Uses cachix/install-nix-action with pinned Nix version\n- Configures build-dir = /nix/build (nothing-but-nix workaround)\n- Integrates magic-nix-cache and cachix setup\n- Hatchet protocol support for configurable space levels\n- All workflows delegate Nix setup to this single action\n\nAcceptance criteria:\n- .github/actions/setup-nix/action.yml implemented (port from vanixiets)\n- ci.yaml nixci job uses setup-nix action\n- python-test.yaml uses setup-nix action\n- build-nix-images.yaml uses setup-nix action (replaces inline maximize-build-space)\n- .github/actions/build-nix-image/ updated (its Nix install steps replaced by setup-nix)\n- scripts/ci/maximize-build-space.sh removed (superseded by nothing-but-nix)\n- setup-python-uv action evaluated for removal (if all Python CI runs via nix develop)\n\nReference: ~/projects/nix-workspace/vanixiets/.github/actions/setup-nix/action.yml","status":"closed","priority":2,"issue_type":"task","owner":"cameron.ray.smith@gmail.com","created_at":"2026-02-02T20:24:06.14337-05:00","created_by":"Cameron Smith","updated_at":"2026-02-02T21:16:20.627824-05:00","closed_at":"2026-02-02T21:16:20.627824-05:00","close_reason":"Implemented in 0b1e4fa, setup-nix action ported from vanixiets"} {"id":"pnt-mgq","title":"Migrate dev containers to nix2container via upgraded nixpod","description":"Update the dev container builds (containerImage, devcontainerImage) to use nix2container once nixpod itself has completed its nix2container migration.\n\nCurrent state:\n- nix/modules/containers.nix imports buildMultiUserNixImage from nixpod\n- nixpod uses dockerTools.buildLayeredImageWithNixDb internally\n- flocken handles multi-arch manifest creation for dev containers\n- Dev containers include multi-user Nix daemon, home-manager activation, s6-overlay\n\nBlocked on: nixpod completing its nix2container migration (refactor-container-builds branch has research docs with full API mapping and implementation plan)\n\nTarget state:\n- nixpod exports nix2container-based builders (buildMultiUserNixImage rewritten internally)\n- python-nix-template's dev containers consume upgraded nixpod\n- Dev container manifests use crane-based tooling (from pnt-5vr production container work)\n- s6-overlay, home-manager activation, multi-user Nix preserved in container content\n\nAcceptance criteria:\n- Dev containers build using nixpod's nix2container-based API\n- flocken fully removed from flake.nix (production containers handled by pnt-5vr)\n- No regression in dev container functionality (Jupyter, code-server, etc.)\n- Multi-arch publishing works via nix2container transport\n\nReference: ~/projects/nix-workspace/nixpod-home/docs/notes/development/container-build-refactoring.md\nReference: ~/projects/nix-workspace/nixpod-home/containers/nix.nix","status":"open","priority":2,"issue_type":"task","owner":"cameron.ray.smith@gmail.com","created_at":"2026-02-02T21:47:38.830624-05:00","created_by":"Cameron Smith","updated_at":"2026-02-02T21:47:38.830624-05:00"} From 6f61ab04800d3f971b0f2b08387d586f1503410f Mon Sep 17 00:00:00 2001 From: Cameron Smith Date: Tue, 3 Feb 2026 10:31:54 -0500 Subject: [PATCH 134/134] chore(beads): close pnt-j6f after dendritic migration --- .beads/issues.jsonl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.beads/issues.jsonl b/.beads/issues.jsonl index ce26644..7f39b35 100644 --- a/.beads/issues.jsonl +++ b/.beads/issues.jsonl @@ -15,7 +15,7 @@ {"id":"pnt-dre.4","title":"Implement cached-ci-job composite action pattern","description":"Add .github/actions/cached-ci-job composite action following typescript-nix-template pattern. Content-addressed caching with hash-sources and force-run support. Update CI to use category-based matrix builds.\n\nPost-federation CI adaptation: the migration from uv workspace to per-package independent locks (pnt-4jg.1) means CI must now discover and iterate packages under packages/. The matrix strategy needs a package axis in addition to the category axis, producing either a {package} x {category} matrix or per-package reusable workflow dispatches. Review how ci.yaml currently enumerates packages and ensure the composite action pattern supports per-package resolution of lock files, dependency caches, and build artifacts.\n\nAcceptance criteria:\n- .github/actions/cached-ci-job composite action implemented\n- Content-addressed caching with hash-sources and force-run support\n- CI matrix discovers packages/ dynamically (not hardcoded)\n- Matrix crosses package x category dimensions\n- Per-package uv.lock files used for cache keys (not root lock)\n- Category-based builds follow typescript-nix-template pattern","status":"closed","priority":2,"issue_type":"task","owner":"cameron.ray.smith@gmail.com","created_at":"2026-01-19T11:54:56.79376-05:00","created_by":"Cameron Smith","updated_at":"2026-02-02T15:55:30.748155-05:00","closed_at":"2026-02-02T15:55:30.748155-05:00","close_reason":"Implemented cached-ci-job composite action (ported from typescript-nix-template), per-package CI justfile recipes (ci-sync, ci-lint, ci-test, ci-typecheck, ci-check, list-packages-json), rewrote python-test.yaml to use nix develop -c just \u003crecipe\u003e, added dynamic package discovery and force_run to ci.yaml. All CI steps expressible as nix develop -c just \u003crecipe\u003e.","dependencies":[{"issue_id":"pnt-dre.4","depends_on_id":"pnt-dre","type":"parent-child","created_at":"2026-01-19T11:54:56.794334-05:00","created_by":"Cameron Smith"}],"comments":[{"id":2,"issue_id":"pnt-dre.4","author":"Cameron Smith","text":"Minimal CI path fixes applied in d0cab2a as part of pnt-4jg.1 fixups: cache-dependency-glob updated to packages/*/uv.lock, uv sync/lint/test moved into per-package working-directory, ci.yaml path filters updated.\n\nRemaining for pnt-dre.4: replace setup-python/setup-uv actions with nix develop -c just \u003crecipe\u003e pattern, add justfile recipes for per-package sync/test/lint/typecheck, implement cached-ci-job composite action, dynamic package discovery.","created_at":"2026-02-02T20:17:02Z"}]} {"id":"pnt-dre.5","title":"Add omnix template integration","description":"Configure om.templates in flake with parameter definitions. Add template-verify justfile recipe. Create .github/workflows/template.yaml for CI validation.","status":"closed","priority":2,"issue_type":"task","owner":"cameron.ray.smith@gmail.com","created_at":"2026-01-19T11:54:57.668262-05:00","created_by":"Cameron Smith","updated_at":"2026-02-02T15:56:15.624906-05:00","closed_at":"2026-02-02T15:56:15.624906-05:00","close_reason":"om.templates, template-verify recipe, and template.yaml workflow already existed. Fixed stale path-ignore filters for per-package lock pattern.","dependencies":[{"issue_id":"pnt-dre.5","depends_on_id":"pnt-dre","type":"parent-child","created_at":"2026-01-19T11:54:57.66888-05:00","created_by":"Cameron Smith"}]} {"id":"pnt-edl","title":"Modernize nix module architecture and template validation","description":"Migrate python-nix-template to dendritic flake-parts architecture (import-tree) matching vanixiets, ironstar, and typescript-nix-template conventions. Fix template.yaml workflow to properly validate instantiated templates including PyO3/maturin extensions.\n\nMotivation: Current nix/modules/ uses hand-rolled readDir discovery instead of import-tree. Template CI test (test-omnix-template) fails because it runs nix develop -c pytest which cannot load PyO3 _native extension (maturin packages are excluded from editableOverlay by design). Both issues block PR #44 from being fully validated.\n\nReference implementations:\n- vanixiets: modules/ with import-tree, 200+ auto-discovered modules\n- ironstar: modules/ with import-tree, crane for Rust builds\n- typescript-nix-template: modules/ with import-tree, two-variant template testing\n\nSequencing: Migration first (structural), then template workflow fix (validation). Template test depends on knowing the final module layout.","status":"open","priority":2,"issue_type":"epic","owner":"cameron.ray.smith@gmail.com","created_at":"2026-02-03T10:09:57.390595-05:00","created_by":"Cameron Smith","updated_at":"2026-02-03T10:09:57.390595-05:00"} -{"id":"pnt-j6f","title":"Migrate to dendritic flake-parts with import-tree","description":"Restructure nix module architecture to match reference implementations (vanixiets, ironstar, typescript-nix-template).\n\nChanges required:\n- Add import-tree as flake input (github:vic/import-tree or equivalent)\n- Move nix/modules/*.nix to modules/*.nix (top-level)\n- Replace readDir-based discovery in flake.nix with: flake-parts.lib.mkFlake { inherit inputs; } (inputs.import-tree ./modules)\n- Add systems.nix module (extract system list from flake.nix)\n- Add flake-parts.nix module (external module imports like nix-unit)\n- Keep nix/packages/pnt-cli/ and nix/lib/ as non-module utilities (imported explicitly by python.nix)\n- Update all relative paths in modules that reference nix/packages/ or nix/lib/ (now one level up)\n- containers.nix is 355 lines — evaluate splitting into containers/dev.nix and containers/production.nix\n- Update template.nix conditional paths to reflect new module locations\n- Verify nix flake check passes after restructure\n- Update .github/workflows/ path filters if they reference nix/modules/\n\nKey architectural decisions:\n- Modules communicate through _module.args (python.nix exports) and config namespace (pre-commit.devShell)\n- import-tree auto-discovers all .nix files in modules/ tree\n- No manual imports list in flake.nix — adding a file to modules/ auto-includes it\n- nix/packages/ stays as explicit utility imports (not auto-discovered modules)","status":"in_progress","priority":2,"issue_type":"task","owner":"cameron.ray.smith@gmail.com","created_at":"2026-02-03T10:10:03.187287-05:00","created_by":"Cameron Smith","updated_at":"2026-02-03T10:26:41.701696-05:00","dependencies":[{"issue_id":"pnt-j6f","depends_on_id":"pnt-edl","type":"child-of","created_at":"2026-02-03T10:10:17.67297-05:00","created_by":"Cameron Smith"}]} +{"id":"pnt-j6f","title":"Migrate to dendritic flake-parts with import-tree","description":"Restructure nix module architecture to match reference implementations (vanixiets, ironstar, typescript-nix-template).\n\nChanges required:\n- Add import-tree as flake input (github:vic/import-tree or equivalent)\n- Move nix/modules/*.nix to modules/*.nix (top-level)\n- Replace readDir-based discovery in flake.nix with: flake-parts.lib.mkFlake { inherit inputs; } (inputs.import-tree ./modules)\n- Add systems.nix module (extract system list from flake.nix)\n- Add flake-parts.nix module (external module imports like nix-unit)\n- Keep nix/packages/pnt-cli/ and nix/lib/ as non-module utilities (imported explicitly by python.nix)\n- Update all relative paths in modules that reference nix/packages/ or nix/lib/ (now one level up)\n- containers.nix is 355 lines — evaluate splitting into containers/dev.nix and containers/production.nix\n- Update template.nix conditional paths to reflect new module locations\n- Verify nix flake check passes after restructure\n- Update .github/workflows/ path filters if they reference nix/modules/\n\nKey architectural decisions:\n- Modules communicate through _module.args (python.nix exports) and config namespace (pre-commit.devShell)\n- import-tree auto-discovers all .nix files in modules/ tree\n- No manual imports list in flake.nix — adding a file to modules/ auto-includes it\n- nix/packages/ stays as explicit utility imports (not auto-discovered modules)","status":"closed","priority":2,"issue_type":"task","owner":"cameron.ray.smith@gmail.com","created_at":"2026-02-03T10:10:03.187287-05:00","created_by":"Cameron Smith","updated_at":"2026-02-03T10:31:49.978228-05:00","closed_at":"2026-02-03T10:31:49.978228-05:00","close_reason":"Implemented in 25fcac8. Migrated nix/modules/ to modules/ with import-tree.","dependencies":[{"issue_id":"pnt-j6f","depends_on_id":"pnt-edl","type":"child-of","created_at":"2026-02-03T10:10:17.67297-05:00","created_by":"Cameron Smith"}]} {"id":"pnt-m1w","title":"Fix template.yaml workflow for proper PyO3 and multi-variant validation","description":"Align template.yaml with typescript-nix-template patterns and fix the test-omnix-template job that currently fails with ModuleNotFoundError for pnt_cli._native and pnt_functional.\n\nRoot cause: The current test runs nix develop -c pytest on instantiated template, but:\n- pnt-cli PyO3 _native extension is excluded from editableOverlay (maturin incompatible)\n- pnt-functional is not on PYTHONPATH in nix develop without editable overlay\n- This fails both in CI and locally — it is a fundamental workflow gap\n\nFix approach (align with typescript-nix-template):\n- Replace nix develop -c pytest with nix flake check --accept-flake-config\n- nix flake check exercises all Nix builds including maturin wheel, validating PyO3 integration\n- Add set-variables job (debug flags, skip-ci, checkout details)\n- Test TWO variants matching monorepo-package boolean parameter:\n 1. Full monorepo (monorepo-package=true): includes pnt-functional + pnt-cli\n 2. Single package (monorepo-package=false): main package only\n- Fix cachix reference: instantiated template tries pnt-mono.cachix.org which 401s (expected for fresh project, but should be parameterized or removed)\n- Consider adding lightweight smoke test after flake check: nix develop -c python -c 'import pnt_mono'\n- Add cached-ci-job composite action if available in .github/actions/\n\nReference: typescript-nix-template .github/workflows/template.yaml tests full and minimal variants with git init, bun install, nix flake check sequence.","status":"open","priority":2,"issue_type":"task","owner":"cameron.ray.smith@gmail.com","created_at":"2026-02-03T10:10:08.916223-05:00","created_by":"Cameron Smith","updated_at":"2026-02-03T10:10:08.916223-05:00","dependencies":[{"issue_id":"pnt-m1w","depends_on_id":"pnt-edl","type":"child-of","created_at":"2026-02-03T10:10:17.838035-05:00","created_by":"Cameron Smith"},{"issue_id":"pnt-m1w","depends_on_id":"pnt-j6f","type":"blocked-by","created_at":"2026-02-03T10:10:18.005313-05:00","created_by":"Cameron Smith"},{"issue_id":"pnt-m1w","depends_on_id":"pnt-3qp","type":"blocked-by","created_at":"2026-02-03T10:20:21.254918-05:00","created_by":"Cameron Smith"}]} {"id":"pnt-m3t","title":"Adopt setup-nix composite action with nothing-but-nix pattern","description":"Port the vanixiets setup-nix composite action to python-nix-template, replacing inline Nix installation across all workflows.\n\nCurrent state:\n- ci.yaml, python-test.yaml, build-nix-images.yaml each inline DeterminateSystems/nix-installer-action\n- build-nix-images.yaml uses ad-hoc maximize-build-space shell script\n- scripts/ci/maximize-build-space.sh exists but is not wired into workflows\n\nTarget state (matching vanixiets):\n- .github/actions/setup-nix/action.yml composite action\n- Uses wimpysworld/nothing-but-nix for space reclamation (replaces maximize-build-space.sh)\n- Uses cachix/install-nix-action with pinned Nix version\n- Configures build-dir = /nix/build (nothing-but-nix workaround)\n- Integrates magic-nix-cache and cachix setup\n- Hatchet protocol support for configurable space levels\n- All workflows delegate Nix setup to this single action\n\nAcceptance criteria:\n- .github/actions/setup-nix/action.yml implemented (port from vanixiets)\n- ci.yaml nixci job uses setup-nix action\n- python-test.yaml uses setup-nix action\n- build-nix-images.yaml uses setup-nix action (replaces inline maximize-build-space)\n- .github/actions/build-nix-image/ updated (its Nix install steps replaced by setup-nix)\n- scripts/ci/maximize-build-space.sh removed (superseded by nothing-but-nix)\n- setup-python-uv action evaluated for removal (if all Python CI runs via nix develop)\n\nReference: ~/projects/nix-workspace/vanixiets/.github/actions/setup-nix/action.yml","status":"closed","priority":2,"issue_type":"task","owner":"cameron.ray.smith@gmail.com","created_at":"2026-02-02T20:24:06.14337-05:00","created_by":"Cameron Smith","updated_at":"2026-02-02T21:16:20.627824-05:00","closed_at":"2026-02-02T21:16:20.627824-05:00","close_reason":"Implemented in 0b1e4fa, setup-nix action ported from vanixiets"} {"id":"pnt-mgq","title":"Migrate dev containers to nix2container via upgraded nixpod","description":"Update the dev container builds (containerImage, devcontainerImage) to use nix2container once nixpod itself has completed its nix2container migration.\n\nCurrent state:\n- nix/modules/containers.nix imports buildMultiUserNixImage from nixpod\n- nixpod uses dockerTools.buildLayeredImageWithNixDb internally\n- flocken handles multi-arch manifest creation for dev containers\n- Dev containers include multi-user Nix daemon, home-manager activation, s6-overlay\n\nBlocked on: nixpod completing its nix2container migration (refactor-container-builds branch has research docs with full API mapping and implementation plan)\n\nTarget state:\n- nixpod exports nix2container-based builders (buildMultiUserNixImage rewritten internally)\n- python-nix-template's dev containers consume upgraded nixpod\n- Dev container manifests use crane-based tooling (from pnt-5vr production container work)\n- s6-overlay, home-manager activation, multi-user Nix preserved in container content\n\nAcceptance criteria:\n- Dev containers build using nixpod's nix2container-based API\n- flocken fully removed from flake.nix (production containers handled by pnt-5vr)\n- No regression in dev container functionality (Jupyter, code-server, etc.)\n- Multi-arch publishing works via nix2container transport\n\nReference: ~/projects/nix-workspace/nixpod-home/docs/notes/development/container-build-refactoring.md\nReference: ~/projects/nix-workspace/nixpod-home/containers/nix.nix","status":"open","priority":2,"issue_type":"task","owner":"cameron.ray.smith@gmail.com","created_at":"2026-02-02T21:47:38.830624-05:00","created_by":"Cameron Smith","updated_at":"2026-02-02T21:47:38.830624-05:00"}