I’m learning nix by setting up a python development environment, but I’m not sure what the idiomatic way of accomplishing everything is. I’ve compiled a list of questions that I’d be grateful for any recommendations on.
- Make sure that no one can access versions of python besides the version that I setup when doing
nix develop
. I was surprised that my system wide python was even available in the dev shell since that isn’t very “pure”, and there’s an “impure” flag that exists (that I’m not using). The only real reason to usenix develop
is to do some debugging in that environment but I’ll have people that don’t know nix using these environments one day and I want to minimize errors. - Enable pip packages that have native dependencies to run. They fail finding
libstdc++.so.6
, which makes sense. I can fix this by setting theLD_LIBRARY_PATH
, which also makes sense, but that seems like something you don’t want to do with nix, and probably isn’t cross platform. What’s the right way of getting things to work in pip that happen to look for these without having to manually package them and consume them through some non pip/poetry method? - The poetryWrapper is how I’m guaranteeing the poetry configuration in a single location. I don’t want to have to do something different in the dev shell vs the app/packages sections and this seems ok. I looked up the poetry package and it doesn’t have any options to actually set these in a first class nix way so this was my fallback. Is there a better way?
- I want to get poetry version
1.7.1
. I accomplished that by adding a poetry-pkg input that points to the version of nixos that I know most recently built that version, and I found that by going to linux build history of poetry and paging backwards until I found a1.7.1
build, then grabbed the revision from the inputs tab. I’m assuming this isn’t guarnateed to work across platforms since I browsed from thex86_64-linux
build history. What’s the right way of finding and installing the right semver version of any given application? - is
buildInputs = builtins.attrValues self.packages.${system};
in the dev shell an ok way of just saying “add everything I have here too”? - I plan to make a bunch of these commands available in a makefile and just never directly interact with nix, For example,
make run
would executenix run .#poetry -- run python -m app.main
. This seems to work well butnix run
definitely has overhead. It delays the command by a few seconds. Is there a workaround for that delay that doesn’t involve just using nix develop all the time?
Here is what I have so far. I’m finding the nix language to be quite ugly (giving some perl vibes) and the extensive use of util and implicitly defined functions online makes things very hard to understand with the apparent state of the docs. I’d like to avoid nesting, util functions, and any implicit behavior as much as possible, at least for now. I’d like it to look as simple as possible.
{
description = "Python development environment";
inputs = {
nixpkgs.url = "github:nixos/nixpkgs?ref=nixos-unstable";
poetry-pkg.url = "github:nixos/nixpkgs?ref=73de017ef2d18a04ac4bfd0c02650007ccb31c2a";
flake-utils.url = "github:numtide/flake-utils";
};
outputs = { self, nixpkgs, poetry-pkg, flake-utils }: flake-utils.lib.eachSystem [
# Some native python dependencies don't exist for windows
"x86_64-linux" "x86_64-darwin" "aarch64-linux" "aarch64-darwin"
] (system:
let
pkgs = nixpkgs.legacyPackages.${system};
pythonPkg = nixpkgs.legacyPackages.x86_64-linux.python310;
poetryPkg = poetry-pkg.legacyPackages.${system}.poetry;
poetryWrapper = pkgs.writeScriptBin "poetry" ''
#!${pkgs.bash}/bin/bash
export LD_LIBRARY_PATH=${pkgs.stdenv.cc.cc.lib}/lib
${poetryPkg}/bin/poetry config virtualenvs.in-project true
${poetryPkg}/bin/poetry env use ${pythonPkg}/bin/python3
exec ${poetryPkg}/bin/poetry "$@"
'';
in {
packages = {
python310 = pythonPkg;
poetry = poetryWrapper;
};
apps = {
poetry = {
type = "app";
program = "${self.packages.${system}.poetry}/bin/poetry";
};
python = {
type = "app";
program = "${self.packages.${system}.python310}/bin/python3";
};
};
devShells.default = pkgs.mkShell {
# Everything defined in the packages section
buildInputs = builtins.attrValues self.packages.${system};
shellHook = ''
# Make sure the wrong python/poetry can't be used
unset PYTHONPATH
export PATH=${pkgs.lib.makeBinPath (builtins.attrValues self.packages.${system})}
'';
};
});
}
Any general tips would be great too. Like, is there a nicer way to specify the program?