Using uv to build and install Python CLI apps

Using uv to build and install Python CLI apps

February 22, 2025

Not going to do the whole article but Rodrigo Girão Serrão had a couple of items that I didn’t know about.

Step 4: install the project globally

To install the project to make it available globally in your system you will use another feature of uv: the ability to manage commands from Python packages. The uv documentation explains everything in detail, so I’ll just jump to the fun stuff for this short tutorial.

Make sure you are in the project directory and run the command:

uv tool install . -e

The command uv tool is what lets you tap into the capabilities that uv has to deal with commands from Python packages. The dot . tells uv to install the package you’re in and the flag -e makes it an “editable” installation, which means that changes you make to the source code of the package are instantly reflected in the command you can run. (You’ll want to omit the flag -e if you intend to do serious versioning of your project, for example.)

Bonus step: better command name

myproj is a bit of a weird command name, so you can do one of two things to fix it:

  1. go back in time and recreate the project with a more appropriate name; or
  2. configure your project to have a more sensible command name.

Let me show how option 2 works, to show you a bit of how everything can be done by hand. Open the file pyproject.toml and look for this section:

[project.scripts] myproj = "myproj:main"

Edit that section so it looks like this:

[project.scripts] mywc = "myproj:main"

This tells uv that the command mywc will run by looking for the function main in the module myproj. (Remember that the CLI was implemented in the function main?)

After modifying the file and saving it, you need to reinstall the project explicitly. I know I said -e would reflect changes automatically… but that’s for code changes. This is a project configuration, so you need to force uv to install the project again:

uv tool install . -e --force

After this, you should be able to use the command mywc and the command myproj should be gone. Here is an example I ran from a random directory in my system:

❯ mywc ~/.python_history 1509 3714 32797 /Users/rodrigogs/.python_history