Python

From NixOS Wiki
Revision as of 22:32, 14 June 2020 by Lionello (talk | contribs) (fix pkgs.mkShell)
Jump to: navigation, search

The Python packages available to the interpreter must be declared when installing Python.

To install, say Python 3 with pandas and requests, define a new package python-with-my-packages:

with pkgs;
let
  my-python-packages = python-packages: with python-packages; [
    pandas
    requests
    # other python packages you want
  ]; 
  python-with-my-packages = python3.withPackages my-python-packages;
in ...

You can put python-with-my-packages into your environment.systemPackages for a system-wide installation, for instance. Be mindful that pythonX.withPackages creates a pythonX-Y.Z.W-env package which is read only, so you can't use pip to install packages in, say, a virtual environment (as described below). Put python in your configuration.nix if you want to use the solution as described in the section "Python Virtual Environment".

There are several versions of Python available. Replace python3 with python2 or pypy in the above snippet according to your needs.

Explanation (optional)

We defined a function my-python-packages which takes as input a set python-packages and returns a list of attributes thereof.

Using alternative packages

We saw above how to install Python packages using nixpkgs. Since these are written by hand by nixpkgs maintainers, it isn't uncommon for packages you want to be missing or out of date.

Python virtual environment

Starting from Python 3 virtual environment is natively supported. The Python 3 venv approach has the benefit of forcing you to choose a specific version of the Python 3 interpreter that should be used to create the virtual environment. This avoids any confusion as to which Python installation the new environment is based on.

From Python 3.3 to 3.4, the recommended way to create a virtual environment was to use the pyvenv command-line tool that also comes included with your Python 3 installation by default. But on 3.6 and above, python3 -m venv is the way to go.

Put your packages in a requirements.txt:

pandas
requests

Then setup the virtualenv:

python -m venv .venv
source .venv/bin/activate
pip install -r requirements.txt

Emulating virtualenv with nix-shell

In some cases virtualenv fails to install a library because it requires patching on NixOS (example 1, example 2, general issue). In this cases it is better to replace those libraries with ones from Nix.

Let's say, that nanomsg library fails to install in virtualenv. Then write a `default.nix` file:

let pkgs = import <nixpkgs> {};
     nanomsg-py = .... build expression for this python library;
in pkgs.mkShell {
  buildInputs = [
    pkgs.pythonPackages.pip
    nanomsg-py
  ];
  shellHook = ''
            alias pip="PIP_PREFIX='$(pwd)/_build/pip_packages' \pip"
            export PYTHONPATH="$(pwd)/_build/pip_packages/lib/python2.7/site-packages:$PYTHONPATH"
            unset SOURCE_DATE_EPOCH
  '';
}

After entering the environment with `nix-shell`, you can install new python libraries with dump `pip install`, but nanomsg will be detected as installed.

Discussion and consequences of this approach are in PR https://github.com/NixOS/nixpkgs/pull/55265.

conda

Install the package conda and run

conda-shell
conda-install
conda env update --file environment.yml

Imperative use

It is also possible to use conda-install directly. On first use, run

conda-shell
conda-install

to set up conda in ~/.conda

pypi2nix

Contribution guidelines

Libraries

According to the official guidelines for python new package expressions for libraries should be placed in pkgs/development/python-modules/<name>/default.nix. Those expressions are then referenced from pkgs/top-level/python-packages.nix like in this example:

{
  aenum = callPackage ../development/python-modules/aenum { };
}

The reasoning behind this is the large size of pkgs/top-level/python-packages.nix.

Applications

Python applications instead should be referenced directly from pkgs/top-level/all-packages.nix.

The expression should take pythonPackages as one of the arguments, which guarantees that packages belong to the same set. For example:

{ lib
, pythonPackages
}:

with pythonPackages;

buildPythonApplication rec {
# ...

Special Modules

GNOME

gobject-introspection based python modules need some environment variables to work correctly. For standalone applications, wrapGAppsHook (see the relevant documentation) wraps the executable with the necessary variables. But this is not fit for development. In this case use a nix-shell with gobject-introspection and all the libraries you are using (gtk and so on) as buildInputs. For example:

$ nix-shell -p gobjectIntrospection gtk3 'python2.withPackages (ps: with ps; [ pygobject3 ])' --run "python -c \"import pygtkcompat; pygtkcompat.enable_gtk(version='3.0')\""

Or, if you want to use matplotlib interactively:

$ nix-shell -p gobjectIntrospection gtk3 'python36.withPackages(ps : with ps; [ matplotlib pygobject3 ipython ])'
$ ipython
In [1]: import matplotlib
In [2]: matplotlib.use('gtk3agg')
In [3]: import matplotlib.pyplot as plt
In [4]: plt.ion()
In [5]: plt.plot([1,3,2,4])

You can also set backend : GTK3Agg in your ~/.config/matplotlib/matplotlibrc file to avoid having to call matplotlib.use('gtk3agg').

External Documentation