From 11eb0771136262166fce89218602755c1aa7fcf1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leon=20Schwarz=C3=A4ugl?= Date: Tue, 31 Dec 2024 13:39:03 +0100 Subject: [PATCH] feat: overhauled template system (WIP) --- SwarselSystems.org | 172 +++++++++++------------ pkgs/default.nix | 1 + pkgs/project/default.nix | 5 + profiles/common/home/custom-packages.nix | 35 +---- profiles/common/home/direnv.nix | 1 + programs/emacs/init.el | 8 +- scripts/project.sh | 7 + templates/default.nix | 8 ++ templates/python/.envrc | 1 + templates/python/README.md | 5 + templates/python/flake.nix | 134 ++++++++++++++++++ templates/python/pyproject.toml | 21 +++ templates/python/src/name/__init__.py | 2 + templates/python/uv.lock | 55 ++++++++ 14 files changed, 330 insertions(+), 125 deletions(-) create mode 100644 pkgs/project/default.nix create mode 100644 scripts/project.sh create mode 100644 templates/default.nix create mode 100644 templates/python/.envrc create mode 100644 templates/python/README.md create mode 100644 templates/python/flake.nix create mode 100644 templates/python/pyproject.toml create mode 100644 templates/python/src/name/__init__.py create mode 100644 templates/python/uv.lock diff --git a/SwarselSystems.org b/SwarselSystems.org index d9a8c68..c2839fb 100644 --- a/SwarselSystems.org +++ b/SwarselSystems.org @@ -415,61 +415,63 @@ In this section I am creating some attributes that define general concepts of my #+begin_src nix :tangle no :noweb-ref flakeoutputgeneral - inherit lib nixModules mixedModules homeModules; + inherit lib nixModules mixedModules homeModules; - nixosModules = import ./modules/nixos { inherit lib; }; - homeManagerModules = import ./modules/home { inherit lib; }; - packages = lib.swarselsystems.forEachSystem (pkgs: import ./pkgs { inherit lib pkgs; }); - formatter = lib.swarselsystems.forEachSystem (pkgs: pkgs.nixpkgs-fmt); - overlays = import ./overlays { inherit self lib inputs; }; + nixosModules = import ./modules/nixos { inherit lib; }; + homeManagerModules = import ./modules/home { inherit lib; }; + packages = lib.swarselsystems.forEachSystem (pkgs: import ./pkgs { inherit lib pkgs; }); + formatter = lib.swarselsystems.forEachSystem (pkgs: pkgs.nixpkgs-fmt); + overlays = import ./overlays { inherit self lib inputs; }; - apps = lib.swarselsystems.forAllSystems (system: - let - appNames = [ - "swarsel-bootstrap" - "swarsel-install" - "swarsel-rebuild" - "swarsel-postinstall" - ]; - appSet = lib.swarselsystems.mkApps system appNames self; - in - { - inherit appSet; - default = appSet.bootstrap; - }); + apps = lib.swarselsystems.forAllSystems (system: + let + appNames = [ + "swarsel-bootstrap" + "swarsel-install" + "swarsel-rebuild" + "swarsel-postinstall" + ]; + appSet = lib.swarselsystems.mkApps system appNames self; + in + { + inherit appSet; + default = appSet.bootstrap; + }); - devShells = lib.swarselsystems.forAllSystems (system: - let - pkgs = lib.swarselsystems.pkgsFor.${system}; - checks = self.checks.${system}; - in - { - default = pkgs.mkShell { - NIX_CONFIG = "experimental-features = nix-command flakes"; - inherit (checks.pre-commit-check) shellHook; - buildInputs = checks.pre-commit-check.enabledPackages; - nativeBuildInputs = [ - pkgs.nix - pkgs.home-manager - pkgs.git - pkgs.just - pkgs.age - pkgs.ssh-to-age - pkgs.sops - pkgs.statix - pkgs.deadnix - pkgs.nixpkgs-fmt - ]; - }; - } - ); + devShells = lib.swarselsystems.forAllSystems (system: + let + pkgs = lib.swarselsystems.pkgsFor.${system}; + checks = self.checks.${system}; + in + { + default = pkgs.mkShell { + NIX_CONFIG = "experimental-features = nix-command flakes"; + inherit (checks.pre-commit-check) shellHook; + buildInputs = checks.pre-commit-check.enabledPackages; + nativeBuildInputs = [ + pkgs.nix + pkgs.home-manager + pkgs.git + pkgs.just + pkgs.age + pkgs.ssh-to-age + pkgs.sops + pkgs.statix + pkgs.deadnix + pkgs.nixpkgs-fmt + ]; + }; + } + ); - checks = lib.swarselsystems.forAllSystems (system: - let - pkgs = nixpkgs.legacyPackages.${system}; - in - import ./checks { inherit self inputs system pkgs; } - ); + templates = import ./templates; + + checks = lib.swarselsystems.forAllSystems (system: + let + pkgs = nixpkgs.legacyPackages.${system}; + in + import ./checks { inherit self inputs system pkgs; } + ); #+end_src @@ -2071,6 +2073,7 @@ Note: The structure of generating the packages was changed in commit =2cf03a3 re "ts2t" "vershell" "eontimer" + "project" ]; in lib.swarselsystems.mkPackages packageNames pkgs @@ -3532,6 +3535,26 @@ This script allows for quick git branch switching. #+end_src +**** project + +#+begin_src shell :tangle scripts/project.sh + set -euo pipefail + + if [ ! -d "$(pwd)/.git" ]; then + git init + fi + nix flake init --template "$FLAKE"#"$1" + direnv allow +#+end_src + +#+begin_src nix :tangle pkgs/project/default.nix + { self, name, writeShellApplication }: + writeShellApplication { + inherit name; + text = builtins.readFile "${self}/scripts/${name}.sh"; + } +#+end_src + *** Overlays (additions, overrides, nixpkgs-stable) :PROPERTIES: :CUSTOM_ID: h:5e3e21e0-57af-4dad-b32f-6400af9b7aab @@ -8545,42 +8568,9 @@ This is just a separate container for derivations defined in [[#h:64a5cc16-6b16- ts2t vershell eontimer + project swarsel-bootstrap - - (pkgs.writeScriptBin "project" '' - #! ${pkgs.bash}/bin/bash - if [ "$1" == "rust" ]; then - cp ~/.dotfiles/templates/rust_flake.nix ./flake.nix - cp ~/.dotfiles/templates/toolchain.toml . - elif [ "$1" == "cpp" ]; then - cp ~/.dotfiles/templates/cpp_flake.nix ./flake.nix - elif [ "$1" == "python" ]; then - cp ~/.dotfiles/templates/py_flake.nix ./flake.nix - elif [ "$1" == "cuda" ]; then - cp ~/.dotfiles/templates/cu_flake.nix ./flake.nix - elif [ "$1" == "other" ]; then - cp ~/.dotfiles/templates/other_flake.nix ./flake.nix - elif [ "$1" == "latex" ]; then - if [ "$2" == "" ]; then - echo "No filename specified, usage: 'project latex '" - exit 0 - fi - cp ~/.dotfiles/templates/tex_standard.tex ./"$2".tex - exit 0 - else - echo "No valid argument given. Valid arguments are rust cpp python, cuda" - exit 0 - fi - echo "use flake" >> .envrc - direnv allow - '') - - - - - - ]; } #+end_src @@ -8954,6 +8944,7 @@ Enables direnv, which I use for nearly all of my nix dev flakes. { programs.direnv = { enable = true; + silent = true; nix-direnv.enable = true; }; } @@ -13394,11 +13385,16 @@ In order to update the language grammars, run the next command below. :CUSTOM_ID: h:82ddeef2-99f8-465b-ba36-07c3eaad717b :END: +In emacs, there are two packages for managing dev environments - emacs-direnv (direnv) and envrc. Direnv uses the global Emacs environment whereas envrc is buffer-local. I do not really care about this difference. What is more important to me is that emacs should not block upon handling a bigger flake.nix while setting up the dev environment. This seems to be better handled by envrc. + #+begin_src emacs-lisp - (use-package direnv - :custom (direnv-always-show-summary nil) - :config (direnv-mode)) + ;; (use-package direnv + ;; :custom (direnv-always-show-summary nil) + ;; :config (direnv-mode)) + + (use-package envrc + :hook (after-init . envrc-global-mode)) #+end_src diff --git a/pkgs/default.nix b/pkgs/default.nix index df56659..94b72b5 100644 --- a/pkgs/default.nix +++ b/pkgs/default.nix @@ -24,6 +24,7 @@ let "ts2t" "vershell" "eontimer" + "project" ]; in lib.swarselsystems.mkPackages packageNames pkgs diff --git a/pkgs/project/default.nix b/pkgs/project/default.nix new file mode 100644 index 0000000..de6a2e6 --- /dev/null +++ b/pkgs/project/default.nix @@ -0,0 +1,5 @@ +{ self, name, writeShellApplication }: +writeShellApplication { + inherit name; + text = builtins.readFile "${self}/scripts/${name}.sh"; +} diff --git a/profiles/common/home/custom-packages.nix b/profiles/common/home/custom-packages.nix index 843a7c1..5980ed0 100644 --- a/profiles/common/home/custom-packages.nix +++ b/profiles/common/home/custom-packages.nix @@ -21,41 +21,8 @@ ts2t vershell eontimer + project swarsel-bootstrap - - (pkgs.writeScriptBin "project" '' - #! ${pkgs.bash}/bin/bash - if [ "$1" == "rust" ]; then - cp ~/.dotfiles/templates/rust_flake.nix ./flake.nix - cp ~/.dotfiles/templates/toolchain.toml . - elif [ "$1" == "cpp" ]; then - cp ~/.dotfiles/templates/cpp_flake.nix ./flake.nix - elif [ "$1" == "python" ]; then - cp ~/.dotfiles/templates/py_flake.nix ./flake.nix - elif [ "$1" == "cuda" ]; then - cp ~/.dotfiles/templates/cu_flake.nix ./flake.nix - elif [ "$1" == "other" ]; then - cp ~/.dotfiles/templates/other_flake.nix ./flake.nix - elif [ "$1" == "latex" ]; then - if [ "$2" == "" ]; then - echo "No filename specified, usage: 'project latex '" - exit 0 - fi - cp ~/.dotfiles/templates/tex_standard.tex ./"$2".tex - exit 0 - else - echo "No valid argument given. Valid arguments are rust cpp python, cuda" - exit 0 - fi - echo "use flake" >> .envrc - direnv allow - '') - - - - - - ]; } diff --git a/profiles/common/home/direnv.nix b/profiles/common/home/direnv.nix index 7681fea..47a14a2 100644 --- a/profiles/common/home/direnv.nix +++ b/profiles/common/home/direnv.nix @@ -2,6 +2,7 @@ _: { programs.direnv = { enable = true; + silent = true; nix-direnv.enable = true; }; } diff --git a/programs/emacs/init.el b/programs/emacs/init.el index c32e033..41f6e76 100644 --- a/programs/emacs/init.el +++ b/programs/emacs/init.el @@ -1151,10 +1151,12 @@ create a new one." :config (global-treesit-auto-mode) (setq treesit-auto-install 'prompt)) +;; (use-package direnv +;; :custom (direnv-always-show-summary nil) +;; :config (direnv-mode)) -(use-package direnv - :custom (direnv-always-show-summary nil) - :config (direnv-mode)) +(use-package envrc + :hook (after-init . envrc-global-mode)) (use-package avy :bind diff --git a/scripts/project.sh b/scripts/project.sh new file mode 100644 index 0000000..10bff03 --- /dev/null +++ b/scripts/project.sh @@ -0,0 +1,7 @@ +set -euo pipefail + +if [ ! -d "$(pwd)/.git" ]; then + git init +fi +nix flake init --template "$FLAKE"#"$1" +direnv allow diff --git a/templates/default.nix b/templates/default.nix new file mode 100644 index 0000000..7d7eb73 --- /dev/null +++ b/templates/default.nix @@ -0,0 +1,8 @@ +rec { + python = { + path = ./python; + description = + "Python Project"; + }; + default = python; +} diff --git a/templates/python/.envrc b/templates/python/.envrc new file mode 100644 index 0000000..3550a30 --- /dev/null +++ b/templates/python/.envrc @@ -0,0 +1 @@ +use flake diff --git a/templates/python/README.md b/templates/python/README.md new file mode 100644 index 0000000..2b42b41 --- /dev/null +++ b/templates/python/README.md @@ -0,0 +1,5 @@ +# Python template using uv2nix + +### How to use + +1) `` diff --git a/templates/python/flake.nix b/templates/python/flake.nix new file mode 100644 index 0000000..25dffc8 --- /dev/null +++ b/templates/python/flake.nix @@ -0,0 +1,134 @@ +{ + description = "Hello world flake using uv2nix"; + + inputs = { + 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"; + inputs.nixpkgs.follows = "nixpkgs"; + }; + + pyproject-build-systems = { + url = "github:pyproject-nix/build-system-pkgs"; + inputs.pyproject-nix.follows = "pyproject-nix"; + inputs.uv2nix.follows = "uv2nix"; + inputs.nixpkgs.follows = "nixpkgs"; + }; + }; + + outputs = + { nixpkgs + , uv2nix + , pyproject-nix + , pyproject-build-systems + , ... + }: + let + inherit (nixpkgs) lib; + + # Load a uv workspace from a workspace root. + # Uv2nix treats all uv projects as workspace projects. + workspace = uv2nix.lib.workspace.loadWorkspace { workspaceRoot = ./.; }; + + # Create package overlay from workspace. + overlay = workspace.mkPyprojectOverlay { + # Prefer prebuilt binary wheels as a package source. + # Sdists are less likely to "just work" because of the metadata missing from uv.lock. + # Binary wheels are more likely to, but may still require overrides for library dependencies. + sourcePreference = "wheel"; # or sourcePreference = "sdist"; + # Optionally customise PEP 508 environment + # environ = { + # platform_release = "5.10.65"; + # }; + }; + + # Extend generated overlay with build fixups + # + # Uv2nix can only work with what it has, and uv.lock is missing essential metadata to perform some builds. + # This is an additional overlay implementing build fixups. + # See: + # - https://pyproject-nix.github.io/uv2nix/FAQ.html + pyprojectOverrides = _final: _prev: { + # Implement build fixups here. + }; + + pkgs = nixpkgs.legacyPackages.x86_64-linux; + python = pkgs.python312; + + # Construct package set + pythonSet = + # Use base package set from pyproject.nix builders + (pkgs.callPackage pyproject-nix.build.packages { + inherit python; + }).overrideScope + ( + lib.composeManyExtensions [ + pyproject-build-systems.overlays.default + overlay + pyprojectOverrides + ] + ); + + in + { + # Package a virtual environment as our main application. + # + # Enable no optional dependencies for production build. + packages.x86_64-linux.default = pythonSet.mkVirtualEnv "name-env" workspace.deps.default; + + # This example provides two different modes of development: + # - Impurely using uv to manage virtual environments + # - Pure development using uv2nix to manage virtual environments + devShells.x86_64-linux = { + # This devShell uses uv2nix to construct a virtual environment purely from Nix, using the same dependency specification as the application. + # The notable difference is that we also apply another overlay here enabling editable mode ( https://setuptools.pypa.io/en/latest/userguide/development_mode.html ). + # + # This means that any changes done to your local files do not require a rebuild. + default = + let + # Create an overlay enabling editable mode for all local dependencies. + editableOverlay = workspace.mkEditablePyprojectOverlay { + # Use environment variable + root = "$REPO_ROOT"; + # Optional: Only enable editable for these packages + # members = [ "hello-world" ]; + }; + + # Override previous set with our overrideable overlay. + editablePythonSet = pythonSet.overrideScope editableOverlay; + + # Build virtual environment, with local packages being editable. + # + # Enable all optional dependencies for development. + virtualenv = editablePythonSet.mkVirtualEnv "name-dev-env" workspace.deps.all; + + in + pkgs.mkShell { + packages = [ + virtualenv + pkgs.uv + ]; + shellHook = '' + # Undo dependency propagation by nixpkgs. + unset PYTHONPATH + + # Don't create venv using uv + export UV_NO_SYNC=1 + + # Prevent uv from downloading managed Python's + export UV_PYTHON_DOWNLOADS=never + + # Get repository root using git. This is expanded at runtime by the editable `.pth` machinery. + export REPO_ROOT=$(git rev-parse --show-toplevel) + ''; + }; + }; + }; +} diff --git a/templates/python/pyproject.toml b/templates/python/pyproject.toml new file mode 100644 index 0000000..fc56e7f --- /dev/null +++ b/templates/python/pyproject.toml @@ -0,0 +1,21 @@ +[project] +name = "name" +version = "0.1.0" +description = "Add your description here" +readme = "README.md" +requires-python = ">=3.12" +dependencies = [ + "urllib3>=2.2.3", +] + +[project.scripts] +hello = "name:hello" + +[build-system] +requires = ["hatchling"] +build-backend = "hatchling.build" + +[dependency-groups] +dev = [ + "ruff>=0.6.7", +] diff --git a/templates/python/src/name/__init__.py b/templates/python/src/name/__init__.py new file mode 100644 index 0000000..aa5ad22 --- /dev/null +++ b/templates/python/src/name/__init__.py @@ -0,0 +1,2 @@ +def hello() -> None: + print("Hello from hello-world!") diff --git a/templates/python/uv.lock b/templates/python/uv.lock new file mode 100644 index 0000000..a3baf62 --- /dev/null +++ b/templates/python/uv.lock @@ -0,0 +1,55 @@ +version = 1 +requires-python = ">=3.12" + +[[package]] +name = "name" +version = "0.1.0" +source = { editable = "." } +dependencies = [ + { name = "urllib3" }, +] + +[package.dev-dependencies] +dev = [ + { name = "ruff" }, +] + +[package.metadata] +requires-dist = [{ name = "urllib3", specifier = ">=2.2.3" }] + +[package.metadata.requires-dev] +dev = [{ name = "ruff", specifier = ">=0.6.7" }] + +[[package]] +name = "ruff" +version = "0.8.4" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/34/37/9c02181ef38d55b77d97c68b78e705fd14c0de0e5d085202bb2b52ce5be9/ruff-0.8.4.tar.gz", hash = "sha256:0d5f89f254836799af1615798caa5f80b7f935d7a670fad66c5007928e57ace8", size = 3402103 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/05/67/f480bf2f2723b2e49af38ed2be75ccdb2798fca7d56279b585c8f553aaab/ruff-0.8.4-py3-none-linux_armv6l.whl", hash = "sha256:58072f0c06080276804c6a4e21a9045a706584a958e644353603d36ca1eb8a60", size = 10546415 }, + { url = "https://files.pythonhosted.org/packages/eb/7a/5aba20312c73f1ce61814e520d1920edf68ca3b9c507bd84d8546a8ecaa8/ruff-0.8.4-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:ffb60904651c00a1e0b8df594591770018a0f04587f7deeb3838344fe3adabac", size = 10346113 }, + { url = "https://files.pythonhosted.org/packages/76/f4/c41de22b3728486f0aa95383a44c42657b2db4062f3234ca36fc8cf52d8b/ruff-0.8.4-py3-none-macosx_11_0_arm64.whl", hash = "sha256:6ddf5d654ac0d44389f6bf05cee4caeefc3132a64b58ea46738111d687352296", size = 9943564 }, + { url = "https://files.pythonhosted.org/packages/0e/f0/afa0d2191af495ac82d4cbbfd7a94e3df6f62a04ca412033e073b871fc6d/ruff-0.8.4-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e248b1f0fa2749edd3350a2a342b67b43a2627434c059a063418e3d375cfe643", size = 10805522 }, + { url = "https://files.pythonhosted.org/packages/12/57/5d1e9a0fd0c228e663894e8e3a8e7063e5ee90f8e8e60cf2085f362bfa1a/ruff-0.8.4-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:bf197b98ed86e417412ee3b6c893f44c8864f816451441483253d5ff22c0e81e", size = 10306763 }, + { url = "https://files.pythonhosted.org/packages/04/df/f069fdb02e408be8aac6853583572a2873f87f866fe8515de65873caf6b8/ruff-0.8.4-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c41319b85faa3aadd4d30cb1cffdd9ac6b89704ff79f7664b853785b48eccdf3", size = 11359574 }, + { url = "https://files.pythonhosted.org/packages/d3/04/37c27494cd02e4a8315680debfc6dfabcb97e597c07cce0044db1f9dfbe2/ruff-0.8.4-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:9f8402b7c4f96463f135e936d9ab77b65711fcd5d72e5d67597b543bbb43cf3f", size = 12094851 }, + { url = "https://files.pythonhosted.org/packages/81/b1/c5d7fb68506cab9832d208d03ea4668da9a9887a4a392f4f328b1bf734ad/ruff-0.8.4-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e4e56b3baa9c23d324ead112a4fdf20db9a3f8f29eeabff1355114dd96014604", size = 11655539 }, + { url = "https://files.pythonhosted.org/packages/ef/38/8f8f2c8898dc8a7a49bc340cf6f00226917f0f5cb489e37075bcb2ce3671/ruff-0.8.4-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:736272574e97157f7edbbb43b1d046125fce9e7d8d583d5d65d0c9bf2c15addf", size = 12912805 }, + { url = "https://files.pythonhosted.org/packages/06/dd/fa6660c279f4eb320788876d0cff4ea18d9af7d9ed7216d7bd66877468d0/ruff-0.8.4-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e5fe710ab6061592521f902fca7ebcb9fabd27bc7c57c764298b1c1f15fff720", size = 11205976 }, + { url = "https://files.pythonhosted.org/packages/a8/d7/de94cc89833b5de455750686c17c9e10f4e1ab7ccdc5521b8fe911d1477e/ruff-0.8.4-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:13e9ec6d6b55f6da412d59953d65d66e760d583dd3c1c72bf1f26435b5bfdbae", size = 10792039 }, + { url = "https://files.pythonhosted.org/packages/6d/15/3e4906559248bdbb74854af684314608297a05b996062c9d72e0ef7c7097/ruff-0.8.4-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:97d9aefef725348ad77d6db98b726cfdb075a40b936c7984088804dfd38268a7", size = 10400088 }, + { url = "https://files.pythonhosted.org/packages/a2/21/9ed4c0e8133cb4a87a18d470f534ad1a8a66d7bec493bcb8bda2d1a5d5be/ruff-0.8.4-py3-none-musllinux_1_2_i686.whl", hash = "sha256:ab78e33325a6f5374e04c2ab924a3367d69a0da36f8c9cb6b894a62017506111", size = 10900814 }, + { url = "https://files.pythonhosted.org/packages/0d/5d/122a65a18955bd9da2616b69bc839351f8baf23b2805b543aa2f0aed72b5/ruff-0.8.4-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:8ef06f66f4a05c3ddbc9121a8b0cecccd92c5bf3dd43b5472ffe40b8ca10f0f8", size = 11268828 }, + { url = "https://files.pythonhosted.org/packages/43/a9/1676ee9106995381e3d34bccac5bb28df70194167337ed4854c20f27c7ba/ruff-0.8.4-py3-none-win32.whl", hash = "sha256:552fb6d861320958ca5e15f28b20a3d071aa83b93caee33a87b471f99a6c0835", size = 8805621 }, + { url = "https://files.pythonhosted.org/packages/10/98/ed6b56a30ee76771c193ff7ceeaf1d2acc98d33a1a27b8479cbdb5c17a23/ruff-0.8.4-py3-none-win_amd64.whl", hash = "sha256:f21a1143776f8656d7f364bd264a9d60f01b7f52243fbe90e7670c0dfe0cf65d", size = 9660086 }, + { url = "https://files.pythonhosted.org/packages/13/9f/026e18ca7d7766783d779dae5e9c656746c6ede36ef73c6d934aaf4a6dec/ruff-0.8.4-py3-none-win_arm64.whl", hash = "sha256:9183dd615d8df50defa8b1d9a074053891ba39025cf5ae88e8bcb52edcc4bf08", size = 9074500 }, +] + +[[package]] +name = "urllib3" +version = "2.3.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/aa/63/e53da845320b757bf29ef6a9062f5c669fe997973f966045cb019c3f4b66/urllib3-2.3.0.tar.gz", hash = "sha256:f8c5449b3cf0861679ce7e0503c7b44b5ec981bec0d1d3795a07f1ba96f0204d", size = 307268 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/c8/19/4ec628951a74043532ca2cf5d97b7b14863931476d117c471e8e2b1eb39f/urllib3-2.3.0-py3-none-any.whl", hash = "sha256:1cee9ad369867bfdbbb48b7dd50374c0967a0bb7710050facf0dd6911440e3df", size = 128369 }, +]