
The problem is that optional-dependencies looks something like: optional-dependencies = { extra1 = [ package1 package2 ]; }; And the goal is to transform that into some JSON that works as a pyproject file. So, its supposed to look something like: { "optional-dependencies": { "extra1": [ "package1" "package2" ] } } Previously, we were trying to do that converstion with: optional-dependencies = lib.mapAttrs (_: lib.getName) optional-dependencies; The problem is that we're calling lib.getName on the array of dependencies. Instead, we convert the code to call lib.getName on each individual dependency in the array.
100 lines
2.6 KiB
Nix
100 lines
2.6 KiB
Nix
{
|
|
buildPythonPackage,
|
|
lib,
|
|
hatchling,
|
|
tomli-w,
|
|
}:
|
|
{
|
|
pname,
|
|
version,
|
|
|
|
# Editable root as string.
|
|
# Environment variables will be expanded at runtime using os.path.expandvars.
|
|
root,
|
|
|
|
# Arguments passed on verbatim to buildPythonPackage
|
|
derivationArgs ? { },
|
|
|
|
# Python dependencies
|
|
dependencies ? [ ],
|
|
optional-dependencies ? { },
|
|
|
|
# PEP-518 build-system https://peps.python.org/pep-518
|
|
build-system ? [ ],
|
|
|
|
# PEP-621 entry points https://peps.python.org/pep-0621/#entry-points
|
|
scripts ? { },
|
|
gui-scripts ? { },
|
|
entry-points ? { },
|
|
|
|
passthru ? { },
|
|
meta ? { },
|
|
}:
|
|
|
|
# Create a PEP-660 (https://peps.python.org/pep-0660/) editable package pointing to an impure location outside the Nix store.
|
|
# 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.
|
|
|
|
assert lib.isString root;
|
|
let
|
|
# In editable mode build-system's are considered to be runtime dependencies.
|
|
dependencies' = dependencies ++ build-system;
|
|
|
|
pyproject = {
|
|
# PEP-621 project table
|
|
project = {
|
|
name = pname;
|
|
inherit
|
|
version
|
|
scripts
|
|
gui-scripts
|
|
entry-points
|
|
;
|
|
dependencies = map lib.getName dependencies';
|
|
optional-dependencies = lib.mapAttrs (_: map lib.getName) optional-dependencies;
|
|
};
|
|
|
|
# Allow empty package
|
|
tool.hatch.build.targets.wheel.bypass-selection = true;
|
|
|
|
# Include our editable pointer file in build
|
|
tool.hatch.build.targets.wheel.force-include."_${pname}.pth" = "_${pname}.pth";
|
|
|
|
# Build editable package using hatchling
|
|
build-system = {
|
|
requires = [ "hatchling" ];
|
|
build-backend = "hatchling.build";
|
|
};
|
|
};
|
|
|
|
in
|
|
buildPythonPackage (
|
|
{
|
|
inherit
|
|
pname
|
|
version
|
|
optional-dependencies
|
|
passthru
|
|
meta
|
|
;
|
|
dependencies = dependencies';
|
|
|
|
pyproject = true;
|
|
|
|
unpackPhase = ''
|
|
python -c "import json, tomli_w; print(tomli_w.dumps(json.load(open('$pyprojectContentsPath'))))" > pyproject.toml
|
|
echo 'import os.path, sys; sys.path.insert(0, os.path.expandvars("${root}"))' > _${pname}.pth
|
|
'';
|
|
|
|
build-system = [ hatchling ];
|
|
}
|
|
// derivationArgs
|
|
// {
|
|
# Note: Using formats.toml generates another intermediary derivation that needs to be built.
|
|
# We inline the same functionality for better UX.
|
|
nativeBuildInputs = (derivationArgs.nativeBuildInputs or [ ]) ++ [ tomli-w ];
|
|
pyprojectContents = builtins.toJSON pyproject;
|
|
passAsFile = [ "pyprojectContents" ];
|
|
preferLocalBuild = true;
|
|
}
|
|
)
|