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