pythonRelaxDepsHook: init
We have a common pattern here in nixpkgs for Python applications: when a
Python package ships with either a requirements.txt or setup.py file, we
generally end up having to modify its version restriction, otherwise we have
build failures since we package only one specific version of each package
normally.
However, this end up being done in a completely ad-hoc way: some people
use substituteInPlace, some others use sed, others uses patches, etc.
In many cases, the code ends up being buggy, so it may work in one
version and breaks on the next one. We can instead implement one
standard way of doing this, and trying to be a correct as possible.
So this is what this commit does: it implements a new build hook, that
when called will automatically patch the wheel file. This is one of the
most generic ways to patch Python dependencies, and should work in
multiple cases.
2022-04-28 19:58:59 +00:00
|
|
|
# shellcheck shell=bash
|
|
|
|
|
|
|
|
# Setup hook that modifies Python dependencies versions.
|
|
|
|
#
|
|
|
|
# Example usage in a derivation:
|
|
|
|
#
|
|
|
|
# { …, pythonPackages, … }:
|
|
|
|
#
|
|
|
|
# pythonPackages.buildPythonPackage {
|
|
|
|
# …
|
|
|
|
# nativeBuildInputs = [ pythonPackages.pythonRelaxDepsHook ];
|
|
|
|
#
|
|
|
|
# # This will relax the dependency restrictions
|
|
|
|
# # e.g.: abc>1,<=2 -> abc
|
|
|
|
# pythonRelaxDeps = [ "abc" ];
|
|
|
|
# # This will relax all dependencies restrictions instead
|
|
|
|
# # pythonRelaxDeps = true;
|
|
|
|
# # This will remove the dependency
|
|
|
|
# # e.g.: cde>1,<=2 -> <nothing>
|
|
|
|
# pythonRemoveDeps = [ "cde" ];
|
|
|
|
# # This will remove all dependencies from the project
|
|
|
|
# # pythonRemoveDeps = true;
|
|
|
|
# …
|
|
|
|
# }
|
2022-10-31 15:57:39 +00:00
|
|
|
#
|
|
|
|
# IMPLEMENTATION NOTES:
|
|
|
|
#
|
|
|
|
# The "Requires-Dist" dependency specification format is described in PEP 508.
|
|
|
|
# Examples that the regular expressions in this hook needs to support:
|
|
|
|
#
|
|
|
|
# Requires-Dist: foo
|
|
|
|
# -> foo
|
|
|
|
# Requires-Dist: foo[optional]
|
|
|
|
# -> foo[optional]
|
|
|
|
# Requires-Dist: foo[optional]~=1.2.3
|
|
|
|
# -> foo[optional]
|
|
|
|
# Requires-Dist: foo[optional, xyz] (~=1.2.3)
|
|
|
|
# -> foo[optional, xyz]
|
|
|
|
# Requires-Dist: foo[optional]~=1.2.3 ; os_name = "posix"
|
|
|
|
# -> foo[optional] ; os_name = "posix"
|
|
|
|
#
|
|
|
|
# Currently unsupported: URL specs (foo @ https://example.com/a.zip).
|
pythonRelaxDepsHook: init
We have a common pattern here in nixpkgs for Python applications: when a
Python package ships with either a requirements.txt or setup.py file, we
generally end up having to modify its version restriction, otherwise we have
build failures since we package only one specific version of each package
normally.
However, this end up being done in a completely ad-hoc way: some people
use substituteInPlace, some others use sed, others uses patches, etc.
In many cases, the code ends up being buggy, so it may work in one
version and breaks on the next one. We can instead implement one
standard way of doing this, and trying to be a correct as possible.
So this is what this commit does: it implements a new build hook, that
when called will automatically patch the wheel file. This is one of the
most generic ways to patch Python dependencies, and should work in
multiple cases.
2022-04-28 19:58:59 +00:00
|
|
|
|
|
|
|
_pythonRelaxDeps() {
|
|
|
|
local -r metadata_file="$1"
|
|
|
|
|
|
|
|
if [[ -z "${pythonRelaxDeps:-}" ]] || [[ "$pythonRelaxDeps" == 0 ]]; then
|
|
|
|
return
|
|
|
|
elif [[ "$pythonRelaxDeps" == 1 ]]; then
|
|
|
|
sed -i "$metadata_file" -r \
|
2022-10-31 15:57:39 +00:00
|
|
|
-e 's/(Requires-Dist: [a-zA-Z0-9_.-]+\s*(\[[^]]+\])?)[^;]*(;.*)?/\1\3/'
|
pythonRelaxDepsHook: init
We have a common pattern here in nixpkgs for Python applications: when a
Python package ships with either a requirements.txt or setup.py file, we
generally end up having to modify its version restriction, otherwise we have
build failures since we package only one specific version of each package
normally.
However, this end up being done in a completely ad-hoc way: some people
use substituteInPlace, some others use sed, others uses patches, etc.
In many cases, the code ends up being buggy, so it may work in one
version and breaks on the next one. We can instead implement one
standard way of doing this, and trying to be a correct as possible.
So this is what this commit does: it implements a new build hook, that
when called will automatically patch the wheel file. This is one of the
most generic ways to patch Python dependencies, and should work in
multiple cases.
2022-04-28 19:58:59 +00:00
|
|
|
else
|
|
|
|
for dep in $pythonRelaxDeps; do
|
|
|
|
sed -i "$metadata_file" -r \
|
2022-10-31 15:57:39 +00:00
|
|
|
-e "s/(Requires-Dist: $dep\s*(\[[^]]+\])?)[^;]*(;.*)?/\1\3/"
|
pythonRelaxDepsHook: init
We have a common pattern here in nixpkgs for Python applications: when a
Python package ships with either a requirements.txt or setup.py file, we
generally end up having to modify its version restriction, otherwise we have
build failures since we package only one specific version of each package
normally.
However, this end up being done in a completely ad-hoc way: some people
use substituteInPlace, some others use sed, others uses patches, etc.
In many cases, the code ends up being buggy, so it may work in one
version and breaks on the next one. We can instead implement one
standard way of doing this, and trying to be a correct as possible.
So this is what this commit does: it implements a new build hook, that
when called will automatically patch the wheel file. This is one of the
most generic ways to patch Python dependencies, and should work in
multiple cases.
2022-04-28 19:58:59 +00:00
|
|
|
done
|
|
|
|
fi
|
|
|
|
}
|
|
|
|
|
|
|
|
_pythonRemoveDeps() {
|
|
|
|
local -r metadata_file="$1"
|
|
|
|
|
|
|
|
if [[ -z "${pythonRemoveDeps:-}" ]] || [[ "$pythonRemoveDeps" == 0 ]]; then
|
|
|
|
return
|
|
|
|
elif [[ "$pythonRemoveDeps" == 1 ]]; then
|
|
|
|
sed -i "$metadata_file" \
|
|
|
|
-e '/Requires-Dist:.*/d'
|
|
|
|
else
|
|
|
|
for dep in $pythonRemoveDeps; do
|
|
|
|
sed -i "$metadata_file" \
|
|
|
|
-e "/Requires-Dist: $dep/d"
|
|
|
|
done
|
|
|
|
fi
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
pythonRelaxDepsHook() {
|
|
|
|
pushd dist
|
|
|
|
|
2022-06-07 14:54:30 +00:00
|
|
|
# See https://peps.python.org/pep-0491/#escaping-and-unicode
|
2023-08-11 10:39:07 +00:00
|
|
|
local -r pkg_name="${pname//[^[:alnum:].]/_}"
|
pythonRelaxDepsHook: init
We have a common pattern here in nixpkgs for Python applications: when a
Python package ships with either a requirements.txt or setup.py file, we
generally end up having to modify its version restriction, otherwise we have
build failures since we package only one specific version of each package
normally.
However, this end up being done in a completely ad-hoc way: some people
use substituteInPlace, some others use sed, others uses patches, etc.
In many cases, the code ends up being buggy, so it may work in one
version and breaks on the next one. We can instead implement one
standard way of doing this, and trying to be a correct as possible.
So this is what this commit does: it implements a new build hook, that
when called will automatically patch the wheel file. This is one of the
most generic ways to patch Python dependencies, and should work in
multiple cases.
2022-04-28 19:58:59 +00:00
|
|
|
local -r unpack_dir="unpacked"
|
2023-08-11 10:39:07 +00:00
|
|
|
local -r metadata_file="$unpack_dir/$pkg_name*/$pkg_name*.dist-info/METADATA"
|
pythonRelaxDepsHook: init
We have a common pattern here in nixpkgs for Python applications: when a
Python package ships with either a requirements.txt or setup.py file, we
generally end up having to modify its version restriction, otherwise we have
build failures since we package only one specific version of each package
normally.
However, this end up being done in a completely ad-hoc way: some people
use substituteInPlace, some others use sed, others uses patches, etc.
In many cases, the code ends up being buggy, so it may work in one
version and breaks on the next one. We can instead implement one
standard way of doing this, and trying to be a correct as possible.
So this is what this commit does: it implements a new build hook, that
when called will automatically patch the wheel file. This is one of the
most generic ways to patch Python dependencies, and should work in
multiple cases.
2022-04-28 19:58:59 +00:00
|
|
|
|
2022-06-12 10:46:30 +00:00
|
|
|
# We generally shouldn't have multiple wheel files, but let's be safer here
|
|
|
|
for wheel in "$pkg_name"*".whl"; do
|
|
|
|
@pythonInterpreter@ -m wheel unpack --dest "$unpack_dir" "$wheel"
|
|
|
|
rm -rf "$wheel"
|
pythonRelaxDepsHook: init
We have a common pattern here in nixpkgs for Python applications: when a
Python package ships with either a requirements.txt or setup.py file, we
generally end up having to modify its version restriction, otherwise we have
build failures since we package only one specific version of each package
normally.
However, this end up being done in a completely ad-hoc way: some people
use substituteInPlace, some others use sed, others uses patches, etc.
In many cases, the code ends up being buggy, so it may work in one
version and breaks on the next one. We can instead implement one
standard way of doing this, and trying to be a correct as possible.
So this is what this commit does: it implements a new build hook, that
when called will automatically patch the wheel file. This is one of the
most generic ways to patch Python dependencies, and should work in
multiple cases.
2022-04-28 19:58:59 +00:00
|
|
|
|
2023-08-11 10:39:07 +00:00
|
|
|
# Using no quotes on purpose since we need to expand the glob from `$metadata_file`
|
|
|
|
_pythonRelaxDeps $metadata_file
|
|
|
|
_pythonRemoveDeps $metadata_file
|
pythonRelaxDepsHook: init
We have a common pattern here in nixpkgs for Python applications: when a
Python package ships with either a requirements.txt or setup.py file, we
generally end up having to modify its version restriction, otherwise we have
build failures since we package only one specific version of each package
normally.
However, this end up being done in a completely ad-hoc way: some people
use substituteInPlace, some others use sed, others uses patches, etc.
In many cases, the code ends up being buggy, so it may work in one
version and breaks on the next one. We can instead implement one
standard way of doing this, and trying to be a correct as possible.
So this is what this commit does: it implements a new build hook, that
when called will automatically patch the wheel file. This is one of the
most generic ways to patch Python dependencies, and should work in
multiple cases.
2022-04-28 19:58:59 +00:00
|
|
|
|
2022-06-12 10:46:30 +00:00
|
|
|
if (( "${NIX_DEBUG:-0}" >= 1 )); then
|
|
|
|
echo "pythonRelaxDepsHook: resulting METADATA for '$wheel':"
|
2023-08-11 10:39:07 +00:00
|
|
|
cat $metadata_file
|
2022-06-12 10:46:30 +00:00
|
|
|
fi
|
pythonRelaxDepsHook: init
We have a common pattern here in nixpkgs for Python applications: when a
Python package ships with either a requirements.txt or setup.py file, we
generally end up having to modify its version restriction, otherwise we have
build failures since we package only one specific version of each package
normally.
However, this end up being done in a completely ad-hoc way: some people
use substituteInPlace, some others use sed, others uses patches, etc.
In many cases, the code ends up being buggy, so it may work in one
version and breaks on the next one. We can instead implement one
standard way of doing this, and trying to be a correct as possible.
So this is what this commit does: it implements a new build hook, that
when called will automatically patch the wheel file. This is one of the
most generic ways to patch Python dependencies, and should work in
multiple cases.
2022-04-28 19:58:59 +00:00
|
|
|
|
2023-08-11 10:39:07 +00:00
|
|
|
@pythonInterpreter@ -m wheel pack "$unpack_dir/$pkg_name"*
|
2022-06-12 10:46:30 +00:00
|
|
|
done
|
pythonRelaxDepsHook: init
We have a common pattern here in nixpkgs for Python applications: when a
Python package ships with either a requirements.txt or setup.py file, we
generally end up having to modify its version restriction, otherwise we have
build failures since we package only one specific version of each package
normally.
However, this end up being done in a completely ad-hoc way: some people
use substituteInPlace, some others use sed, others uses patches, etc.
In many cases, the code ends up being buggy, so it may work in one
version and breaks on the next one. We can instead implement one
standard way of doing this, and trying to be a correct as possible.
So this is what this commit does: it implements a new build hook, that
when called will automatically patch the wheel file. This is one of the
most generic ways to patch Python dependencies, and should work in
multiple cases.
2022-04-28 19:58:59 +00:00
|
|
|
|
2022-10-03 15:22:23 +00:00
|
|
|
# Remove the folder since it will otherwise be in the dist output.
|
|
|
|
rm -rf "$unpack_dir"
|
|
|
|
|
pythonRelaxDepsHook: init
We have a common pattern here in nixpkgs for Python applications: when a
Python package ships with either a requirements.txt or setup.py file, we
generally end up having to modify its version restriction, otherwise we have
build failures since we package only one specific version of each package
normally.
However, this end up being done in a completely ad-hoc way: some people
use substituteInPlace, some others use sed, others uses patches, etc.
In many cases, the code ends up being buggy, so it may work in one
version and breaks on the next one. We can instead implement one
standard way of doing this, and trying to be a correct as possible.
So this is what this commit does: it implements a new build hook, that
when called will automatically patch the wheel file. This is one of the
most generic ways to patch Python dependencies, and should work in
multiple cases.
2022-04-28 19:58:59 +00:00
|
|
|
popd
|
|
|
|
}
|
|
|
|
|
|
|
|
postBuild+=" pythonRelaxDepsHook"
|