Uv: Running a script with dependencies

(docs.astral.sh)

Comments

simonw 21 July 2025
The "declaring script dependencies" thing is incredibly useful: https://docs.astral.sh/uv/guides/scripts/#declaring-script-d...

  # /// script
  # dependencies = [
  #   "requests<3",
  #   "rich",
  # ]
  # ///
  import requests, rich
  # ... script goes here
Save that as script.py and you can use "uv run script.py" to run it with the specified dependencies, magically installed into a temporary virtual environment without you having to think about them at all.

It's an implementation of Python PEP 723: https://peps.python.org/pep-0723/

Claude 4 actually knows about this trick, which means you can ask it to write you a Python script "with inline script dependencies" and it will do the right thing, e.g. https://claude.ai/share/1217b467-d273-40d0-9699-f6a38113f045 - the prompt there was:

  Write a Python script with inline script
  dependencies that uses httpx and click to
  download a large file and show a progress bar
Prior to Claude 4 I had a custom Claude project that included special instructions on how to do this, but that's not necessary any more: https://simonwillison.net/2024/Dec/19/one-shot-python-tools/
hoherd 22 July 2025
One gotcha I caught myself in with this technique is using it in a script that would remediate a situation where my home has lost internet and needed the router to be power cycled. When the internet is out, `uv` cannot download the dependencies specified in the script, and the script would fail. Thankfully I noticed this problem after writing it but before needing it to actually work, and refactored my setup to pre-install the needed dependencies. But don't make the same mistake I almost made! Don't use this for code that may need to run airgapped! Even with uv caching you may still get a cache miss.
gopalv 21 July 2025
This is my absolute favourite uv features and the reason I switched to uv.

I have a bunch of scripts in my git-hooks which have dependencies which I don't want in my main venv.

#!/usr/bin/env -S uv run --script --python 3.13

This single feature meant that I could use the dependencies without making its own venv, but just include "brew install uv" as instructions to the devs.

AceJohnny2 22 July 2025
Note that this only works for single-file scripts.

If you have a project with modules, and you'd like a module to declare its dependencies, this won't work. uv will only get those dependencies declared in the invoked file.

For a multi-file project, you must have a `pyproject.toml`, see https://docs.astral.sh/uv/guides/projects/#managing-dependen...

In both cases, the script/project writer can use `uv add <dependency>`, just in the single-file case they must add `--script`.

gkfasdfasdf 22 July 2025
I love this feature of uv but getting linters/language servers to pick up the venv when editing the files is a bit of a pain. I currently have a script 'uv-edit' which I am using to run Neovim with the correct environment:

  #!/bin/bash
  SCRIPT="$1"; shift
  uv sync --quiet --script "$SCRIPT" && exec uv run --python "$(uv python find --script "$SCRIPT")" nvim "$SCRIPT" "$@"
Hackbraten 22 July 2025
I wish there was a straightforward way to let VS Code pick up the venv that uv transparently creates.

Out of the box, the Python extension redlines all the third-party imports.

As a workaround, I have to plunge into the guts of uv's Cache directory to tell VS Code the cached venv path manually, and cross fingers that it won't recreate that venv too often.

staplung 22 July 2025
Love this feature of UV. Here's a one-liner to launch jupyter notebook without even "installing" it:

  uv run --with jupyter jupyter notebook
Everything is put into a temporary virtual environment that's cleaned up afterwards. Best thing is that if you run it from a project it will pick up those dependencies as well.
theesm 22 July 2025
I've been doing something similiar utilizing guix shell[0] setting my shebang to e.g.:

#!/usr/bin/env -S guix shell python python-requests python-pandas -- python3

in scripts for including per-script dependencies. This is language agnostic as long as the interpreter and its dependencies are available as guix packages. I think there may be a similiar approach for utilizing nix shells that way as well.

[0]: https://guix.gnu.org/manual/en/html_node/Invoking-guix-shell...

m4r71n 22 July 2025
Oh nice, I was already a happy user of the uv-specific shebang with in-script dependencies, but the `uv lock --script example.py` command to create a lock file that is specific to one script takes it to another level! Amazing how this feels so natural and yet only appeared after 20+ years of Python packaging.
ezquerra 22 July 2025
I recently found a small issue with `uv run`. If you run a script from outside the project folder, it looks for the pyproject.toml on the folder from which you are calling `uv run`, not on the folder where the python script is located (or its parents)! Because of that scripts that store their dependencies in a pyproject.toml cannot be run successfully using a “bare” `uv run path/to/my/script.py` from outside the project folder.

You can work around this surprising behavior by always using inline dependencies, or by using the `--project` argument but this requires that you type the script path twice which is pretty inconvenient.

Other than that uv is awesome, but this small quirk is quite annoying.

heisenzombie 22 July 2025
Quick plug here for a simple Jupyter kernel I created:

https://github.com/tobinjones/uvkernel

It’s a pretty minimal wrapper around “uv” and “iPython” to provide the functionality from the article, but for Jupyter notebooks. It’s similar to other projects, but I think my implementation is the least intrusive and a good “citizen” of the Jupyter ecosystem.

There’s also this work-in-progress:

https://github.com/tobinjones/pep723widget

Which provides a companion Jupyter plugin to manage the embedded script dependencies of noteboooks with a UI. Warning — this one is partially vibe-coded and very early days.

trostaft 22 July 2025
This is pretty great. Passing python code out to my students is usually also confronted with the question of "How do I run it?", which is usually terrible to answer. Now, I can just tell them to get uv (single command) and run it.
sam_bristow 22 July 2025
There are a lot of bits and pieces that are clicking into place lately in the Python ecosystem. Recently I've been using the combination of Marimo and these uv script dependencies for building reproducible rwporting and diagnostic tooling for other teams.
rr808 22 July 2025
How many package managers can one language have? Its a simple language but setting it up is just incredibly bad. Maybe this is the one or should I wait for the next?
satertek 22 July 2025
Why doesn't pip support PEP 723? I'm all for spreading the love of our lord and savior uv, but it should be necessary to have an official implementation.
wanderingmind 22 July 2025
As a tangent, one issue I face is how to force cursor to use uv over pip. I have placed it in rules and also explicitly add a rules.yml file in every agent conversation. It still tries to push through pip 4 out of 10 times. Any recommendations on best practice to force cursor to use uv will make a significant dent in productivity
Humphrey 22 July 2025
Oh this looks amazing! I had pretty much stopped using Python for my one-off scripts because of the hassle of dependencies. I can't wait to try this out.
SafeDusk 22 July 2025
I am using this feature in my MCP servers and it is a god send! Some details on how I do it can be found at https://blog.toolkami.com/toolkami-shttp-server/.
stephenhandley 22 July 2025
This almost as great as how much I love that this gets posted like once every two weeks
hamandcheese 22 July 2025
My favorite part of this is the `exclude-newer` feature, giving you a somewhat reproducible script for very low effort.
damnever 22 July 2025
I like it, and I once thought about this as well:

> Python doesn't require a requirements.txt file, but if you don't maintain this file, or neglect to provide one, it could result in broken functionalities - an unfortunate circumstance for a scripting language.

https://twitter.com/_damnever/status/1697247813854503250

Svoka 22 July 2025
More comments the topic - https://news.ycombinator.com/item?id=44369388

Fun with uv and PEP 723

640 points | 227 comments

runjake 22 July 2025
If you’re at all interested in this topic, I strongly recommend you read Simon Willison’s blog at https://simonwillison.net/

He does all the legwork and boils it down into an easily-understandable manner.

He’s also a user her in this thread at simonw. Just an immensely useful guy.

jemiluv8 22 July 2025
I kinda always struggled to grok python's package management and module system. UV is finally making things more understandable and just as good as the nodejs packaging and module system that I'm more comfortable with. This new feature is kinda awesome. Even surpassing the DX of the node ecosystem.
frizlab 22 July 2025
I do this in Swift, using swift-sh[1].

Works well, but the compilation of the dependencies (first run of the script) can be a bit long. A problem which uv (Python) probably won’t have…

[1] https://github.com/xcode-actions/swift-sh

cassiogo 22 July 2025
Maybe worth mentioning that ruby has a very similar feature https://bundler.io/guides/bundler_in_a_single_file_ruby_scri...
ayerajath 22 July 2025
https://docs.astral.sh/uv/guides/scripts/#declaring-script-d...

this is neat af. my throw-away scripts folder will be cleaner now.

imjonse 22 July 2025
One case this may not work well is when one of the dependencies is Pytorch. Uv has explicit support for Pytorch ( https://docs.astral.sh/uv/guides/integration/pytorch/ ) but with the script headers I don't see a way to pick the most appropriate wheel index (cpu vs cuda vs rocm)
EnnEmmEss 23 July 2025
This is a pretty nice feature which I use quite often. There are still some edge cases where it cannot be used to the fullest extent though. https://github.com/astral-sh/uv/issues/14472 for example.
jbaber 22 July 2025
I just looked this up yesterday by sheer coincidence and was happy it actually worked. What brought it to your attention today?
exographicskip 22 July 2025
Heard about this! Finally did something with it and I'm happy with how this tiny gist turned out:

https://gist.github.com/pythoninthegrass/e5b0e23041fe3352666...

tl;dr

Installs 3 deps into the uv cache, then does the following:

1. httpx to call get request from github api

2. sh (library) to run ls command for current directory

3. python-decouple to read an .env file or env var

poulpy123 22 July 2025
For this use case I would try first to compile the script with nuitka. A single binary is more manageable than doing that
imcritic 22 July 2025
I hate such poor docs that don't explain how things work, and instead prefer hiding behind some "magic".

> Constraints can be added to the requested dependency if specific versions are needed:

> uv run --with 'rich>12,<13' example.py

Why not mention that this will make uv download specified versions of specified packages somewhere on the disk. Where? Are those packages going to get cached somewhere? Or will it re-download those same packages again and again every time you run this command?

pavlov 22 July 2025
As a non-Python person, I find “uv” to be a confusing name.

For a long time I assumed it’s a Python wrapper for libuv which is a much older and well-known project. But apparently it’s Python package manager #137 “this one finally works, really, believe me”

abhisek 22 July 2025
Uh oh. I am thinking all the ways this can be misused to ship malicious dependencies. Pretty much all SCA tools today will be blind to this.
pmarreck 22 July 2025
This is pretty easy to do if you have Nix

https://github.com/pmarreck/yt-transcriber

A commandline youtube transcription tool I built that runs on Mac (nix-darwin) which automatically pulls in all the dependencies it needs