From c9f27c3f4754aa7f61f6f70a0425f2491dbeecbb Mon Sep 17 00:00:00 2001 From: fusion44 Date: Fri, 3 Jul 2026 15:30:17 +0200 Subject: [PATCH] chore(nix): migrate flake from poetry2nix to uv2nix The project switched from poetry to uv in 44385ca, but the flake still built everything through poetry2nix (an undeclared input resolved via the flake registry) and no longer evaluated against the uv-based pyproject.toml. - build packages.blitz-api as a uv2nix virtualenv from uv.lock (wheels preferred), keeping the bin/api entry point the NixOS module expects - replace the poetry dev shell with a uv-based tooling shell that mirrors devenv.nix - move click to the main dependencies: the api console script imports it at runtime, so a production install without the dev group would crash on startup - update the nixpkgs pin so the dev shell ships a uv that understands the current lockfile revision Co-Authored-By: Claude Fable 5 --- app/server.py | 2 +- flake.lock | 146 +++++++++++++++++------------------------------ flake.nix | 109 ++++++++++++++++++++++++----------- pyproject.toml | 3 +- requirements.txt | 1 + uv.lock | 4 +- 6 files changed, 133 insertions(+), 132 deletions(-) diff --git a/app/server.py b/app/server.py index 6f5f109..386b518 100644 --- a/app/server.py +++ b/app/server.py @@ -14,7 +14,7 @@ import click # isort:skip help="Set the ASGI 'root_path' for applications submounted below a given URL path.", ) def main(port, host, root_path): - """Launched with `poetry run api` at root level""" + """Launched with `uv run api` at root level""" p = "" if root_path is not None and root_path != "": diff --git a/flake.lock b/flake.lock index 6f2dd85..c713cb1 100644 --- a/flake.lock +++ b/flake.lock @@ -18,52 +18,13 @@ "type": "github" } }, - "flake-utils_2": { - "inputs": { - "systems": "systems_2" - }, - "locked": { - "lastModified": 1726560853, - "narHash": "sha256-X6rJYSESBVr3hBoH0WbKE5KvhPU5bloyZ2L4K60/fPQ=", - "owner": "numtide", - "repo": "flake-utils", - "rev": "c1dfcf08411b08f6b8615f7d8971a2bfa81d5e8a", - "type": "github" - }, - "original": { - "owner": "numtide", - "repo": "flake-utils", - "type": "github" - } - }, - "nix-github-actions": { - "inputs": { - "nixpkgs": [ - "poetry2nix", - "nixpkgs" - ] - }, - "locked": { - "lastModified": 1729742964, - "narHash": "sha256-B4mzTcQ0FZHdpeWcpDYPERtyjJd/NIuaQ9+BV1h+MpA=", - "owner": "nix-community", - "repo": "nix-github-actions", - "rev": "e04df33f62cdcf93d73e9a04142464753a16db67", - "type": "github" - }, - "original": { - "owner": "nix-community", - "repo": "nix-github-actions", - "type": "github" - } - }, "nixpkgs": { "locked": { - "lastModified": 1739446958, - "narHash": "sha256-+/bYK3DbPxMIvSL4zArkMX0LQvS7rzBKXnDXLfKyRVc=", + "lastModified": 1782723713, + "narHash": "sha256-oPXCU/SSUokcGaJREHibG1CBX3+s/W7orDWQOZDsEeQ=", "owner": "NixOS", "repo": "nixpkgs", - "rev": "2ff53fe64443980e139eaa286017f53f88336dd0", + "rev": "b5aa0fbd538984f6e3d201be0005b4463d8b09f8", "type": "github" }, "original": { @@ -73,28 +34,49 @@ "type": "github" } }, - "poetry2nix": { + "pyproject-build-systems": { "inputs": { - "flake-utils": "flake-utils_2", - "nix-github-actions": "nix-github-actions", "nixpkgs": [ "nixpkgs" ], - "systems": "systems_3", - "treefmt-nix": "treefmt-nix" + "pyproject-nix": [ + "pyproject-nix" + ], + "uv2nix": [ + "uv2nix" + ] }, "locked": { - "lastModified": 1746721691, - "narHash": "sha256-M01XrCCnM6/iTm5L4NYc0/GFJAnuxFsEsn9gdkB7pgY=", - "owner": "fusion44", - "repo": "poetry2nix", - "rev": "cc3336142abb08a2dd3eda202e572a26a39c68bc", + "lastModified": 1782093830, + "narHash": "sha256-6gmEVe69+KlRkZD4PEEV5xAlB9CB0Y9TiuEgQjDrKTQ=", + "owner": "pyproject-nix", + "repo": "build-system-pkgs", + "rev": "430680a19bc85a3bda55f12e4cc1a1aadcf2e478", "type": "github" }, "original": { - "owner": "fusion44", - "ref": "nb", - "repo": "poetry2nix", + "owner": "pyproject-nix", + "repo": "build-system-pkgs", + "type": "github" + } + }, + "pyproject-nix": { + "inputs": { + "nixpkgs": [ + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1782905613, + "narHash": "sha256-SvXJcAemihifkTn4BGvyE5K1FJX9bl4U8DQ5pqKvD0s=", + "owner": "pyproject-nix", + "repo": "pyproject.nix", + "rev": "7af23cfe91064865ecf2e835da28b45b3c6f49fd", + "type": "github" + }, + "original": { + "owner": "pyproject-nix", + "repo": "pyproject.nix", "type": "github" } }, @@ -102,7 +84,9 @@ "inputs": { "flake-utils": "flake-utils", "nixpkgs": "nixpkgs", - "poetry2nix": "poetry2nix" + "pyproject-build-systems": "pyproject-build-systems", + "pyproject-nix": "pyproject-nix", + "uv2nix": "uv2nix" } }, "systems": { @@ -120,54 +104,26 @@ "type": "github" } }, - "systems_2": { - "locked": { - "lastModified": 1681028828, - "narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=", - "owner": "nix-systems", - "repo": "default", - "rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e", - "type": "github" - }, - "original": { - "owner": "nix-systems", - "repo": "default", - "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" - } - }, - "treefmt-nix": { + "uv2nix": { "inputs": { "nixpkgs": [ - "poetry2nix", "nixpkgs" + ], + "pyproject-nix": [ + "pyproject-nix" ] }, "locked": { - "lastModified": 1730120726, - "narHash": "sha256-LqHYIxMrl/1p3/kvm2ir925tZ8DkI0KA10djk8wecSk=", - "owner": "numtide", - "repo": "treefmt-nix", - "rev": "9ef337e492a5555d8e17a51c911ff1f02635be15", + "lastModified": 1782810559, + "narHash": "sha256-loy132LKn8QfiPbFJhdTjm+yZG3zklyOQhVabLyx2l4=", + "owner": "pyproject-nix", + "repo": "uv2nix", + "rev": "2f698e4b5a3c6004edaf051543542f18a36afe77", "type": "github" }, "original": { - "owner": "numtide", - "repo": "treefmt-nix", + "owner": "pyproject-nix", + "repo": "uv2nix", "type": "github" } } diff --git a/flake.nix b/flake.nix index 10a15b1..8865e6a 100644 --- a/flake.nix +++ b/flake.nix @@ -4,68 +4,111 @@ inputs = { flake-utils.url = "github:numtide/flake-utils"; nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable"; + + pyproject-nix = { + url = "github:pyproject-nix/pyproject.nix"; + inputs.nixpkgs.follows = "nixpkgs"; + }; + + uv2nix = { + url = "github:pyproject-nix/uv2nix"; + inputs = { + pyproject-nix.follows = "pyproject-nix"; + nixpkgs.follows = "nixpkgs"; + }; + }; + + pyproject-build-systems = { + url = "github:pyproject-nix/build-system-pkgs"; + inputs = { + pyproject-nix.follows = "pyproject-nix"; + uv2nix.follows = "uv2nix"; + nixpkgs.follows = "nixpkgs"; + }; + }; }; outputs = { self, nixpkgs, flake-utils, - poetry2nix, + pyproject-nix, + uv2nix, + pyproject-build-systems, }: let name = "blitz-api"; + inherit (nixpkgs) lib; + + workspace = uv2nix.lib.workspace.loadWorkspace {workspaceRoot = ./.;}; + + # Prefer prebuilt binary wheels: building grpcio & friends from + # source is slow and needs extra native build inputs. + overlay = workspace.mkPyprojectOverlay { + sourcePreference = "wheel"; + }; systems = flake-utils.lib.eachDefaultSystem (system: let pkgs = nixpkgs.legacyPackages.${system}; - inherit (poetry2nix.lib.mkPoetry2Nix {inherit pkgs;}) mkPoetryApplication overrides mkPoetryEnv; - poetryDev = mkPoetryEnv { - projectDir = ./.; - preferWheels = true; - overrides = overrides.withDefaults (final: prev: { - ruff = prev.ruff.override { - preferWheel = true; - }; - }); - }; + # 3.12 to match devenv.nix; RaspiBlitz 1.12 ships 3.11 + python = pkgs.python312; + + pythonSet = + (pkgs.callPackage pyproject-nix.build.packages { + inherit python; + }).overrideScope ( + lib.composeManyExtensions [ + pyproject-build-systems.overlays.default + overlay + ] + ); + + venv = pythonSet.mkVirtualEnv "${name}-env" workspace.deps.default; in { packages = { default = self.packages.${system}.${name}; - ${name} = mkPoetryApplication { - projectDir = ./.; - meta.mainProgram = name; - }; - poetryDev = mkPoetryEnv { - projectDir = ./.; - preferWheels = true; - }; + # A virtualenv with blitz_api and all of its dependencies. + # Provides the `api` console script used by the NixOS module. + ${name} = venv.overrideAttrs (old: { + meta = (old.meta or {}) // {mainProgram = "api";}; + }); }; + # Python dependencies are managed impurely via `uv sync` into + # ./.venv, mirroring devenv.nix; this shell provides the tooling. devShells.default = pkgs.mkShell { - # TODO: dirty dirty to be able to run the app. May break other packages. - # https://discourse.nixos.org/t/using-nix-shells-without-polluting-repositories/37362 - shellHook = '' - export LD_LIBRARY_PATH="$LD_LIBRARY_PATH:${ - with pkgs; - lib.makeLibraryPath [pkgs.stdenv.cc.cc.lib] - }" - ''; - nativeBuildInputs = with pkgs; [ + packages = with pkgs; [ + python + uv + stdenv.cc.cc - poetry - poetryDev pyright + isort alejandra statix ruff - ruff-lsp redis - pueue + nushell + typos + typos-lsp sshpass bitcoind lnd clightning - pueue ]; + + env = { + # use the nix-provided interpreter and never download one + UV_PYTHON = python.interpreter; + UV_PYTHON_DOWNLOADS = "never"; + }; + + shellHook = '' + unset PYTHONPATH + export LD_LIBRARY_PATH="$LD_LIBRARY_PATH:${ + lib.makeLibraryPath [pkgs.stdenv.cc.cc.lib] + }" + ''; }; }); diff --git a/pyproject.toml b/pyproject.toml index c684ba0..862c43b 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -24,6 +24,8 @@ dependencies = [ "deepdiff==8.6.1", "loguru==0.7.3", "celery[redis]==5.6.2", + # used by the `api` console script entry point (app/server.py) + "click==8.3.1", ] [project.scripts] @@ -36,7 +38,6 @@ dev = [ "coverage==7.13.2", "ruff==0.14.14", "debugpy==1.8.20", - "click==8.3.1", "watchfiles==1.1.1", ] diff --git a/requirements.txt b/requirements.txt index 679ca72..40ef608 100644 --- a/requirements.txt +++ b/requirements.txt @@ -37,6 +37,7 @@ charset-normalizer==3.4.2 # via requests click==8.3.1 # via + # blitz-api (pyproject.toml) # celery # click-didyoumean # click-plugins diff --git a/uv.lock b/uv.lock index 91fecfc..1e01573 100644 --- a/uv.lock +++ b/uv.lock @@ -155,6 +155,7 @@ dependencies = [ { name = "anyio" }, { name = "async-timeout" }, { name = "celery", extra = ["redis"] }, + { name = "click" }, { name = "deepdiff" }, { name = "fastapi", extra = ["standard-no-fastapi-cloud-cli"] }, { name = "grpcio" }, @@ -173,7 +174,6 @@ dependencies = [ [package.dev-dependencies] dev = [ - { name = "click" }, { name = "coverage" }, { name = "debugpy" }, { name = "pytest" }, @@ -188,6 +188,7 @@ requires-dist = [ { name = "anyio", specifier = "==4.9.0" }, { name = "async-timeout", specifier = "==5.0.1" }, { name = "celery", extras = ["redis"], specifier = "==5.6.2" }, + { name = "click", specifier = "==8.3.1" }, { name = "deepdiff", specifier = "==8.6.1" }, { name = "fastapi", extras = ["standard-no-fastapi-cloud-cli"], specifier = "==0.128.0" }, { name = "grpcio", specifier = "==1.76.0" }, @@ -206,7 +207,6 @@ requires-dist = [ [package.metadata.requires-dev] dev = [ - { name = "click", specifier = "==8.3.1" }, { name = "coverage", specifier = "==7.13.2" }, { name = "debugpy", specifier = "==1.8.20" }, { name = "pytest", specifier = "==9.0.2" },