1# Python {#python}
2
3## Reference {#reference}
4
5### Interpreters {#interpreters}
6
7@python-interpreter-table@
8
9The Nix expressions for the interpreters can be found in
10`pkgs/development/interpreters/python`.
11
12All packages depending on any Python interpreter get appended
13`out/{python.sitePackages}` to `$PYTHONPATH` if such directory
14exists.
15
16#### Missing `tkinter` module standard library {#missing-tkinter-module-standard-library}
17
18To reduce closure size the `Tkinter`/`tkinter` is available as a separate package, `pythonPackages.tkinter`.
19
20#### Attributes on interpreters packages {#attributes-on-interpreters-packages}
21
22Each interpreter has the following attributes:
23
24- `libPrefix`. Name of the folder in `${python}/lib/` for corresponding interpreter.
25- `interpreter`. Alias for `${python}/bin/${executable}`.
26- `buildEnv`. Function to build python interpreter environments with extra packages bundled together. See [](#python.buildenv-function) for usage and documentation.
27- `withPackages`. Simpler interface to `buildEnv`. See [](#python.withpackages-function) for usage and documentation.
28- `sitePackages`. Alias for `lib/${libPrefix}/site-packages`.
29- `executable`. Name of the interpreter executable, e.g. `python3.10`.
30- `pkgs`. Set of Python packages for that specific interpreter. The package set can be modified by overriding the interpreter and passing `packageOverrides`.
31
32### Building packages and applications {#building-packages-and-applications}
33
34Python libraries and applications that use tools to follow PEP 517 (e.g. `setuptools` or `hatchling`, etc.) or
35previous tools such as `distutils` are typically built with respectively the [`buildPythonPackage`](#buildpythonpackage-function) and
36[`buildPythonApplication`](#buildpythonapplication-function) functions. These two functions also support installing a `wheel`.
37
38All Python packages reside in `pkgs/top-level/python-packages.nix` and all
39applications elsewhere. In case a package is used as both a library and an
40application, then the package should be in `pkgs/top-level/python-packages.nix`
41since only those packages are made available for all interpreter versions. The
42preferred location for library expressions is in
43`pkgs/development/python-modules`. It is important that these packages are
44called from `pkgs/top-level/python-packages.nix` and not elsewhere, to guarantee
45the right version of the package is built.
46
47Based on the packages defined in `pkgs/top-level/python-packages.nix` an
48attribute set is created for each available Python interpreter. The available
49sets are
50
51* `pkgs.python27Packages`
52* `pkgs.python3Packages`
53* `pkgs.python310Packages`
54* `pkgs.python311Packages`
55* `pkgs.python312Packages`
56* `pkgs.python313Packages`
57* `pkgs.python314Packages`
58* `pkgs.pypy27Packages`
59* `pkgs.pypy310Packages`
60
61and the aliases
62
63* `pkgs.python2Packages` pointing to `pkgs.python27Packages`
64* `pkgs.python3Packages` pointing to `pkgs.python313Packages`
65* `pkgs.pythonPackages` pointing to `pkgs.python2Packages`
66* `pkgs.pypy2Packages` pointing to `pkgs.pypy27Packages`
67* `pkgs.pypy3Packages` pointing to `pkgs.pypy310Packages`
68* `pkgs.pypyPackages` pointing to `pkgs.pypy2Packages`
69
70
71#### `buildPythonPackage` function {#buildpythonpackage-function}
72
73The `buildPythonPackage` function has its name binding in
74`pkgs/development/interpreters/python/python-packages-base.nix` and is
75implemented in `pkgs/development/interpreters/python/mk-python-derivation.nix`
76using setup hooks.
77
78The following is an example:
79
80```nix
81{
82 lib,
83 buildPythonPackage,
84 fetchPypi,
85
86 # build-system
87 setuptools,
88 setuptools-scm,
89
90 # dependencies
91 attrs,
92 pluggy,
93 py,
94 setuptools,
95 six,
96
97 # tests
98 hypothesis,
99}:
100
101buildPythonPackage rec {
102 pname = "pytest";
103 version = "3.3.1";
104 pyproject = true;
105
106 src = fetchPypi {
107 inherit pname version;
108 hash = "sha256-z4Q23FnYaVNG/NOrKW3kZCXsqwDWQJbOvnn7Ueyy65M=";
109 };
110
111 postPatch = ''
112 # don't test bash builtins
113 rm testing/test_argcomplete.py
114 '';
115
116 build-system = [
117 setuptools
118 setuptools-scm
119 ];
120
121 dependencies = [
122 attrs
123 py
124 setuptools
125 six
126 pluggy
127 ];
128
129 nativeCheckInputs = [ hypothesis ];
130
131 meta = {
132 changelog = "https://github.com/pytest-dev/pytest/releases/tag/${version}";
133 description = "Framework for writing tests";
134 homepage = "https://github.com/pytest-dev/pytest";
135 license = lib.licenses.mit;
136 maintainers = with lib.maintainers; [
137 lovek323
138 madjar
139 lsix
140 ];
141 };
142}
143```
144
145The `buildPythonPackage` mainly does four things:
146
147* In the [`buildPhase`](#build-phase), it calls `${python.pythonOnBuildForHost.interpreter} -m build --wheel` to
148 build a wheel binary zipfile.
149* In the [`installPhase`](#ssec-install-phase), it installs the wheel file using `${python.pythonOnBuildForHost.interpreter} -m installer *.whl`.
150* In the [`postFixup`](#var-stdenv-postFixup) phase, the `wrapPythonPrograms` bash function is called to
151 wrap all programs in the `$out/bin/*` directory to include `$PATH`
152 environment variable and add dependent libraries to script's `sys.path`.
153* In the [`installCheck`](#ssec-installCheck-phase) phase, `${python.interpreter} -m pytest` is run.
154
155By default tests are run because [`doCheck = true`](#var-stdenv-doCheck). Test dependencies, like
156e.g. the test runner, should be added to [`nativeCheckInputs`](#var-stdenv-nativeCheckInputs).
157
158By default `meta.platforms` is set to the same value
159as the interpreter unless overridden otherwise.
160
161##### `buildPythonPackage` parameters {#buildpythonpackage-parameters}
162
163All parameters from [`stdenv.mkDerivation`](#sec-using-stdenv) function are still supported. The
164following are specific to `buildPythonPackage`:
165
166* `catchConflicts ? true`: If `true`, abort package build if a package name
167 appears more than once in dependency tree. Default is `true`.
168* `disabled ? false`: If `true`, package is not built for the particular Python
169 interpreter version.
170* `dontWrapPythonPrograms ? false`: Skip wrapping of Python programs.
171* `permitUserSite ? false`: Skip setting the `PYTHONNOUSERSITE` environment
172 variable in wrapped programs.
173* `pyproject`: Whether the pyproject format should be used. As all other formats
174 are deprecated, you are recommended to set this to `true`. When you do so,
175 `pypaBuildHook` will be used, and you can add the required build dependencies
176 from `build-system.requires` to `build-system`. Note that the pyproject
177 format falls back to using `setuptools`, so you can use `pyproject = true`
178 even if the package only has a `setup.py`. When set to `false`, you can
179 use the existing [hooks](#setup-hooks) or provide your own logic to build the
180 package. This can be useful for packages that don't support the pyproject
181 format. When unset, the legacy `setuptools` hooks are used for backwards
182 compatibility.
183* `makeWrapperArgs ? []`: A list of strings. Arguments to be passed to
184 [`makeWrapper`](#fun-makeWrapper), which wraps generated binaries. By default, the arguments to
185 [`makeWrapper`](#fun-makeWrapper) set `PATH` and `PYTHONPATH` environment variables before calling
186 the binary. Additional arguments here can allow a developer to set environment
187 variables which will be available when the binary is run. For example,
188 `makeWrapperArgs = ["--set" "FOO" "BAR" "--set" "BAZ" "QUX"]`.
189
190 ::: {.note}
191 When `__structuredAttrs = false`, the attribute `makeWrapperArgs` is passed as a space-separated string to the build script. Developers should use `prependToVar` or `appendToVar` to add arguments to it in build phases, or use `__structuredAttrs = true` to ensure that `makeWrapperArgs` is passed as a Bash array.
192
193 For compatibility purposes,
194 when `makeWrapperArgs` shell variable is specified as a space-separated string (instead of a Bash array) in the build script, the string content is Bash-expanded before concatenated into the `wrapProgram` command. Still, developers should not rely on such behaviours, but use `__structuredAttrs = true` to specify flags containing spaces (e.g. `makeWrapperArgs = [ "--set" "GREETING" "Hello, world!" ]`), or use -pre and -post phases to specify flags with Bash-expansions (e.g. `preFixup = ''makeWrapperArgs+=(--prefix PATH : "$SOME_PATH")`'').
195 :::
196
197* `namePrefix`: Prepends text to `${name}` parameter. In case of libraries, this
198 defaults to `"python3.8-"` for Python 3.8, etc., and in case of applications to `""`.
199* `pypaBuildFlags ? []`: A list of strings. Arguments to be passed to `python -m build --wheel`.
200* `pythonPath ? []`: List of packages to be added into `$PYTHONPATH`. Packages
201 in `pythonPath` are not propagated (contrary to [`propagatedBuildInputs`](#var-stdenv-propagatedBuildInputs)).
202* `preShellHook`: Hook to execute commands before `shellHook`.
203* `postShellHook`: Hook to execute commands after `shellHook`.
204* `removeBinByteCode ? true`: Remove bytecode from `/bin`. Bytecode is only
205 created when the filenames end with `.py`.
206* `setupPyGlobalFlags ? []`: List of flags passed to `setup.py` command.
207* `setupPyBuildFlags ? []`: List of flags passed to `setup.py build_ext` command.
208
209The [`stdenv.mkDerivation`](#sec-using-stdenv) function accepts various parameters for describing
210build inputs (see "Specifying dependencies"). The following are of special
211interest for Python packages, either because these are primarily used, or
212because their behaviour is different:
213
214* `nativeBuildInputs ? []`: Build-time only dependencies. Typically executables.
215* `build-system ? []`: Build-time only Python dependencies. Items listed in `build-system.requires`/`setup_requires`.
216* `buildInputs ? []`: Build and/or run-time dependencies that need to be
217 compiled for the host machine. Typically non-Python libraries which are being
218 linked.
219* `nativeCheckInputs ? []`: Dependencies needed for running the [`checkPhase`](#ssec-check-phase). These
220 are added to [`nativeBuildInputs`](#var-stdenv-nativeBuildInputs) when [`doCheck = true`](#var-stdenv-doCheck). Items listed in
221 `tests_require` go here.
222* `dependencies ? []`: Aside from propagating dependencies,
223 `buildPythonPackage` also injects code into and wraps executables with the
224 paths included in this list. Items listed in `install_requires` go here.
225* `optional-dependencies ? { }`: Optional feature flagged dependencies. Items listed in `extras_require` go here.
226
227
228##### Overriding Python packages {#overriding-python-packages}
229
230The `buildPythonPackage` function has a `overridePythonAttrs` method that can be
231used to override the package. In the following example we create an environment
232where we have the `blaze` package using an older version of `pandas`. We
233override first the Python interpreter and pass `packageOverrides` which contains
234the overrides for packages in the package set.
235
236```nix
237with import <nixpkgs> { };
238
239(
240 let
241 python =
242 let
243 packageOverrides = self: super: {
244 pandas = super.pandas.overridePythonAttrs (old: rec {
245 version = "0.19.1";
246 src = fetchPypi {
247 pname = "pandas";
248 inherit version;
249 hash = "sha256-JQn+rtpy/OA2deLszSKEuxyttqBzcAil50H+JDHUdCE=";
250 };
251 });
252 };
253 in
254 pkgs.python3.override {
255 inherit packageOverrides;
256 self = python;
257 };
258
259 in
260 python.withPackages (ps: [ ps.blaze ])
261).env
262```
263
264The next example shows a non trivial overriding of the `blas` implementation to
265be used through out all of the Python package set:
266
267```nix
268{
269 python3MyBlas = pkgs.python3.override {
270 packageOverrides = self: super: {
271 # We need toPythonModule for the package set to evaluate this
272 blas = super.toPythonModule (super.pkgs.blas.override { blasProvider = super.pkgs.mkl; });
273 lapack = super.toPythonModule (super.pkgs.lapack.override { lapackProvider = super.pkgs.mkl; });
274 };
275 };
276}
277```
278
279This is particularly useful for numpy and scipy users who want to gain speed with other blas implementations.
280Note that using `scipy = super.scipy.override { blas = super.pkgs.mkl; };` will likely result in
281compilation issues, because scipy dependencies need to use the same blas implementation as well.
282
283#### `buildPythonApplication` function {#buildpythonapplication-function}
284
285The [`buildPythonApplication`](#buildpythonapplication-function) function is practically the same as
286[`buildPythonPackage`](#buildpythonpackage-function). The main purpose of this function is to build a Python
287package where one is interested only in the executables, and not importable
288modules. For that reason, when adding this package to a [`python.buildEnv`](#python.buildenv-function), the
289modules won't be made available.
290
291Another difference is that [`buildPythonPackage`](#buildpythonpackage-function) by default prefixes the names of
292the packages with the version of the interpreter. Because this is irrelevant for
293applications, the prefix is omitted.
294
295When packaging a Python application with [`buildPythonApplication`](#buildpythonapplication-function), it should be
296called with `callPackage` and passed `python3` or `python3Packages` (possibly
297specifying an interpreter version), like this:
298
299```nix
300{
301 lib,
302 python3Packages,
303 fetchPypi,
304}:
305
306python3Packages.buildPythonApplication rec {
307 pname = "luigi";
308 version = "2.7.9";
309 pyproject = true;
310
311 src = fetchPypi {
312 inherit pname version;
313 hash = "sha256-Pe229rT0aHwA98s+nTHQMEFKZPo/yw6sot8MivFDvAw=";
314 };
315
316 build-system = with python3Packages; [ setuptools ];
317
318 dependencies = with python3Packages; [
319 tornado
320 python-daemon
321 ];
322
323 meta = {
324 # ...
325 };
326}
327```
328
329This is then added to `pkgs/by-name` just as any other application would be.
330
331Since the package is an application, a consumer doesn't need to care about
332Python versions or modules, which is why they don't go in `python3Packages`.
333
334#### `toPythonApplication` function {#topythonapplication-function}
335
336A distinction is made between applications and libraries, however, sometimes a
337package is used as both. In this case the package is added as a library to
338`python-packages.nix` and as an application to `pkgs/by-name`. To reduce
339duplication the `toPythonApplication` can be used to convert a library to an
340application.
341
342The Nix expression shall use [`buildPythonPackage`](#buildpythonpackage-function) and be called from
343`python-packages.nix`. A reference shall be created from `pkgs/by-name` to
344the attribute in `python-packages.nix`, and the `toPythonApplication` shall be
345applied to the reference:
346
347```nix
348{ python3Packages }:
349
350python3Packages.toPythonApplication python3Packages.youtube-dl
351```
352
353#### `toPythonModule` function {#topythonmodule-function}
354
355In some cases, such as bindings, a package is created using
356[`stdenv.mkDerivation`](#sec-using-stdenv) and added as attribute in `pkgs/by-name` or in `all-packages.nix`. The Python
357bindings should be made available from `python-packages.nix`. The
358`toPythonModule` function takes a derivation and makes certain Python-specific
359modifications.
360
361```nix
362{
363 opencv = toPythonModule (
364 pkgs.opencv.override {
365 enablePython = true;
366 pythonPackages = self;
367 }
368 );
369}
370```
371
372Do pay attention to passing in the right Python version!
373
374#### `mkPythonMetaPackage` function {#mkpythonmetapackage-function}
375
376This will create a meta package containing [metadata files](https://packaging.python.org/en/latest/specifications/recording-installed-packages/) to satisfy a dependency on a package, without it actually having been installed into the environment.
377In nixpkgs this is used to package Python packages with split binary/source distributions such as [psycopg2](https://pypi.org/project/psycopg2/)/[psycopg2-binary](https://pypi.org/project/psycopg2-binary/).
378
379```nix
380mkPythonMetaPackage {
381 pname = "psycopg2-binary";
382 inherit (psycopg2) optional-dependencies version;
383 dependencies = [ psycopg2 ];
384 meta = { inherit (psycopg2.meta) description homepage; };
385}
386```
387
388#### `mkPythonEditablePackage` function {#mkpythoneditablepackage-function}
389
390When developing Python packages it's common to install packages in [editable mode](https://setuptools.pypa.io/en/latest/userguide/development_mode.html).
391Like `mkPythonMetaPackage` this function exists to create an otherwise empty package, but also containing a pointer to an impure location outside the Nix store that can be changed without rebuilding.
392
393The editable root is passed as a string. Normally `.pth` files contains absolute paths to the mutable location. This isn't always ergonomic with Nix, so environment variables are expanded at runtime.
394This means that a shell hook setting up something like a `$REPO_ROOT` variable can be used as the relative package root.
395
396As an implementation detail, the [PEP-518](https://peps.python.org/pep-0518/) `build-system` specified won't be used, but instead the editable package will be built using [hatchling](https://pypi.org/project/hatchling/).
397The `build-system`'s provided will instead become runtime dependencies of the editable package.
398
399Note that overriding packages deeper in the dependency graph _can_ work, but it's not the primary use case and overriding existing packages can make others break in unexpected ways.
400
401```nix
402{
403 pkgs ? import <nixpkgs> { },
404}:
405
406let
407 pyproject = pkgs.lib.importTOML ./pyproject.toml;
408
409 myPython = pkgs.python.override {
410 self = myPython;
411 packageOverrides = pyfinal: pyprev: {
412 # An editable package with a script that loads our mutable location
413 my-editable = pyfinal.mkPythonEditablePackage {
414 # Inherit project metadata from pyproject.toml
415 pname = pyproject.project.name;
416 inherit (pyproject.project) version;
417
418 # The editable root passed as a string
419 root = "$REPO_ROOT/src"; # Use environment variable expansion at runtime
420
421 # Inject a script (other PEP-621 entrypoints are also accepted)
422 inherit (pyproject.project) scripts;
423 };
424 };
425 };
426
427 pythonEnv = myPython.withPackages (ps: [ ps.my-editable ]);
428
429in
430pkgs.mkShell { packages = [ pythonEnv ]; }
431```
432
433#### `python.buildEnv` function {#python.buildenv-function}
434
435Python environments can be created using the low-level `pkgs.buildEnv` function.
436This example shows how to create an environment that has the Pyramid Web Framework.
437Saving the following as `default.nix`
438
439```nix
440with import <nixpkgs> { };
441
442python3.buildEnv.override {
443 extraLibs = [ python3Packages.pyramid ];
444 ignoreCollisions = true;
445}
446```
447
448and running `nix-build` will create
449
450```
451/nix/store/cf1xhjwzmdki7fasgr4kz6di72ykicl5-python-2.7.8-env
452```
453
454with wrapped binaries in `bin/`.
455
456You can also use the `env` attribute to create local environments with needed
457packages installed. This is somewhat comparable to `virtualenv`. For example,
458running `nix-shell` with the following `shell.nix`
459
460```nix
461with import <nixpkgs> { };
462
463(python3.buildEnv.override {
464 extraLibs = with python3Packages; [
465 numpy
466 requests
467 ];
468}).env
469```
470
471will drop you into a shell where Python will have the
472specified packages in its path.
473
474##### `python.buildEnv` arguments {#python.buildenv-arguments}
475
476
477* `extraLibs`: List of packages installed inside the environment.
478* `postBuild`: Shell command executed after the build of environment.
479* `ignoreCollisions`: Ignore file collisions inside the environment (default is `false`).
480* `permitUserSite`: Skip setting the `PYTHONNOUSERSITE` environment variable in
481 wrapped binaries in the environment.
482
483#### `python.withPackages` function {#python.withpackages-function}
484
485The [`python.withPackages`](#python.withpackages-function) function provides a simpler interface to the [`python.buildEnv`](#python.buildenv-function) functionality.
486It takes a function as an argument that is passed the set of python packages and returns the list
487of the packages to be included in the environment. Using the [`withPackages`](#python.withpackages-function) function, the previous
488example for the Pyramid Web Framework environment can be written like this:
489
490```nix
491with import <nixpkgs> { };
492
493python.withPackages (ps: [ ps.pyramid ])
494```
495
496[`withPackages`](#python.withpackages-function) passes the correct package set for the specific interpreter
497version as an argument to the function. In the above example, `ps` equals
498`pythonPackages`. But you can also easily switch to using python3:
499
500```nix
501with import <nixpkgs> { };
502
503python3.withPackages (ps: [ ps.pyramid ])
504```
505
506Now, `ps` is set to `python3Packages`, matching the version of the interpreter.
507
508As [`python.withPackages`](#python.withpackages-function) uses [`python.buildEnv`](#python.buildenv-function) under the hood, it also
509supports the `env` attribute. The `shell.nix` file from the previous section can
510thus be also written like this:
511
512```nix
513with import <nixpkgs> { };
514
515(python3.withPackages (
516 ps: with ps; [
517 numpy
518 requests
519 ]
520)).env
521```
522
523In contrast to [`python.buildEnv`](#python.buildenv-function), [`python.withPackages`](#python.withpackages-function) does not support the
524more advanced options such as `ignoreCollisions = true` or `postBuild`. If you
525need them, you have to use [`python.buildEnv`](#python.buildenv-function).
526
527Python 2 namespace packages may provide `__init__.py` that collide. In that case
528[`python.buildEnv`](#python.buildenv-function) should be used with `ignoreCollisions = true`.
529
530#### Setup hooks {#setup-hooks}
531
532The following are setup hooks specifically for Python packages. Most of these
533are used in [`buildPythonPackage`](#buildpythonpackage-function).
534
535- `eggUnpackhook` to move an egg to the correct folder so it can be installed
536 with the `eggInstallHook`
537- `eggBuildHook` to skip building for eggs.
538- `eggInstallHook` to install eggs.
539- `pypaBuildHook` to build a wheel using
540 [`pypa/build`](https://pypa-build.readthedocs.io/en/latest/index.html) and
541 PEP 517/518. Note a build system (e.g. `setuptools` or `flit`) should still
542 be added as `build-system`.
543- `pypaInstallHook` to install wheels.
544- `pytestCheckHook` to run tests with `pytest`. See [example usage](#using-pytestcheckhook).
545- `pythonCatchConflictsHook` to fail if the package depends on two different versions of the same dependency.
546- `pythonImportsCheckHook` to check whether importing the listed modules works.
547- `pythonRelaxDepsHook` will relax Python dependencies restrictions for the package.
548 See [example usage](#using-pythonrelaxdepshook).
549- `pythonRemoveBinBytecode` to remove bytecode from the `/bin` folder.
550- `setuptoolsBuildHook` to build a wheel using `setuptools`.
551- `sphinxHook` to build documentation and manpages using Sphinx.
552- `venvShellHook` to source a Python 3 `venv` at the `venvDir` location. A
553 `venv` is created if it does not yet exist. `postVenvCreation` can be used to
554 to run commands only after venv is first created.
555- `wheelUnpackHook` to move a wheel to the correct folder so it can be installed
556 with the `pipInstallHook`.
557- `unittestCheckHook` will run tests with `python -m unittest discover`. See [example usage](#using-unittestcheckhook).
558
559## User Guide {#user-guide}
560
561### Using Python {#using-python}
562
563#### Overview {#overview}
564
565Several versions of the Python interpreter are available on Nix, as well as a
566high amount of packages. The attribute `python3` refers to the default
567interpreter, which is currently CPython 3.13. The attribute `python` refers to
568CPython 2.7 for backwards compatibility. It is also possible to refer to
569specific versions, e.g., `python313` refers to CPython 3.13, and `pypy` refers to
570the default PyPy interpreter.
571
572Python is used a lot, and in different ways. This affects also how it is
573packaged. In the case of Python on Nix, an important distinction is made between
574whether the package is considered primarily an application, or whether it should
575be used as a library, i.e., of primary interest are the modules in
576`site-packages` that should be importable.
577
578In the Nixpkgs tree Python applications can be found throughout, depending on
579what they do, and are called from the main package set. Python libraries,
580however, are in separate sets, with one set per interpreter version.
581
582The interpreters have several common attributes. One of these attributes is
583`pkgs`, which is a package set of Python libraries for this specific
584interpreter. E.g., the `toolz` package corresponding to the default interpreter
585is `python3.pkgs.toolz`, and the CPython 3.13 version is `python313.pkgs.toolz`.
586The main package set contains aliases to these package sets, e.g.
587`pythonPackages` refers to `python.pkgs` and `python313Packages` to
588`python313.pkgs`.
589
590#### Installing Python and packages {#installing-python-and-packages}
591
592The Nix and NixOS manuals explain how packages are generally installed. In the
593case of Python and Nix, it is important to make a distinction between whether the
594package is considered an application or a library.
595
596Applications on Nix are typically installed into your user profile imperatively
597using `nix-env -i`, and on NixOS declaratively by adding the package name to
598`environment.systemPackages` in `/etc/nixos/configuration.nix`. Dependencies
599such as libraries are automatically installed and should not be installed
600explicitly.
601
602The same goes for Python applications. Python applications can be installed in
603your profile, and will be wrapped to find their exact library dependencies,
604without impacting other applications or polluting your user environment.
605
606But Python libraries you would like to use for development cannot be installed,
607at least not individually, because they won't be able to find each other
608resulting in import errors. Instead, it is possible to create an environment
609with [`python.buildEnv`](#python.buildenv-function) or [`python.withPackages`](#python.withpackages-function) where the interpreter and other
610executables are wrapped to be able to find each other and all of the modules.
611
612In the following examples we will start by creating a simple, ad-hoc environment
613with a nix-shell that has `numpy` and `toolz` in Python 3.13; then we will create
614a re-usable environment in a single-file Python script; then we will create a
615full Python environment for development with this same environment.
616
617Philosophically, this should be familiar to users who are used to a `venv` style
618of development: individual projects create their own Python environments without
619impacting the global environment or each other.
620
621#### Ad-hoc temporary Python environment with `nix-shell` {#ad-hoc-temporary-python-environment-with-nix-shell}
622
623The simplest way to start playing with the way nix wraps and sets up Python
624environments is with `nix-shell` at the cmdline. These environments create a
625temporary shell session with a Python and a *precise* list of packages (plus
626their runtime dependencies), with no other Python packages in the Python
627interpreter's scope.
628
629To create a Python 3.13 session with `numpy` and `toolz` available, run:
630
631```sh
632$ nix-shell -p 'python313.withPackages(ps: with ps; [ numpy toolz ])'
633```
634
635By default `nix-shell` will start a `bash` session with this interpreter in our
636`PATH`, so if we then run:
637
638```Python console
639[nix-shell:~/src/nixpkgs]$ python3
640Python 3.13.3 (main, Apr 8 2025, 13:54:08) [GCC 14.2.1 20250322] on linux
641Type "help", "copyright", "credits" or "license" for more information.
642>>> import numpy; import toolz
643```
644
645Note that no other modules are in scope, even if they were imperatively
646installed into our user environment as a dependency of a Python application:
647
648```Python console
649>>> import requests
650Traceback (most recent call last):
651 File "<stdin>", line 1, in <module>
652ModuleNotFoundError: No module named 'requests'
653```
654
655We can add as many additional modules onto the `nix-shell` as we need, and we
656will still get 1 wrapped Python interpreter. We can start the interpreter
657directly like so:
658
659```sh
660$ nix-shell -p "python313.withPackages (ps: with ps; [ numpy toolz requests ])" --run python3
661Python 3.13.3 (main, Apr 8 2025, 13:54:08) [GCC 14.2.1 20250322] on linux
662Type "help", "copyright", "credits" or "license" for more information.
663>>> import requests
664>>>
665```
666
667Notice that this time it built a new Python environment, which now includes
668`requests`. Building an environment just creates wrapper scripts that expose the
669selected dependencies to the interpreter while re-using the actual modules. This
670means if any other env has installed `requests` or `numpy` in a different
671context, we don't need to recompile them -- we just recompile the wrapper script
672that sets up an interpreter pointing to them. This matters much more for "big"
673modules like `pytorch` or `tensorflow`.
674
675Module names usually match their names on [pypi.org](https://pypi.org/), but
676normalized according to PEP 503/508. (e.g. Foo__Bar.baz -> foo-bar-baz)
677You can use the [Nixpkgs search website](https://nixos.org/nixos/packages.html)
678to find them as well (along with non-python packages).
679
680At this point we can create throwaway experimental Python environments with
681arbitrary dependencies. This is a good way to get a feel for how the Python
682interpreter and dependencies work in Nix and NixOS, but to do some actual
683development, we'll want to make it a bit more persistent.
684
685##### Running Python scripts and using `nix-shell` as shebang {#running-python-scripts-and-using-nix-shell-as-shebang}
686
687Sometimes, we have a script whose header looks like this:
688
689```python
690#!/usr/bin/env python3
691import numpy as np
692a = np.array([1,2])
693b = np.array([3,4])
694print(f"The dot product of {a} and {b} is: {np.dot(a, b)}")
695```
696
697Executing this script requires a `python3` that has `numpy`. Using what we learned
698in the previous section, we could startup a shell and just run it like so:
699
700```ShellSession
701$ nix-shell -p 'python313.withPackages (ps: with ps; [ numpy ])' --run 'python3 foo.py'
702The dot product of [1 2] and [3 4] is: 11
703```
704
705But if we maintain the script ourselves, and if there are more dependencies, it
706may be nice to encode those dependencies in source to make the script re-usable
707without that bit of knowledge. That can be done by using `nix-shell` as a
708[shebang](https://en.wikipedia.org/wiki/Shebang_(Unix)), like so:
709
710```python
711#!/usr/bin/env nix-shell
712#!nix-shell -i python3 -p "python3.withPackages(ps: [ ps.numpy ])"
713import numpy as np
714a = np.array([1,2])
715b = np.array([3,4])
716print(f"The dot product of {a} and {b} is: {np.dot(a, b)}")
717```
718
719Then we execute it, without requiring any environment setup at all!
720
721```sh
722$ ./foo.py
723The dot product of [1 2] and [3 4] is: 11
724```
725
726If the dependencies are not available on the host where `foo.py` is executed, it
727will build or download them from a Nix binary cache prior to starting up, prior
728that it is executed on a machine with a multi-user Nix installation.
729
730This provides a way to ship a self bootstrapping Python script, akin to a
731statically linked binary, where it can be run on any machine (provided nix is
732installed) without having to assume that `numpy` is installed globally on the
733system.
734
735By default it is pulling the import checkout of Nixpkgs itself from our nix
736channel, which is nice as it cache-aligns with our other package builds, but we
737can make it fully reproducible by pinning the `nixpkgs` import:
738
739```python
740#!/usr/bin/env nix-shell
741#!nix-shell -i python3 -p "python3.withPackages (ps: [ ps.numpy ])"
742#!nix-shell -I nixpkgs=https://github.com/NixOS/nixpkgs/archive/e51209796c4262bfb8908e3d6d72302fe4e96f5f.tar.gz
743import numpy as np
744a = np.array([1,2])
745b = np.array([3,4])
746print(f"The dot product of {a} and {b} is: {np.dot(a, b)}")
747```
748
749This will execute with the exact same versions of Python 3.10, numpy, and system
750dependencies a year from now as it does today, because it will always use
751exactly git commit `e51209796c4262bfb8908e3d6d72302fe4e96f5f` of Nixpkgs for all
752of the package versions.
753
754This is also a great way to ensure the script executes identically on different
755servers.
756
757##### Load environment from `.nix` expression {#load-environment-from-.nix-expression}
758
759We've now seen how to create an ad-hoc temporary shell session, and how to
760create a single script with Python dependencies, but in the course of normal
761development we're usually working in an entire package repository.
762
763As explained [in the `nix-shell` section](https://nixos.org/manual/nix/stable/command-ref/nix-shell) of the Nix manual, `nix-shell` can also load an expression from a `.nix` file.
764Say we want to have Python 3.13, `numpy` and `toolz`, like before,
765in an environment. We can add a `shell.nix` file describing our dependencies:
766
767```nix
768with import <nixpkgs> { };
769(python313.withPackages (
770 ps: with ps; [
771 numpy
772 toolz
773 ]
774)).env
775```
776
777And then at the command line, just typing `nix-shell` produces the same
778environment as before. In a normal project, we'll likely have many more
779dependencies; this can provide a way for developers to share the environments
780with each other and with CI builders.
781
782What's happening here?
783
7841. We begin with importing the Nix Packages collections. `import <nixpkgs>`
785 imports the `<nixpkgs>` function, `{}` calls it and the `with` statement
786 brings all attributes of `nixpkgs` in the local scope. These attributes form
787 the main package set.
7882. Then we create a Python 3.13 environment with the [`withPackages`](#python.withpackages-function) function, as before.
7893. The [`withPackages`](#python.withpackages-function) function expects us to provide a function as an argument
790 that takes the set of all Python packages and returns a list of packages to
791 include in the environment. Here, we select the packages `numpy` and `toolz`
792 from the package set.
793
794To combine this with `mkShell` you can:
795
796```nix
797with import <nixpkgs> { };
798let
799 pythonEnv = python313.withPackages (ps: [
800 ps.numpy
801 ps.toolz
802 ]);
803in
804mkShell {
805 packages = [
806 pythonEnv
807
808 black
809 mypy
810
811 libffi
812 openssl
813 ];
814}
815```
816
817This will create a unified environment that has not just our Python interpreter
818and its Python dependencies, but also tools like `black` or `mypy` and libraries
819like `libffi` and `openssl` in scope. This is generic and can span any number of
820tools or languages across the Nixpkgs ecosystem.
821
822##### Installing environments globally on the system {#installing-environments-globally-on-the-system}
823
824Up to now, we've been creating environments scoped to an ad-hoc shell session,
825or a single script, or a single project. This is generally advisable, as it
826avoids pollution across contexts.
827
828However, sometimes we know we will often want a Python with some basic packages,
829and want this available without having to enter into a shell or build context.
830This can be useful to have things like vim/emacs editors and plugins or shell
831tools "just work" without having to set them up, or when running other software
832that expects packages to be installed globally.
833
834To create your own custom environment, create a file in `~/.config/nixpkgs/overlays/`
835that looks like this:
836
837```nix
838# ~/.config/nixpkgs/overlays/myEnv.nix
839self: super: {
840 myEnv = super.buildEnv {
841 name = "myEnv";
842 paths = [
843 # A Python 3 interpreter with some packages
844 (self.python3.withPackages (
845 ps: with ps; [
846 pyflakes
847 pytest
848 black
849 ]
850 ))
851
852 # Some other packages we'd like as part of this env
853 self.mypy
854 self.black
855 self.ripgrep
856 self.tmux
857 ];
858 };
859}
860```
861
862You can then build and install this to your profile with:
863
864```sh
865nix-env -iA myEnv
866```
867
868One limitation of this is that you can only have 1 Python env installed
869globally, since they conflict on the `python` to load out of your `PATH`.
870
871If you get a conflict or prefer to keep the setup clean, you can have `nix-env`
872atomically *uninstall* all other imperatively installed packages and replace
873your profile with just `myEnv` by using the `--replace` flag.
874
875##### Environment defined in `/etc/nixos/configuration.nix` {#environment-defined-in-etcnixosconfiguration.nix}
876
877For the sake of completeness, here's how to install the environment system-wide
878on NixOS.
879
880```nix
881{
882 # ...
883
884 environment.systemPackages = with pkgs; [
885 (python310.withPackages (
886 ps: with ps; [
887 numpy
888 toolz
889 ]
890 ))
891 ];
892}
893```
894
895### Developing with Python {#developing-with-python}
896
897Above, we were mostly just focused on use cases and what to do to get started
898creating working Python environments in nix.
899
900Now that you know the basics to be up and running, it is time to take a step
901back and take a deeper look at how Python packages are packaged on Nix.
902
903#### Python library packages in Nixpkgs {#python-library-packages-in-nixpkgs}
904
905With Nix all packages are built by functions. The main function in Nix for
906building Python libraries is [`buildPythonPackage`](#buildpythonpackage-function). Let's see how we can build the
907`toolz` package.
908
909```nix
910{
911 lib,
912 buildPythonPackage,
913 fetchPypi,
914 setuptools,
915}:
916
917buildPythonPackage rec {
918 pname = "toolz";
919 version = "0.10.0";
920 pyproject = true;
921
922 src = fetchPypi {
923 inherit pname version;
924 hash = "sha256-CP3V73yWSArRHBLUct4hrNMjWZlvaaUlkpm1QP66RWA=";
925 };
926
927 build-system = [ setuptools ];
928
929 # has no tests
930 doCheck = false;
931
932 pythonImportsCheck = [
933 "toolz.itertoolz"
934 "toolz.functoolz"
935 "toolz.dicttoolz"
936 ];
937
938 meta = {
939 changelog = "https://github.com/pytoolz/toolz/releases/tag/${version}";
940 homepage = "https://github.com/pytoolz/toolz";
941 description = "List processing tools and functional utilities";
942 license = lib.licenses.bsd3;
943 };
944}
945```
946
947What happens here? The function [`buildPythonPackage`](#buildpythonpackage-function) is called and as argument
948it accepts a set. In this case the set is a recursive set, `rec`. One of the
949arguments is the name of the package, which consists of a basename (generally
950following the name on PyPI) and a version. Another argument, `src` specifies the
951source, which in this case is fetched from PyPI using the helper function
952`fetchPypi`. The argument `doCheck` is used to set whether tests should be run
953when building the package. Since there are no tests, we rely on [`pythonImportsCheck`](#using-pythonimportscheck)
954to test whether the package can be imported. Furthermore, we specify some meta
955information. The output of the function is a derivation.
956
957An expression for `toolz` can be found in the Nixpkgs repository. As explained
958in the introduction of this Python section, a derivation of `toolz` is available
959for each interpreter version, e.g. `python313.pkgs.toolz` refers to the `toolz`
960derivation corresponding to the CPython 3.13 interpreter.
961
962The above example works when you're directly working on
963`pkgs/top-level/python-packages.nix` in the Nixpkgs repository. Often though,
964you will want to test a Nix expression outside of the Nixpkgs tree.
965
966The following expression creates a derivation for the `toolz` package,
967and adds it along with a `numpy` package to a Python environment.
968
969```nix
970with import <nixpkgs> { };
971
972(
973 let
974 my_toolz = python313.pkgs.buildPythonPackage rec {
975 pname = "toolz";
976 version = "0.10.0";
977 pyproject = true;
978
979 src = fetchPypi {
980 inherit pname version;
981 hash = "sha256-CP3V73yWSArRHBLUct4hrNMjWZlvaaUlkpm1QP66RWA=";
982 };
983
984 build-system = [ python313.pkgs.setuptools ];
985
986 # has no tests
987 doCheck = false;
988
989 meta = {
990 homepage = "https://github.com/pytoolz/toolz/";
991 description = "List processing tools and functional utilities";
992 # [...]
993 };
994 };
995
996 in
997 python313.withPackages (
998 ps: with ps; [
999 numpy
1000 my_toolz
1001 ]
1002 )
1003).env
1004```
1005
1006Executing `nix-shell` will result in an environment in which you can use
1007Python 3.13 and the `toolz` package. As you can see we had to explicitly mention
1008for which Python version we want to build a package.
1009
1010So, what did we do here? Well, we took the Nix expression that we used earlier
1011to build a Python environment, and said that we wanted to include our own
1012version of `toolz`, named `my_toolz`. To introduce our own package in the scope
1013of [`withPackages`](#python.withpackages-function) we used a `let` expression. You can see that we used
1014`ps.numpy` to select numpy from the nixpkgs package set (`ps`). We did not take
1015`toolz` from the Nixpkgs package set this time, but instead took our own version
1016that we introduced with the `let` expression.
1017
1018#### Handling dependencies {#handling-dependencies}
1019
1020Our example, `toolz`, does not have any dependencies on other Python packages or system libraries.
1021[`buildPythonPackage`](#buildpythonpackage-function) uses the the following arguments in the following circumstances:
1022
1023- `dependencies` - For Python runtime dependencies.
1024- `build-system` - For Python build-time requirements.
1025- [`buildInputs`](#var-stdenv-buildInputs) - For non-Python build-time requirements.
1026- [`nativeCheckInputs`](#var-stdenv-nativeCheckInputs) - For test dependencies
1027
1028Dependencies can belong to multiple arguments, for example if something is both a build time requirement & a runtime dependency.
1029
1030The following example shows which arguments are given to [`buildPythonPackage`](#buildpythonpackage-function) in
1031order to build [`datashape`](https://github.com/blaze/datashape).
1032
1033```nix
1034{
1035 lib,
1036 buildPythonPackage,
1037 fetchPypi,
1038
1039 # build dependencies
1040 setuptools,
1041
1042 # dependencies
1043 numpy,
1044 multipledispatch,
1045 python-dateutil,
1046
1047 # tests
1048 pytestCheckHook,
1049}:
1050
1051buildPythonPackage rec {
1052 pname = "datashape";
1053 version = "0.4.7";
1054 pyproject = true;
1055
1056 src = fetchPypi {
1057 inherit pname version;
1058 hash = "sha256-FLLvdm1MllKrgTGC6Gb0k0deZeVYvtCCLji/B7uhong=";
1059 };
1060
1061 build-system = [ setuptools ];
1062
1063 dependencies = [
1064 multipledispatch
1065 numpy
1066 python-dateutil
1067 ];
1068
1069 nativeCheckInputs = [ pytestCheckHook ];
1070
1071 meta = {
1072 changelog = "https://github.com/blaze/datashape/releases/tag/${version}";
1073 homepage = "https://github.com/ContinuumIO/datashape";
1074 description = "Data description language";
1075 license = lib.licenses.bsd2;
1076 };
1077}
1078```
1079
1080We can see several runtime dependencies, `numpy`, `multipledispatch`, and
1081`python-dateutil`. Furthermore, we have [`nativeCheckInputs`](#var-stdenv-nativeCheckInputs) with `pytestCheckHook`.
1082`pytestCheckHook` is a test runner hook and is only used during the [`checkPhase`](#ssec-check-phase) and is
1083therefore not added to `dependencies`.
1084
1085In the previous case we had only dependencies on other Python packages to consider.
1086Occasionally you have also system libraries to consider. E.g., `lxml` provides
1087Python bindings to `libxml2` and `libxslt`. These libraries are only required
1088when building the bindings and are therefore added as [`buildInputs`](#var-stdenv-buildInputs).
1089
1090```nix
1091{
1092 lib,
1093 buildPythonPackage,
1094 fetchPypi,
1095 setuptools,
1096 libxml2,
1097 libxslt,
1098}:
1099
1100buildPythonPackage rec {
1101 pname = "lxml";
1102 version = "3.4.4";
1103 pyproject = true;
1104
1105 src = fetchPypi {
1106 inherit pname version;
1107 hash = "sha256-s9NiusRxFydHzaNRMjjxFcvWxfi45jGb9ql6eJJyQJk=";
1108 };
1109
1110 build-system = [ setuptools ];
1111
1112 buildInputs = [
1113 libxml2
1114 libxslt
1115 ];
1116
1117 # tests are meant to be ran "in-place" in the same directory as src
1118 doCheck = false;
1119
1120 pythonImportsCheck = [
1121 "lxml"
1122 "lxml.etree"
1123 ];
1124
1125 meta = {
1126 changelog = "https://github.com/lxml/lxml/releases/tag/lxml-${version}";
1127 description = "Pythonic binding for the libxml2 and libxslt libraries";
1128 homepage = "https://lxml.de";
1129 license = lib.licenses.bsd3;
1130 maintainers = with lib.maintainers; [ sjourdois ];
1131 };
1132}
1133```
1134
1135In this example `lxml` and Nix are able to work out exactly where the relevant
1136files of the dependencies are. This is not always the case.
1137
1138The example below shows bindings to The Fastest Fourier Transform in the West,
1139commonly known as FFTW. On Nix we have separate packages of FFTW for the
1140different types of floats (`"single"`, `"double"`, `"long-double"`). The
1141bindings need all three types, and therefore we add all three as [`buildInputs`](#var-stdenv-buildInputs).
1142The bindings don't expect to find each of them in a different folder, and
1143therefore we have to set `LDFLAGS` and `CFLAGS`.
1144
1145```nix
1146{
1147 lib,
1148 buildPythonPackage,
1149 fetchPypi,
1150
1151 # build dependencies
1152 setuptools,
1153
1154 # dependencies
1155 fftw,
1156 fftwFloat,
1157 fftwLongDouble,
1158 numpy,
1159 scipy,
1160}:
1161
1162buildPythonPackage rec {
1163 pname = "pyfftw";
1164 version = "0.9.2";
1165 pyproject = true;
1166
1167 src = fetchPypi {
1168 inherit pname version;
1169 hash = "sha256-9ru2r6kwhUCaskiFoaPNuJCfCVoUL01J40byvRt4kHQ=";
1170 };
1171
1172 build-system = [ setuptools ];
1173
1174 buildInputs = [
1175 fftw
1176 fftwFloat
1177 fftwLongDouble
1178 ];
1179
1180 dependencies = [
1181 numpy
1182 scipy
1183 ];
1184
1185 preConfigure = ''
1186 export LDFLAGS="-L${fftw.dev}/lib -L${fftwFloat.out}/lib -L${fftwLongDouble.out}/lib"
1187 export CFLAGS="-I${fftw.dev}/include -I${fftwFloat.dev}/include -I${fftwLongDouble.dev}/include"
1188 '';
1189
1190 # Tests cannot import pyfftw. pyfftw works fine though.
1191 doCheck = false;
1192
1193 pythonImportsCheck = [ "pyfftw" ];
1194
1195 meta = {
1196 changelog = "https://github.com/pyFFTW/pyFFTW/releases/tag/v${version}";
1197 description = "Pythonic wrapper around FFTW, the FFT library, presenting a unified interface for all the supported transforms";
1198 homepage = "http://hgomersall.github.com/pyFFTW";
1199 license = with lib.licenses; [
1200 bsd2
1201 bsd3
1202 ];
1203 };
1204}
1205```
1206
1207Note also the line [`doCheck = false;`](#var-stdenv-doCheck), we explicitly disabled running the test-suite.
1208
1209#### Testing Python Packages {#testing-python-packages}
1210
1211It is highly encouraged to have testing as part of the package build. This
1212helps to avoid situations where the package was able to build and install,
1213but is not usable at runtime.
1214Your package should provide its own [`checkPhase`](#ssec-check-phase).
1215
1216::: {.note}
1217The [`checkPhase`](#ssec-check-phase) for python maps to the `installCheckPhase` on a
1218normal derivation. This is due to many python packages not behaving well
1219to the pre-installed version of the package. Version info, and natively
1220compiled extensions generally only exist in the install directory, and
1221thus can cause issues when a test suite asserts on that behavior.
1222:::
1223
1224::: {.note}
1225Tests should only be disabled if they don't agree with nix
1226(e.g. external dependencies, network access, flakey tests), however,
1227as many tests should be enabled as possible. Failing tests can still be
1228a good indication that the package is not in a valid state.
1229:::
1230
1231::: {.note}
1232We only want to test the functionality of a package. In particular, we are not
1233interested in coverage, formatting, and type checking. If pytest fails with
1234`unrecognized arguments: --cov`, add `pytest-cov-stub` to `nativeCheckInputs`
1235rather than `pytest-cov`.
1236:::
1237
1238#### Using pytest {#using-pytest}
1239
1240Pytest is the most common test runner for python repositories. A trivial
1241test run would be:
1242
1243```nix
1244{
1245 nativeCheckInputs = [ pytest ];
1246 checkPhase = ''
1247 runHook preCheck
1248
1249 pytest
1250
1251 runHook postCheck
1252 '';
1253}
1254```
1255
1256However, many repositories' test suites do not translate well to nix's build
1257sandbox, and will generally need many tests to be disabled.
1258
1259This is achievable by
1260- Including paths or test items (`path/to/file.py::MyClass` or `path/to/file.py::MyClass::test_method`) with positional arguments.
1261- Excluding paths with `--ignore` or globbed paths with `--ignore-glob`.
1262- Excluding test items using the `--deselect` flag.
1263- Including or excluding classes or test methods by their name using the `-k` flag.
1264- Including or excluding test by their marks using the `-m` flag.
1265
1266We highly recommend `pytestCheckHook` for an easier and more structural setup.
1267
1268#### Using pytestCheckHook {#using-pytestcheckhook}
1269
1270`pytestCheckHook` is a convenient hook which will set up (or configure)
1271a [`checkPhase`](#ssec-check-phase) to run `pytest`. This is also beneficial
1272when a package may need many items disabled to run the test suite.
1273Most packages use `pytest` or `unittest`, which is compatible with `pytest`,
1274so you will most likely use `pytestCheckHook`.
1275
1276To use `pytestCheckHook`, add it to `nativeCheckInputs`.
1277Adding `pytest` is not required, since it is included with `pytestCheckHook`.
1278
1279```nix
1280{ nativeCheckInputs = [ pytestCheckHook ]; }
1281```
1282
1283`pytestCheckHook` recognizes the following attributes:
1284
1285`enabledTestPaths` and `disabledTestPaths`
1286
1287: To specify path globs (files or directories) or test items.
1288
1289`enabledTests` and `disabledTests`
1290
1291: To specify keywords for class names or test method names.
1292
1293`enabledTestMarks` and `disabledTestMarks`
1294
1295: To specify test marks.
1296
1297`pytestFlags`
1298
1299: To append additional command-line arguments to `pytest`.
1300
1301By default, `pytest` automatically discovers which tests to run.
1302If tests are explicitly enabled, only those tests will run.
1303A test, that is both enabled and disabled, will not run.
1304
1305The following example demonstrates usage of various `pytestCheckHook` attributes:
1306
1307```nix
1308{
1309 nativeCheckInputs = [ pytestCheckHook ];
1310
1311 # Allow running the following test paths and test objects.
1312 enabledTestPaths = [
1313 # Find tests under the tests directory.
1314 # The trailing slash is not necessary.
1315 "tests/"
1316
1317 # Additionally run test_foo
1318 "other-tests/test_foo.py::Foo::test_foo"
1319 ];
1320
1321 # Override the above-enabled test paths and test objects.
1322 disabledTestPaths = [
1323 # Tests under tests/integration requires additional data.
1324 "tests/integration"
1325 ];
1326
1327 # Allow tests by keywords matching their class names or method names.
1328 enabledTests = [
1329 # pytest by default only runs test methods begin with "test_" or end with "_test".
1330 # This includes all functions whose name contains "test".
1331 "test"
1332 ];
1333
1334 # Override the above-enabled tests by keywords matching their class names or method names.
1335 disabledTests = [
1336 # Tests touching networks.
1337 "upload"
1338 "download"
1339 ];
1340
1341 # Additional pytest flags
1342 pytestFlags = [
1343 # Disable benchmarks and run benchmarking tests only once.
1344 "--benchmark-disable"
1345 ];
1346}
1347```
1348
1349These attributes are all passed into the derivation directly
1350and added to the `pytest` command without additional Bash expansion.
1351It requires `__structuredAttrs = true` to pass list elements containing spaces.
1352
1353The `<enabled/disabled>TestsPaths` attributes expand Unix-style globs.
1354If a test path contains characters like `*`, `?`, `[`, or `]`, you can
1355quote them with square brackets (`[*]`, `[?]`, `[[]`, and `[]]`) to match literally.
1356
1357The `<enabled/disabled>Tests` and `<enabled/disabled>TestMarks` attribute pairs
1358form a logical expression `((included_element1) or (included_element2)) and not (excluded_element1) and not (excluded_element2)`
1359which will be passed to pytest's `-k` and `-m` flags respectively.
1360With `__structuredAttrs = true` enabled, they additionally support sub-expressions.
1361
1362For example, you could disable test items like `TestFoo::test_bar_functionality`
1363by disabling tests that match both `"Foo"` **and** `"bar"`:
1364
1365```nix
1366{
1367 __structuredAttrs = true;
1368
1369 disabledTests = [ "Foo and bar" ];
1370}
1371```
1372
1373The main benefits of using `pytestCheckHook` to construct `pytest` commands
1374is structuralization and eval-time accessibility.
1375This is especially helpful to select tests or specify flags conditionally:
1376
1377```nix
1378{
1379 disabledTests = [
1380 # touches network
1381 "download"
1382 "update"
1383 ]
1384 ++ lib.optionals (pythonAtLeast "3.8") [
1385 # broken due to python3.8 async changes
1386 "async"
1387 ]
1388 ++ lib.optionals stdenv.buildPlatform.isDarwin [
1389 # can fail when building with other packages
1390 "socket"
1391 ];
1392}
1393```
1394
1395#### Using pythonImportsCheck {#using-pythonimportscheck}
1396
1397Although unit tests are highly preferred to validate correctness of a package, not
1398all packages have test suites that can be run easily, and some have none at all.
1399To help ensure the package still works, [`pythonImportsCheck`](#using-pythonimportscheck) can attempt to import
1400the listed modules.
1401
1402```nix
1403{
1404 pythonImportsCheck = [
1405 "requests"
1406 "urllib"
1407 ];
1408}
1409```
1410
1411roughly translates to:
1412
1413```nix
1414{
1415 postCheck = ''
1416 PYTHONPATH=$out/${python.sitePackages}:$PYTHONPATH
1417 python -c "import requests; import urllib"
1418 '';
1419}
1420```
1421
1422However, this is done in its own phase, and not dependent on whether [`doCheck = true;`](#var-stdenv-doCheck).
1423
1424This can also be useful in verifying that the package doesn't assume commonly
1425present packages (e.g. `setuptools`).
1426
1427#### Using pythonRelaxDepsHook {#using-pythonrelaxdepshook}
1428
1429It is common for upstream to specify a range of versions for its package
1430dependencies. This makes sense, since it ensures that the package will be built
1431with a subset of packages that is well tested. However, this commonly causes
1432issues when packaging in Nixpkgs, because the dependencies that this package
1433may need are too new or old for the package to build correctly. We also cannot
1434package multiple versions of the same package since this may cause conflicts
1435in `PYTHONPATH`.
1436
1437One way to side step this issue is to relax the dependencies. This can be done
1438by either removing the package version range or by removing the package
1439declaration entirely. This can be done using the `pythonRelaxDepsHook` hook. For
1440example, given the following `requirements.txt` file:
1441
1442```
1443pkg1<1.0
1444pkg2
1445pkg3>=1.0,<=2.0
1446```
1447
1448we can do:
1449
1450```nix
1451{
1452 pythonRelaxDeps = [
1453 "pkg1"
1454 "pkg3"
1455 ];
1456 pythonRemoveDeps = [ "pkg2" ];
1457}
1458```
1459
1460which would result in the following `requirements.txt` file:
1461
1462```
1463pkg1
1464pkg3
1465```
1466
1467Another option is to pass `true`, that will relax/remove all dependencies, for
1468example:
1469
1470```nix
1471{ pythonRelaxDeps = true; }
1472```
1473
1474which would result in the following `requirements.txt` file:
1475
1476```
1477pkg1
1478pkg2
1479pkg3
1480```
1481
1482In general you should always use `pythonRelaxDeps`, because `pythonRemoveDeps`
1483will convert build errors into runtime errors. However `pythonRemoveDeps` may
1484still be useful in exceptional cases, and also to remove dependencies wrongly
1485declared by upstream (for example, declaring `black` as a runtime dependency
1486instead of a dev dependency).
1487
1488Keep in mind that while the examples above are done with `requirements.txt`,
1489`pythonRelaxDepsHook` works by modifying the resulting wheel file, so it should
1490work with any of the [existing hooks](#setup-hooks).
1491
1492The `pythonRelaxDepsHook` has no effect on build time dependencies, such as
1493those specified in `build-system`. If a package requires incompatible build
1494time dependencies, they should be removed in `postPatch` through
1495`substituteInPlace` or similar.
1496
1497For ease of use, both `buildPythonPackage` and `buildPythonApplication` will
1498automatically add `pythonRelaxDepsHook` if either `pythonRelaxDeps` or
1499`pythonRemoveDeps` is specified.
1500
1501#### Using unittestCheckHook {#using-unittestcheckhook}
1502
1503`unittestCheckHook` is a hook which will set up (or configure) a [`checkPhase`](#ssec-check-phase) to run `python -m unittest discover`:
1504
1505```nix
1506{
1507 nativeCheckInputs = [ unittestCheckHook ];
1508
1509 unittestFlags = [
1510 "-s"
1511 "tests"
1512 "-v"
1513 ];
1514}
1515```
1516
1517`pytest` is compatible with `unittest`, so in most cases you can use `pytestCheckHook` instead.
1518
1519#### Using sphinxHook {#using-sphinxhook}
1520
1521The `sphinxHook` is a helpful tool to build documentation and manpages
1522using the popular Sphinx documentation generator.
1523It is setup to automatically find common documentation source paths and
1524render them using the default `html` style.
1525
1526```nix
1527{
1528 outputs = [
1529 "out"
1530 "doc"
1531 ];
1532
1533 nativeBuildInputs = [ sphinxHook ];
1534}
1535```
1536
1537The hook will automatically build and install the artifact into the
1538`doc` output, if it exists. It also provides an automatic diversion
1539for the artifacts of the `man` builder into the `man` target.
1540
1541```nix
1542{
1543 outputs = [
1544 "out"
1545 "doc"
1546 "man"
1547 ];
1548
1549 # Use multiple builders
1550 sphinxBuilders = [
1551 "singlehtml"
1552 "man"
1553 ];
1554}
1555```
1556
1557Overwrite `sphinxRoot` when the hook is unable to find your
1558documentation source root.
1559
1560```nix
1561{
1562 # Configure sphinxRoot for uncommon paths
1563 sphinxRoot = "weird/docs/path";
1564}
1565```
1566
1567The hook is also available to packages outside the python ecosystem by
1568referencing it using `sphinxHook` from top-level.
1569
1570### Organising your packages {#organising-your-packages}
1571
1572So far we discussed how you can use Python on Nix, and how you can develop with
1573it. We've looked at how you write expressions to package Python packages, and we
1574looked at how you can create environments in which specified packages are
1575available.
1576
1577At some point you'll likely have multiple packages which you would
1578like to be able to use in different projects. In order to minimise unnecessary
1579duplication we now look at how you can maintain a repository with your
1580own packages. The important functions here are `import` and `callPackage`.
1581
1582### Including a derivation using `callPackage` {#including-a-derivation-using-callpackage}
1583
1584Earlier we created a Python environment using [`withPackages`](#python.withpackages-function), and included the
1585`toolz` package via a `let` expression.
1586Let's split the package definition from the environment definition.
1587
1588We first create a function that builds `toolz` in `~/path/to/toolz/release.nix`
1589
1590```nix
1591{
1592 lib,
1593 buildPythonPackage,
1594 fetchPypi,
1595 setuptools,
1596}:
1597
1598buildPythonPackage rec {
1599 pname = "toolz";
1600 version = "0.10.0";
1601 pyproject = true;
1602
1603 src = fetchPypi {
1604 inherit pname version;
1605 hash = "sha256-CP3V73yWSArRHBLUct4hrNMjWZlvaaUlkpm1QP66RWA=";
1606 };
1607
1608 build-system = [ setuptools ];
1609
1610 meta = {
1611 changelog = "https://github.com/pytoolz/toolz/releases/tag/${version}";
1612 homepage = "https://github.com/pytoolz/toolz/";
1613 description = "List processing tools and functional utilities";
1614 license = lib.licenses.bsd3;
1615 };
1616}
1617```
1618
1619It takes an argument [`buildPythonPackage`](#buildpythonpackage-function). We now call this function using
1620`callPackage` in the definition of our environment
1621
1622```nix
1623with import <nixpkgs> { };
1624
1625(
1626 let
1627 toolz = callPackage /path/to/toolz/release.nix {
1628 buildPythonPackage = python3Packages.buildPythonPackage;
1629 };
1630 in
1631 python3.withPackages (ps: [
1632 ps.numpy
1633 toolz
1634 ])
1635).env
1636```
1637
1638Important to remember is that the Python version for which the package is made
1639depends on the `python` derivation that is passed to [`buildPythonPackage`](#buildpythonpackage-function). Nix
1640tries to automatically pass arguments when possible, which is why generally you
1641don't explicitly define which `python` derivation should be used. In the above
1642example we use [`buildPythonPackage`](#buildpythonpackage-function) that is part of the set `python3Packages`,
1643and in this case the `python3` interpreter is automatically used.
1644
1645## FAQ {#faq}
1646
1647### How to solve circular dependencies? {#how-to-solve-circular-dependencies}
1648
1649Consider the packages `A` and `B` that depend on each other. When packaging `B`,
1650a solution is to override package `A` not to depend on `B` as an input. The same
1651should also be done when packaging `A`.
1652
1653### How to override a Python package? {#how-to-override-a-python-package}
1654
1655We can override the interpreter and pass `packageOverrides`. In the following
1656example we rename the `pandas` package and build it.
1657
1658```nix
1659with import <nixpkgs> { };
1660
1661(
1662 let
1663 python =
1664 let
1665 packageOverrides = self: super: {
1666 pandas = super.pandas.overridePythonAttrs (old: {
1667 name = "foo";
1668 });
1669 };
1670 in
1671 pkgs.python310.override { inherit packageOverrides; };
1672
1673 in
1674 python.withPackages (ps: [ ps.pandas ])
1675).env
1676```
1677
1678Using `nix-build` on this expression will build an environment that contains the
1679package `pandas` but with the new name `foo`.
1680
1681All packages in the package set will use the renamed package. A typical use case
1682is to switch to another version of a certain package. For example, in the
1683Nixpkgs repository we have multiple versions of `django` and `scipy`. In the
1684following example we use a different version of `scipy` and create an
1685environment that uses it. All packages in the Python package set will now use
1686the updated `scipy` version.
1687
1688```nix
1689with import <nixpkgs> { };
1690
1691(
1692 let
1693 packageOverrides = self: super: { scipy = super.scipy_0_17; };
1694 in
1695 (pkgs.python310.override { inherit packageOverrides; }).withPackages (ps: [ ps.blaze ])
1696).env
1697```
1698
1699The requested package `blaze` depends on `pandas` which itself depends on `scipy`.
1700
1701If you want the whole of Nixpkgs to use your modifications, then you can use
1702`overlays` as explained in this manual. In the following example we build a
1703`inkscape` using a different version of `numpy`.
1704
1705```nix
1706let
1707 pkgs = import <nixpkgs> { };
1708 newpkgs = import pkgs.path {
1709 overlays = [
1710 (self: super: {
1711 python310 =
1712 let
1713 packageOverrides = python-self: python-super: {
1714 numpy = python-super.numpy_1_18;
1715 };
1716 in
1717 super.python310.override { inherit packageOverrides; };
1718 })
1719 ];
1720 };
1721in
1722newpkgs.inkscape
1723```
1724
1725### `python setup.py bdist_wheel` cannot create .whl {#python-setup.py-bdist_wheel-cannot-create-.whl}
1726
1727Executing `python setup.py bdist_wheel` in a `nix-shell`fails with
1728
1729```
1730ValueError: ZIP does not support timestamps before 1980
1731```
1732
1733This is because files from the Nix store (which have a timestamp of the UNIX
1734epoch of January 1, 1970) are included in the .ZIP, but .ZIP archives follow the
1735DOS convention of counting timestamps from 1980.
1736
1737The command `bdist_wheel` reads the `SOURCE_DATE_EPOCH` environment variable,
1738which `nix-shell` sets to 1. Unsetting this variable or giving it a value
1739corresponding to 1980 or later enables building wheels.
1740
1741Use 1980 as timestamp:
1742
1743```shell
1744nix-shell --run "SOURCE_DATE_EPOCH=315532800 python3 setup.py bdist_wheel"
1745```
1746
1747or the current time:
1748
1749```shell
1750nix-shell --run "SOURCE_DATE_EPOCH=$(date +%s) python3 setup.py bdist_wheel"
1751```
1752
1753or unset `SOURCE_DATE_EPOCH`:
1754
1755```shell
1756nix-shell --run "unset SOURCE_DATE_EPOCH; python3 setup.py bdist_wheel"
1757```
1758
1759### `install_data` / `data_files` problems {#install_data-data_files-problems}
1760
1761If you get the following error:
1762
1763```
1764could not create '/nix/store/6l1bvljpy8gazlsw2aw9skwwp4pmvyxw-python-2.7.8/etc':
1765Permission denied
1766```
1767
1768This is a [known bug](https://github.com/pypa/setuptools/issues/130) in
1769`setuptools`. Setuptools `install_data` does not respect `--prefix`. An example
1770of such package using the feature is `pkgs/tools/X11/xpra/default.nix`.
1771
1772As workaround install it as an extra `preInstall` step:
1773
1774```shell
1775${python.pythonOnBuildForHost.interpreter} setup.py install_data --install-dir=$out --root=$out
1776sed -i '/ = data\_files/d' setup.py
1777```
1778
1779### Rationale of non-existent global site-packages {#rationale-of-non-existent-global-site-packages}
1780
1781On most operating systems a global `site-packages` is maintained. This however
1782becomes problematic if you want to run multiple Python versions or have multiple
1783versions of certain libraries for your projects. Generally, you would solve such
1784issues by creating virtual environments using `virtualenv`.
1785
1786On Nix each package has an isolated dependency tree which, in the case of
1787Python, guarantees the right versions of the interpreter and libraries or
1788packages are available. There is therefore no need to maintain a global `site-packages`.
1789
1790If you want to create a Python environment for development, then the recommended
1791method is to use `nix-shell`, either with or without the [`python.buildEnv`](#python.buildenv-function)
1792function.
1793
1794### How to consume Python modules using pip in a virtual environment like I am used to on other Operating Systems? {#how-to-consume-python-modules-using-pip-in-a-virtual-environment-like-i-am-used-to-on-other-operating-systems}
1795
1796While this approach is not very idiomatic from Nix perspective, it can still be
1797useful when dealing with pre-existing projects or in situations where it's not
1798feasible or desired to write derivations for all required dependencies.
1799
1800This is an example of a `default.nix` for a `nix-shell`, which allows to consume
1801a virtual environment created by `venv`, and install Python modules through
1802`pip` the traditional way.
1803
1804Create this `default.nix` file, together with a `requirements.txt` and
1805execute `nix-shell`.
1806
1807```nix
1808with import <nixpkgs> { };
1809
1810let
1811 pythonPackages = python3Packages;
1812in
1813pkgs.mkShell rec {
1814 name = "impurePythonEnv";
1815 venvDir = "./.venv";
1816 buildInputs = [
1817 # A Python interpreter including the 'venv' module is required to bootstrap
1818 # the environment.
1819 pythonPackages.python
1820
1821 # This executes some shell code to initialize a venv in $venvDir before
1822 # dropping into the shell
1823 pythonPackages.venvShellHook
1824
1825 # Those are dependencies that we would like to use from nixpkgs, which will
1826 # add them to PYTHONPATH and thus make them accessible from within the venv.
1827 pythonPackages.numpy
1828 pythonPackages.requests
1829
1830 # In this particular example, in order to compile any binary extensions they may
1831 # require, the Python modules listed in the hypothetical requirements.txt need
1832 # the following packages to be installed locally:
1833 taglib
1834 openssl
1835 git
1836 libxml2
1837 libxslt
1838 libzip
1839 zlib
1840 ];
1841
1842 # Run this command, only after creating the virtual environment
1843 postVenvCreation = ''
1844 unset SOURCE_DATE_EPOCH
1845 pip install -r requirements.txt
1846 '';
1847
1848 # Now we can execute any commands within the virtual environment.
1849 # This is optional and can be left out to run pip manually.
1850 postShellHook = ''
1851 # allow pip to install wheels
1852 unset SOURCE_DATE_EPOCH
1853 '';
1854
1855}
1856```
1857
1858In case the supplied venvShellHook is insufficient, or when Python 2 support is
1859needed, you can define your own shell hook and adapt to your needs like in the
1860following example:
1861
1862```nix
1863with import <nixpkgs> { };
1864
1865let
1866 venvDir = "./.venv";
1867 pythonPackages = python3Packages;
1868in
1869pkgs.mkShell rec {
1870 name = "impurePythonEnv";
1871 buildInputs = [
1872 pythonPackages.python
1873 # Needed when using python 2.7
1874 # pythonPackages.virtualenv
1875 # ...
1876 ];
1877
1878 # This is very close to how venvShellHook is implemented, but
1879 # adapted to use 'virtualenv'
1880 shellHook = ''
1881 SOURCE_DATE_EPOCH=$(date +%s)
1882
1883 if [ -d "${venvDir}" ]; then
1884 echo "Skipping venv creation, '${venvDir}' already exists"
1885 else
1886 echo "Creating new venv environment in path: '${venvDir}'"
1887 # Note that the module venv was only introduced in python 3, so for 2.7
1888 # this needs to be replaced with a call to virtualenv
1889 ${pythonPackages.python.interpreter} -m venv "${venvDir}"
1890 fi
1891
1892 # Under some circumstances it might be necessary to add your virtual
1893 # environment to PYTHONPATH, which you can do here too;
1894 # PYTHONPATH=$PWD/${venvDir}/${pythonPackages.python.sitePackages}/:$PYTHONPATH
1895
1896 source "${venvDir}/bin/activate"
1897
1898 # As in the previous example, this is optional.
1899 pip install -r requirements.txt
1900 '';
1901}
1902```
1903
1904Note that the `pip install` is an imperative action. So every time `nix-shell`
1905is executed it will attempt to download the Python modules listed in
1906requirements.txt. However these will be cached locally within the `virtualenv`
1907folder and not downloaded again.
1908
1909### How to override a Python package from `configuration.nix`? {#how-to-override-a-python-package-from-configuration.nix}
1910
1911If you need to change a package's attribute(s) from `configuration.nix` you could do:
1912
1913```nix
1914{
1915 nixpkgs.config.packageOverrides = super: {
1916 python3 = super.python3.override {
1917 packageOverrides = python-self: python-super: {
1918 twisted = python-super.twisted.overridePythonAttrs (oldAttrs: {
1919 src = super.fetchPypi {
1920 pname = "Twisted";
1921 version = "19.10.0";
1922 hash = "sha256-c5S6fycq5yKnTz2Wnc9Zm8TvCTvDkgOHSKSQ8XJKUV0=";
1923 extension = "tar.bz2";
1924 };
1925 });
1926 };
1927 };
1928 };
1929}
1930```
1931
1932`python3Packages.twisted` is now globally overridden.
1933All packages and also all NixOS services that reference `twisted`
1934(such as `services.buildbot-worker`) now use the new definition.
1935Note that `python-super` refers to the old package set and `python-self`
1936to the new, overridden version.
1937
1938To modify only a Python package set instead of a whole Python derivation, use
1939this snippet:
1940
1941```nix
1942{
1943 myPythonPackages = python3Packages.override { overrides = self: super: { twisted = <...>; }; };
1944}
1945```
1946
1947### How to override a Python package using overlays? {#how-to-override-a-python-package-using-overlays}
1948
1949Use the following overlay template:
1950
1951```nix
1952self: super: {
1953 python = super.python.override {
1954 packageOverrides = python-self: python-super: {
1955 twisted = python-super.twisted.overrideAttrs (oldAttrs: {
1956 src = super.fetchPypi {
1957 pname = "Twisted";
1958 version = "19.10.0";
1959 hash = "sha256-c5S6fycq5yKnTz2Wnc9Zm8TvCTvDkgOHSKSQ8XJKUV0=";
1960 extension = "tar.bz2";
1961 };
1962 });
1963 };
1964 };
1965}
1966```
1967
1968### How to override a Python package for all Python versions using extensions? {#how-to-override-a-python-package-for-all-python-versions-using-extensions}
1969
1970The following overlay overrides the call to [`buildPythonPackage`](#buildpythonpackage-function) for the
1971`foo` package for all interpreters by appending a Python extension to the
1972`pythonPackagesExtensions` list of extensions.
1973
1974```nix
1975final: prev: {
1976 pythonPackagesExtensions = prev.pythonPackagesExtensions ++ [
1977 (python-final: python-prev: {
1978 foo = python-prev.foo.overridePythonAttrs (oldAttrs: {
1979 # ...
1980 });
1981 })
1982 ];
1983}
1984```
1985
1986### How to use Intel’s MKL with numpy and scipy? {#how-to-use-intels-mkl-with-numpy-and-scipy}
1987
1988MKL can be configured using an overlay. See the section "[Using overlays to
1989configure alternatives](#sec-overlays-alternatives-blas-lapack)".
1990
1991### What inputs do `setup_requires`, `install_requires` and `tests_require` map to? {#what-inputs-do-setup_requires-install_requires-and-tests_require-map-to}
1992
1993In a `setup.py` or `setup.cfg` it is common to declare dependencies:
1994
1995* `setup_requires` corresponds to `build-system`
1996* `install_requires` corresponds to `dependencies`
1997* `tests_require` corresponds to [`nativeCheckInputs`](#var-stdenv-nativeCheckInputs)
1998
1999### How to enable interpreter optimizations? {#optimizations}
2000
2001The Python interpreters are by default not built with optimizations enabled, because
2002the builds are in that case not reproducible. To enable optimizations, override the
2003interpreter of interest, e.g using
2004
2005```nix
2006let
2007 pkgs = import ./. { };
2008 mypython = pkgs.python3.override {
2009 enableOptimizations = true;
2010 reproducibleBuild = false;
2011 self = mypython;
2012 };
2013in
2014mypython
2015```
2016
2017### How to add optional dependencies? {#python-optional-dependencies}
2018
2019Some packages define optional dependencies for additional features. With
2020`setuptools` this is called `extras_require` and `flit` calls it
2021`extras-require`, while PEP 621 calls these `optional-dependencies`.
2022
2023```nix
2024{
2025 optional-dependencies = {
2026 complete = [ distributed ];
2027 };
2028}
2029```
2030
2031and letting the package requiring the extra add the list to its dependencies
2032
2033```nix
2034{
2035 dependencies = [
2036 # ...
2037 ]
2038 ++ dask.optional-dependencies.complete;
2039}
2040```
2041
2042This method is using `passthru`, meaning that changing `optional-dependencies` of a package won't cause it to rebuild.
2043
2044Note this method is preferred over adding parameters to builders, as that can
2045result in packages depending on different variants and thereby causing
2046collisions.
2047
2048::: {.note}
2049The `optional-dependencies` attribute should only be used for dependency groups
2050as defined in package metadata. If a package gracefully handles missing
2051dependencies in runtime but doesn't advertise it through package metadata, then
2052these dependencies should not be listed at all. (One may still have to list
2053them in `nativeCheckInputs` to pass test suite.)
2054:::
2055
2056### How to contribute a Python package to nixpkgs? {#tools}
2057
2058Packages inside nixpkgs must use the [`buildPythonPackage`](#buildpythonpackage-function) or [`buildPythonApplication`](#buildpythonapplication-function) function directly,
2059because we can only provide security support for non-vendored dependencies.
2060
2061We recommend [nix-init](https://github.com/nix-community/nix-init) for creating new python packages within nixpkgs,
2062as it already prefetches the source, parses dependencies for common formats and prefills most things in `meta`.
2063When using the tool, pull from the original source repository instead of PyPI, if possible.
2064
2065See also [contributing section](#contributing).
2066
2067### Are Python interpreters built deterministically? {#deterministic-builds}
2068
2069The Python interpreters are now built deterministically. Minor modifications had
2070to be made to the interpreters in order to generate deterministic bytecode. This
2071has security implications and is relevant for those using Python in a
2072`nix-shell`.
2073
2074When the environment variable `DETERMINISTIC_BUILD` is set, all bytecode will
2075have timestamp 1. The [`buildPythonPackage`](#buildpythonpackage-function) function sets `DETERMINISTIC_BUILD=1`
2076and [PYTHONHASHSEED=0](https://docs.python.org/3.13/using/cmdline.html#envvar-PYTHONHASHSEED).
2077Both are also exported in `nix-shell`.
2078
2079### How to provide automatic tests to Python packages? {#automatic-tests}
2080
2081It is recommended to test packages as part of the build process.
2082Source distributions (`sdist`) often include test files, but not always.
2083
2084The best practice today is to pass a test hook (e.g. pytestCheckHook, unittestCheckHook) into nativeCheckInputs.
2085This will reconfigure the checkPhase to make use of that particular test framework.
2086Occasionally packages don't make use of a common test framework, which may then require a custom checkPhase.
2087
2088#### Common issues {#common-issues}
2089
2090* Tests that attempt to access `$HOME` can be fixed by using `writableTmpDirAsHomeHook` in
2091 `nativeCheckInputs`, which sets up a writable temporary directory as the home directory. Alternatively,
2092 you can achieve the same effect manually (e.g. in `preCheck`) with: `export HOME=$(mktemp -d)`.
2093* Compiling with Cython causes tests to fail with a `ModuleNotLoadedError`.
2094 This can be fixed with two changes in the derivation: 1) replacing `pytest` with
2095 `pytestCheckHook` and 2) adding a `preCheck` containing `cd $out` to run
2096 tests within the built output.
2097
2098## Contributing {#contributing}
2099
2100### Contributing guidelines {#contributing-guidelines}
2101
2102The following rules are desired to be respected:
2103
2104* Python libraries are called from `python-packages.nix` and packaged with
2105 [`buildPythonPackage`](#buildpythonpackage-function). The expression of a library should be in
2106 `pkgs/development/python-modules/<name>/default.nix`.
2107* Python applications live outside of `python-packages.nix` and are packaged
2108 with [`buildPythonApplication`](#buildpythonapplication-function).
2109* Make sure libraries build for all Python interpreters.
2110 If it fails to build on some Python versions, consider disabling them by setting `disable = pythonAtLeast "3.x"` along with a comment.
2111* The two parameters, `pyproject` and `build-system` are set to avoid the legacy setuptools/distutils build.
2112* Only unversioned attributes (e.g. `pydantic`, but not `pypdantic_1`) can be included in `dependencies`,
2113 since due to `PYTHONPATH` limitations we can only ever support a single version for libraries
2114 without running into duplicate module name conflicts.
2115* The version restrictions of `dependencies` can be relaxed by [`pythonRelaxDepsHook`](#using-pythonrelaxdepshook).
2116* Make sure the tests are enabled using for example [`pytestCheckHook`](#using-pytestcheckhook) and, in the case of
2117 libraries, are passing for all interpreters. If certain tests fail they can be
2118 disabled individually. Try to avoid disabling the tests altogether. In any
2119 case, when you disable tests, leave a comment explaining not only _what_ the failure
2120 is but _why_ the test failure can be ignored for safe distribution with nixpkgs.
2121* `pythonImportsCheck` is set. This is still a good smoke test even if `pytestCheckHook` is set.
2122* `meta.platforms` takes the default value in many cases.
2123 It does not need to be set explicitly unless the package requires a specific platform.
2124* The file is formatted with `nixfmt-rfc-style`.
2125* Commit names of Python libraries must reflect that they are Python
2126 libraries (e.g. `python3Packages.numpy: 1.11 -> 1.12` rather than `numpy: 1.11 -> 1.12`).
2127 See also [`pkgs/README.md`](https://github.com/NixOS/nixpkgs/blob/master/pkgs/README.md#commit-conventions).
2128* Attribute names in `python-packages.nix` as well as `pname`s should match the
2129 library's name on PyPI, but be normalized according to [PEP
2130 0503](https://www.python.org/dev/peps/pep-0503/#normalized-names). This means
2131 that characters should be converted to lowercase and `.` and `_` should be
2132 replaced by a single `-` (foo-bar-baz instead of Foo__Bar.baz).
2133 If necessary, `pname` has to be given a different value within `fetchPypi`.
2134* It's generally preferable to fetch `src` directly from the repo and not from
2135 PyPI. Use `fetchPypi` when there's a clear technical reason to do so.
2136* Packages from sources such as GitHub and GitLab that do not exist on PyPI
2137 should not use a name that is already used on PyPI. When possible, they should
2138 use the package repository name prefixed with the owner (e.g. organization) name
2139 and using a `-` as delimiter.
2140* Attribute names in `python-packages.nix` should be sorted alphanumerically to
2141 avoid merge conflicts and ease locating attributes.
2142* Non-python runtime dependencies should be added via explicit wrapping or
2143 patching (using e.g. `substituteInPlace`), rather than through propagation via
2144 `dependencies`/`propagatedBuildInputs`, to reduce clutter in `$PATH`.
2145
2146This list is useful for reviewers as well as for self-checking when submitting packages.
2147
2148## Package set maintenance {#python-package-set-maintenance}
2149
2150The whole Python package set has a lot of packages that do not see regular
2151updates, because they either are a very fragile component in the Python
2152ecosystem, like for example the `hypothesis` package, or packages that have
2153no maintainer, so maintenance falls back to the package set maintainers.
2154
2155### Updating packages in bulk {#python-package-bulk-updates}
2156
2157A tool to bulk-update numerous Python libraries is available in the
2158repository at `maintainers/scripts/update-python-libraries`.
2159
2160It can quickly update minor or major versions for all packages selected
2161and create update commits, and supports the `fetchPypi`, `fetchurl` and
2162`fetchFromGitHub` fetchers. When updating lots of packages that are
2163hosted on GitHub, exporting a `GITHUB_API_TOKEN` is highly recommended.
2164
2165Updating packages in bulk leads to lots of breakages, which is why a
2166stabilization period on the `python-updates` branch is required.
2167
2168If a package is fragile and often breaks during these bulks updates, it
2169may be reasonable to set `passthru.skipBulkUpdate = true` in the
2170derivation. This decision should not be made on a whim and should
2171always be supported by a qualifying comment.
2172
2173Once the branch is sufficiently stable it should normally be merged
2174into the `staging` branch.
2175
2176An exemplary call to update all python libraries between minor versions
2177would be:
2178
2179```ShellSession
2180$ maintainers/scripts/update-python-libraries --target minor --commit --use-pkgs-prefix pkgs/development/python-modules/**/default.nix
2181```
2182
2183## CPython Update Schedule {#python-cpython-update-schedule}
2184
2185With [PEP 602](https://www.python.org/dev/peps/pep-0602/), CPython now
2186follows a yearly release cadence. In nixpkgs, all supported interpreters
2187are made available, but only the most recent two
2188interpreters package sets are built; this is a compromise between being
2189the latest interpreter, and what the majority of the Python packages support.
2190
2191New CPython interpreters are released in October. Generally, it takes some
2192time for the majority of active Python projects to support the latest stable
2193interpreter. To help ease the migration for Nixpkgs users
2194between Python interpreters the schedule below will be used:
2195
2196| When | Event |
2197| --- | --- |
2198| After YY.11 Release | Bump CPython package set window. The latest and previous latest stable should now be built. |
2199| After YY.05 Release | Bump default CPython interpreter to latest stable. |
2200
2201In practice, this means that the Python community will have had a stable interpreter
2202for ~2 months before attempting to update the package set. And this will
2203allow for ~7 months for Python applications to support the latest interpreter.