Nix python: Difference between revisions
Line 30: | Line 30: | ||
<blockquote> | <blockquote> | ||
{{ NOTE | | {{ NOTE | | ||
Python's user site does separates python versions, but package versions.<br> | Python's user site does separates python versions, but not package versions.<br> | ||
It is not safe to share packages this way. | It is not safe to share packages this way. | ||
}} | }} |
Latest revision as of 15:26, 3 April 2022
Projects
mach-nix https://github.com/DavHau/mach-nix nix-direnv https://github.com/nix-community/nix-direnv
Tutorials
vanilla nix + python https://github.com/FRidh/python-on-nix/blob/master/tutorial.md python development with nix https://thomazleite.com/posts/development-with-nix-python/ C, javascript, python, haskell managed together by nix https://matrix.ai/blog/developing-with-nix/ nix wiki: python https://nixos.wiki/wiki/Python
Package Providers
vanilla nix
NOTE:
Python's user site does separates python versions, but not package versions.
It is not safe to share packages this way.Nix allows you to define a package for a python-version interpreter,
and set the packages you want installed to it.This is simplest method, choosing either install packages locally, and/or using nix provided packages (less, older).
default.nix (base package)
# 'python' exposed for dependency injection in shell.nix { pkgs ? import <nixpkgs> {}, python ? pkgs.python38 }: pkgs.stdenv.mkDerivation { name = "nixpython-1.0.0"; buildInputs = [ pkgs.hello python python.pkgs.pytest python.pkgs.pylint python.pkgs.bootstrapped-pip ]; }
shell.nix (adds development python deps to default.nix)
# shell.nix { pkgs ? import <nixpkgs> {}, python ? pkgs.python38 }: let extra-os-pkgs = pkgs.config.vim-base; # ex: [ curl ripgrep ... ] vim-python-pkgs = pkgs.config.vim-python-pkgs; # ex: [ rope autopep8 jedi ...] pkg = import ./default.nix { python = python; }; nix-python-pkgs = (map (x: builtins.getAttr x python.pkgs) (builtins.filter (x: builtins.hasAttr x python.pkgs) vim-python-pkgs)); pip-python-pkgs = (builtins.filter (x: !builtins.hasAttr x python.pkgs) vim-python-pkgs); in pkg.overrideAttrs( old: { buildInputs = old.buildInputs ++ extra-os-pkgs ++ nix-python-pkgs; shellHook = (if builtins.hasAttr "shellHook" old then builtins.getAttr "shellHook" old else "") + "\npython -m pip install --target=.pkgs " + (builtins.concatStringsSep " " pip-python-pkgs) + "\nexport PYTHONPATH=$PYTHONPATH:$(pwd)/.pkgs"; } )${PACKAGE}/.envrc
use_nixpipenv
pipenv greatly simplifies deployment.
All nix is concerned about is os packages, pipenv takes care of python and it's libs.
development is performed within the pipenv shell, which is persisted independently of the OS packages.Injecting editor packages is less straightforwards, it is set outside of nix.
${PACKAGE}/default.nix
# Defines minimal env to run code/tests within interpreter. # (optionally, override with your preferred packages in with a `shell.nix`) # # If you just want to run tests, use `python setup.py test`. # See https://nixos.org/features.html # # Run: # nix-shell { pkgs ? import <nixpkgs> {} }: pkgs.stdenv.mkDerivation { pname = "myproject"; version = "1.0.0"; buildInputs = [ pkgs.pipenv pkgs.python38 ]; }${PACKAGE}/shell.nix
# vim: ft=nix # # Overrides default.nix, for inserting your own development tools. # # INSTRUCTIONS: # Copy this file to `shell.nix` and alter with desired packages. # # RUN: # nix-shell { pkgs ? import <nixpkgs> {} }: let extra-os-packages = pkgs.config.vim-base; # ex: [ neovim ripgrep ... ] vim-python-pkgs = pkgs.config.vim-python-pkgs; # ex: [ rope autopep8 jedi ...] pkg = import ./default.nix {}; install-missing-devpython-pkgs = ''PIPENV_INSTALLED=("$(pipenv run pip list | awk -F' ' '{ print $1 }' | tail -n +3)")'' + pkgs.lib.strings.concatMapStrings (x: "\necho $PIPENV_INSTALLED | tr ' ' '\n' | grep '^${x}\$' || pipenv run pip install ${x}") vim-python-pkgs; in pkg.overrideAttrs( old: { buildInputs = old.buildInputs ++ extra-os-packages; shellHook = (if builtins.hasAttr "shellHook" old then builtins.getAttr "shellHook" old else "") + install-missing-devpython-pkgs; } )${PACKAGE}/Pipfile
[[source]] name = "pypi" url = "https://pypi.org/simple" verify_ssl = true [dev-packages] [packages] recommonmark = "*" groundwork-sphinx-theme = "*" sphinx-markdown-tables = "*" Sphinx = "*" [requires] python_version = "3.9"${PACKAGE}/.envrc
use_nixnix-shell # (or use direnv hook) pipenv install # install requirements from Pipfile pipenv shell # enter pipenv
mach-nix
mach-nix is a tool that maps all python packages from pypi.org to nix packges.
It's usage is interchangeable with the workflow for vanilla nix.
It is straightforwards to wrap default.nix and inject additional requirements for your editor.shell.nix (describe shell, not build)
# ./shell.nix { pkgs ? import <nixpkgs> {} }: let mach-nix = import ( builtins.fetchGit { url = "https://github.com/DavHau/mach-nix/"; ref = "3.1.1"; } ) { python = "python38"; }; python-requirements = (builtins.readFile ./requirements.txt); customPython = mach-nix.mkPython { requirements = python-requirements; }; in pkgs.mkShell { buildInputs = [ customPython ]; }default.nix (describe build, in addition to shell)
# ./default.nix { pkgs ? import <nixpkgs> {} }: let mach-nix = import ( builtins.fetchGit { url = "https://github.com/DavHau/mach-nix/"; ref = "3.1.1"; } ) { python = "python38"; }; customPython = mach-nix.mkPython { requirements = builtins.readFile ./requirements.txt; }; in pkgs.stdenv.mkDerivation rec { name = "nixpython"; version = "1.0.1"; buildInputs = [ customPython ]; }Interactive shell with additional python-requirements
# ./default.nix # # package exposing a python interpreter, with six/requests installed to it. { pkgs ? import <nixpkgs> {} }: let mach-nix = import ( builtins.fetchGit { url = "https://github.com/DavHau/mach-nix/"; ref = "2.0.0"; } ); customPython = mach-nix.mkPython { python = pkgs.python38; requirements = '' six requirements '' }; in pkgs.stdenv.mkDerivation rec { name = "nixpython"; version = "1.0.1"; buildInputs = [ customPython ]; }# nix shell # # adds 'rope' package to resolved python interpreter pkgs = import <nixpkgs> {} pkg = import ./default.nix {} # find 'python' package from buildInputs (if available) python_pkgs = builtins.filter (x: builtins.hasAttr "python" x) pkg.buildInputs python_pkg = if (builtins.length python_pkgs) > 0 then builtins.head python_pkgs else null # assemble requirements inputs = pkg.buildInputs inputs = (if !(builtins.isNull python_pkg) then inputs ++ [python_pkg.pkgs.rope] else inputs) pkg-dev = pkgs.stdenv.mkDerivation { name="foo"; buildInputs=inputs; } :s pkg-devDevelopment Environment Notes
Nix adds python packages to your $PYTHONPATH
You'll need to add them to sys.path within vim if you use mach-nix, since the interpreter is not selected by default in vim.# ~/.vimrc if has("unix") && ($IN_NIX_SHELL != "") " vanilla nix packages are separate PYTHONPATH entries execute "python3 import sys;sys.path = '".$PYTHONPATH."'.split(\":\") + sys.path" " mach-nix packages use alt/2nd python interpreter. Add it's packages to PYTHONPATH let sitepackages = system("python3 -c 'import site;print(site.getsitepackages()[0])'") execute "python3 import sys;sys.path.insert(0, '" . trim(sitepackages) . "')" end