You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1027 lines
40 KiB
1027 lines
40 KiB
![]()
8 years ago
|
# Python
|
||
|
|
||
|
## User Guide
|
||
|
|
||
|
### Using Python
|
||
|
|
||
![]()
7 years ago
|
#### Overview
|
||
|
|
||
|
Several versions of the Python interpreter are available on Nix, as well as a
|
||
|
high amount of packages. The attribute `python` refers to the default
|
||
|
interpreter, which is currently CPython 2.7. It is also possible to refer to
|
||
|
specific versions, e.g. `python35` refers to CPython 3.5, and `pypy` refers to
|
||
|
the default PyPy interpreter.
|
||
|
|
||
|
Python is used a lot, and in different ways. This affects also how it is
|
||
|
packaged. In the case of Python on Nix, an important distinction is made between
|
||
|
whether the package is considered primarily an application, or whether it should
|
||
|
be used as a library, i.e., of primary interest are the modules in
|
||
|
`site-packages` that should be importable.
|
||
|
|
||
|
In the Nixpkgs tree Python applications can be found throughout, depending on
|
||
|
what they do, and are called from the main package set. Python libraries,
|
||
|
however, are in separate sets, with one set per interpreter version.
|
||
|
|
||
|
The interpreters have several common attributes. One of these attributes is
|
||
|
`pkgs`, which is a package set of Python libraries for this specific
|
||
|
interpreter. E.g., the `toolz` package corresponding to the default interpreter
|
||
|
is `python.pkgs.toolz`, and the CPython 3.5 version is `python35.pkgs.toolz`.
|
||
|
The main package set contains aliases to these package sets, e.g.
|
||
|
`pythonPackages` refers to `python.pkgs` and `python35Packages` to
|
||
|
`python35.pkgs`.
|
||
|
|
||
![]()
8 years ago
|
#### Installing Python and packages
|
||
|
|
||
![]()
7 years ago
|
The Nix and NixOS manuals explain how packages are generally installed. In the
|
||
|
case of Python and Nix, it is important to make a distinction between whether the
|
||
|
package is considered an application or a library.
|
||
![]()
8 years ago
|
|
||
![]()
7 years ago
|
Applications on Nix are typically installed into your user
|
||
![]()
8 years ago
|
profile imperatively using `nix-env -i`, and on NixOS declaratively by adding the
|
||
|
package name to `environment.systemPackages` in `/etc/nixos/configuration.nix`.
|
||
|
Dependencies such as libraries are automatically installed and should not be
|
||
|
installed explicitly.
|
||
|
|
||
|
The same goes for Python applications and libraries. Python applications can be
|
||
![]()
7 years ago
|
installed in your profile. But Python libraries you would like to use for
|
||
|
development cannot be installed, at least not individually, because they won't
|
||
|
be able to find each other resulting in import errors. Instead, it is possible
|
||
|
to create an environment with `python.buildEnv` or `python.withPackages` where
|
||
|
the interpreter and other executables are able to find each other and all of the
|
||
|
modules.
|
||
![]()
8 years ago
|
|
||
![]()
7 years ago
|
In the following examples we create an environment with Python 3.5, `numpy` and
|
||
|
`toolz`. As you may imagine, there is one limitation here, and that's that
|
||
|
you can install only one environment at a time. You will notice the complaints
|
||
|
about collisions when you try to install a second environment.
|
||
![]()
8 years ago
|
|
||
![]()
7 years ago
|
##### Environment defined in separate `.nix` file
|
||
![]()
8 years ago
|
|
||
![]()
7 years ago
|
Create a file, e.g. `build.nix`, with the following expression
|
||
|
```nix
|
||
|
with import <nixpkgs> {};
|
||
|
|
||
|
python35.withPackages (ps: with ps; [ numpy toolz ])
|
||
|
```
|
||
|
and install it in your profile with
|
||
|
```shell
|
||
|
nix-env -if build.nix
|
||
|
```
|
||
|
Now you can use the Python interpreter, as well as the extra packages (`numpy`,
|
||
|
`toolz`) that you added to the environment.
|
||
|
|
||
|
##### Environment defined in `~/.config/nixpkgs/config.nix`
|
||
|
|
||
|
If you prefer to, you could also add the environment as a package override to the Nixpkgs set, e.g.
|
||
|
using `config.nix`,
|
||
|
```nix
|
||
|
{ # ...
|
||
|
|
||
|
packageOverrides = pkgs: with pkgs; {
|
||
|
myEnv = python35.withPackages (ps: with ps; [ numpy toolz ]);
|
||
|
};
|
||
|
}
|
||
|
```
|
||
|
and install it in your profile with
|
||
|
```shell
|
||
|
nix-env -iA nixpkgs.myEnv
|
||
|
```
|
||
|
The environment is is installed by referring to the attribute, and considering
|
||
|
the `nixpkgs` channel was used.
|
||
|
|
||
|
##### Environment defined in `/etc/nixos/configuration.nix`
|
||
|
|
||
|
For the sake of completeness, here's another example how to install the environment system-wide.
|
||
|
|
||
|
```nix
|
||
|
{ # ...
|
||
|
|
||
|
environment.systemPackages = with pkgs; [
|
||
|
(python35.withPackages(ps: with ps; [ numpy toolz ]))
|
||
|
];
|
||
|
}
|
||
![]()
8 years ago
|
```
|
||
|
|
||
![]()
7 years ago
|
#### Temporary Python environment with `nix-shell`
|
||
![]()
8 years ago
|
|
||
![]()
7 years ago
|
The examples in the previous section showed how to install a Python environment
|
||
|
into a profile. For development you may need to use multiple environments.
|
||
|
`nix-shell` gives the possibility to temporarily load another environment, akin
|
||
|
to `virtualenv`.
|
||
|
|
||
|
There are two methods for loading a shell with Python packages. The first and recommended method
|
||
|
is to create an environment with `python.buildEnv` or `python.withPackages` and load that. E.g.
|
||
|
```sh
|
||
|
$ nix-shell -p 'python35.withPackages(ps: with ps; [ numpy toolz ])'
|
||
|
```
|
||
|
opens a shell from which you can launch the interpreter
|
||
![]()
8 years ago
|
```sh
|
||
|
[nix-shell:~] python3
|
||
|
```
|
||
![]()
7 years ago
|
The other method, which is not recommended, does not create an environment and requires you to list the packages directly,
|
||
![]()
8 years ago
|
|
||
|
```sh
|
||
![]()
7 years ago
|
$ nix-shell -p python35.pkgs.numpy python35.pkgs.toolz
|
||
|
```
|
||
|
Again, it is possible to launch the interpreter from the shell.
|
||
|
The Python interpreter has the attribute `pkgs` which contains all Python libraries for that specific interpreter.
|
||
|
|
||
|
##### Load environment from `.nix` expression
|
||
|
As explained in the Nix manual, `nix-shell` can also load an
|
||
|
expression from a `.nix` file. Say we want to have Python 3.5, `numpy`
|
||
|
and `toolz`, like before, in an environment. Consider a `shell.nix` file
|
||
|
with
|
||
|
```nix
|
||
|
with import <nixpkgs> {};
|
||
|
|
||
![]()
7 years ago
|
(python35.withPackages (ps: [ps.numpy ps.toolz])).env
|
||
![]()
8 years ago
|
```
|
||
![]()
7 years ago
|
Executing `nix-shell` gives you again a Nix shell from which you can run Python.
|
||
|
|
||
|
What's happening here?
|
||
![]()
8 years ago
|
|
||
![]()
7 years ago
|
1. We begin with importing the Nix Packages collections. `import <nixpkgs>` imports the `<nixpkgs>` function, `{}` calls it and the `with` statement brings all attributes of `nixpkgs` in the local scope. These attributes form the main package set.
|
||
|
2. Then we create a Python 3.5 environment with the `withPackages` function.
|
||
|
3. The `withPackages` function expects us to provide a function as an argument that takes the set of all python packages and returns a list of packages to include in the environment. Here, we select the packages `numpy` and `toolz` from the package set.
|
||
![]()
8 years ago
|
|
||
![]()
7 years ago
|
##### Execute command with `--run`
|
||
|
A convenient option with `nix-shell` is the `--run`
|
||
|
option, with which you can execute a command in the `nix-shell`. We can
|
||
|
e.g. directly open a Python shell
|
||
|
```sh
|
||
|
$ nix-shell -p python35Packages.numpy python35Packages.toolz --run "python3"
|
||
|
```
|
||
|
or run a script
|
||
![]()
8 years ago
|
```sh
|
||
|
$ nix-shell -p python35Packages.numpy python35Packages.toolz --run "python3 myscript.py"
|
||
|
```
|
||
|
|
||
![]()
7 years ago
|
##### `nix-shell` as shebang
|
||
|
In fact, for the second use case, there is a more convenient method. You can
|
||
![]()
8 years ago
|
add a [shebang](https://en.wikipedia.org/wiki/Shebang_(Unix)) to your script
|
||
![]()
7 years ago
|
specifying which dependencies `nix-shell` needs. With the following shebang, you
|
||
|
can just execute `./myscript.py`, and it will make available all dependencies and
|
||
![]()
8 years ago
|
run the script in the `python3` shell.
|
||
|
|
||
|
```py
|
||
|
#! /usr/bin/env nix-shell
|
||
![]()
7 years ago
|
#! nix-shell -i python3 -p "python3.withPackages(ps: [ps.numpy])"
|
||
![]()
8 years ago
|
|
||
|
import numpy
|
||
|
|
||
|
print(numpy.__version__)
|
||
|
```
|
||
|
|
||
|
### Developing with Python
|
||
|
|
||
![]()
7 years ago
|
Now that you know how to get a working Python environment with Nix, it is time
|
||
|
to go forward and start actually developing with Python. We will first have a
|
||
|
look at how Python packages are packaged on Nix. Then, we will look at how you
|
||
|
can use development mode with your code.
|
||
![]()
8 years ago
|
|
||
![]()
7 years ago
|
#### Packaging a library
|
||
![]()
8 years ago
|
|
||
![]()
7 years ago
|
With Nix all packages are built by functions. The main function in Nix for
|
||
|
building Python libraries is `buildPythonPackage`. Let's see how we can build the
|
||
|
`toolz` package.
|
||
![]()
8 years ago
|
|
||
|
```nix
|
||
![]()
7 years ago
|
{ # ...
|
||
![]()
8 years ago
|
|
||
![]()
7 years ago
|
toolz = buildPythonPackage rec {
|
||
![]()
7 years ago
|
pname = "toolz";
|
||
![]()
7 years ago
|
version = "0.7.4";
|
||
![]()
8 years ago
|
|
||
![]()
7 years ago
|
src = fetchPypi {
|
||
|
inherit pname version;
|
||
![]()
7 years ago
|
sha256 = "43c2c9e5e7a16b6c88ba3088a9bfc82f7db8e13378be7c78d6c14a5f8ed05afd";
|
||
|
};
|
||
|
|
||
![]()
7 years ago
|
doCheck = false;
|
||
|
|
||
![]()
7 years ago
|
meta = {
|
||
|
homepage = "http://github.com/pytoolz/toolz/";
|
||
|
description = "List processing tools and functional utilities";
|
||
|
license = licenses.bsd3;
|
||
|
maintainers = with maintainers; [ fridh ];
|
||
|
};
|
||
![]()
8 years ago
|
};
|
||
![]()
7 years ago
|
}
|
||
![]()
8 years ago
|
```
|
||
|
|
||
|
What happens here? The function `buildPythonPackage` is called and as argument
|
||
![]()
7 years ago
|
it accepts a set. In this case the set is a recursive set, `rec`. One of the
|
||
|
arguments is the name of the package, which consists of a basename (generally
|
||
|
following the name on PyPi) and a version. Another argument, `src` specifies the
|
||
|
source, which in this case is fetched from PyPI using the helper function
|
||
|
`fetchPypi`. The argument `doCheck` is used to set whether tests should be run
|
||
|
when building the package. Furthermore, we specify some (optional) meta
|
||
|
information. The output of the function is a derivation.
|
||
|
|
||
|
An expression for `toolz` can be found in the Nixpkgs repository. As explained
|
||
|
in the introduction of this Python section, a derivation of `toolz` is available
|
||
|
for each interpreter version, e.g. `python35.pkgs.toolz` refers to the `toolz`
|
||
|
derivation corresponding to the CPython 3.5 interpreter.
|
||
![]()
8 years ago
|
The above example works when you're directly working on
|
||
|
`pkgs/top-level/python-packages.nix` in the Nixpkgs repository. Often though,
|
||
![]()
7 years ago
|
you will want to test a Nix expression outside of the Nixpkgs tree.
|
||
![]()
8 years ago
|
|
||
![]()
7 years ago
|
The following expression creates a derivation for the `toolz` package,
|
||
|
and adds it along with a `numpy` package to a Python environment.
|
||
![]()
8 years ago
|
|
||
|
```nix
|
||
|
with import <nixpkgs> {};
|
||
|
|
||
|
( let
|
||
![]()
7 years ago
|
my_toolz = python35.pkgs.buildPythonPackage rec {
|
||
|
pname = "toolz";
|
||
|
version = "0.7.4";
|
||
|
|
||
|
src = python35.pkgs.fetchPypi {
|
||
|
inherit pname version;
|
||
|
sha256 = "43c2c9e5e7a16b6c88ba3088a9bfc82f7db8e13378be7c78d6c14a5f8ed05afd";
|
||
![]()
8 years ago
|
};
|
||
|
|
||
![]()
8 years ago
|
doCheck = false;
|
||
|
|
||
![]()
8 years ago
|
meta = {
|
||
|
homepage = "http://github.com/pytoolz/toolz/";
|
||
|
description = "List processing tools and functional utilities";
|
||
|
};
|
||
|
};
|
||
|
|
||
![]()
7 years ago
|
in python35.withPackages (ps: [ps.numpy my_toolz])
|
||
![]()
8 years ago
|
).env
|
||
|
```
|
||
![]()
7 years ago
|
Executing `nix-shell` will result in an environment in which you can use
|
||
|
Python 3.5 and the `toolz` package. As you can see we had to explicitly mention
|
||
|
for which Python version we want to build a package.
|
||
![]()
8 years ago
|
|
||
![]()
7 years ago
|
So, what did we do here? Well, we took the Nix expression that we used earlier
|
||
|
to build a Python environment, and said that we wanted to include our own
|
||
|
version of `toolz`, named `my_toolz`. To introduce our own package in the scope
|
||
|
of `withPackages` we used a `let` expression. You can see that we used
|
||
|
`ps.numpy` to select numpy from the nixpkgs package set (`ps`). We did not take
|
||
|
`toolz` from the Nixpkgs package set this time, but instead took our own version
|
||
|
that we introduced with the `let` expression.
|
||
![]()
8 years ago
|
|
||
![]()
7 years ago
|
#### Handling dependencies
|
||
![]()
8 years ago
|
|
||
![]()
7 years ago
|
Our example, `toolz`, does not have any dependencies on other Python
|
||
![]()
8 years ago
|
packages or system libraries. According to the manual, `buildPythonPackage`
|
||
|
uses the arguments `buildInputs` and `propagatedBuildInputs` to specify dependencies. If something is
|
||
|
exclusively a build-time dependency, then the dependency should be included as a
|
||
|
`buildInput`, but if it is (also) a runtime dependency, then it should be added
|
||
|
to `propagatedBuildInputs`. Test dependencies are considered build-time dependencies.
|
||
|
|
||
|
The following example shows which arguments are given to `buildPythonPackage` in
|
||
|
order to build [`datashape`](https://github.com/blaze/datashape).
|
||
|
|
||
|
```nix
|
||
![]()
7 years ago
|
{ # ...
|
||
![]()
8 years ago
|
|
||
![]()
7 years ago
|
datashape = buildPythonPackage rec {
|
||
![]()
7 years ago
|
pname = "datashape";
|
||
![]()
7 years ago
|
version = "0.4.7";
|
||
![]()
8 years ago
|
|
||
![]()
7 years ago
|
src = fetchPypi {
|
||
|
inherit pname version;
|
||
![]()
7 years ago
|
sha256 = "14b2ef766d4c9652ab813182e866f493475e65e558bed0822e38bf07bba1a278";
|
||
|
};
|
||
![]()
8 years ago
|
|
||
![]()
7 years ago
|
checkInputs = with self; [ pytest ];
|
||
![]()
7 years ago
|
propagatedBuildInputs = with self; [ numpy multipledispatch dateutil ];
|
||
|
|
||
|
meta = {
|
||
|
homepage = https://github.com/ContinuumIO/datashape;
|
||
|
description = "A data description language";
|
||
|
license = licenses.bsd2;
|
||
|
maintainers = with maintainers; [ fridh ];
|
||
|
};
|
||
![]()
8 years ago
|
};
|
||
![]()
7 years ago
|
}
|
||
![]()
8 years ago
|
```
|
||
|
|
||
|
We can see several runtime dependencies, `numpy`, `multipledispatch`, and
|
||
|
`dateutil`. Furthermore, we have one `buildInput`, i.e. `pytest`. `pytest` is a
|
||
|
test runner and is only used during the `checkPhase` and is therefore not added
|
||
|
to `propagatedBuildInputs`.
|
||
|
|
||
|
In the previous case we had only dependencies on other Python packages to consider.
|
||
|
Occasionally you have also system libraries to consider. E.g., `lxml` provides
|
||
|
Python bindings to `libxml2` and `libxslt`. These libraries are only required
|
||
|
when building the bindings and are therefore added as `buildInputs`.
|
||
|
|
||
|
```nix
|
||
![]()
7 years ago
|
{ # ...
|
||
![]()
8 years ago
|
|
||
![]()
7 years ago
|
lxml = buildPythonPackage rec {
|
||
![]()
7 years ago
|
pname = "lxml";
|
||
|
version = "3.4.4";
|
||
![]()
8 years ago
|
|
||
![]()
7 years ago
|
src = fetchPypi {
|
||
|
inherit pname version;
|
||
![]()
7 years ago
|
sha256 = "16a0fa97hym9ysdk3rmqz32xdjqmy4w34ld3rm3jf5viqjx65lxk";
|
||
|
};
|
||
![]()
8 years ago
|
|
||
![]()
7 years ago
|
buildInputs = with self; [ pkgs.libxml2 pkgs.libxslt ];
|
||
|
|
||
|
meta = {
|
||
|
description = "Pythonic binding for the libxml2 and libxslt libraries";
|
||
|
homepage = http://lxml.de;
|
||
|
license = licenses.bsd3;
|
||
|
maintainers = with maintainers; [ sjourdois ];
|
||
|
};
|
||
![]()
8 years ago
|
};
|
||
![]()
7 years ago
|
}
|
||
![]()
8 years ago
|
```
|
||
|
|
||
|
In this example `lxml` and Nix are able to work out exactly where the relevant
|
||
|
files of the dependencies are. This is not always the case.
|
||
|
|
||
|
The example below shows bindings to The Fastest Fourier Transform in the West, commonly known as
|
||
|
FFTW. On Nix we have separate packages of FFTW for the different types of floats
|
||
|
(`"single"`, `"double"`, `"long-double"`). The bindings need all three types,
|
||
|
and therefore we add all three as `buildInputs`. The bindings don't expect to
|
||
|
find each of them in a different folder, and therefore we have to set `LDFLAGS`
|
||
|
and `CFLAGS`.
|
||
|
|
||
|
```nix
|
||
![]()
7 years ago
|
{ # ...
|
||
![]()
8 years ago
|
|
||
![]()
7 years ago
|
pyfftw = buildPythonPackage rec {
|
||
![]()
7 years ago
|
pname = "pyFFTW";
|
||
![]()
7 years ago
|
version = "0.9.2";
|
||
![]()
8 years ago
|
|
||
![]()
7 years ago
|
src = fetchPypi {
|
||
|
inherit pname version;
|
||
![]()
7 years ago
|
sha256 = "f6bbb6afa93085409ab24885a1a3cdb8909f095a142f4d49e346f2bd1b789074";
|
||
|
};
|
||
![]()
8 years ago
|
|
||
![]()
7 years ago
|
buildInputs = [ pkgs.fftw pkgs.fftwFloat pkgs.fftwLongDouble];
|
||
![]()
8 years ago
|
|
||
![]()
7 years ago
|
propagatedBuildInputs = with self; [ numpy scipy ];
|
||
![]()
8 years ago
|
|
||
![]()
7 years ago
|
# Tests cannot import pyfftw. pyfftw works fine though.
|
||
|
doCheck = false;
|
||
![]()
8 years ago
|
|
||
![]()
7 years ago
|
preConfigure = ''
|
||
|
export LDFLAGS="-L${pkgs.fftw.dev}/lib -L${pkgs.fftwFloat.out}/lib -L${pkgs.fftwLongDouble.out}/lib"
|
||
|
export CFLAGS="-I${pkgs.fftw.dev}/include -I${pkgs.fftwFloat.dev}/include -I${pkgs.fftwLongDouble.dev}/include"
|
||
|
'';
|
||
|
|
||
|
meta = {
|
||
|
description = "A pythonic wrapper around FFTW, the FFT library, presenting a unified interface for all the supported transforms";
|
||
|
homepage = http://hgomersall.github.com/pyFFTW/;
|
||
|
license = with licenses; [ bsd2 bsd3 ];
|
||
|
maintainer = with maintainers; [ fridh ];
|
||
|
};
|
||
![]()
8 years ago
|
};
|
||
![]()
7 years ago
|
}
|
||
![]()
8 years ago
|
```
|
||
|
Note also the line `doCheck = false;`, we explicitly disabled running the test-suite.
|
||
|
|
||
|
|
||
|
#### Develop local package
|
||
|
|
||
![]()
8 years ago
|
As a Python developer you're likely aware of [development mode](http://setuptools.readthedocs.io/en/latest/setuptools.html#development-mode) (`python setup.py develop`);
|
||
![]()
8 years ago
|
instead of installing the package this command creates a special link to the project code.
|
||
|
That way, you can run updated code without having to reinstall after each and every change you make.
|
||
![]()
8 years ago
|
Development mode is also available. Let's see how you can use it.
|
||
![]()
8 years ago
|
|
||
|
In the previous Nix expression the source was fetched from an url. We can also refer to a local source instead using
|
||
![]()
7 years ago
|
`src = ./path/to/source/tree;`
|
||
![]()
8 years ago
|
|
||
|
If we create a `shell.nix` file which calls `buildPythonPackage`, and if `src`
|
||
|
is a local source, and if the local source has a `setup.py`, then development
|
||
|
mode is activated.
|
||
|
|
||
|
In the following example we create a simple environment that
|
||
|
has a Python 3.5 version of our package in it, as well as its dependencies and
|
||
|
other packages we like to have in the environment, all specified with `propagatedBuildInputs`.
|
||
|
Indeed, we can just add any package we like to have in our environment to `propagatedBuildInputs`.
|
||
|
|
||
|
```nix
|
||
![]()
7 years ago
|
with import <nixpkgs> {};
|
||
![]()
8 years ago
|
with pkgs.python35Packages;
|
||
|
|
||
|
buildPythonPackage rec {
|
||
|
name = "mypackage";
|
||
|
src = ./path/to/package/source;
|
||
|
propagatedBuildInputs = [ pytest numpy pkgs.libsndfile ];
|
||
![]()
7 years ago
|
}
|
||
![]()
8 years ago
|
```
|
||
|
|
||
|
It is important to note that due to how development mode is implemented on Nix it is not possible to have multiple packages simultaneously in development mode.
|
||
|
|
||
|
|
||
|
### Organising your packages
|
||
|
|
||
|
So far we discussed how you can use Python on Nix, and how you can develop with
|
||
|
it. We've looked at how you write expressions to package Python packages, and we
|
||
|
looked at how you can create environments in which specified packages are
|
||
|
available.
|
||
|
|
||
|
At some point you'll likely have multiple packages which you would
|
||
|
like to be able to use in different projects. In order to minimise unnecessary
|
||
|
duplication we now look at how you can maintain yourself a repository with your
|
||
|
own packages. The important functions here are `import` and `callPackage`.
|
||
|
|
||
|
### Including a derivation using `callPackage`
|
||
|
|
||
![]()
8 years ago
|
Earlier we created a Python environment using `withPackages`, and included the
|
||
![]()
8 years ago
|
`toolz` package via a `let` expression.
|
||
|
Let's split the package definition from the environment definition.
|
||
|
|
||
|
We first create a function that builds `toolz` in `~/path/to/toolz/release.nix`
|
||
|
|
||
|
```nix
|
||
|
{ pkgs, buildPythonPackage }:
|
||
|
|
||
|
buildPythonPackage rec {
|
||
![]()
7 years ago
|
pname = "toolz";
|
||
![]()
8 years ago
|
version = "0.7.4";
|
||
|
|
||
![]()
7 years ago
|
src = fetchPypi {
|
||
|
inherit pname version;
|
||
![]()
8 years ago
|
sha256 = "43c2c9e5e7a16b6c88ba3088a9bfc82f7db8e13378be7c78d6c14a5f8ed05afd";
|
||
|
};
|
||
|
|
||
|
meta = {
|
||
|
homepage = "http://github.com/pytoolz/toolz/";
|
||
|
description = "List processing tools and functional utilities";
|
||
|
license = licenses.bsd3;
|
||
|
maintainers = with maintainers; [ fridh ];
|
||
|
};
|
||
![]()
7 years ago
|
}
|
||
![]()
8 years ago
|
```
|
||
|
|
||
|
It takes two arguments, `pkgs` and `buildPythonPackage`.
|
||
|
We now call this function using `callPackage` in the definition of our environment
|
||
|
|
||
|
```nix
|
||
|
with import <nixpkgs> {};
|
||
|
|
||
|
( let
|
||
![]()
7 years ago
|
toolz = pkgs.callPackage /path/to/toolz/release.nix {
|
||
|
pkgs = pkgs;
|
||
|
buildPythonPackage = pkgs.python35Packages.buildPythonPackage;
|
||
|
};
|
||
![]()
8 years ago
|
in pkgs.python35.withPackages (ps: [ ps.numpy toolz ])
|
||
![]()
8 years ago
|
).env
|
||
|
```
|
||
|
|
||
|
Important to remember is that the Python version for which the package is made
|
||
|
depends on the `python` derivation that is passed to `buildPythonPackage`. Nix
|
||
|
tries to automatically pass arguments when possible, which is why generally you
|
||
|
don't explicitly define which `python` derivation should be used. In the above
|
||
|
example we use `buildPythonPackage` that is part of the set `python35Packages`,
|
||
|
and in this case the `python35` interpreter is automatically used.
|
||
|
|
||
|
|
||
|
|
||
|
## Reference
|
||
|
|
||
|
### Interpreters
|
||
|
|
||
![]()
7 years ago
|
Versions 2.7, 3.3, 3.4, 3.5 and 3.6 of the CPython interpreter are available as
|
||
![]()
7 years ago
|
respectively `python27`, `python34`, `python35` and `python36`. The PyPy interpreter
|
||
![]()
8 years ago
|
is available as `pypy`. The aliases `python2` and `python3` correspond to respectively `python27` and
|
||
![]()
8 years ago
|
`python35`. The default interpreter, `python`, maps to `python2`.
|
||
![]()
8 years ago
|
The Nix expressions for the interpreters can be found in
|
||
![]()
8 years ago
|
`pkgs/development/interpreters/python`.
|
||
|
|
||
|
All packages depending on any Python interpreter get appended
|
||
|
`out/{python.sitePackages}` to `$PYTHONPATH` if such directory
|
||
|
exists.
|
||
|
|
||
![]()
8 years ago
|
#### Missing `tkinter` module standard library
|
||
|
|
||
![]()
8 years ago
|
To reduce closure size the `Tkinter`/`tkinter` is available as a separate package, `pythonPackages.tkinter`.
|
||
![]()
8 years ago
|
|
||
![]()
8 years ago
|
#### Attributes on interpreters packages
|
||
|
|
||
|
Each interpreter has the following attributes:
|
||
|
|
||
|
- `libPrefix`. Name of the folder in `${python}/lib/` for corresponding interpreter.
|
||
|
- `interpreter`. Alias for `${python}/bin/${executable}`.
|
||
|
- `buildEnv`. Function to build python interpreter environments with extra packages bundled together. See section *python.buildEnv function* for usage and documentation.
|
||
![]()
8 years ago
|
- `withPackages`. Simpler interface to `buildEnv`. See section *python.withPackages function* for usage and documentation.
|
||
![]()
8 years ago
|
- `sitePackages`. Alias for `lib/${libPrefix}/site-packages`.
|
||
![]()
8 years ago
|
- `executable`. Name of the interpreter executable, e.g. `python3.4`.
|
||
![]()
8 years ago
|
- `pkgs`. Set of Python packages for that specific interpreter. The package set can be modified by overriding the interpreter and passing `packageOverrides`.
|
||
![]()
8 years ago
|
|
||
|
### Building packages and applications
|
||
|
|
||
![]()
8 years ago
|
Python libraries and applications that use `setuptools` or
|
||
|
`distutils` are typically build with respectively the `buildPythonPackage` and
|
||
|
`buildPythonApplication` functions. These two functions also support installing a `wheel`.
|
||
![]()
8 years ago
|
|
||
|
All Python packages reside in `pkgs/top-level/python-packages.nix` and all
|
||
![]()
8 years ago
|
applications elsewhere. In case a package is used as both a library and an application,
|
||
|
then the package should be in `pkgs/top-level/python-packages.nix` since only those packages are made
|
||
|
available for all interpreter versions. The preferred location for library expressions is in
|
||
![]()
8 years ago
|
`pkgs/development/python-modules`. It is important that these packages are
|
||
![]()
8 years ago
|
called from `pkgs/top-level/python-packages.nix` and not elsewhere, to guarantee
|
||
![]()
8 years ago
|
the right version of the package is built.
|
||
|
|
||
|
Based on the packages defined in `pkgs/top-level/python-packages.nix` an
|
||
|
attribute set is created for each available Python interpreter. The available
|
||
|
sets are
|
||
|
|
||
|
* `pkgs.python27Packages`
|
||
|
* `pkgs.python34Packages`
|
||
|
* `pkgs.python35Packages`
|
||
![]()
7 years ago
|
* `pkgs.python36Packages`
|
||
![]()
8 years ago
|
* `pkgs.pypyPackages`
|
||
|
|
||
|
and the aliases
|
||
|
|
||
![]()
8 years ago
|
* `pkgs.python2Packages` pointing to `pkgs.python27Packages`
|
||
![]()
7 years ago
|
* `pkgs.python3Packages` pointing to `pkgs.python36Packages`
|
||
![]()
8 years ago
|
* `pkgs.pythonPackages` pointing to `pkgs.python2Packages`
|
||
![]()
8 years ago
|
|
||
|
#### `buildPythonPackage` function
|
||
|
|
||
|
The `buildPythonPackage` function is implemented in
|
||
![]()
8 years ago
|
`pkgs/development/interpreters/python/build-python-package.nix`
|
||
![]()
8 years ago
|
|
||
![]()
8 years ago
|
The following is an example:
|
||
![]()
7 years ago
|
```nix
|
||
![]()
8 years ago
|
|
||
![]()
7 years ago
|
buildPythonPackage rec {
|
||
|
version = "3.3.1";
|
||
|
pname = "pytest";
|
||
![]()
8 years ago
|
|
||
![]()
7 years ago
|
preCheck = ''
|
||
|
# don't test bash builtins
|
||
|
rm testing/test_argcomplete.py
|
||
|
'';
|
||
![]()
8 years ago
|
|
||
![]()
7 years ago
|
src = fetchPypi {
|
||
|
inherit pname version;
|
||
|
sha256 = "cf8436dc59d8695346fcd3ab296de46425ecab00d64096cebe79fb51ecb2eb93";
|
||
|
};
|
||
![]()
8 years ago
|
|
||
![]()
7 years ago
|
checkInputs = [ hypothesis ];
|
||
|
buildInputs = [ setuptools_scm ];
|
||
|
propagatedBuildInputs = [ attrs py setuptools six pluggy ];
|
||
|
|
||
|
meta = with stdenv.lib; {
|
||
|
maintainers = with maintainers; [ domenkozar lovek323 madjar lsix ];
|
||
|
description = "Framework for writing tests";
|
||
![]()
7 years ago
|
};
|
||
|
}
|
||
![]()
7 years ago
|
|
||
![]()
7 years ago
|
```
|
||
![]()
8 years ago
|
|
||
|
The `buildPythonPackage` mainly does four things:
|
||
|
|
||
![]()
8 years ago
|
* In the `buildPhase`, it calls `${python.interpreter} setup.py bdist_wheel` to
|
||
|
build a wheel binary zipfile.
|
||
![]()
8 years ago
|
* In the `installPhase`, it installs the wheel file using `pip install *.whl`.
|
||
![]()
8 years ago
|
* In the `postFixup` phase, the `wrapPythonPrograms` bash function is called to
|
||
|
wrap all programs in the `$out/bin/*` directory to include `$PATH`
|
||
|
environment variable and add dependent libraries to script's `sys.path`.
|
||
![]()
8 years ago
|
* In the `installCheck` phase, `${python.interpreter} setup.py test` is ran.
|
||
|
|
||
|
As in Perl, dependencies on other Python packages can be specified in the
|
||
|
`buildInputs` and `propagatedBuildInputs` attributes. If something is
|
||
|
exclusively a build-time dependency, use `buildInputs`; if it’s (also) a runtime
|
||
|
dependency, use `propagatedBuildInputs`.
|
||
|
|
||
|
By default tests are run because `doCheck = true`. Test dependencies, like
|
||
|
e.g. the test runner, should be added to `buildInputs`.
|
||
|
|
||
|
By default `meta.platforms` is set to the same value
|
||
![]()
7 years ago
|
as the interpreter unless overridden otherwise.
|
||
![]()
8 years ago
|
|
||
|
##### `buildPythonPackage` parameters
|
||
|
|
||
|
All parameters from `mkDerivation` function are still supported.
|
||
|
|
||
|
* `namePrefix`: Prepended text to `${name}` parameter. Defaults to `"python3.3-"` for Python 3.3, etc. Set it to `""` if you're packaging an application or a command line tool.
|
||
|
* `disabled`: If `true`, package is not build for particular python interpreter version. Grep around `pkgs/top-level/python-packages.nix` for examples.
|
||
|
* `setupPyBuildFlags`: List of flags passed to `setup.py build_ext` command.
|
||
|
* `pythonPath`: List of packages to be added into `$PYTHONPATH`. Packages in `pythonPath` are not propagated (contrary to `propagatedBuildInputs`).
|
||
|
* `preShellHook`: Hook to execute commands before `shellHook`.
|
||
|
* `postShellHook`: Hook to execute commands after `shellHook`.
|
||
|
* `makeWrapperArgs`: A list of strings. Arguments to be passed to `makeWrapper`, which wraps generated binaries. By default, the arguments to `makeWrapper` set `PATH` and `PYTHONPATH` environment variables before calling the binary. Additional arguments here can allow a developer to set environment variables which will be available when the binary is run. For example, `makeWrapperArgs = ["--set FOO BAR" "--set BAZ QUX"]`.
|
||
|
* `installFlags`: A list of strings. Arguments to be passed to `pip install`. To pass options to `python setup.py install`, use `--install-option`. E.g., `installFlags=["--install-option='--cpp_implementation'"].
|
||
![]()
8 years ago
|
* `format`: Format of the source. Valid options are `setuptools` (default), `flit`, `wheel`, and `other`. `setuptools` is for when the source has a `setup.py` and `setuptools` is used to build a wheel, `flit`, in case `flit` should be used to build a wheel, and `wheel` in case a wheel is provided. In case you need to provide your own `buildPhase` and `installPhase` you can use `other`.
|
||
![]()
8 years ago
|
* `catchConflicts` If `true`, abort package build if a package name appears more than once in dependency tree. Default is `true`.
|
||
![]()
8 years ago
|
* `checkInputs` Dependencies needed for running the `checkPhase`. These are added to `buildInputs` when `doCheck = true`.
|
||
![]()
8 years ago
|
|
||
![]()
7 years ago
|
##### Overriding Python packages
|
||
|
|
||
![]()
7 years ago
|
The `buildPythonPackage` function has a `overridePythonAttrs` method that
|
||
![]()
7 years ago
|
can be used to override the package. In the following example we create an
|
||
|
environment where we have the `blaze` package using an older version of `pandas`.
|
||
|
We override first the Python interpreter and pass
|
||
|
`packageOverrides` which contains the overrides for packages in the package set.
|
||
|
|
||
|
```nix
|
||
|
with import <nixpkgs> {};
|
||
|
|
||
|
(let
|
||
|
python = let
|
||
|
packageOverrides = self: super: {
|
||
![]()
7 years ago
|
pandas = super.pandas.overridePythonAttrs(old: rec {
|
||
![]()
7 years ago
|
version = "0.19.1";
|
||
|
src = super.fetchPypi {
|
||
|
pname = "pandas";
|
||
|
inherit version;
|
||
|
sha256 = "08blshqj9zj1wyjhhw3kl2vas75vhhicvv72flvf1z3jvapgw295";
|
||
|
};
|
||
|
});
|
||
|
};
|
||
|
in pkgs.python3.override {inherit packageOverrides;};
|
||
|
|
||
|
in python.withPackages(ps: [ps.blaze])).env
|
||
|
```
|
||
|
|
||
![]()
8 years ago
|
#### `buildPythonApplication` function
|
||
|
|
||
|
The `buildPythonApplication` function is practically the same as `buildPythonPackage`.
|
||
|
The difference is that `buildPythonPackage` by default prefixes the names of the packages with the version of the interpreter.
|
||
|
Because with an application we're not interested in multiple version the prefix is dropped.
|
||
|
|
||
|
#### python.buildEnv function
|
||
|
|
||
|
Python environments can be created using the low-level `pkgs.buildEnv` function.
|
||
|
This example shows how to create an environment that has the Pyramid Web Framework.
|
||
|
Saving the following as `default.nix`
|
||
![]()
7 years ago
|
```nix
|
||
|
with import <nixpkgs> {};
|
||
![]()
8 years ago
|
|
||
![]()
7 years ago
|
python.buildEnv.override {
|
||
|
extraLibs = [ pkgs.pythonPackages.pyramid ];
|
||
|
ignoreCollisions = true;
|
||
|
}
|
||
|
```
|
||
![]()
8 years ago
|
|
||
|
and running `nix-build` will create
|
||
![]()
7 years ago
|
```
|
||
|
/nix/store/cf1xhjwzmdki7fasgr4kz6di72ykicl5-python-2.7.8-env
|
||
|
```
|
||
![]()
8 years ago
|
|
||
|
with wrapped binaries in `bin/`.
|
||
|
|
||
|
You can also use the `env` attribute to create local environments with needed
|
||
|
packages installed. This is somewhat comparable to `virtualenv`. For example,
|
||
|
running `nix-shell` with the following `shell.nix`
|
||
![]()
7 years ago
|
```nix
|
||
|
with import <nixpkgs> {};
|
||
![]()
8 years ago
|
|
||
![]()
7 years ago
|
(python3.buildEnv.override {
|
||
![]()
7 years ago
|
extraLibs = with python3Packages; [ numpy requests ];
|
||
![]()
7 years ago
|
}).env
|
||
|
```
|
||
![]()
8 years ago
|
|
||
|
will drop you into a shell where Python will have the
|
||
|
specified packages in its path.
|
||
|
|
||
|
|
||
|
##### `python.buildEnv` arguments
|
||
|
|
||
|
* `extraLibs`: List of packages installed inside the environment.
|
||
|
* `postBuild`: Shell command executed after the build of environment.
|
||
|
* `ignoreCollisions`: Ignore file collisions inside the environment (default is `false`).
|
||
|
|
||
![]()
8 years ago
|
#### python.withPackages function
|
||
|
|
||
|
The `python.withPackages` function provides a simpler interface to the `python.buildEnv` functionality.
|
||
![]()
7 years ago
|
It takes a function as an argument that is passed the set of python packages and returns the list
|
||
![]()
8 years ago
|
of the packages to be included in the environment. Using the `withPackages` function, the previous
|
||
|
example for the Pyramid Web Framework environment can be written like this:
|
||
![]()
7 years ago
|
```nix
|
||
|
with import <nixpkgs> {};
|
||
![]()
8 years ago
|
|
||
![]()
7 years ago
|
python.withPackages (ps: [ps.pyramid])
|
||
|
```
|
||
![]()
8 years ago
|
|
||
![]()
7 years ago
|
`withPackages` passes the correct package set for the specific interpreter version as an
|
||
![]()
8 years ago
|
argument to the function. In the above example, `ps` equals `pythonPackages`.
|
||
|
But you can also easily switch to using python3:
|
||
![]()
7 years ago
|
```nix
|
||
|
with import <nixpkgs> {};
|
||
![]()
7 years ago
|
|
||
![]()
7 years ago
|
python3.withPackages (ps: [ps.pyramid])
|
||
|
```
|
||
![]()
8 years ago
|
|
||
|
Now, `ps` is set to `python3Packages`, matching the version of the interpreter.
|
||
|
|
||
|
As `python.withPackages` simply uses `python.buildEnv` under the hood, it also supports the `env`
|
||
|
attribute. The `shell.nix` file from the previous section can thus be also written like this:
|
||
![]()
7 years ago
|
```nix
|
||
|
with import <nixpkgs> {};
|
||
![]()
8 years ago
|
|
||
![]()
7 years ago
|
(python36.withPackages (ps: [ps.numpy ps.requests])).env
|
||
![]()
7 years ago
|
```
|
||
![]()
8 years ago
|
|
||
|
In contrast to `python.buildEnv`, `python.withPackages` does not support the more advanced options
|
||
|
such as `ignoreCollisions = true` or `postBuild`. If you need them, you have to use `python.buildEnv`.
|
||
|
|
||
![]()
7 years ago
|
Python 2 namespace packages may provide `__init__.py` that collide. In that case `python.buildEnv`
|
||
|
should be used with `ignoreCollisions = true`.
|
||
|
|
||
![]()
8 years ago
|
### Development mode
|
||
|
|
||
|
Development or editable mode is supported. To develop Python packages
|
||
|
`buildPythonPackage` has additional logic inside `shellPhase` to run `pip
|
||
|
install -e . --prefix $TMPDIR/`for the package.
|
||
|
|
||
|
Warning: `shellPhase` is executed only if `setup.py` exists.
|
||
|
|
||
|
Given a `default.nix`:
|
||
![]()
7 years ago
|
```nix
|
||
|
with import <nixpkgs> {};
|
||
![]()
8 years ago
|
|
||
![]()
7 years ago
|
buildPythonPackage { name = "myproject";
|
||
![]()
8 years ago
|
|
||
![]()
7 years ago
|
buildInputs = with pkgs.pythonPackages; [ pyramid ];
|
||
![]()
8 years ago
|
|
||
![]()
7 years ago
|
src = ./.; }
|
||
|
```
|
||
![]()
8 years ago
|
|
||
|
Running `nix-shell` with no arguments should give you
|
||
![]()
8 years ago
|
the environment in which the package would be built with
|
||
![]()
8 years ago
|
`nix-build`.
|
||
|
|
||
|
Shortcut to setup environments with C headers/libraries and python packages:
|
||
![]()
7 years ago
|
```shell
|
||
|
nix-shell -p pythonPackages.pyramid zlib libjpeg git
|
||
|
```
|
||
![]()
8 years ago
|
|
||
|
Note: There is a boolean value `lib.inNixShell` set to `true` if nix-shell is invoked.
|
||
|
|
||
|
### Tools
|
||
|
|
||
|
Packages inside nixpkgs are written by hand. However many tools exist in
|
||
|
community to help save time. No tool is preferred at the moment.
|
||
|
|
||
|
- [python2nix](https://github.com/proger/python2nix) by Vladimir Kirillov
|
||
|
- [pypi2nix](https://github.com/garbas/pypi2nix) by Rok Garbas
|
||
|
- [pypi2nix](https://github.com/offlinehacker/pypi2nix) by Jaka Hudoklin
|
||
|
|
||
![]()
7 years ago
|
### Deterministic builds
|
||
|
|
||
|
Python 2.7, 3.5 and 3.6 are now built deterministically and 3.4 mostly.
|
||
|
Minor modifications had to be made to the interpreters in order to generate
|
||
|
deterministic bytecode. This has security implications and is relevant for
|
||
|
those using Python in a `nix-shell`.
|
||
|
|
||
|
When the environment variable `DETERMINISTIC_BUILD` is set, all bytecode will have timestamp 1.
|
||
![]()
7 years ago
|
The `buildPythonPackage` function sets `DETERMINISTIC_BUILD=1` and
|
||
|
[PYTHONHASHSEED=0](https://docs.python.org/3.5/using/cmdline.html#envvar-PYTHONHASHSEED).
|
||
![]()
7 years ago
|
Both are also exported in `nix-shell`.
|
||
|
|
||
|
|
||
![]()
7 years ago
|
### Automatic tests
|
||
|
|
||
|
It is recommended to test packages as part of the build process.
|
||
|
Source distributions (`sdist`) often include test files, but not always.
|
||
|
|
||
|
By default the command `python setup.py test` is run as part of the
|
||
|
`checkPhase`, but often it is necessary to pass a custom `checkPhase`. An
|
||
|
example of such a situation is when `py.test` is used.
|
||
|
|
||
|
#### Common issues
|
||
|
|
||
![]()
7 years ago
|
- Non-working tests can often be deselected. By default `buildPythonPackage` runs `python setup.py test`.
|
||
|
Most python modules follows the standard test protocol where the pytest runner can be used instead.
|
||
|
`py.test` supports a `-k` parameter to ignore test methods or classes:
|
||
|
|
||
|
```nix
|
||
|
buildPythonPackage {
|
||
|
# ...
|
||
|
# assumes the tests are located in tests
|
||
|
checkInputs = [ pytest ];
|
||
|
checkPhase = ''
|
||
|
py.test -k 'not function_name and not other_function' tests
|
||
|
'';
|
||
|
}
|
||
|
```
|
||
![]()
7 years ago
|
- Unicode issues can typically be fixed by including `glibcLocales` in `buildInputs` and exporting `LC_ALL=en_US.utf-8`.
|
||
|
- Tests that attempt to access `$HOME` can be fixed by using the following work-around before running tests (e.g. `preCheck`): `export HOME=$(mktemp -d)`
|
||
|
|
||
![]()
8 years ago
|
## FAQ
|
||
|
|
||
|
### How to solve circular dependencies?
|
||
|
|
||
|
Consider the packages `A` and `B` that depend on each other. When packaging `B`,
|
||
|
a solution is to override package `A` not to depend on `B` as an input. The same
|
||
|
should also be done when packaging `A`.
|
||
|
|
||
|
### How to override a Python package?
|
||
|
|
||
![]()
8 years ago
|
We can override the interpreter and pass `packageOverrides`.
|
||
|
In the following example we rename the `pandas` package and build it.
|
||
|
```nix
|
||
![]()
8 years ago
|
with import <nixpkgs> {};
|
||
|
|
||
![]()
7 years ago
|
(let
|
||
![]()
8 years ago
|
python = let
|
||
|
packageOverrides = self: super: {
|
||
![]()
7 years ago
|
pandas = super.pandas.overridePythonAttrs(old: {name="foo";});
|
||
![]()
8 years ago
|
};
|
||
|
in pkgs.python35.override {inherit packageOverrides;};
|
||
![]()
8 years ago
|
|
||
![]()
7 years ago
|
in python.withPackages(ps: [ps.pandas])).env
|
||
![]()
8 years ago
|
```
|
||
![]()
7 years ago
|
Using `nix-build` on this expression will build an environment that contains the
|
||
|
package `pandas` but with the new name `foo`.
|
||
![]()
8 years ago
|
|
||
![]()
8 years ago
|
All packages in the package set will use the renamed package.
|
||
|
A typical use case is to switch to another version of a certain package.
|
||
|
For example, in the Nixpkgs repository we have multiple versions of `django` and `scipy`.
|
||
|
In the following example we use a different version of `scipy` and create an environment that uses it.
|
||
|
All packages in the Python package set will now use the updated `scipy` version.
|
||
![]()
8 years ago
|
|
||
![]()
8 years ago
|
```nix
|
||
|
with import <nixpkgs> {};
|
||
|
|
||
![]()
7 years ago
|
( let
|
||
|
packageOverrides = self: super: {
|
||
|
scipy = super.scipy_0_17;
|
||
|
};
|
||
|
in (pkgs.python35.override {inherit packageOverrides;}).withPackages (ps: [ps.blaze])
|
||
![]()
8 years ago
|
).env
|
||
![]()
8 years ago
|
```
|
||
![]()
8 years ago
|
The requested package `blaze` depends on `pandas` which itself depends on `scipy`.
|
||
![]()
8 years ago
|
|
||
![]()
8 years ago
|
If you want the whole of Nixpkgs to use your modifications, then you can use `overlays`
|
||
![]()
8 years ago
|
as explained in this manual. In the following example we build a `inkscape` using a different version of `numpy`.
|
||
![]()
7 years ago
|
```nix
|
||
![]()
8 years ago
|
let
|
||
|
pkgs = import <nixpkgs> {};
|
||
![]()
8 years ago
|
newpkgs = import pkgs.path { overlays = [ (pkgsself: pkgssuper: {
|
||
![]()
8 years ago
|
python27 = let
|
||
|
packageOverrides = self: super: {
|
||
|
numpy = super.numpy_1_10;
|
||
|
};
|
||
|
in pkgssuper.python27.override {inherit packageOverrides;};
|
||
![]()
8 years ago
|
} ) ]; };
|
||
![]()
8 years ago
|
in newpkgs.inkscape
|
||
![]()
8 years ago
|
```
|
||
|
|
||
![]()
8 years ago
|
### `python setup.py bdist_wheel` cannot create .whl
|
||
|
|
||
![]()
8 years ago
|
Executing `python setup.py bdist_wheel` in a `nix-shell `fails with
|
||
![]()
8 years ago
|
```
|
||
|
ValueError: ZIP does not support timestamps before 1980
|
||
|
```
|
||
![]()
6 years ago
|
|
||
|
This is because files from the Nix store (which have a timestamp of the UNIX epoch of January 1, 1970) are included in the .ZIP, but .ZIP archives follow the DOS convention of counting timestamps from 1980.
|
||
|
|
||
|
The command `bdist_wheel` reads the `SOURCE_DATE_EPOCH` environment variable, which `nix-shell` sets to 1. Unsetting this variable or giving it a value corresponding to 1980 or later enables building wheels.
|
||
![]()
8 years ago
|
|
||
|
Use 1980 as timestamp:
|
||
![]()
7 years ago
|
```shell
|
||
![]()
8 years ago
|
nix-shell --run "SOURCE_DATE_EPOCH=315532800 python3 setup.py bdist_wheel"
|
||
![]()
8 years ago
|
```
|
||
|
or the current time:
|
||
![]()
7 years ago
|
```shell
|
||
![]()
8 years ago
|
nix-shell --run "SOURCE_DATE_EPOCH=$(date +%s) python3 setup.py bdist_wheel"
|
||
![]()
8 years ago
|
```
|
||
![]()
6 years ago
|
or unset `SOURCE_DATE_EPOCH`:
|
||
![]()
7 years ago
|
```shell
|
||
![]()
8 years ago
|
nix-shell --run "unset SOURCE_DATE_EPOCH; python3 setup.py bdist_wheel"
|
||
![]()
8 years ago
|
```
|
||
![]()
8 years ago
|
|
||
|
### `install_data` / `data_files` problems
|
||
|
|
||
|
If you get the following error:
|
||
![]()
7 years ago
|
```
|
||
|
could not create '/nix/store/6l1bvljpy8gazlsw2aw9skwwp4pmvyxw-python-2.7.8/etc':
|
||
|
Permission denied
|
||
|
```
|
||
|
This is a [known bug](https://github.com/pypa/setuptools/issues/130) in `setuptools`.
|
||
![]()
8 years ago
|
Setuptools `install_data` does not respect `--prefix`. An example of such package using the feature is `pkgs/tools/X11/xpra/default.nix`.
|
||
|
As workaround install it as an extra `preInstall` step:
|
||
![]()
7 years ago
|
```shell
|
||
|
${python.interpreter} setup.py install_data --install-dir=$out --root=$out
|
||
|
sed -i '/ = data\_files/d' setup.py
|
||
|
```
|
||
![]()
8 years ago
|
|
||
|
### Rationale of non-existent global site-packages
|
||
|
|
||
|
On most operating systems a global `site-packages` is maintained. This however
|
||
|
becomes problematic if you want to run multiple Python versions or have multiple
|
||
|
versions of certain libraries for your projects. Generally, you would solve such
|
||
|
issues by creating virtual environments using `virtualenv`.
|
||
|
|
||
|
On Nix each package has an isolated dependency tree which, in the case of
|
||
|
Python, guarantees the right versions of the interpreter and libraries or
|
||
|
packages are available. There is therefore no need to maintain a global `site-packages`.
|
||
|
|
||
|
If you want to create a Python environment for development, then the recommended
|
||
|
method is to use `nix-shell`, either with or without the `python.buildEnv`
|
||
|
function.
|
||
|
|
||
![]()
8 years ago
|
### How to consume python modules using pip in a virtualenv like I am used to on other Operating Systems ?
|
||
|
|
||
|
This is an example of a `default.nix` for a `nix-shell`, which allows to consume a `virtualenv` environment,
|
||
|
and install python modules through `pip` the traditional way.
|
||
|
|
||
|
Create this `default.nix` file, together with a `requirements.txt` and simply execute `nix-shell`.
|
||
|
|
||
![]()
7 years ago
|
```nix
|
||
![]()
8 years ago
|
with import <nixpkgs> {};
|
||
![]()
8 years ago
|
with pkgs.python27Packages;
|
||
|
|
||
![]()
7 years ago
|
stdenv.mkDerivation {
|
||
![]()
8 years ago
|
name = "impurePythonEnv";
|
||
|
buildInputs = [
|
||
![]()
8 years ago
|
# these packages are required for virtualenv and pip to work:
|
||
|
#
|
||
|
python27Full
|
||
|
python27Packages.virtualenv
|
||
|
python27Packages.pip
|
||
![]()
7 years ago
|
# the following packages are related to the dependencies of your python
|
||
|
# project.
|
||
|
# In this particular example the python modules listed in the
|
||
|
# requirements.tx require the following packages to be installed locally
|
||
![]()
8 years ago
|
# in order to compile any binary extensions they may require.
|
||
|
#
|
||
![]()
8 years ago
|
taglib
|
||
|
openssl
|
||
|
git
|
||
|
libxml2
|
||
|
libxslt
|
||
|
libzip
|
||
|
stdenv
|
||
|
zlib ];
|
||
|
src = null;
|
||
|
shellHook = ''
|
||
![]()
8 years ago
|
# set SOURCE_DATE_EPOCH so that we can use python wheels
|
||
|
SOURCE_DATE_EPOCH=$(date +%s)
|
||
![]()
7 years ago
|
virtualenv --no-setuptools venv
|
||
![]()
8 years ago
|
export PATH=$PWD/venv/bin:$PATH
|
||
![]()
8 years ago
|
pip install -r requirements.txt
|
||
![]()
8 years ago
|
'';
|
||
|
}
|
||
|
```
|
||
![]()
8 years ago
|
|
||
![]()
8 years ago
|
Note that the `pip install` is an imperative action. So every time `nix-shell`
|
||
![]()
7 years ago
|
is executed it will attempt to download the python modules listed in
|
||
![]()
8 years ago
|
requirements.txt. However these will be cached locally within the `virtualenv`
|
||
|
folder and not downloaded again.
|
||
|
|
||
![]()
7 years ago
|
### How to override a Python package from `configuration.nix`?
|
||
|
|
||
|
If you need to change a package's attribute(s) from `configuration.nix` you could do:
|
||
|
|
||
|
```nix
|
||
|
nixpkgs.config.packageOverrides = superP: {
|
||
|
pythonPackages = superP.pythonPackages.override {
|
||
|
overrides = self: super: {
|
||
|
bepasty-server = super.bepasty-server.overrideAttrs ( oldAttrs: {
|
||
|
src = pkgs.fetchgit {
|
||
|
url = "https://github.com/bepasty/bepasty-server";
|
||
|
sha256 = "9ziqshmsf0rjvdhhca55sm0x8jz76fsf2q4rwh4m6lpcf8wr0nps";
|
||
|
rev = "e2516e8cf4f2afb5185337073607eb9e84a61d2d";
|
||
|
};
|
||
|
});
|
||
|
};
|
||
|
};
|
||
|
};
|
||
|
```
|
||
|
|
||
|
If you are using the `bepasty-server` package somewhere, for example in `systemPackages` or indirectly from `services.bepasty`, then a `nixos-rebuild switch` will rebuild the system but with the `bepasty-server` package using a different `src` attribute. This way one can modify `python` based software/libraries easily. Using `self` and `super` one can also alter dependencies (`buildInputs`) between the old state (`self`) and new state (`super`).
|
||
![]()
8 years ago
|
|
||
![]()
7 years ago
|
### How to override a Python package using overlays?
|
||
|
|
||
|
To alter a python package using overlays, you would use the following approach:
|
||
|
|
||
|
```nix
|
||
|
self: super:
|
||
|
rec {
|
||
|
python = super.python.override {
|
||
|
packageOverrides = python-self: python-super: {
|
||
|
bepasty-server = python-super.bepasty-server.overrideAttrs ( oldAttrs: {
|
||
|
src = self.pkgs.fetchgit {
|
||
|
url = "https://github.com/bepasty/bepasty-server";
|
||
|
sha256 = "9ziqshmsf0rjvdhhca55sm0x8jz76fsf2q4rwh4m6lpcf8wr0nps";
|
||
|
rev = "e2516e8cf4f2afb5185337073607eb9e84a61d2d";
|
||
|
};
|
||
|
});
|
||
|
};
|
||
|
};
|
||
|
pythonPackages = python.pkgs;
|
||
|
}
|
||
|
```
|
||
|
|
||
![]()
8 years ago
|
## Contributing
|
||
|
|
||
|
### Contributing guidelines
|
||
|
|
||
|
Following rules are desired to be respected:
|
||
|
|
||
![]()
7 years ago
|
* Python libraries are called from `python-packages.nix` and packaged with `buildPythonPackage`. The expression of a library should be in `pkgs/development/python-modules/<name>/default.nix`. Libraries in `pkgs/top-level/python-packages.nix` are sorted quasi-alphabetically to avoid merge conflicts.
|
||
![]()
7 years ago
|
* Python applications live outside of `python-packages.nix` and are packaged with `buildPythonApplication`.
|
||
|
* Make sure libraries build for all Python interpreters.
|
||
|
* By default we enable tests. Make sure the tests are found and, in the case of libraries, are passing for all interpreters. If certain tests fail they can be disabled individually. Try to avoid disabling the tests altogether. In any case, when you disable tests, leave a comment explaining why.
|
||
![]()
7 years ago
|
* Commit names of Python libraries should reflect that they are Python libraries, so write for example `pythonPackages.numpy: 1.11 -> 1.12`.
|
||
|
|