9 ms·
Uv: Running a script with dependencies
- gopalv 1y agoThis 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.
- Bluestein 1y agoI honestly believe this is a killer (killer) feature.-
- dwood_dev 1y agoCompletely agree. UV for stalled what was going to be a major project to move lots of python to golang. There will still be a lot migrated, but smaller script like things are no longer in scope.
- abdusco 1y agoI still write small some scripts in golang when the bootup time is important. Python still takes its time to boot up, and it's not the best tool for the job if it's gonna be called like a shell utility for thousands of files, for example.
- theshrike79 1y agoAll my "permanent" scripts were transferred to Go a while ago with LLM assistance. They're the ones that just keep running in cron with zero modifications. Python is when I need to iterate fast and just edit crap on the go, most of those will also be migrated to Go after they stabilise - unless there's a library dependency that prevents it. `uv` is nice, but it's not "static binary that runs literally anywhere with no prerequisites" -nice
- alkh 1y agoIf I may interject, does anyone have any idea why the `-S` flag is required? Testing this out on my machine with a BSD env, `/usr/bin/env -S uv run --python 3.11 python` and `/usr/bin/env uv run --python 3.11 python` do the same thing (launch a Python interactive shell). Man page for env doesn't clarify a lot to me, as the end result still seems to be the same("Split apart the given string into multiple strings, and process each of the resulting strings as separate arguments to the env utility...")
- Hello71 1y agohttps://en.wikipedia.org/wiki/Shebang_(Unix)#Argument_splitting https://en.wikipedia.org/wiki/Shebang_(Unix)#Argument_splitt...
- alkh 1y agoThanks, but the main question is how come the behaviour is still the same whether you pass the flag or not? I would get it if it just failed without "-S" but it works as intended. I am wondering if this is cause I might not be using the GNU version of env, so this is less relevant? Edit: looks to be the version thing indeed, this doesn't work for someone on Ubuntu
- fc417fc802 1y agoAt some point coreutils added -S in order to support the behavior of BSD and MacOS. I would guess that whatever implementation you're using then added -S as a noop in order to (at long last) permit the portable usage of multi-argument shebang lines. Until both of those things happened there was no portable way to pass multiple arguments in a shebang. You used to have to do really stupid things (ex https://unix.stackexchange.com/a/399698 https://unix.stackexchange.com/a/399698). https://www.gnu.org/software/coreutils/manual/html_node/env-invocation.html#g_t_002dS_002f_002d_002dsplit_002dstring-usage-in-scripts https://www.gnu.org/software/coreutils/manual/html_node/env-...
- alkh 1y ago
- simonw 1y agoThe "declaring script dependencies" thing is incredibly useful: https://docs.astral.sh/uv/guides/scripts/#declaring-script-dependencies 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/ 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 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://simonwillison.net/2024/Dec/19/one-shot-python-tools/
- minimaxir 1y agoI thought that was a heart emoticon next to requests, for a second.
- tayloramurphy 1y agoI mean, who doesn't love requests?
- tczMUFlmoNk 1y agoWell... maybe the people who have stopped working on it due to the mysterious disappearance of 30,000 fundraised dollars, selling paid support but "delegat[ing] the actual work to unpaid volunteers", and a pattern of other issues from other community members who have not spoken up about them. https://vorpus.org/blog/why-im-not-collaborating-with-kenneth-reitz/ https://vorpus.org/blog/why-im-not-collaborating-with-kennet... https://news.ycombinator.com/item?id=19826680 https://news.ycombinator.com/item?id=19826680
- satertek 1y agoWhy 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.
- simonw 1y agoI don't know if there's an official reason, but my guess is that it's slightly out of scope for pip: pip is a packaging installation tool, not a virtual environment managing system. 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-project-development-scripts/67194 https://discuss.python.org/t/idea-introduce-standardize-proj...
- zahlman 1y agoIt's completely out of scope for pip, which is purely about modifying the set of packages installed into non-transient environments. Pipx is a wrapper that does more or less what you're looking for (including PEP 723 support), but it arbitrarily refuses to process top-level packages unless they specify an entry point (which makes them "applications" even with abstract dependencies). I'm planning to support it in PAPER, which can roughly be described as my vision of what pip and pipx, taken together, should have been.
- Humphrey 1y agoOh 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.
- bb88 1y agoI've played with it for a while now, and for one off scripts where python might make more sense than bash, e.g., I write the script this way with uv, and then I only need uv and the script. 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.
- bananapub 1y ago> this kinda sorta doesn't make it go away entirely it absolutely can, `uv` can also pin the python interpreter it uses with `requires-python = "==3.11"` or whatever.
- bb88 1y agoNo, because with golang you can drop the binary in an empty docker container and you're done -- you never have to recompile it or worry about your pypi mirror disappearing. If you're deploying a python script with uv, it needs some kind of internet connection. Jar files are closer maybe...
- nomel 1y agoAm I crazy for having my default interactive shell "/bin/env python" point to a virtual environment with all the random dependencies that my one off scripts need, so I can just run "python oneoneoff.py"? All of my one off scripts combined use maybe a dozen dependencies. If I need more, I just install them there. I use pyenv, so it's trivial to change the version of python that the interactive shell uses (default or temporary within the current shell). 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.
- m4r71n 1y agoOh 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.
- billyjmc 1y agoWhat’s your use case for locking dependencies on a single script? 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.
- m4r71n 1y agoJust better visibility into the dependencies that come with the script (exactly for things like vulnerability scanning that you mention). It's also easier for reproducibility in someone else's environment when I can give them the exact list of dependencies instead of having them resolve it themselves using the inline declarations. Explicit is better than implicit :-)
- AceJohnny2 1y agoNote 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-dependencies 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`.
- heisenzombie 1y agoQuick plug here for a simple Jupyter kernel I created: https://github.com/tobinjones/uvkernel 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 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.
- rented_mule 1y agoThere is also marimo. For my use cases it has been a fantastic upgrade from Jupyter. I use it in the style of TFA (notebooks are just Python files). In the notebook UI, you can add packages to the script headers. It's so nice to have many notebooks in one directory with independent, but reproducible environments. 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. https://docs.astral.sh/uv/guides/integration/marimo/ https://docs.astral.sh/uv/guides/integration/marimo/
- Svoka 1y agoMore comments the topic - https://news.ycombinator.com/item?id=44369388 https://news.ycombinator.com/item?id=44369388 Fun with uv and PEP 723 640 points | 227 comments
- rr808 1y agoHow 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?
- xyse53 1y agoI recommend trying it, it gets a ton of hype but I think for good reason. This is the one.
- roywiggins 1y agoimo all I usually need is pip-tools and venv, but uv kind of bundles the two together in a very natural way (and is very fast)
- nomel 1y agoUnless you're installing a new version of python, I have trouble seeing how preceding all the normal command with "uv" can be seen as much of a difference.
- roywiggins 1y agoIt's not that much of a difference, but it is faster, and when you do need to switch pythons, you're already set up. uv also has some different workflows, universal lock files, and the caching is also nice. And the PEP 723 support is cool! Poetry was a big difference, it was also very slow for me, and so I never picked it up.
- selcuka 1y agoI had the same sentiment, but uv seems to have eliminated the competition. Installing uv using your OS package manager is enough as it can also download and install (isolated) Python interpreters as well.
- frollogaston 1y agoExcept pip still exists and is default, and even if they adopted uv as default instead, all the legacy stuff takes years to change.
- imcritic 1y agoI 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?
- frosting1337 1y agoI mean... it's in the docs? https://docs.astral.sh/uv/concepts/cache/ https://docs.astral.sh/uv/concepts/cache/
- Technetium 1y agoCaching linked on the left: https://docs.astral.sh/uv/concepts/cache/ https://docs.astral.sh/uv/concepts/cache/ The index of the Concepts section says: "Looking for a quick introduction to features? See the guides instead." 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.
- trostaft 1y agoThis 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.
- SafeDusk 1y agoI 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/ https://blog.toolkami.com/toolkami-shttp-server/.
- bb88 1y agoThere's a lot of small one off things where deploying uv and the script makes it easy to use. A lot of use cases for golang can be replaced with uv.
- hamandcheese 1y agoMy favorite part of this is the `exclude-newer` feature, giving you a somewhat reproducible script for very low effort.
- jbaber 1y agoI just looked this up yesterday by sheer coincidence and was happy it actually worked. What brought it to your attention today?
- mdaniel 1y agoAlmost certainly the thread about jqfmt: https://news.ycombinator.com/item?id=44637716 https://news.ycombinator.com/item?id=44637716
- hoherd 1y agoOne 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.
- indigodaddy 1y agoBut don't you have to only ever run it once to have the deps/venv for subsequent runs?
- do_not_redeem 1y agoI don't know if uv garbage collects its cache, but it wouldn't surprise me. Otherwise disk usage would grow indefinitely.
- freddie_mercury 1y agoYes, disk usage grows indefinitely https://github.com/astral-sh/uv/issues/5731 https://github.com/astral-sh/uv/issues/5731
- zahlman 1y agoIf you indefinitely grow the collection of packages that you have in use in permanent virtual environments, then yes your disk usage will and should grow indefinitely anyway. There's not much point recycling contents from a package cache unless you currently don't have a venv using that package and also don't reasonably expect to have one in the near future. And I'm saying this as the guy complaining all the time about things like the size of Numpy wheels.
- akx 1y ago`uv run --offline` will use cached dependencies and not check for newer versions. Works for `uvx` too, i.e. `uvx --offline ...`.
- staplung 1y agoLove 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.
- laurent_du 1y agoI do this all the time as well with `uv run --with ipython --with boto3 ipython`. Great time-saver.
- slhck 1y agoNote that it's not really "cleaned up" insofar as there is a uv cache folder that will grow bigger over time as you keep using that feature.
- akshayka 1y agoVery nice. Here's a one liner for marimo notebooks: uvx marimo edit A one liner with marimo that also respects (and records) inline script metadata using uv: uvx marimo edit --sandbox my_notebook.py https://docs.astral.sh/uv/guides/integration/marimo/ https://docs.astral.sh/uv/guides/integration/marimo/
- ayerajath 1y agohttps://docs.astral.sh/uv/guides/scripts/#declaring-script-dependencies https://docs.astral.sh/uv/guides/scripts/#declaring-script-d... this is neat af. my throw-away scripts folder will be cleaner now.
- exographicskip 1y agoHeard about this! Finally did something with it and I'm happy with how this tiny gist turned out: https://gist.github.com/pythoninthegrass/e5b0e23041fe33526669bb2487bd6042 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
- abhisek 1y agoUh 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.
- ndr 1y agowhy would you ship `uv` though?
- Hackbraten 1y agoI 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.
- nsarrazin 1y agoYou can find the env path with `uv python find --script "${filePath}` I've been working on a VSCode extension to automatically detect and activate the right interpreter: https://marketplace.visualstudio.com/items?itemName=nsarrazin.pep723-uv-interpreter https://marketplace.visualstudio.com/items?itemName=nsarrazi...
- ebri 1y agoCould you tell me how you do this in code ? Started using uv in a very old school team and they don’t like uv simply because it’s new. Something like this is what they base it on.
- Hackbraten 1y agoIt's super cumbersome so I can't really recommend it for work. I invoke the "Select Interpreter" action. A file selector opens, then I go to the user cache directory (e.g. ~/.cache on Linux, something like %LOCALAPPDATA%\Cache on Windows). It has a `uv` subdirectory, then I drill further down until I find the directory where uv keeps its venvs. Find the venv that corresponds to your script, then go to its `bin` subdirectory and select the Python executable. The upside is that you only have to do this once per script. The downside is that you have to do this once per script.
- jjfoooo4 1y agoI also just activate the desired virtual env and start VS Code from the command line within it
- ezquerra 1y agoI 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.
- imjonse 1y agoOne 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/ 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)
- sam_bristow 1y agoThere 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.
- damnever 1y agoI 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 https://twitter.com/_damnever/status/1697247813854503250
- poulpy123 1y agoFor this use case I would try first to compile the script with nuitka. A single binary is more manageable than doing that
- stephenhandley 1y agoThis almost as great as how much I love that this gets posted like once every two weeks
- jufter 1y agoI'm glad it was reposted so I saw it. I may actually use python for scripting now because uv makes it so easy.
- wanderingmind 1y agoAs 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
- williamdclt 1y agomore of a bandaid than anything else, but maybe something like this might help: alias pip='echo "do not use pip, use uv instead" && false' You can put that in your bashrc or zshrc. There's a way to detect if it's a cursor shell to only apply the alias in this case, but I can't remember how off the top of my head!
- Bluestein 1y ago> alias pip='echo "do not use pip, use uv instead" && false' Interesting times, eh? Who (who!) would have told us all we'd be aliasing terminal commands to *natural language* instructions - for machine consumption, I means. Not for the dumb intern ... (I am assuming that must have happened at some point - ie. having a verboten command echo "here be dragons" to the PFY ...)
- theesm 1y agoI'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.html https://guix.gnu.org/manual/en/html_node/Invoking-guix-shell...
- zahlman 1y agoDo these environments reuse existing system-installed packages and hard-link the files?
- jemiluv8 1y agoI 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.
- pavlov 1y agoAs 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”
- cassiogo 1y agoMaybe worth mentioning that ruby has a very similar feature https://bundler.io/guides/bundler_in_a_single_file_ruby_script.html https://bundler.io/guides/bundler_in_a_single_file_ruby_scri...
- gkfasdfasdf 1y agoI 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" "$@"
- pmarreck 1y agoThis is pretty easy to do if you have Nix https://github.com/pmarreck/yt-transcriber 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
- runjake 1y agoIf you’re at all interested in this topic, I strongly recommend you read Simon Willison’s blog at https://simonwillison.net/ 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.
- frizlab 1y agoI 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 https://github.com/xcode-actions/swift-sh
- EnnEmmEss 1y agoThis 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 https://github.com/astral-sh/uv/issues/14472 for example.