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" },