Ship your own command-line app that anyone installs with one line
Build tidyup, a small Python tool that sorts a messy Downloads folder, shows you the plan first with --dry-run, and can undo itself. Then install it like a real program with one uv command and share it from GitHub in one line. Publishing to PyPI is an optional last step.
tidyup, with proper --help pages, a --dry-run mode, a confirm prompt and a one-command undopyproject.toml, a src layout, an entry point and 14 passing teststidyup works in any terminal, in any folder- The one-line command that installs it on anyone else's computer straight from GitHub
- The safe route to PyPI: TestPyPI first, scoped tokens, then trusted publishing from GitHub with no password stored anywhere
- Windows, Mac or Linux, with about 60MB free. uv downloads Python 3.12 if you don't have it, plus two small libraries (Typer and Rich).
- uv, ideally 0.12 or newer. Step 1 installs or updates it. If you've never used it, Turn a Python script into a web app is a gentler first go.
- Basic terminal skills:
cd, running a command, opening a file in an editor. If that's new, do the Terminal survival kit first. - A code editor. VS Code ↗ is free. Notepad or TextEdit work too.
- For step 6 only: Git and a free GitHub account. Install anything from GitHub shows you how to install Git, and Use Git without memorising commands sets up your Git name and email.
- For step 7 only (optional): free accounts on TestPyPI and PyPI. Both insist on two-factor authentication, so have an authenticator app on your phone.
Make the package skeleton with uv
A loose .py file only works on your PC. One uv command gives you the shape of a proper installable package, so you start right instead of fixing it later.
To make something other people can install with one command, Python needs a package: your code in a folder, plus a
pyproject.tomlfile that says its name, its version, what it depends on, and which command it creates. uv ↗ makes that skeleton for you, then builds, tests and installs it.Check you have uv and which version:
Terminaluv --versionYou want 0.12 or newer. To update:
uv self updateif you used uv's own installer,winget upgrade --id astral-sh.uv -eif you used winget,brew upgrade uvon a Mac with Homebrew. No uv at all? Install it, then close the terminal and open a new one:Windowswinget install --id=astral-sh.uv -eMac / Linuxcurl -LsSf https://astral.sh/uv/install.sh | shNow make the project. The
--packageflag is the important part: it gives you asrcfolder, a build system and a command-line entry point, all the things a plain script project doesn't have.Windowscd $HOME\Documents uv init --package tidyup cd tidyupMac / Linuxcd ~/Documents uv init --package tidyup cd tidyupOutputInitialized project `tidyup` at `...\tidyup`You get this layout. uv also made the folder a Git repository, with a
.gitignorethat keeps the.venvfolder and build files out of it:Project layouttidyup/ ├── .gitignore ├── .python-version ├── README.md ├── pyproject.toml └── src/ └── tidyup/ └── __init__.pyOpen
pyproject.tomlin your editor. This is what uv wrote:pyproject.toml[project] name = "tidyup" version = "0.1.0" description = "Add your description here" readme = "README.md" requires-python = ">=3.12" dependencies = [] [project.scripts] tidyup = "tidyup:main" [build-system] requires = ["uv_build>=0.12.24,<0.13.0"] build-backend = "uv_build"- [project.scripts] is the entry point. The left side is the command people will type:
tidyup. The right side says where Python finds the code to run: themainfunction in thetidyuppackage. When the package is installed, a small launcher calledtidyup(tidyup.exeon Windows) is made that runs it. - [build-system] names the tool that turns your folder into an installable file. uv uses its own,
uv_build. The upper limit (<0.13.0) stops a future uv release from quietly changing how your package builds. - requires-python comes from the Python uv found on your PC. Yours may say a different version. Anything from 3.10 up works with this mission.
- [project.scripts] is the entry point. The left side is the command people will type:
Change the description to something real, like
"Tidy a messy folder (like Downloads) into subfolders by file type.". It shows on PyPI if you publish. Then run the command uv already wired up:Terminaluv run tidyupOutputUsing CPython 3.12.13 Creating virtual environment at: .venv Building tidyup @ file:///.../tidyup Built tidyup @ file:///.../tidyup Installed 1 package in 31ms Hello from tidyup!uv runmade a private environment (.venv) inside the project, installed your package into it, and ran thetidyupcommand from there. Nothing has been installed for the rest of your PC yet. That comes in step 5.TipThe finished project is in the starter kit: tidyup-starter.zip (13KB). Use it to check your work or to skip the typing. The steps below build the same files one at a time, so you understand each piece.
uv run tidyup prints Hello from tidyup!If it breaksuv made a main.py and no src folder + 2 more
uv made a main.py and no src folder
--package. Without it, uv makes a plain script project with no entry point. Delete the folder and run uv init --package tidyup again.It says it failed to spawn tidyup (program not found)
[project.scripts] section is missing or misspelt. Run cd tidyup and check pyproject.toml matches the one above.