I keep being be impressed by uv
MP 170: It understands my old projects!
A few years ago I made a small project that automatically adds borders to screenshots, because macOS doesn't have a built-in tool to easily do that. For a couple years I installed it globally on every system I used, so I could always run add-border in any directory I was working in. But I didn't use it for a while. In the meantime I got a new computer, and at some point I found it wasn't available when I needed it.
Rather than looking at my old documentation, I tried running it with uv. It didn't work using the first command I tried, but uv was able to tell me the correct command to use. That's such a nice user experience!
I keep coming back to this project
I wrote py-image-border shortly after starting this newsletter, because I found myself repeatedly adding borders to screenshots for these posts. A lot of screenshots have white backgrounds, so the images get lost when viewed in light mode in a published post. I added borders in Preview a few times, but it was slow and inconsistent.
I keep going back to this project, for two reasons. One, it continues to do its one job really well. Every time I need a border for a screenshot, it generates that border exactly how I want it. Maybe you can have an AI do a task like this, but there's something really nice about using a small, deterministic low-footprint tool instead of burning a bunch of AI resources to do so. Second, it's a nice concrete example project for discussing how AI has significantly changed the programming world. This is exactly the kind of project that could only be produced by a programmer just a few years ago, but can be built well enough by just about any AI these days. You used to be able to get a job if you could build a tool like this on your own. The bar for getting paid to work on programming projects is significantly higher than it was just a short time ago.
Running add-border with uv
I've been using uv to run projects for a while now, so I tried it recently when I needed to run py-image-border on a new system for the first time. I had no idea if it would work, but I tried it. Here's what I got:
$ uvx py-image-border may_activity.png An executable named `py-image-border` is not provided by package `py-image-border`. The following executables are available: - add-border Use `uvx --from py-image-border add-border` instead.
It didn't work, because py-image-border is the name of the package, but the actual command is add-border. But uvx, an alias for uv tool run, suggests the correct command to try.
Let's try it!
$ uvx --from py-image-border add-border may_activity.png New image saved at may_activity_bordered.png
It worked. :)

How it knows
I was impressed at how well this all worked, so I was curious to understand how uvx determines the correct way to run the add-border command. It's rather straightforward, although all the steps in the process can seem complex the first time you learn about them. In the project's pyproject.toml file, this block specifies how the project should be run:
[project.scripts] add-border = "py_image_border.add_border:main"
This says the add-border command will run the main() function in the file add_border.py, which is found in the py_image_border/ directory.
If you've ever poked around in the source files of an installed Python package, you might have seen a folder ending in .dist-info. Inside that folder is a file named entry_points.txt. Here's what's in that file for py-image-border:
[console_scripts] add-border=py_image_border.add_border:main
This is the same information, with the label [console_scripts] in place of [project.scripts]. uv grabs this information from PyPI, and uses it to show the correct command to use when running the project.
The high-level process outlined here is relatively straightforward, but what I remain impressed about is the external simplicity of uv. I chose to look at the packaging information in pyproject.toml and py_image_border-2023.4.14.2.dist-info because I was curious about what exactly uv was finding there. But if all you want to do is run a Python project, you don't have to look closely at the project nearly as often anymore. You can try running the project with uv, and it will either run the first time, or quite likely tell you how to run the project.
Conclusions
For the first couple years uv was out the general advice from posts like this was, "You should try uv." Now that we're a bit farther along in the evolution of Python packaging, I'd change that to "You should explore all the things you can do with uv."
If you're still using uv as a faster pip, consider trying to run your tools and projects with uv and uvx. You might find a nice friendly user experience that's right at your fingertips.