How can I use nix-shell and uv together to create a self-contained script?

Say I want to create a self-contained python script (including dependencies) and I want to use packages that uv knows how to install, but nix doesn’t.

Using e.g. python3Packages.rich works

For python packages that are in nixpkgs, this works great:

nix-rich:

#!/usr/bin/env nix-shell
#! nix-shell -i python3 --pure
#! nix-shell -p python3 python3Packages.rich
#! nix-shell -I nixpkgs=https://github.com/NixOS/nixpkgs/archive/c570c1f5304493cafe133b8d843c7c1c4a10d3a6.tar.gz

import time
from rich.progress import track

for i in track(range(20), description="For example:"):
    time.sleep(0.05)

Can I use uv run also? How?

Lets pretend there was no nix package for rich. There is also uv, where uv run --script --quiet allows to create self-contained scripts:

A working uv script

This installs rich using uv, not nix:

uv-rich:

#!/usr/bin/env -S uv run --script --quiet
# /// script
# requires-python = ">=3.12"
# dependencies = [
#     "rich",
# ]
# ///

import time
from rich.progress import track

for i in track(range(20), description="For example:"):
    time.sleep(0.05)

However, this requires uv to be in the path.

How can I combine a nix-shell script with uv run, so it first loads whatever nix packages I want and then runs uv run so it installs any python dependencies with uv?

I’ve tried:

combined:

#!/usr/bin/env nix-shell
#! nix-shell -i env --pure
#! nix-shell -p uv
#! nix-shell -I nixpkgs=https://github.com/NixOS/nixpkgs/archive/c570c1f5304493cafe133b8d843c7c1c4a10d3a6.tar.gz
#! /usr/bin/env -S uv run --script
# /// script
# requires-python = ">=3.12"
# dependencies = [
#     "rich",
# ]
# ///

import time
from rich.progress import track

for i in track(range(20), description="For example:"):
    time.sleep(0.05)

But

$ ./combined 
/usr/bin/env: 'nix-shell': No such file or directory

I’ve also tried combinations of -i and --run but not had much success.

Perhaps related: I’m guessing (but not sure) that one of the problems is that I need multiple parameters to the uv command, i.e. uv run --script. A similar related question would be how would I run a perl script with the -w (or some other) command line option? If I knew the answer to that I might be able to get this working with uv also…

The -i argument will be run as the interpreter, so this seems to work:

#! /usr/bin/env nix-shell
#! nix-shell -i "uv run --script --quiet" -p uv
# /// script
# requires-python = ">=3.12"
# dependencies = [
#     "rich",
# ]
# ///

import time
from rich.progress import track

for i in track(range(20), description="For example:"):
    time.sleep(0.05)
1 Like

Fantastic. I didn’t know one could quote multiple arguments. Here is the full example:

#!/usr/bin/env nix-shell
#! nix-shell -i "uv run --script --quiet" --pure
#! nix-shell -p uv
#! nix-shell -I nixpkgs=https://github.com/NixOS/nixpkgs/archive/c570c1f5304493cafe133b8d843c7c1c4a10d3a6.tar.gz
# /// script
# requires-python = ">=3.12"
# dependencies = [
#     "rich",
# ]
# ///

import time
from rich.progress import track

for i in track(range(20), description="For example:"):
    time.sleep(0.05)

And similarly for perl -w:

#!/usr/bin/env nix-shell
#! nix-shell -i "perl -w" --pure
#! nix-shell -p perl
#! nix-shell -I nixpkgs=https://github.com/NixOS/nixpkgs/archive/c570c1f5304493cafe133b8d843c7c1c4a10d3a6.tar.gz

print "Warnings are on? $^W\n";
1 Like