summary refs log tree commit diff
path: root/pkgs/development/interpreters/python/mk-python-derivation.nix
blob: 7718bdfde5d34116bdb9c2394a67af62d7173666 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
# Generic builder.

{ lib
, config
, python
, wrapPython
, setuptools
, unzip
, ensureNewerSourcesForZipFilesHook
# Whether the derivation provides a Python module or not.
, toPythonModule
, namePrefix
, writeScript
, update-python-libraries
}:

{ name ? "${attrs.pname}-${attrs.version}"

# Build-time dependencies for the package
, nativeBuildInputs ? []

# Run-time dependencies for the package
, buildInputs ? []

# Dependencies needed for running the checkPhase.
# These are added to buildInputs when doCheck = true.
, checkInputs ? []

# propagate build dependencies so in case we have A -> B -> C,
# C can import package A propagated by B
, propagatedBuildInputs ? []

# DEPRECATED: use propagatedBuildInputs
, pythonPath ? []

# used to disable derivation, useful for specific python versions
, disabled ? false

# Raise an error if two packages are installed with the same name
, catchConflicts ? true

# Additional arguments to pass to the makeWrapper function, which wraps
# generated binaries.
, makeWrapperArgs ? []

# Skip wrapping of python programs altogether
, dontWrapPythonPrograms ? false

# Remove bytecode from bin folder.
# When a Python script has the extension `.py`, bytecode is generated
# Typically, executables in bin have no extension, so no bytecode is generated.
# However, some packages do provide executables with extensions, and thus bytecode is generated.
, removeBinBytecode ? true

, meta ? {}

, passthru ? {}

, doCheck ? config.doCheckByDefault or false

, ... } @ attrs:


# Keep extra attributes from `attrs`, e.g., `patchPhase', etc.
if disabled
then throw "${name} not supported for interpreter ${python.executable}"
else

let self = toPythonModule (python.stdenv.mkDerivation (builtins.removeAttrs attrs [
    "disabled" "checkInputs" "doCheck" "doInstallCheck" "dontWrapPythonPrograms" "catchConflicts"
  ] // {

  name = namePrefix + name;

  nativeBuildInputs = [ ensureNewerSourcesForZipFilesHook ]
    ++ nativeBuildInputs;

  buildInputs = [ wrapPython ]
    ++ lib.optional (lib.hasSuffix "zip" (attrs.src.name or "")) unzip
#     ++ lib.optional catchConflicts setuptools # If we no longer propagate setuptools
    ++ buildInputs
    ++ pythonPath;

  # Propagate python and setuptools. We should stop propagating setuptools.
  propagatedBuildInputs = propagatedBuildInputs ++ [ python setuptools ];

  # Python packages don't have a checkPhase, only an installCheckPhase
  doCheck = false;
  doInstallCheck = doCheck;
  installCheckInputs = checkInputs;

  postFixup = lib.optionalString (!dontWrapPythonPrograms) ''
    wrapPythonPrograms
  '' + lib.optionalString removeBinBytecode ''
    if [ -d "$out/bin" ]; then
      rm -rf "$out/bin/__pycache__"                 # Python 3
      find "$out/bin" -type f -name "*.pyc" -delete # Python 2
    fi
  '' + lib.optionalString catchConflicts ''
    # Check if we have two packages with the same name in the closure and fail.
    # If this happens, something went wrong with the dependencies specs.
    # Intentionally kept in a subdirectory, see catch_conflicts/README.md.
    ${python.pythonForBuild.interpreter} ${./catch_conflicts}/catch_conflicts.py
  '' + attrs.postFixup or '''';

  # Python packages built through cross-compilation are always for the host platform.
  disallowedReferences = lib.optionals (python.stdenv.hostPlatform != python.stdenv.buildPlatform) [ python.pythonForBuild ];

  meta = {
    # default to python's platforms
    platforms = python.meta.platforms;
    isBuildPythonPackage = python.meta.platforms;
  } // meta;
}));

passthru.updateScript = let
    filename = builtins.head (lib.splitString ":" self.meta.position);
  in attrs.passthru.updateScript or [ update-python-libraries filename ];
in lib.extendDerivation true passthru self