# /// 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/https://vorpus.org/blog/why-im-not-collaborating-with-kennet...
Kenneth Reitz has probably done more to enrich my life than most anyone else who builds things. I wouldn't begrudge him the idea of a nice workstation for his years of labour. Yeah, he's very imperfect, but the author has absolutely lost me
It would be like saying, "Don't use Laplace transforms because he did some unsavory thing at some point in time."
I liked Requests way back when but prefer httpx or aiohttp. I liked piping for about a month when it first came out, but jumped ship pretty quickly. I'm not familiar with his other works.
I also wouldn't begrudge the guy a laptop, but I do get what the author was saying. His original fundraiser felt off, like, if you want a nice laptop, just say so, but don't create specious justifications for it.
Those two tools are modeled after `requests`, so Reitz still has an influence in your life even if you don't use his implementation directly.
It was good when it was new but it’s dangerously unmaintained today and nobody should be using it any more. Use niquests, httpx, or aiohttp. Niquests has a compatible API if you need a drop-in replacement.
Others like pip-tools have support in the roadmap (https://github.com/jazzband/pip-tools/issues/2027)
#!/usr/bin/env -S uv run --script
# /// script
# dependencies = [
# "requests<3",
# "rich",
# ]
# ///
import requests, rich
# ... script goes here
Usually, when I use uv along with a pyproject.toml, I'll activate the venv before starting neovim, and then my LSP (basedpyright) is aware of the dependencies and it all just works. But with inline dependencies, I'm not sure what the best way to do this is.
I usually end up just manually creating a venv with the dependencies so I can edit inside of it, but then I run the script using the shebang/inline dependencies when I'm done developing it.
# make a venv somehow, probably via the editor so it knows about the venv, saving a 3rd step to tell it which venv to use
$ env VIRTUAL_ENV=.venv/ uv sync --script foo.py
but it's still janky, not sure it saves much mental taxThis gave me the questionable idea of doing the same sort of thing for Go: https://github.com/imjasonh/gos
(Not necessarily endorsing, I was just curious to see how it would go, and it worked out okay!)
(I realise there are some architectural issues with making it built-in syntax-magic comments are easier for external tools to parse, whereas the Python core has very limited knowledge of packaging and dependencies… still, one of these days…)
"Any Python script may have top-level comment blocks that MUST start with the line # /// TYPE where TYPE determines how to process the content. That is: a single #, followed by a single space, followed by three forward slashes, followed by a single space, followed by the type of metadata. Block MUST end with the line # ///. That is: a single #, followed by a single space, followed by three forward slashes. The TYPE MUST only consist of ASCII letters, numbers and hyphens."
That's the syntax.
Built-in language syntax.
It might be “built-in syntax” from a specification viewpoint, but does CPython itself know anything about it? Does CPython’s parser reject scripts which violate this specification?
And even if CPython does know about it (or comes to do so in the future), the fact that it looks like a comment makes its status as “built-in syntax” non-obvious to the uninitiated
uv, being both, is a more natural fit for an implementation of that PEP.
Here's a relevant discussion: https://discuss.python.org/t/idea-introduce-standardize-proj...
One of the complaints about python is that a script stops working over time (because the python installation changes with os updates), and this kinda sorta doesn't make it go away entirely, but what it does do is to eliminate a bunch of the hassle to getting things to work.
it absolutely can, `uv` can also pin the python interpreter it uses with `requires-python = "==3.11"` or whatever.
From my perspective, people seem to make it difficult to use python, more from not understanding the difference between interactive shell and non-interactive shell configurations (if you think the above breaks system tools that use python, then you don't understand the difference, nor that system tools use /bin/python rather than /usr/env python), with a bit of cargo-cult mixed in, more than anything.
Implicit solutions like yours have lower cost of entrance, but larger cost of support. uv python scripts just work if you set them up once
One things that’s useful to my organization is that we can then proceed to scan the lockfile’s declared dependencies with, e.g., `trivy fs uv.lock` to make sure we’re not running code with known CVEs.
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`.
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.
Marimo notebooks are easy to diff when committing to git. Plus you get AI coding assistants in the notebook, a reactive UI framework, the ability to run in the browser with Pyodide on WASM, and more. It will also translate your old Jupyter notebooks for you.
For me, what uv is to package managers, marimo is to notebooks.
Fun with uv and PEP 723
640 points | 227 comments
This is the one.
> 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?
Maybe there should instead be a link to the Concepts section for people who want more details, but I feel it's fine as it is.
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.this is neat af. my throw-away scripts folder will be cleaner now.
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
gopalv•6h ago
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.
Bluestein•6h ago
dwood_dev•6h ago
abdusco•4h ago
alkh•5h ago
Hello71•5h ago
alkh•5h ago
fc417fc802•5h ago
https://www.gnu.org/software/coreutils/manual/html_node/env-...
alkh•4h ago
"To test env -S on the command line, use single quotes for the -S string to emulate a single parameter. Single quotes are not needed when using env -S in a shebang line on the first line of a script (the operating system already treats it as one argument)"(from your second link).
This is different for shebang on Mac though:
GNU env works with or without '-S':
#!/opt/homebrew/bin/genv -S bash -v
echo "hello world!"
BSD env works with or without '-S' too:
#!/usr/bin/env -S bash -v
echo "hello world!"
To conclude, looks like adding `-S` is the safest option for comparability sake :).
Skunkleton•5h ago
alkh•5h ago