https://www.bitecode.dev/p/uv-tricks [https] Bite code! SubscribeSign in Share this post [https] Bite code! Bite code! UV tricks Copy link Facebook Email Notes More UV tricks Don't forget to uv self update before trying those Dec 15, 2024 18 Share this post [https] Bite code! Bite code! UV tricks Copy link Facebook Email Notes More 4 1 Share Summary You can test things in your venv without polluting it using uv run --with, create almost standalone scripts with uv init --script or convert a PDF to markdown by running uvx markitdown file.pdf. It's fast, it saves space, it avoids bootstrapping problems, and it makes Python workflows just a little nicer every day. [ ] Subscribe Soon my friend, soon... While it is true I'm not ready to recommend uv quite yet (I'm planning to write a full review in a few months to conclude my year of testing it), I have been using it extensively on my own projects, in training and with certain clients. I also know a lot of you are as well, there is a real enthusiasm about the tool, so for those that made the jump, why not share cool tips about it? Because one thing about uv, is that it is independent of the Python runtime, yet capable of fully bootstrapping a whole project, and very quickly at that, so it enables novel use cases and patterns. Some are just new, some are things that were not practical before, and some are just old stuff but getting better. uv run uv run will run any command inside the currently activated virtual environment, and if it's not activated but exists in the current directory with a common name (E.G: .venv), then it will transparently use that. But this command comes with some cool goodies. First, it can run a command with a temporary dependency made available, without polluting your virtual environment. For example, let's say you want to create a jupyter notebook and load your code in it. Normally, you'd have to install it in your project. But jupyter is huge! It has many dependencies, and installing it would pollute your project. With uv you can the --with argument to provide a temporary dependency to your project and run a command: uv run --with jupyter jupyter notebook This will: * Create a temporary venv. * Install jupyter in it. * Run the command with your project, your venv and the temporary venv available together transparently. The result is that you can run jupyter in your project without having to really install it in your project! Plus, the first time it's slow (it has to install everything), but the follow-up times, it will use a cache and it will be fast. Also, because of the way uv deals with the cache (using hard links), if you have 10 projects that use the same version of jupyter, you only install one copy of it instead of one for each project as before. This works with everything. Want to run your project with ipython? Wanna run ruff or mypy once only? E.G: I like qtconsole to do exploratory programming, but it installs jupyter and qt5, which means it's massive, so I rarely used it. Now it's just: uv run --with pyqt5 --with qtconsole jupyter qtconsole uv run also understand PEP 723 inline dependencies. You have a quick script and you want to use typer for argument parsing? Before uv, I used a shared venv for all my local scripts and installed the deps manually. Now my script looks like this: # /// script # dependencies = [ # "typer", # ] # /// import typer def main(name: str): print(f"Hello {name}") if __name__ == "__main__": typer.run(main) This will automatically install the dependencies in a temp venv and run the script: uv run hello.py bitecode Reading inline script metadata from: hello.py Hello bitecode On linux you can even add this shebang (then chmod +x it), and ./ hello.py will automatically call uv run: #!/usr/bin/env -S uv run If you don't remember how to create those scripts with inline deps, no worries, uv has your back with uv init --script: uv init --script my_script.py Initialized script at `my_script.py` cat my_script.py # /// script # requires-python = ">=3.11" # dependencies = [] # /// def main() -> None: print("Hello from my_script.py!") if __name__ == "__main__": main() uv init is useful in general (it initializes a full project, including a .gitigore and a minimal pyproject.toml), but with --script it only creates a single file, ready for scripting. uvx uvx is a second command that is installed next to uv when you set it up, and it's the equivalent of npx or pipx, but with uv goodness. Meaning it's fast, it has great caching, supports git repositories, is in full rust (so no chicken and egg or PATH problem), and has the --with option. This is great for two things: * quickly testing stuff. * running Python utilities without worrying about setup. You want to test pendulum in an ipython shell with python 3.13? uvx --with pendulum -p 3.13 ipython Installed 21 packages in 27ms Python 3.11.11 (main, Dec 4 2024, 08:55:08) [GCC 13.2.0] Type 'copyright', 'credits' or 'license' for more information IPython 8.30.0 -- An enhanced Interactive Python. Type '?' for help. Exception reporting mode: Plain Doctest mode is: ON >>> import pendulum >>> pendulum.now() DateTime(2024, 12, 15, 21, 52, 56, 856087, tzinfo=Timezone('Europe/Paris') You want to run the latest textual demo from the Will McGugan? Output of uvx -p 3.12 --from git+https://github.com/willmcgugan/ terminal-tree.git terminal-tree Yes I have way too many dotfiles Note how my first attempt failed, but the excellent error message made it instantly solvable. Want to download the mp3 of our Charlie Marsh (uv's team leader) interview (this does require ffmpeg to be installed prior)? uvx --no-cache --from yt-dlp[default] yt-dlp --extract-audio --audio-format mp3 https://www.bitecode.dev/p/charlie-marsh-on-astral-uv-and-the This works on YouTube or Soundcloud, thanks to the excellent yt-dlp project. --no-cache forces yt-dlp to update every time, which is required given the countermeasures change so often and the setup time is tiny compared to the video download time. Python has many such tools you want to fire once in a while and forget it: * cog: the weird and excellent inline templating tool. * httpie: the better alternative to curl for simple HTTP requests. * copier: the success of cookiecutter to initialize projects. * markitdown: the office/pdf to markdown converter. All those little things that used to be frictions are now an uv away, making our Python workflows a bit nicer every day. The cache can grow quite a lot and quickly though, because it's so tempting to use it all the time. Cleaning up may be a good idea once in a while: $ uv cache clean Clearing cache at: /home/user/.cache/uv Removed 269615 files (23.8GiB) They didn't accept my "uv subscribe-to-bitecode" pull request, but you can still use this dashing HTML input [ ] Subscribe 18 Share this post [https] Bite code! Bite code! UV tricks Copy link Facebook Email Notes More 4 1 Share PreviousNext Discussion about this post CommentsRestacks [htt] [ ] [ ] [ ] [ ] [htt] Kare Dec 17 Liked by Bite Code! Thank you for the article. Regarding scripts, I find the uv add --script method very convenient instead of the init script method. ( https://docs.astral.sh/uv/guides/scripts/# declaring-script-dependencies) Expand full comment Reply Share 1 reply by Bite Code! [htt] Improv Dec 16 Still not into uv; it feels like giving up on python to be writing its packaging tools in a rival language. At least conda is almost entirely in python. Expand full comment Reply Share 1 reply 2 more comments... TopLatestDiscussions No posts Ready for more? [ ] Subscribe (c) 2025 Bite Code! Privacy [?] Terms [?] Collection notice Start WritingGet the app Substack is the home for great culture Share Copy link Facebook Email Notes More This site requires JavaScript to run correctly. Please turn on JavaScript or unblock scripts