This project requires Python 3.6.
This project isn't packaged, and traditionally uses:
$ python -m venv venv
$ source venv/bin/activate
$ pip install "${pypi_deps[@]}"
$ pip freeze > requirements.txt
Our shell.nix
then starts out simply, with just one build input:
{ pkgs ? import <nixpkgs> { } }:
pkgs.mkShell {
name = "python-example-nixpkgs-dev-env";
buildInputs = [
(pkgs.python36.withPackages (pyPkgs: [
]))
];
}
This can now run an executable main.py
with all the imports commented out.
If you want to add packages, it's all ready to.
This example works with just uncommenting urllib3
's import.
(python.withPackages (pyPkgs: [
pyPkgs.urllib3
]))
By using pythonPackages.venvShellHook
(see the
Nixpkgs manual, §15.17.3.6. How to consume python
modules using pip in a virtual environment like I am used to on other
Operating Systems?),
a traditional venv
-based Python development environment can be established.
pkgs.mkShell {
buildInputs = [
python
pythonPackages.venvShellHook
];
}
Unfortunately, this doesn't quite carry over to
direnv & lorri
that well (see also nix-direnv#32),
as venvShellHook
's hook uses a function.
However, we can replicate its effects in .envrc
by looking at what
<nixpkgs/pkgs/development/interpreters/python/hooks/venv-shell-hook.sh>
does:
# pre(venvShellHook)
unset venvDir
# lorri
eval "$(lorri direnv)"
# venvShellHook
if [[ -v venvDir ]]; then
if [[ -d "${venvDir}" ]]; then
printf "%s\n" "Skipping venv creation, '${venvDir}' already exists"
source "${venvDir}/bin/activate"
else
printf "%s\n" "Creating new venv environment in path: '${venvDir}'"
python -m venv "${venvDir}"
source "${venvDir}/bin/activate"
fi
fi
Only running if $venvDir
is defined by the Nix shell allows this .envrc
to be used with or without venvShellHook
present in the shell.
With that all done, pip
works.
To ensure things are set up properly,
let's fully install the venv in a pure Nix shell.
$ rm -rf .venv && nix-shell --pure --run 'pip install -r requirements.txt'
pip install
fails with an error on kappa==0.6.0
.
Complete output from command python setup.py egg_info:
Traceback (most recent call last):
File "<string>", line 1, in <module>
File "/run/user/1000/pip-install-gydqfy_d/kappa/setup.py", line 54, in <module>
run_setup()
File "/run/user/1000/pip-install-gydqfy_d/kappa/setup.py", line 22, in run_setup
long_description=open_file('README.rst').read(),
File "/nix/store/5rxscqabwp1mkq0x11x04bbh5gvqdkad-python3-3.6.10/lib/python3.6/encodings/ascii.py", line 26, in decode
return codecs.ascii_decode(input, self.errors)[0]
UnicodeDecodeError: 'ascii' codec can't decode byte 0xe2 in position 2339: ordinal not in range(128)
This is a problem that you normally don't have to deal with in Nixpkgs.
Amending LANG = "C.UTF-8";
to your shell attributes fixes it, though.
And ./main.py
succeeds with all dependencies uncommented.
(If you stop using this shell, don't forget to remove .venv
.)
mach-nix provides easier environments from requirements.txt
.
mach-nix is not included in Nixpkgs, so we'll pin a version (the latest release's tag at time of writing).
$ niv add github DavHau/mach-nix -r 2.3.0
Expose mach-nix's expressions (alongside niv's expression):
import pkgsPath {
config = { };
overlays = [ (pkgsSuper: pkgs: {
mach-nix = import sources.mach-nix;
inherit (import sources.niv { }) niv;
}) ];
}
And write the shell (a bit strange, but it works):
(pkgs.mach-nix.mkPythonShell {
requirements = builtins.readFile ./requirements.txt;
inherit pkgs python;
}).overrideAttrs (oldAttrs: {
name = "${name}-mach-nix";
nativeBuildInputs = oldAttrs.nativeBuildInputs or [ ] ++ [
pkgs.niv
];
})
shell.nix
no longer evaluates, though.
From nix-shell --pure --show-trace --run ':'
(a no-op on success):
Some requirements could not be resolved.
Top level requirements:
Flask==1.1.1 Flask-Cors==3.0.8 Flask-JWT-Extended==3.23.0 Flask-SQLAlchemy==2.4.1 Flask-Migrate==2.5.3 Jinja2==2.10.1 passlib==1
.7.1 PyMySQL==0.9.3 pymssql==2.1.4 PyYAML==5.1.2 requests==2.22.0 SQLAlchemy==1.3.8 urllib3==1.25.6 Werkzeug==0.16.0 zappa==0.48
.2 cx-Oracle==7.2.2 pytz==2019.3
Providers:
{'_default': 'wheel,sdist,nixpkgs',
'gdal': 'nixpkgs',
'pip': 'nixpkgs',
'setupmeta': 'wheel',
'setuptools': 'nixpkgs',
'wheel': 'nixpkgs,sdist'}
Mach-nix version: 2.3.0
Python: 3.6.10
Cause: None
The requirements which caused the error:
kappa==0.6.0 - parent: zappa:0.48.2
I have no idea what's going on here.
Throughout these examples,
the sources.json
& sources.nix
files and sources
expression
are provided and managed by niv.
niv is an easy way to pin dependencies for your Nix expressions,
and easily update them later.
niv is already set up here, and will just work for updates.
If you want to install from scratch (e.g. into a new repository),
nix-shell -p niv
will get you bootstrapped
until you can import it from sources
into your own shell.
niv's documentation explains all this pretty well.