From: wayne+blog@waynewerner.com To: everyone.everywhere.all.at.once Date: Tue, 09 Sep 2025 13:56:53 -0500 Subject: uv, fabric, and you
Do you like Python's uv
or fabric
?
Or uv
, fabric
, and you!
If you're like me, you may be uv
-hesitant. After all,
uv is really just Yet Another Tool that you have
to come to grips with and why can't I just python -m venv --prompt my-cool-stuff
and .venv/bin/python -m pip install
my packages?
And that's a great question! Ultimately... you can!
But uv
provides two things that I mark as absolute killer features.
I don't know what there is really to say about the cache. But uv
gets it
right. Every time you download a new version of a package, uv
stores it
locally on your machine so instead of pip
taking a hot second to do
dependency resolution and download all of the packages... it just works. It
also has some pretty slick pyproject.toml
management features that make a lot
of the things I used to do manually completely automatic. Meaning I can build
packages and create packages with practically zero effort. I can add
dependencies to my packages and it all just does the right thing. It's very
nice.
When I first saw this functionality honestly I thought it was stupid.
# /// script
# dependencies = ["requests"]
# ///
import requests
print(requests.get('http://example.com'))
I thought it was a complete waste of my time. I can just create my more or less
global python, or do python -m pip install --user request
and I'm totally
fine here.
But... this actually works great for one-offs, especially coupled with uv
's
cache. It just checks the version and installs the newer one or whatever you
have specified. And you never have to worry about conflicting packages for
different versions of your little one-off scripts. If it's too small to make a
full package out of, this is an utterly useful tool for writing things and
sharing with your team because all they need to do is run uv run yourscript.py
and it will download all the dependencies. You don't have to
teach them about virtual environments, or site-packages, or anything. Just
uv run cool-tool.py
Fabric is a useful lil' automation platform. It's not ultra powerfull (I mean,
it is for what it is), but I would say that it finds a niche in a similar vein
to the /// scripts
bit. It gives you the ability to run commands on N hosts,
including locally, and easily capture output, copy files, and other
shenanigans. If you're not in the market for something as robust as
Salt then honestly Fabric is pretty hard to beat.
But... it's kind of awkward to type this:
uv run --with fabric fab -H localhost sometask
The normal invocation is:
fab -H localhost sometask
Sure, you could uv tool install fabric
but what if you don't want to?
Well, even if you declare a @task
, you don't get quite the same functionality by
running
uv run fabric.py
But with a little reverse engineering of what the entrypoint is for fabric normally, behold:
# /// script
# dependencies = ['fabric']
# ///
from fabric import task
@task
def cool(c):
c.local('echo Hey dude!')
if __name__ == "__main__":
import sys
from fabric.main import program
sys.exit(program.run())
Save that in a fabric.py
and both of these work:
uv run fabric.py -H localhost cool
uv run --with fabric fab -H localhost cool
Take your pick!