diff --git a/doc/languages-frameworks/python.md b/doc/languages-frameworks/python.md index fc0100c5f2d..e7a8b034a11 100644 --- a/doc/languages-frameworks/python.md +++ b/doc/languages-frameworks/python.md @@ -523,7 +523,7 @@ All parameters from `mkDerivation` function are still supported. * `postShellHook`: Hook to execute commands after `shellHook`. * `makeWrapperArgs`: A list of strings. Arguments to be passed to `makeWrapper`, which wraps generated binaries. By default, the arguments to `makeWrapper` set `PATH` and `PYTHONPATH` environment variables before calling the binary. Additional arguments here can allow a developer to set environment variables which will be available when the binary is run. For example, `makeWrapperArgs = ["--set FOO BAR" "--set BAZ QUX"]`. * `installFlags`: A list of strings. Arguments to be passed to `pip install`. To pass options to `python setup.py install`, use `--install-option`. E.g., `installFlags=["--install-option='--cpp_implementation'"]. -* `format`: Format of the source. Options are `setup` for when the source has a `setup.py` and `setuptools` is used to build a wheel, and `wheel` in case the source is already a binary wheel. The default value is `setup`. +* `format`: Format of the source. Valid options are `setuptools` (default), `flit`, `wheel`, and `other`. `setuptools` is for when the source has a `setup.py` and `setuptools` is used to build a wheel, `flit`, in case `flit` should be used to build a wheel, and `wheel` in case a wheel is provided. In case you need to provide your own `buildPhase` and `installPhase` you can use `other`. * `catchConflicts` If `true`, abort package build if a package name appears more than once in dependency tree. Default is `true`. * `checkInputs` Dependencies needed for running the `checkPhase`. These are added to `buildInputs` when `doCheck = true`. diff --git a/pkgs/development/interpreters/python/build-python-package-common.nix b/pkgs/development/interpreters/python/build-python-package-common.nix new file mode 100644 index 00000000000..80d40013f15 --- /dev/null +++ b/pkgs/development/interpreters/python/build-python-package-common.nix @@ -0,0 +1,27 @@ +# This function provides generic bits to install a Python wheel. + +{ python +, bootstrapped-pip +}: + +{ buildInputs ? [] +# Additional flags to pass to "pip install". +, installFlags ? [] +, ... } @ attrs: + +attrs // { + buildInputs = buildInputs ++ [ bootstrapped-pip ]; + + installPhase = attrs.installPhase or '' + runHook preInstall + + mkdir -p "$out/${python.sitePackages}" + export PYTHONPATH="$out/${python.sitePackages}:$PYTHONPATH" + + pushd dist + ${bootstrapped-pip}/bin/pip install *.whl --no-index --prefix=$out --no-cache ${toString installFlags} + popd + + runHook postInstall + ''; +} \ No newline at end of file diff --git a/pkgs/development/interpreters/python/build-python-package-flit.nix b/pkgs/development/interpreters/python/build-python-package-flit.nix new file mode 100644 index 00000000000..8628c3df769 --- /dev/null +++ b/pkgs/development/interpreters/python/build-python-package-flit.nix @@ -0,0 +1,19 @@ +# This function provides specific bits for building a flit-based Python package. + +{ flit +}: + +{ ... } @ attrs: + +attrs // { + buildInputs = [ flit ]; + buildPhase = attrs.buildPhase or '' + runHook preBuild + flit wheel + runHook postBuild + ''; + + # Flit packages do not come with tests. + installCheckPhase = attrs.checkPhase or ":"; + doCheck = attrs.doCheck or false; +} \ No newline at end of file diff --git a/pkgs/development/interpreters/python/build-python-package-setuptools.nix b/pkgs/development/interpreters/python/build-python-package-setuptools.nix new file mode 100644 index 00000000000..f077533ecfe --- /dev/null +++ b/pkgs/development/interpreters/python/build-python-package-setuptools.nix @@ -0,0 +1,56 @@ +# This function provides specific bits for building a setuptools-based Python package. + +{ lib +, python +, bootstrapped-pip +}: + +{ +# passed to "python setup.py build_ext" +# https://github.com/pypa/pip/issues/881 + setupPyBuildFlags ? [] +# Execute before shell hook +, preShellHook ? "" +# Execute after shell hook +, postShellHook ? "" +, ... } @ attrs: + +let + # use setuptools shim (so that setuptools is imported before distutils) + # pip does the same thing: https://github.com/pypa/pip/pull/3265 + setuppy = ./run_setup.py; + +in attrs // { + # we copy nix_run_setup.py over so it's executed relative to the root of the source + # many project make that assumption + buildPhase = attrs.buildPhase or '' + runHook preBuild + cp ${setuppy} nix_run_setup.py + ${python.interpreter} nix_run_setup.py ${lib.optionalString (setupPyBuildFlags != []) ("build_ext " + (lib.concatStringsSep " " setupPyBuildFlags))} bdist_wheel + runHook postBuild + ''; + + installCheckPhase = attrs.checkPhase or '' + runHook preCheck + ${python.interpreter} nix_run_setup.py test + runHook postCheck + ''; + + # Python packages that are installed with setuptools + # are typically distributed with tests. + # With Python it's a common idiom to run the tests + # after the software has been installed. + doCheck = attrs.doCheck or true; + + shellHook = attrs.shellHook or '' + ${preShellHook} + if test -e setup.py; then + tmp_path=$(mktemp -d) + export PATH="$tmp_path/bin:$PATH" + export PYTHONPATH="$tmp_path/${python.sitePackages}:$PYTHONPATH" + mkdir -p $tmp_path/${python.sitePackages} + ${bootstrapped-pip}/bin/pip install -e . --prefix $tmp_path + fi + ${postShellHook} + ''; +} \ No newline at end of file diff --git a/pkgs/development/interpreters/python/build-python-package-wheel.nix b/pkgs/development/interpreters/python/build-python-package-wheel.nix new file mode 100644 index 00000000000..7be0a4c304a --- /dev/null +++ b/pkgs/development/interpreters/python/build-python-package-wheel.nix @@ -0,0 +1,20 @@ +# This function provides specific bits for building a wheel-based Python package. + +{ +}: + +{ ... } @ attrs: + +attrs // { + unpackPhase = '' + mkdir dist + cp $src dist/"''${src#*-}" + ''; + + # Wheels are pre-compiled + buildPhase = attrs.buildPhase or ":"; + installCheckPhase = attrs.checkPhase or ":"; + + # Wheels don't have any checks to run + doCheck = attrs.doCheck or false; +} \ No newline at end of file diff --git a/pkgs/development/interpreters/python/build-python-package.nix b/pkgs/development/interpreters/python/build-python-package.nix index a92296cedba..e15405e2981 100644 --- a/pkgs/development/interpreters/python/build-python-package.nix +++ b/pkgs/development/interpreters/python/build-python-package.nix @@ -7,120 +7,31 @@ , python , mkPythonDerivation , bootstrapped-pip +, flit }: -{ buildInputs ? [] - -# propagate build dependencies so in case we have A -> B -> C, -# C can import package A propagated by B -#, propagatedBuildInputs ? [] - -# passed to "python setup.py build_ext" -# https://github.com/pypa/pip/issues/881 -, setupPyBuildFlags ? [] - -# Execute before shell hook -, preShellHook ? "" - -# Execute after shell hook -, postShellHook ? "" - -# Additional flags to pass to "pip install". -, installFlags ? [] - -, format ? "setup" +let + setuptools-specific = import ./build-python-package-setuptools.nix { inherit lib python bootstrapped-pip; }; + flit-specific = import ./build-python-package-flit.nix { inherit flit; }; + wheel-specific = import ./build-python-package-wheel.nix { }; + common = import ./build-python-package-common.nix { inherit python bootstrapped-pip; }; +in +{ +# Several package formats are supported. +# "setuptools" : Install a common setuptools/distutils based package. This builds a wheel. +# "wheel" : Install from a pre-compiled wheel. +# "flit" : Install a flit package. This builds a wheel. +# "other" : Provide your own buildPhase and installPhase. +format ? "setuptools" , ... } @ attrs: - - - let - # use setuptools shim (so that setuptools is imported before distutils) - # pip does the same thing: https://github.com/pypa/pip/pull/3265 - setuppy = ./run_setup.py; - formatspecific = - if format == "wheel" then - { - unpackPhase = '' - mkdir dist - cp $src dist/"''${src#*-}" - ''; + if format == "setuptools" then common (setuptools-specific attrs) + else if format == "flit" then common (flit-specific attrs) + else if format == "wheel" then common (wheel-specific attrs) + else if format == "other" then {} + else throw "Unsupported format ${format}"; - # Wheels are pre-compiled - buildPhase = attrs.buildPhase or ":"; - installCheckPhase = attrs.checkPhase or ":"; - - # Wheels don't have any checks to run - doCheck = attrs.doCheck or false; - } - else if format == "setup" then - { - # we copy nix_run_setup.py over so it's executed relative to the root of the source - # many project make that assumption - buildPhase = attrs.buildPhase or '' - runHook preBuild - cp ${setuppy} nix_run_setup.py - ${python.interpreter} nix_run_setup.py ${lib.optionalString (setupPyBuildFlags != []) ("build_ext " + (lib.concatStringsSep " " setupPyBuildFlags))} bdist_wheel - runHook postBuild - ''; - - installCheckPhase = attrs.checkPhase or '' - runHook preCheck - ${python.interpreter} nix_run_setup.py test - runHook postCheck - ''; - - # Python packages that are installed with setuptools - # are typically distributed with tests. - # With Python it's a common idiom to run the tests - # after the software has been installed. - doCheck = attrs.doCheck or true; - } - else - throw "Unsupported format ${format}"; - -in mkPythonDerivation ( attrs // { - - # To build and install a wheel we need pip - buildInputs = buildInputs ++ [ bootstrapped-pip ]; - -#inherit propagatedBuildInputs; - - configurePhase = attrs.configurePhase or '' - runHook preConfigure - - # patch python interpreter to write null timestamps when compiling python files - # this way python doesn't try to update them when we freeze timestamps in nix store - export DETERMINISTIC_BUILD=1 - - runHook postConfigure - ''; - - installPhase = attrs.installPhase or '' - runHook preInstall - - mkdir -p "$out/${python.sitePackages}" - export PYTHONPATH="$out/${python.sitePackages}:$PYTHONPATH" - - pushd dist - ${bootstrapped-pip}/bin/pip install *.whl --no-index --prefix=$out --no-cache ${toString installFlags} - popd - - runHook postInstall - ''; - - shellHook = attrs.shellHook or '' - ${preShellHook} - if test -e setup.py; then - tmp_path=$(mktemp -d) - export PATH="$tmp_path/bin:$PATH" - export PYTHONPATH="$tmp_path/${python.sitePackages}:$PYTHONPATH" - mkdir -p $tmp_path/${python.sitePackages} - ${bootstrapped-pip}/bin/pip install -e . --prefix $tmp_path - fi - ${postShellHook} - ''; - -} // formatspecific) +in mkPythonDerivation ( attrs // formatspecific ) \ No newline at end of file diff --git a/pkgs/development/interpreters/python/mk-python-derivation.nix b/pkgs/development/interpreters/python/mk-python-derivation.nix index 0f798c63e8f..c8fedaf75fc 100644 --- a/pkgs/development/interpreters/python/mk-python-derivation.nix +++ b/pkgs/development/interpreters/python/mk-python-derivation.nix @@ -57,6 +57,10 @@ python.stdenv.mkDerivation (builtins.removeAttrs attrs ["disabled"] // { inherit pythonPath; + # patch python interpreter to write null timestamps when compiling python files + # this way python doesn't try to update them when we freeze timestamps in nix store + DETERMINISTIC_BUILD=1; + buildInputs = [ wrapPython ] ++ buildInputs ++ pythonPath ++ [ (ensureNewerSourcesHook { year = "1980"; }) ] ++ (lib.optional (lib.hasSuffix "zip" attrs.src.name or "") unzip) diff --git a/pkgs/top-level/python-packages.nix b/pkgs/top-level/python-packages.nix index ca2e88da94e..dfe5a8841ee 100644 --- a/pkgs/top-level/python-packages.nix +++ b/pkgs/top-level/python-packages.nix @@ -30,6 +30,7 @@ let buildPythonPackage = makeOverridable (callPackage ../development/interpreters/python/build-python-package.nix { inherit mkPythonDerivation; inherit bootstrapped-pip; + flit = self.flit; }); buildPythonApplication = args: buildPythonPackage ({namePrefix="";} // args ); @@ -6563,6 +6564,21 @@ in { propagatedBuildInputs = with self; [ configparser ]; }; + entrypoints_flit = buildPythonPackage rec { + pname = "entrypoints"; + version = "0.2.2"; + name = "${pname}-${version}"; + format = "flit"; + + src = pkgs.fetchFromGitHub { + owner = "takluyver"; + repo = pname; + rev = version; + sha256 = "1asi3xfym1g9z24p9ivzyp4smnl600w8hghlv5dziabj6csj8s1h"; + }; + propagatedBuildInputs = with self; [ configparser ]; + }; + etcd = buildPythonPackage rec { name = "etcd-${version}"; version = "2.0.8"; @@ -6866,6 +6882,29 @@ in { propagatedBuildInputs = with self; [ rpkg offtrac urlgrabber fedora_cert ]; }); + flit = buildPythonPackage rec { + pname = "flit"; + version = "0.10"; + name = "${pname}-${version}"; + + format = "wheel"; + + src = pkgs.fetchurl { + url = https://files.pythonhosted.org/packages/24/98/50a090112a04d9e29155c31a222637668b0a4dd778fefcd3132adc50e877/flit-0.10-py3-none-any.whl; + sha256 = "4566b2e1807abeb1fd7bfaa9b444447556f1720518edfb134b56a6a1272b0428"; + }; + + disabled = !isPy3k; + propagatedBuildInputs = with self; [ docutils requests2 requests_download zipfile36]; + + meta = { + description = "A simple packaging tool for simple packages"; + homepage = https://github.com/takluyver/flit; + license = licenses.bsd3; + maintainer = maintainers.fridh; + }; + }; + Flootty = buildPythonPackage rec { name = "Flootty-3.2.0"; @@ -21731,6 +21770,27 @@ in { }; }; + requests_download = buildPythonPackage rec { + pname = "requests_download"; + version = "0.1.1"; + name = "${pname}-${version}"; + + format = "wheel"; + + src = pkgs.fetchurl { + url = https://files.pythonhosted.org/packages/60/af/10f899f0574a81cbc511124c08d7c7dc46c20d4f956a6a3c793ad4330bb4/requests_download-0.1.1-py2.py3-none-any.whl; + sha256 = "07832a93314bcd619aaeb08611ae245728e66672efb930bc2a300a115a47dab7"; + }; + + propagatedBuildInputs = with self; [ requests2 ]; + + meta = { + description = "Download files using requests and save them to a target path"; + homepage = https://www.github.com/takluyver/requests_download; + license = licenses.mit; + maintainer = maintainers.fridh; + }; + }; requests_oauthlib = buildPythonPackage rec { version = "0.4.1"; @@ -31330,6 +31390,27 @@ in { zeitgeist = if isPy3k then throw "zeitgeist not supported for interpreter ${python.executable}" else (pkgs.zeitgeist.override{python2Packages=self;}).py; + zipfile36 = buildPythonPackage rec { + pname = "zipfile36"; + version = "0.1.3"; + name = "${pname}-${version}"; + + src = pkgs.fetchurl { + url = "mirror://pypi/${builtins.substring 0 1 pname}/${pname}/${name}.tar.gz"; + sha256 = "a78a8dddf4fa114f7fe73df76ffcce7538e23433b7a6a96c1c904023f122aead"; + }; + + checkPhase = '' + ${python.interpreter} -m unittest test_zipfile.py + ''; + + meta = { + description = "Read and write ZIP files - backport of the zipfile module from Python 3.6"; + homepage = https://gitlab.com/takluyver/zipfile36; + license = licenses.psfl; + maintainer = maintainers.fridh; + }; + }; });