at master 2.6 kB view raw
1{ 2 buildPythonPackage, 3 lib, 4 hatchling, 5 tomli-w, 6}: 7{ 8 pname, 9 version, 10 11 # Editable root as string. 12 # Environment variables will be expanded at runtime using os.path.expandvars. 13 root, 14 15 # Arguments passed on verbatim to buildPythonPackage 16 derivationArgs ? { }, 17 18 # Python dependencies 19 dependencies ? [ ], 20 optional-dependencies ? { }, 21 22 # PEP-518 build-system https://peps.python.org/pep-518 23 build-system ? [ ], 24 25 # PEP-621 entry points https://peps.python.org/pep-0621/#entry-points 26 scripts ? { }, 27 gui-scripts ? { }, 28 entry-points ? { }, 29 30 passthru ? { }, 31 meta ? { }, 32}: 33 34# Create a PEP-660 (https://peps.python.org/pep-0660/) editable package pointing to an impure location outside the Nix store. 35# The primary use case of this function is to enable local development workflows where the local package is installed into a virtualenv-like environment using withPackages. 36 37assert lib.isString root; 38let 39 # In editable mode build-system's are considered to be runtime dependencies. 40 dependencies' = dependencies ++ build-system; 41 42 pyproject = { 43 # PEP-621 project table 44 project = { 45 name = pname; 46 inherit 47 version 48 scripts 49 gui-scripts 50 entry-points 51 ; 52 dependencies = map lib.getName dependencies'; 53 optional-dependencies = lib.mapAttrs (_: map lib.getName) optional-dependencies; 54 }; 55 56 # Allow empty package 57 tool.hatch.build.targets.wheel.bypass-selection = true; 58 59 # Include our editable pointer file in build 60 tool.hatch.build.targets.wheel.force-include."_${pname}.pth" = "_${pname}.pth"; 61 62 # Build editable package using hatchling 63 build-system = { 64 requires = [ "hatchling" ]; 65 build-backend = "hatchling.build"; 66 }; 67 }; 68 69in 70buildPythonPackage ( 71 { 72 inherit 73 pname 74 version 75 optional-dependencies 76 passthru 77 meta 78 ; 79 dependencies = dependencies'; 80 81 pyproject = true; 82 83 unpackPhase = '' 84 python -c "import json, tomli_w; print(tomli_w.dumps(json.load(open('$pyprojectContentsPath'))))" > pyproject.toml 85 echo 'import os.path, sys; sys.path.insert(0, os.path.expandvars("${root}"))' > _${pname}.pth 86 ''; 87 88 build-system = [ hatchling ]; 89 } 90 // derivationArgs 91 // { 92 # Note: Using formats.toml generates another intermediary derivation that needs to be built. 93 # We inline the same functionality for better UX. 94 nativeBuildInputs = (derivationArgs.nativeBuildInputs or [ ]) ++ [ tomli-w ]; 95 pyprojectContents = builtins.toJSON pyproject; 96 passAsFile = [ "pyprojectContents" ]; 97 preferLocalBuild = true; 98 } 99)