poetry2nix: 1.2.1 -> 1.3.0

This commit is contained in:
adisbladis 2020-01-13 15:45:00 +00:00
parent 244c89d537
commit 386dbd5aea
No known key found for this signature in database
GPG Key ID: 110BFAD44C6249B7
4 changed files with 237 additions and 132 deletions

View File

@ -20,16 +20,10 @@ let
getFunctorFn = fn: if builtins.typeOf fn == "set" then fn.__functor else fn; getFunctorFn = fn: if builtins.typeOf fn == "set" then fn.__functor else fn;
getAttrDefault = attribute: set: default: (
if builtins.hasAttr attribute set
then builtins.getAttr attribute set
else default
);
# Map SPDX identifiers to license names # Map SPDX identifiers to license names
spdxLicenses = lib.listToAttrs (lib.filter (pair: pair.name != null) (builtins.map (v: { name = if lib.hasAttr "spdxId" v then v.spdxId else null; value = v; }) (lib.attrValues lib.licenses))); spdxLicenses = lib.listToAttrs (lib.filter (pair: pair.name != null) (builtins.map (v: { name = if lib.hasAttr "spdxId" v then v.spdxId else null; value = v; }) (lib.attrValues lib.licenses)));
# Get license by id falling back to input string # Get license by id falling back to input string
getLicenseBySpdxId = spdxId: getAttrDefault spdxId spdxLicenses spdxId; getLicenseBySpdxId = spdxId: spdxLicenses.${spdxId} or spdxId;
# #
# Returns an attrset { python, poetryPackages } for the given lockfile # Returns an attrset { python, poetryPackages } for the given lockfile
@ -65,7 +59,7 @@ let
# closure as python can only ever have one version of a dependency # closure as python can only ever have one version of a dependency
baseOverlay = self: super: baseOverlay = self: super:
let let
getDep = depName: if builtins.hasAttr depName self then self."${depName}" else throw "foo"; getDep = depName: self.${depName};
lockPkgs = builtins.listToAttrs ( lockPkgs = builtins.listToAttrs (
builtins.map ( builtins.map (
@ -74,7 +68,7 @@ let
value = self.mkPoetryDep ( value = self.mkPoetryDep (
pkgMeta // { pkgMeta // {
inherit pwd; inherit pwd;
source = getAttrDefault "source" pkgMeta null; source = pkgMeta.source or null;
files = lockFiles.${name}; files = lockFiles.${name};
pythonPackages = self; pythonPackages = self;
} }
@ -159,12 +153,12 @@ let
passedAttrs = builtins.removeAttrs attrs specialAttrs; passedAttrs = builtins.removeAttrs attrs specialAttrs;
getDeps = depAttr: let getDeps = depAttr: let
deps = getAttrDefault depAttr pyProject.tool.poetry {}; deps = pyProject.tool.poetry.${depAttr} or {};
depAttrs = builtins.map (d: lib.toLower d) (builtins.attrNames deps); depAttrs = builtins.map (d: lib.toLower d) (builtins.attrNames deps);
in in
builtins.map (dep: py.pkgs."${dep}") depAttrs; builtins.map (dep: py.pkgs."${dep}") depAttrs;
getInputs = attr: getAttrDefault attr attrs []; getInputs = attr: attrs.${attr} or [];
mkInput = attr: extraInputs: getInputs attr ++ extraInputs; mkInput = attr: extraInputs: getInputs attr ++ extraInputs;
buildSystemPkgs = poetryLib.getBuildSystemPkgs { buildSystemPkgs = poetryLib.getBuildSystemPkgs {
@ -189,7 +183,7 @@ let
python = py; python = py;
}; };
postPatch = (getAttrDefault "postPatch" passedAttrs "") + '' postPatch = (passedAttrs.postPatch or "") + ''
# Tell poetry not to resolve the path dependencies. Any version is # Tell poetry not to resolve the path dependencies. Any version is
# fine ! # fine !
yj -tj < pyproject.toml | python ${./pyproject-without-path.py} > pyproject.json yj -tj < pyproject.toml | python ${./pyproject-without-path.py} > pyproject.json
@ -199,7 +193,7 @@ let
meta = meta // { meta = meta // {
inherit (pyProject.tool.poetry) description homepage; inherit (pyProject.tool.poetry) description homepage;
license = getLicenseBySpdxId (getAttrDefault "license" pyProject.tool.poetry "unknown"); license = getLicenseBySpdxId (pyProject.tool.poetry.license or "unknown");
}; };
} }

View File

@ -30,22 +30,24 @@ let
in in
(builtins.foldl' combine initial tokens).state; (builtins.foldl' combine initial tokens).state;
fromTOML = toml: if builtins.hasAttr "fromTOML" builtins then builtins.fromTOML toml else fromTOML = builtins.fromTOML or
builtins.fromJSON ( (
builtins.readFile ( toml: builtins.fromJSON (
pkgs.runCommand "from-toml" builtins.readFile (
{ pkgs.runCommand "from-toml"
inherit toml; {
allowSubstitutes = false; inherit toml;
preferLocalBuild = true; allowSubstitutes = false;
} preferLocalBuild = true;
'' }
${pkgs.remarshal}/bin/remarshal \ ''
-if toml \ ${pkgs.remarshal}/bin/remarshal \
-i <(echo "$toml") \ -if toml \
-of json \ -i <(echo "$toml") \
-o $out -of json \
'' -o $out
''
)
) )
); );
readTOML = path: fromTOML (builtins.readFile path); readTOML = path: fromTOML (builtins.readFile path);

View File

@ -16,102 +16,112 @@
, pwd , pwd
, supportedExtensions ? lib.importJSON ./extensions.json , supportedExtensions ? lib.importJSON ./extensions.json
, ... , ...
}: let }:
inherit (poetryLib) isCompatible getManyLinuxDeps fetchFromPypi; pythonPackages.callPackage (
{ preferWheel ? false
}:
inherit (import ./pep425.nix {
inherit lib python;
inherit (pkgs) stdenv;
}) selectWheel
;
fileCandidates = let
supportedRegex = ("^.*?(" + builtins.concatStringsSep "|" supportedExtensions + ")");
matchesVersion = fname: builtins.match ("^.*" + builtins.replaceStrings [ "." ] [ "\\." ] version + ".*$") fname != null;
hasSupportedExtension = fname: builtins.match supportedRegex fname != null;
isCompatibleEgg = fname: ! lib.strings.hasSuffix ".egg" fname || lib.strings.hasSuffix "py${python.pythonVersion}.egg" fname;
in
builtins.filter (f: matchesVersion f.file && hasSupportedExtension f.file && isCompatibleEgg f.file) files;
toPath = s: pwd + "/${s}";
isSource = source != null;
isGit = isSource && source.type == "git";
isLocal = isSource && source.type == "directory";
localDepPath = toPath source.url;
pyProject = poetryLib.readTOML (localDepPath + "/pyproject.toml");
buildSystemPkgs = poetryLib.getBuildSystemPkgs {
inherit pythonPackages pyProject;
};
fileInfo = let
isBdist = f: lib.strings.hasSuffix "whl" f.file;
isSdist = f: ! isBdist f && ! isEgg f;
isEgg = f: lib.strings.hasSuffix ".egg" f.file;
binaryDist = selectWheel fileCandidates;
sourceDist = builtins.filter isSdist fileCandidates;
eggs = builtins.filter isEgg fileCandidates;
lockFileEntry = builtins.head (sourceDist ++ binaryDist ++ eggs);
_isEgg = isEgg lockFileEntry;
in
rec {
inherit (lockFileEntry) file hash;
name = file;
format =
if _isEgg then "egg"
else if lib.strings.hasSuffix ".whl" name then "wheel"
else "setuptools";
kind =
if _isEgg then python.pythonVersion
else if format == "setuptools" then "source"
else (builtins.elemAt (lib.strings.splitString "-" name) 2);
};
baseBuildInputs = lib.optional (name != "setuptools_scm" && name != "setuptools-scm") pythonPackages.setuptools_scm;
in
buildPythonPackage {
pname = name;
version = version;
doCheck = false; # We never get development deps
dontStrip = true;
format = if isLocal then "pyproject" else if isGit then "setuptools" else fileInfo.format;
nativeBuildInputs = if (!isSource && (getManyLinuxDeps fileInfo.name).str != null) then [ autoPatchelfHook ] else [];
buildInputs = baseBuildInputs ++ (if !isSource then (getManyLinuxDeps fileInfo.name).pkg else []);
propagatedBuildInputs =
let let
# Some dependencies like django gets the attribute name django
# but dependencies try to access Django inherit (poetryLib) isCompatible getManyLinuxDeps fetchFromPypi;
deps = builtins.map (d: lib.toLower d) (builtins.attrNames dependencies);
inherit (import ./pep425.nix {
inherit lib python;
inherit (pkgs) stdenv;
}) selectWheel
;
fileCandidates = let
supportedRegex = ("^.*?(" + builtins.concatStringsSep "|" supportedExtensions + ")");
matchesVersion = fname: builtins.match ("^.*" + builtins.replaceStrings [ "." ] [ "\\." ] version + ".*$") fname != null;
hasSupportedExtension = fname: builtins.match supportedRegex fname != null;
isCompatibleEgg = fname: ! lib.strings.hasSuffix ".egg" fname || lib.strings.hasSuffix "py${python.pythonVersion}.egg" fname;
in
builtins.filter (f: matchesVersion f.file && hasSupportedExtension f.file && isCompatibleEgg f.file) files;
toPath = s: pwd + "/${s}";
isSource = source != null;
isGit = isSource && source.type == "git";
isLocal = isSource && source.type == "directory";
localDepPath = toPath source.url;
pyProject = poetryLib.readTOML (localDepPath + "/pyproject.toml");
buildSystemPkgs = poetryLib.getBuildSystemPkgs {
inherit pythonPackages pyProject;
};
fileInfo = let
isBdist = f: lib.strings.hasSuffix "whl" f.file;
isSdist = f: ! isBdist f && ! isEgg f;
isEgg = f: lib.strings.hasSuffix ".egg" f.file;
binaryDist = selectWheel fileCandidates;
sourceDist = builtins.filter isSdist fileCandidates;
eggs = builtins.filter isEgg fileCandidates;
entries = (if preferWheel then binaryDist ++ sourceDist else sourceDist ++ binaryDist) ++ eggs;
lockFileEntry = builtins.head entries;
_isEgg = isEgg lockFileEntry;
in
rec {
inherit (lockFileEntry) file hash;
name = file;
format =
if _isEgg then "egg"
else if lib.strings.hasSuffix ".whl" name then "wheel"
else "setuptools";
kind =
if _isEgg then python.pythonVersion
else if format == "setuptools" then "source"
else (builtins.elemAt (lib.strings.splitString "-" name) 2);
};
baseBuildInputs = lib.optional (name != "setuptools_scm" && name != "setuptools-scm") pythonPackages.setuptools_scm;
in in
(builtins.map (n: pythonPackages.${n}) deps) ++ (if isLocal then buildSystemPkgs else []);
meta = { buildPythonPackage {
broken = ! isCompatible python.version python-versions; pname = name;
license = []; version = version;
};
# We need to retrieve kind from the interpreter and the filename of the package doCheck = false; # We never get development deps
# Interpreters should declare what wheel types they're compatible with (python type + ABI) dontStrip = true;
# Here we can then choose a file based on that info. format = if isLocal then "pyproject" else if isGit then "setuptools" else fileInfo.format;
src = if isGit then (
builtins.fetchGit { nativeBuildInputs = if (!isSource && (getManyLinuxDeps fileInfo.name).str != null) then [ autoPatchelfHook ] else [];
inherit (source) url; buildInputs = baseBuildInputs ++ (if !isSource then (getManyLinuxDeps fileInfo.name).pkg else []);
rev = source.reference;
} propagatedBuildInputs =
) else if isLocal then (localDepPath) else fetchFromPypi { let
pname = name; # Some dependencies like django gets the attribute name django
inherit (fileInfo) file hash kind; # but dependencies try to access Django
}; deps = builtins.map (d: lib.toLower d) (builtins.attrNames dependencies);
} in
(builtins.map (n: pythonPackages.${n}) deps) ++ (if isLocal then buildSystemPkgs else []);
meta = {
broken = ! isCompatible python.version python-versions;
license = [];
};
# We need to retrieve kind from the interpreter and the filename of the package
# Interpreters should declare what wheel types they're compatible with (python type + ABI)
# Here we can then choose a file based on that info.
src = if isGit then (
builtins.fetchGit {
inherit (source) url;
rev = source.reference;
}
) else if isLocal then (localDepPath) else fetchFromPypi {
pname = name;
inherit (fileInfo) file hash kind;
};
}
) {}

View File

@ -5,14 +5,6 @@
self: super: self: super:
let
getAttrDefault = attribute: set: default:
if builtins.hasAttr attribute set
then builtins.getAttr attribute set
else default;
in
{ {
av = super.av.overrideAttrs ( av = super.av.overrideAttrs (
old: { old: {
@ -52,7 +44,7 @@ in
django = ( django = (
super.django.overrideAttrs ( super.django.overrideAttrs (
old: { old: {
propagatedNativeBuildInputs = (getAttrDefault "propagatedNativeBuildInputs" old []) propagatedNativeBuildInputs = (old.propagatedNativeBuildInputs or [])
++ [ pkgs.gettext ]; ++ [ pkgs.gettext ];
} }
) )
@ -64,7 +56,7 @@ in
if ! test -e LICENSE; then if ! test -e LICENSE; then
touch LICENSE touch LICENSE
fi fi
'' + (getAttrDefault "configurePhase" old ""); '' + (old.configurePhase or "");
} }
); );
@ -85,6 +77,13 @@ in
} }
); );
# importlib-metadata has an incomplete dependency specification
importlib-metadata = super.importlib-metadata.overrideAttrs (
old: {
propagatedBuildInputs = old.propagatedBuildInputs ++ lib.optional self.python.isPy2 self.pathlib2;
}
);
lap = super.lap.overrideAttrs ( lap = super.lap.overrideAttrs (
old: { old: {
propagatedBuildInputs = old.propagatedBuildInputs ++ [ propagatedBuildInputs = old.propagatedBuildInputs ++ [
@ -154,6 +153,11 @@ in
} }
); );
# Calls Cargo at build time for source builds and is really tricky to package
maturin = super.maturin.override {
preferWheel = true;
};
mccabe = super.mccabe.overrideAttrs ( mccabe = super.mccabe.overrideAttrs (
old: { old: {
postPatch = '' postPatch = ''
@ -293,6 +297,93 @@ in
} }
); );
pyqt5 = super.pyqt5.overridePythonAttrs (
old: {
format = "other";
nativeBuildInputs = old.nativeBuildInputs ++ [
pkgs.pkgconfig
pkgs.qt5.qmake
pkgs.xorg.lndir
pkgs.qt5.qtbase
pkgs.qt5.qtsvg
pkgs.qt5.qtdeclarative
pkgs.qt5.qtwebchannel
# self.pyqt5-sip
self.sip
];
buildInputs = old.buildInputs ++ [
pkgs.dbus
pkgs.qt5.qtbase
pkgs.qt5.qtsvg
pkgs.qt5.qtdeclarative
self.sip
];
# Fix dbus mainloop
inherit (pkgs.python3.pkgs.pyqt5) patches;
configurePhase = ''
runHook preConfigure
export PYTHONPATH=$PYTHONPATH:$out/${self.python.sitePackages}
mkdir -p $out/${self.python.sitePackages}/dbus/mainloop
${self.python.executable} configure.py -w \
--confirm-license \
--no-qml-plugin \
--bindir=$out/bin \
--destdir=$out/${self.python.sitePackages} \
--stubsdir=$out/${self.python.sitePackages}/PyQt5 \
--sipdir=$out/share/sip/PyQt5 \
--designer-plugindir=$out/plugins/designer
runHook postConfigure
'';
postInstall = ''
ln -s ${self.pyqt5-sip}/${self.python.sitePackages}/PyQt5/sip.* $out/${self.python.sitePackages}/PyQt5/
for i in $out/bin/*; do
wrapProgram $i --prefix PYTHONPATH : "$PYTHONPATH"
done
# # Let's make it a namespace package
# cat << EOF > $out/${self.python.sitePackages}/PyQt5/__init__.py
# from pkgutil import extend_path
# __path__ = extend_path(__path__, __name__)
# EOF
'';
installCheckPhase = let
modules = [
"PyQt5"
"PyQt5.QtCore"
"PyQt5.QtQml"
"PyQt5.QtWidgets"
"PyQt5.QtGui"
];
imports = lib.concatMapStrings (module: "import ${module};") modules;
in
''
echo "Checking whether modules can be imported..."
${self.python.interpreter} -c "${imports}"
'';
doCheck = true;
enableParallelBuilding = true;
}
);
pytest-datadir = super.pytest-datadir.overrideAttrs (
old: {
postInstall = ''
rm -f $out/LICENSE
'';
}
);
python-prctl = super.python-prctl.overrideAttrs ( python-prctl = super.python-prctl.overrideAttrs (
old: { old: {
buildInputs = old.buildInputs ++ [ buildInputs = old.buildInputs ++ [
@ -340,6 +431,14 @@ in
} }
); );
vose-alias-method = super.pytest-datadir.overrideAttrs (
old: {
postInstall = ''
rm -f $out/LICENSE
'';
}
);
# Stop infinite recursion by using bootstrapped pkg from nixpkgs # Stop infinite recursion by using bootstrapped pkg from nixpkgs
wheel = ( wheel = (
pkgs.python3.pkgs.override { pkgs.python3.pkgs.override {