1# Generic builder.
2
3{ lib
4, config
5, python
6, wrapPython
7, setuptools
8, unzip
9, ensureNewerSourcesForZipFilesHook
10# Whether the derivation provides a Python module or not.
11, toPythonModule
12, namePrefix
13}:
14
15{ name ? "${attrs.pname}-${attrs.version}"
16
17# Build-time dependencies for the package
18, nativeBuildInputs ? []
19
20# Run-time dependencies for the package
21, buildInputs ? []
22
23# Dependencies needed for running the checkPhase.
24# These are added to buildInputs when doCheck = true.
25, checkInputs ? []
26
27# propagate build dependencies so in case we have A -> B -> C,
28# C can import package A propagated by B
29, propagatedBuildInputs ? []
30
31# DEPRECATED: use propagatedBuildInputs
32, pythonPath ? []
33
34# used to disable derivation, useful for specific python versions
35, disabled ? false
36
37# Raise an error if two packages are installed with the same name
38, catchConflicts ? true
39
40# Additional arguments to pass to the makeWrapper function, which wraps
41# generated binaries.
42, makeWrapperArgs ? []
43
44# Skip wrapping of python programs altogether
45, dontWrapPythonPrograms ? false
46
47# Remove bytecode from bin folder.
48# When a Python script has the extension `.py`, bytecode is generated
49# Typically, executables in bin have no extension, so no bytecode is generated.
50# However, some packages do provide executables with extensions, and thus bytecode is generated.
51, removeBinBytecode ? true
52
53, meta ? {}
54
55, passthru ? {}
56
57, doCheck ? config.doCheckByDefault or false
58
59, ... } @ attrs:
60
61
62# Keep extra attributes from `attrs`, e.g., `patchPhase', etc.
63if disabled
64then throw "${name} not supported for interpreter ${python.executable}"
65else
66
67toPythonModule (python.stdenv.mkDerivation (builtins.removeAttrs attrs [
68 "disabled" "checkInputs" "doCheck" "doInstallCheck" "dontWrapPythonPrograms" "catchConflicts"
69 ] // {
70
71 name = namePrefix + name;
72
73 nativeBuildInputs = [ ensureNewerSourcesForZipFilesHook ]
74 ++ nativeBuildInputs;
75
76 buildInputs = [ wrapPython ]
77 ++ lib.optional (lib.hasSuffix "zip" (attrs.src.name or "")) unzip
78 ++ lib.optional catchConflicts setuptools # If we no longer propagate setuptools
79 ++ buildInputs
80 ++ pythonPath;
81
82 # Propagate python and setuptools. We should stop propagating setuptools.
83 propagatedBuildInputs = propagatedBuildInputs ++ [ python setuptools ];
84
85 # Python packages don't have a checkPhase, only an installCheckPhase
86 doCheck = false;
87 doInstallCheck = doCheck;
88 installCheckInputs = checkInputs;
89
90 postFixup = lib.optionalString (!dontWrapPythonPrograms) ''
91 wrapPythonPrograms
92 '' + lib.optionalString removeBinBytecode ''
93 if [ -d "$out/bin" ]; then
94 rm -rf "$out/bin/__pycache__" # Python 3
95 find "$out/bin" -type f -name "*.pyc" -delete # Python 2
96 fi
97 '' + lib.optionalString catchConflicts ''
98 # Check if we have two packages with the same name in the closure and fail.
99 # If this happens, something went wrong with the dependencies specs.
100 # Intentionally kept in a subdirectory, see catch_conflicts/README.md.
101 ${python.interpreter} ${./catch_conflicts}/catch_conflicts.py
102 '' + attrs.postFixup or '''';
103
104 meta = {
105 # default to python's platforms
106 platforms = python.meta.platforms;
107 isBuildPythonPackage = python.meta.platforms;
108 } // meta;
109}))