Using uv to build and install Python CLI apps
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:
- go back in time and recreate the project with a more appropriate name; or
- 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