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