at 23.05-pre 6.7 kB view raw
1# Generic builder. 2 3{ lib 4, config 5, python 6, wrapPython 7, unzip 8, ensureNewerSourcesForZipFilesHook 9# Whether the derivation provides a Python module or not. 10, toPythonModule 11, namePrefix 12, update-python-libraries 13, setuptools 14, flitBuildHook 15, pipBuildHook 16, pipInstallHook 17, pythonCatchConflictsHook 18, pythonImportsCheckHook 19, pythonNamespacesHook 20, pythonOutputDistHook 21, pythonRemoveBinBytecodeHook 22, pythonRemoveTestsDirHook 23, setuptoolsBuildHook 24, setuptoolsCheckHook 25, wheelUnpackHook 26, eggUnpackHook 27, eggBuildHook 28, eggInstallHook 29}: 30 31{ name ? "${attrs.pname}-${attrs.version}" 32 33# Build-time dependencies for the package 34, nativeBuildInputs ? [] 35 36# Run-time dependencies for the package 37, buildInputs ? [] 38 39# Dependencies needed for running the checkPhase. 40# These are added to buildInputs when doCheck = true. 41, checkInputs ? [] 42 43# propagate build dependencies so in case we have A -> B -> C, 44# C can import package A propagated by B 45, propagatedBuildInputs ? [] 46 47# DEPRECATED: use propagatedBuildInputs 48, pythonPath ? [] 49 50# Enabled to detect some (native)BuildInputs mistakes 51, strictDeps ? true 52 53, outputs ? [ "out" ] 54 55# used to disable derivation, useful for specific python versions 56, disabled ? false 57 58# Raise an error if two packages are installed with the same name 59# TODO: For cross we probably need a different PYTHONPATH, or not 60# add the runtime deps until after buildPhase. 61, catchConflicts ? (python.stdenv.hostPlatform == python.stdenv.buildPlatform) 62 63# Additional arguments to pass to the makeWrapper function, which wraps 64# generated binaries. 65, makeWrapperArgs ? [] 66 67# Skip wrapping of python programs altogether 68, dontWrapPythonPrograms ? false 69 70# Don't use Pip to install a wheel 71# Note this is actually a variable for the pipInstallPhase in pip's setupHook. 72# It's included here to prevent an infinite recursion. 73, dontUsePipInstall ? false 74 75# Skip setting the PYTHONNOUSERSITE environment variable in wrapped programs 76, permitUserSite ? false 77 78# Remove bytecode from bin folder. 79# When a Python script has the extension `.py`, bytecode is generated 80# Typically, executables in bin have no extension, so no bytecode is generated. 81# However, some packages do provide executables with extensions, and thus bytecode is generated. 82, removeBinBytecode ? true 83 84# Several package formats are supported. 85# "setuptools" : Install a common setuptools/distutils based package. This builds a wheel. 86# "wheel" : Install from a pre-compiled wheel. 87# "flit" : Install a flit package. This builds a wheel. 88# "pyproject": Install a package using a ``pyproject.toml`` file (PEP517). This builds a wheel. 89# "egg": Install a package from an egg. 90# "other" : Provide your own buildPhase and installPhase. 91, format ? "setuptools" 92 93, meta ? {} 94 95, passthru ? {} 96 97, doCheck ? config.doCheckByDefault or false 98 99, disabledTestPaths ? [] 100 101, ... } @ attrs: 102 103 104# Keep extra attributes from `attrs`, e.g., `patchPhase', etc. 105if disabled 106then throw "${name} not supported for interpreter ${python.executable}" 107else 108 109let 110 inherit (python) stdenv; 111 112 withDistOutput = lib.elem format ["pyproject" "setuptools" "flit" "wheel"]; 113 114 name_ = name; 115 116 self = toPythonModule (stdenv.mkDerivation ((builtins.removeAttrs attrs [ 117 "disabled" "checkPhase" "checkInputs" "doCheck" "doInstallCheck" "dontWrapPythonPrograms" "catchConflicts" "format" 118 "disabledTestPaths" "outputs" 119 ]) // { 120 121 name = namePrefix + name_; 122 123 nativeBuildInputs = [ 124 python 125 wrapPython 126 ensureNewerSourcesForZipFilesHook # move to wheel installer (pip) or builder (setuptools, flit, ...)? 127 pythonRemoveTestsDirHook 128 ] ++ lib.optionals catchConflicts [ 129 pythonCatchConflictsHook 130 ] ++ lib.optionals removeBinBytecode [ 131 pythonRemoveBinBytecodeHook 132 ] ++ lib.optionals (lib.hasSuffix "zip" (attrs.src.name or "")) [ 133 unzip 134 ] ++ lib.optionals (format == "setuptools") [ 135 setuptoolsBuildHook 136 ] ++ lib.optionals (format == "flit") [ 137 flitBuildHook 138 ] ++ lib.optionals (format == "pyproject") [ 139 pipBuildHook 140 ] ++ lib.optionals (format == "wheel") [ 141 wheelUnpackHook 142 ] ++ lib.optionals (format == "egg") [ 143 eggUnpackHook eggBuildHook eggInstallHook 144 ] ++ lib.optionals (!(format == "other") || dontUsePipInstall) [ 145 pipInstallHook 146 ] ++ lib.optionals (stdenv.buildPlatform == stdenv.hostPlatform) [ 147 # This is a test, however, it should be ran independent of the checkPhase and checkInputs 148 pythonImportsCheckHook 149 ] ++ lib.optionals (python.pythonAtLeast "3.3") [ 150 # Optionally enforce PEP420 for python3 151 pythonNamespacesHook 152 ] ++ lib.optionals withDistOutput [ 153 pythonOutputDistHook 154 ] ++ nativeBuildInputs; 155 156 buildInputs = buildInputs ++ pythonPath; 157 158 propagatedBuildInputs = propagatedBuildInputs ++ [ 159 # we propagate python even for packages transformed with 'toPythonApplication' 160 # this pollutes the PATH but avoids rebuilds 161 # see https://github.com/NixOS/nixpkgs/issues/170887 for more context 162 python 163 ]; 164 165 inherit strictDeps; 166 167 LANG = "${if python.stdenv.isDarwin then "en_US" else "C"}.UTF-8"; 168 169 # Python packages don't have a checkPhase, only an installCheckPhase 170 doCheck = false; 171 doInstallCheck = attrs.doCheck or true; 172 installCheckInputs = [ 173 ] ++ lib.optionals (format == "setuptools") [ 174 # Longer-term we should get rid of this and require 175 # users of this function to set the `installCheckPhase` or 176 # pass in a hook that sets it. 177 setuptoolsCheckHook 178 ] ++ checkInputs; 179 180 postFixup = lib.optionalString (!dontWrapPythonPrograms) '' 181 wrapPythonPrograms 182 '' + attrs.postFixup or ""; 183 184 # Python packages built through cross-compilation are always for the host platform. 185 disallowedReferences = lib.optionals (python.stdenv.hostPlatform != python.stdenv.buildPlatform) [ python.pythonForBuild ]; 186 187 outputs = outputs ++ lib.optional withDistOutput "dist"; 188 189 meta = { 190 # default to python's platforms 191 platforms = python.meta.platforms; 192 isBuildPythonPackage = python.meta.platforms; 193 } // meta; 194 } // lib.optionalAttrs (attrs?checkPhase) { 195 # If given use the specified checkPhase, otherwise use the setup hook. 196 # Longer-term we should get rid of `checkPhase` and use `installCheckPhase`. 197 installCheckPhase = attrs.checkPhase; 198 } // lib.optionalAttrs (disabledTestPaths != []) { 199 disabledTestPaths = lib.escapeShellArgs disabledTestPaths; 200 })); 201 202 passthru.updateScript = let 203 filename = builtins.head (lib.splitString ":" self.meta.position); 204 in attrs.passthru.updateScript or [ update-python-libraries filename ]; 205in lib.extendDerivation true passthru self