Jump to content

The Rust Tool That Finally Made Python Easy: Meet uv

From JOHNWICK
Revision as of 22:23, 20 November 2025 by PC (talk | contribs) (Created page with "500px I used to dread the “works on my machine” dance. New laptop? New teammate? New CI image? Something always broke. Then one tool cut the friction to almost nothing. It took my setup from layered rituals to a single, confident command. This isn’t a rant. It’s relief. What I Stopped Doing I stopped guessing which Python was installed.
I stopped arguing over pip, pipx, pyenv, virtualenv, and a dozen wrappers.
I st...")
(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)

I used to dread the “works on my machine” dance. New laptop? New teammate? New CI image? Something always broke. Then one tool cut the friction to almost nothing. It took my setup from layered rituals to a single, confident command. This isn’t a rant. It’s relief. What I Stopped Doing I stopped guessing which Python was installed.
I stopped arguing over pip, pipx, pyenv, virtualenv, and a dozen wrappers.
I stopped maintaining separate notes for macOS, Windows, and Linux. Now a project tells the tool what it needs. The tool does the rest. I type one command. It runs. It runs the same way on every machine. That tool is uv. The One-Command Moment Here’s the exact moment it clicked for me. I wrote a plain Python file with its requirements right inside the file. Then I ran it with one command. No manual venv. No manual pip install. No “wait, which Python is active?”

  1. /// script
  2. requires-python = ">=3.10"
  3. dependencies = [
  4. "pandas>=2.2",
  5. "numpy>=2.0",
  6. "pyarrow>=17.0",
  7. ]
  8. ///

import sys import importlib.metadata as md from datetime import datetime

PKGS = ("pandas", "numpy", "pyarrow")

def banner(title: str) -> None:

   print("\n" + "=" * 64)
   print(title)
   print("=" * 64)

def report() -> None:

   banner("Python And Packages")
   print(f"Python: {sys.version.split()[0]}")
   for name in PKGS:
       try:
           print(f"{name}: {md.version(name)}")
       except md.PackageNotFoundError:
           print(f"{name}: not installed")
   banner("Run Stamp")
   print(datetime.utcnow().isoformat(timespec="seconds") + "Z")

if __name__ == "__main__":

   report()

Run it with: uv run script.py That single command creates an isolated environment, installs the right Python if needed, resolves the deps, and executes the script — without me juggling tools or activating anything. On a clean machine, it still “just works.” Architecture In One Glance

          ┌──────────────┐

Developer │ Command │ your intent ──────────▶│ uv run … │─────────────────────────────────────────────┐

          └─────┬────────┘                                             │
                │                                                      │
                ▼                                                      │
         ┌──────────────┐     discovers / downloads                    │
         │ Python Host  │◀─────────────────────────────────────────────┘
         └─────┬────────┘
               │  picks version, creates isolated env
               ▼
       ┌───────────────┐     resolves + installs
       │ Global Cache  │◀────────────────────────┐
       └─────┬─────────┘                         │
             │ shares wheels across projects     │
             ▼                                   │
       ┌───────────────┐        lock + sync      │
       │ Project State │─────────────────────────┘
       │ (pyproject,   │
       │  uv.lock)     │
       └─────┬─────────┘
             │  runs exactly the versions you asked for
             ▼
       ┌───────────────┐
       │ Your Program  │   reproducible run
       └───────────────┘

No rituals. No drift. No “which Python am I on?” The same project yields the same environment on every machine. How Projects Feel Now Starting work is calm. I drop a pyproject.toml into the repo, declare Python and deps, and type one command to sync. When a teammate clones the repo, they type one command and get the same world. CI does the same. There’s a lock file for reproducibility. There’s a global cache so you don’t pay download costs for every project. And when I need a one-off tool, I can run it ephemerally without polluting my system. The day-to-day impact is simple: less setup, fewer weird failures, faster feedback. Why This Feels Different Speed Without Drama. Resolution and installation are fast, even on cold runs. That keeps you in flow instead of staring at a terminal. One Language File. Projects describe their Python version and dependencies in one place. The tool reads it and acts. Everyone gets the same results. Reproducible By Default. A lock file removes “works for me” from the conversation. When a version changes, it’s deliberate, reviewed, and shared. Ephemeral Tools. Need to lint once? Need a quick REPL with a couple of libs? Run a tool in a throwaway env. Nothing leaks into your global system. Version Pinning That Sticks. When a project must be on a specific Python, it stays there — across laptops and CI runners — without a scavenger hunt. None of this asks you to learn a new build system or a new packaging theory. It just trims the friction from the parts we repeat all week. The Human Part We Don’t Admit Most teams don’t lose days to algorithms. They lose days to setup. To mismatched versions. To “it fails only on my machine.” Those days feel avoidable, which makes them sting. The right tool here is not about cleverness. It’s about emotional load. You feel lighter when the basics stop biting. I felt that the first time my script ran clean on a bare machine with one command. Not special. Just steady. That calm is addictive. What To Watch When You Switch Keep your pyproject.toml honest. Declare the Python range you commit to. Add the deps you actually import. Let the lock file carry the exact versions. When you upgrade, upgrade on purpose. Commit both files. That’s it. If you maintain very old projects, stage the switch in a branch. Let the team run it for a few days. You’ll learn which assumptions were hiding in your shell profiles and CI images. Fix them once. Ship it. A Simple Way To Start Today Take one script that matters to you. Add the inline metadata at the top. Run it with one command. Feel the difference. Then pull a small repo, add a pyproject.toml, and lock it. Push that change. Watch how quickly new teammates get moving. You can keep every other habit if you want. You probably won’t. Tell Me Where It Hurts What’s the messiest part of your current Python flow — versions, conflicts, CI speed, or onboarding? Drop the one pain you want gone. I’ll reply with exactly how I’d smooth it with this tool, based on real migrations I’ve done

Read the full article here: https://medium.com/@the_atomic_architect/uv-rust-python-setup-2d11f7f00692