summary refs log tree commit diff
path: root/pkgs/development/interpreters/python/mk-python-derivation.nix
blob: 020298cc8e9f7e38f051171afe2b4d57145c7c8b (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
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
# Generic builder.

{ lib
, config
, python
, wrapPython
, unzip
, ensureNewerSourcesForZipFilesHook
# Whether the derivation provides a Python module or not.
, toPythonModule
, namePrefix
, update-python-libraries
, setuptools
, flitBuildHook
, pipBuildHook
, pipInstallHook
, pythonCatchConflictsHook
, pythonImportsCheckHook
, pythonRemoveBinBytecodeHook
, setuptoolsBuildHook
, setuptoolsCheckHook
, wheelUnpackHook
, eggUnpackHook
, eggBuildHook
, eggInstallHook
}:

{ 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 ? []

# Enabled to detect some (native)BuildInputs mistakes
, strictDeps ? true

# 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

# Don't use Pip to install a wheel
# Note this is actually a variable for the pipInstallPhase in pip's setupHook.
# It's included here to prevent an infinite recursion.
, dontUsePipInstall ? false

# Skip setting the PYTHONNOUSERSITE environment variable in wrapped programs
, permitUserSite ? 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

# Several package formats are supported.
# "setuptools" : Install a common setuptools/distutils based package. This builds a wheel.
# "wheel" : Install from a pre-compiled wheel.
# "flit" : Install a flit package. This builds a wheel.
# "other" : Provide your own buildPhase and installPhase.
, format ? "setuptools"

, 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
  inherit (python) stdenv;

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

  name = namePrefix + name;

  nativeBuildInputs = [
    python
    wrapPython
    ensureNewerSourcesForZipFilesHook  # move to wheel installer (pip) or builder (setuptools, flit, ...)?
  ] ++ lib.optionals catchConflicts [
    setuptools pythonCatchConflictsHook
  ] ++ lib.optionals removeBinBytecode [
    pythonRemoveBinBytecodeHook
  ] ++ lib.optionals (lib.hasSuffix "zip" (attrs.src.name or "")) [
    unzip
  ] ++ lib.optionals (format == "setuptools") [
    setuptoolsBuildHook
  ] ++ lib.optionals (format == "flit") [
    flitBuildHook
  ] ++ lib.optionals (format == "pyproject") [
    pipBuildHook
  ] ++ lib.optionals (format == "wheel") [
    wheelUnpackHook
  ] ++ lib.optionals (format == "egg") [
    eggUnpackHook eggBuildHook eggInstallHook
  ] ++ lib.optionals (!(format == "other") || dontUsePipInstall) [
    pipInstallHook
  ] ++ lib.optionals (stdenv.buildPlatform == stdenv.hostPlatform) [
    # This is a test, however, it should be ran independent of the checkPhase and checkInputs
    pythonImportsCheckHook
  ] ++ nativeBuildInputs;

  buildInputs = buildInputs ++ pythonPath;

  propagatedBuildInputs = propagatedBuildInputs ++ [ python ];

  inherit strictDeps;

  LANG = "${if python.stdenv.isDarwin then "en_US" else "C"}.UTF-8";

  # Python packages don't have a checkPhase, only an installCheckPhase
  doCheck = false;
  doInstallCheck = attrs.doCheck or true;
  installCheckInputs = [
  ] ++ lib.optionals (format == "setuptools") [
    # Longer-term we should get rid of this and require
    # users of this function to set the `installCheckPhase` or
    # pass in a hook that sets it.
    setuptoolsCheckHook
  ] ++ checkInputs;

  postFixup = lib.optionalString (!dontWrapPythonPrograms) ''
    wrapPythonPrograms
  '' + 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;
} // lib.optionalAttrs (attrs?checkPhase) {
  # If given use the specified checkPhase, otherwise use the setup hook.
  # Longer-term we should get rid of `checkPhase` and use `installCheckPhase`.
  installCheckPhase = attrs.checkPhase;
}));

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