1{
2 pkgs,
3 stdenv,
4 lib,
5 python,
6}:
7
8self:
9
10let
11 inherit (self) callPackage;
12
13 namePrefix = python.libPrefix + "-";
14
15 # Derivations built with `buildPythonPackage` can already be overridden with `override`, `overrideAttrs`, and `overrideDerivation`.
16 # This function introduces `overridePythonAttrs` and it overrides the call to `buildPythonPackage`.
17 makeOverridablePythonPackage =
18 f:
19 lib.mirrorFunctionArgs f (
20 origArgs:
21 let
22 args = lib.fix (
23 lib.extends (_: previousAttrs: {
24 passthru = (previousAttrs.passthru or { }) // {
25 overridePythonAttrs = newArgs: makeOverridablePythonPackage f (overrideWith newArgs);
26 };
27 }) (_: origArgs)
28 );
29 result = f args;
30 overrideWith = newArgs: args // (if pkgs.lib.isFunction newArgs then newArgs args else newArgs);
31 in
32 if builtins.isAttrs result then
33 result
34 else if builtins.isFunction result then
35 {
36 overridePythonAttrs = newArgs: makeOverridablePythonPackage f (overrideWith newArgs);
37 __functor = self: result;
38 }
39 else
40 result
41 );
42
43 mkPythonDerivation =
44 if python.isPy3k then ./mk-python-derivation.nix else ./python2/mk-python-derivation.nix;
45
46 buildPythonPackage = makeOverridablePythonPackage (
47 callPackage mkPythonDerivation {
48 inherit namePrefix; # We want Python libraries to be named like e.g. "python3.6-${name}"
49 inherit toPythonModule; # Libraries provide modules
50 }
51 );
52
53 buildPythonApplication = makeOverridablePythonPackage (
54 callPackage mkPythonDerivation {
55 namePrefix = ""; # Python applications should not have any prefix
56 toPythonModule = x: x; # Application does not provide modules.
57 }
58 );
59
60 # Check whether a derivation provides a Python module.
61 hasPythonModule = drv: drv ? pythonModule && drv.pythonModule == python;
62
63 # Get list of required Python modules given a list of derivations.
64 requiredPythonModules =
65 drvs:
66 let
67 modules = lib.filter hasPythonModule drvs;
68 in
69 lib.unique (
70 [ python ] ++ modules ++ lib.concatLists (lib.catAttrs "requiredPythonModules" modules)
71 );
72
73 # Create a PYTHONPATH from a list of derivations. This function recurses into the items to find derivations
74 # providing Python modules.
75 makePythonPath = drvs: lib.makeSearchPath python.sitePackages (requiredPythonModules drvs);
76
77 removePythonPrefix = lib.removePrefix namePrefix;
78
79 mkPythonEditablePackage = callPackage ./editable.nix { };
80
81 mkPythonMetaPackage = callPackage ./meta-package.nix { };
82
83 # Convert derivation to a Python module.
84 toPythonModule =
85 drv:
86 drv.overrideAttrs (oldAttrs: {
87 # Use passthru in order to prevent rebuilds when possible.
88 passthru = (oldAttrs.passthru or { }) // {
89 pythonModule = python;
90 pythonPath = [ ]; # Deprecated, for compatibility.
91 requiredPythonModules = builtins.addErrorContext "while calculating requiredPythonModules for ${drv.name or drv.pname}:" (
92 requiredPythonModules drv.propagatedBuildInputs
93 );
94 };
95 });
96
97 # Convert a Python library to an application.
98 toPythonApplication =
99 drv:
100 drv.overrideAttrs (oldAttrs: {
101 passthru = (oldAttrs.passthru or { }) // {
102 # Remove Python prefix from name so we have a "normal" name.
103 # While the prefix shows up in the store path, it won't be
104 # used by `nix-env`.
105 name = removePythonPrefix oldAttrs.name;
106 pythonModule = false;
107 };
108 });
109
110 disabled =
111 drv:
112 throw "${
113 removePythonPrefix (drv.pname or drv.name)
114 } not supported for interpreter ${python.executable}";
115
116 disabledIf = x: drv: if x then disabled drv else drv;
117
118in
119{
120 inherit lib pkgs stdenv;
121 inherit (python.passthru)
122 isPy27
123 isPy37
124 isPy38
125 isPy39
126 isPy310
127 isPy311
128 isPy312
129 isPy313
130 isPy314
131 isPy3k
132 isPyPy
133 pythonAtLeast
134 pythonOlder
135 ;
136 inherit buildPythonPackage buildPythonApplication;
137 inherit
138 hasPythonModule
139 requiredPythonModules
140 makePythonPath
141 disabled
142 disabledIf
143 ;
144 inherit toPythonModule toPythonApplication;
145 inherit mkPythonMetaPackage mkPythonEditablePackage;
146
147 python = toPythonModule python;
148
149 # Don't take pythonPackages from "global" pkgs scope to avoid mixing python versions.
150 pythonPackages = self;
151}