On using reproducible Python development environments

󰃭 2024-11-05

One of the things I find annoying about using Python is that there are so many ways of making the development environment of a package or set of scripts reproducible. I have a repository that contains several Python scripts that help me with various tasks, mostly related to qBittorrent. Maybe one or two of these scripts can be separated out into a distinct, individual package, but it's generally more convenient for me to have a directory-level development environment activated with direnv where I can run the other scripts too. I've been using nix-shell with a shell.nix file, but this tends to require that I learn the Nix expression language in order to configure shell.nix. I don't like using tools I don't fully understand, and I'm not willing to prioritize learning Nix. It would be nice if I could just use a TOML file to declare everything I need, similar to pyproject.toml, and nix-shell would read this instead of shell.nix. As far as I know, the Nix language doesn't have a way to map the TOML structure to Nix expressions. I've tried devenv.sh, but this adds extra files and cruft that I don't want polluting my development environment. If I use a plain requirements.txt file with a virtualenv, it can't pull in the Python tools I use, like black, isort, bpython, and pyright.

One solution I'm leaning toward is to install these tools with pipx, where they'd be available to my shell environment relative to my home directory at ~/.local/bin/, and use something like

uv venv
source .venv/bin/activate
uv pip install -r requirements.txt
echo "layout python3" > .envrc
direnv allow
printf ".venv\n.direnv\n" | tee -a .gitignore

direnv would activate the virtualenv, which in turn would be relative to that git repository directory.

I'm open to suggestions and am curious how others might have solved this problem. Feel free to reach out to me in the Fediverse at @hyperreal@fedi.hyperreal.coffee.


Enter your instance's address