Well, it seems that quite a lot of people struggle with python on NixOS! Actually, I don't think it's that difficult so let's dive in! This post is meant to be a definitive guide to python usage in NixOs. By usage, I mainly mean 2Β things:
I plan to update this post if other cases present themselves, so don't hesitate to reach out and give me your non-working use-case!
This is the first question I asked myself: why do people think it's difficult?Β From my POV, it is often actually easier than a c++ app for instance. I think it boils down to userbase. I might be wrong, but the python userbase is typically:
After all, why should python dev care about all these low-level considerations? A lot of us use python when we precisely don't want that mess :-)
But the problem is that NixOS breaks some assumptions other distros are making and that in turns breaks some applications relying on those assumptions. To use or package python application (which is more or less the same thing in NixOS), we need to know about those so that we know how to make those applications happy.
Mainly, that "some stuff" will be available globally, once you install the right packages. Usually on other distros, you can assume the following things:
/usr/lib
or other path that is in your LD_LIBRARY_PATHThat's usually why a simple pip install
works out of the box (well, after some apt
or yum
commands sometimes) in other distros! Python (an executable) needed by pip is available in the path, and all the native (.so) libraries that this python program might need directly or through some dependencies will be found, either at build time, or at runtime.
NOTE: pure python applications are not compiled, but some dependencies you may use are. For instance, psycopg2 distributes its source, and you need libpq.h to compile it when doing a pip install
. Numpy is actually coded in C, although they do distribute already compiled wheels for most platforms so you probably won't need anything to compile it.
So actually, let's keep that numpy
example and see what happens if you naively try to install it in NixOS. Let's say you have added python3 to your config, either through environment.systemPackages
or home.packages
. So python3
is in your PATH, like the binaries of all the packages you've directly added in your config. So you merrily go ahead and create a virtualenv:
/tmp via π v3.12.8
β― python3 -m venv .venv
/tmp via π v3.12.8
β― source .venv/bin/activate
/tmp via π v3.12.8 (.venv)
β― pip install numpy
Collecting numpy
Downloading numpy-2.2.5-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.metadata (62 kB)
Downloading numpy-2.2.5-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (16.1 MB)
ββββββββββββββββββββββββββββββββββββββββ 16.1/16.1 MB 45.0 MB/s eta 0:00:00
Installing collected packages: numpy
Successfully installed numpy-2.2.5
Yay! Works perfectly right?
But when we try to import it:
β― python3 -c 'import numpy as np'
Traceback (most recent call last):
File "/tmp/.venv/lib/python3.12/site-packages/numpy/_core/__init__.py", line 23, in <module>
from . import multiarray
File "/tmp/.venv/lib/python3.12/site-packages/numpy/_core/multiarray.py", line 10, in <module>
from . import overrides
File "/tmp/.venv/lib/python3.12/site-packages/numpy/_core/overrides.py", line 7, in <module>
from numpy._core._multiarray_umath import (
ImportError: libstdc++.so.6: cannot open shared object file: No such file or directory
# I omitted the rest, there are many more scary messages after
Bummer! The standard c++ libraries are not found...
We can confirm that if we download a whl from this page, unzip it somewhere and check what one of the included .so needs:
β― ldd numpy/_core/_multiarray_tests.cpython-313t-x86_64-linux-gnu.so
linux-vdso.so.1 (0x00007ffff5e50000)
libstdc++.so.6 => not found
libm.so.6 => /nix/store/p9kdj55g5l39nbrxpjyz5wc1m0s7rzsx-glibc-2.40-66/lib/libm.so.6 (0x00007f9fef8ae000)
libgcc_s.so.1 => /nix/store/y4d9iir0yqmrcswaqfi368d8m1rkv14s-xgcc-13.3.0-libgcc/lib/libgcc_s.so.1 (0x00007f9fef889000)
libc.so.6 => /nix/store/p9kdj55g5l39nbrxpjyz5wc1m0s7rzsx-glibc-2.40-66/lib/libc.so.6 (0x00007f9fef691000)
/nix/store/p9kdj55g5l39nbrxpjyz5wc1m0s7rzsx-glibc-2.40-66/lib64/ld-linux-x86-64.so.2 (0x00007f9fef9c0000)
Notice the "not found".
(Note: NixOS does provide automatically some librairies which you can't avoid if you want anything to work at all, just very few).
If you try to install psycopg2, it's even worse. It does not even install:
β― pip install psycopg2
Collecting psycopg2
Downloading psycopg2-2.9.10.tar.gz (385 kB)
Installing build dependencies ... done
Getting requirements to build wheel ... error
error: subprocess-exited-with-error
Γ Getting requirements to build wheel did not run successfully.
β exit code: 1
β°β> [18 lines of output]
# [...]
Error: pg_config --libdir failed:
[end of output]
note: This error originates from a subprocess, and is likely not a problem with pip.
# [...]
The error is about a missing pg_config
, even though I do have postgresql installed on my machine!
This might be an evidence to some, but still let's say it out loud: being reproducible is the very "raison d'Γͺtre" of nixos, and you can't be reproducible if you depend on some external contingencies. Everything you depend on must be explicitly declared, and each dependency it will be a derivation corresponding to a specific version of a source code (and a specific version of each tool involved anywhere from the build process until the runtime).
So how will we declare all these dependencies? How will we know what to declare? Let's dive in!
To be more exhaustive, there are 2 main ways of using a python application / library:
And I have identified 3 main types of python scripts/applications/libs:
So for each of these
NOTES:
But python in nix is easier than a lot of c++ project for instance.
I think problems is:
This article is for them, not for people thinking "I don't see the problem".
NOTE: I think most of this is not specific to python.
PrincipleΒ : in nix, you have to explicitly give the path to native librairies, you can't rely on any automatic detection.
3 main cases, by increasing order of difficulty:
python myscript.py
or to check the hashbangbuildPythonApplication
(TODO ex) or a writer