✎ Edit content·DAY 023 · POST 5 OF 5 · Common Mistakes

Virtual Environments & uv

Python · 12 slides
DAY 023 · POST 5 OF 5
(REMINDER)
DAY 023
Env Mistakes to Avoid
@saurav_dnj_24github.com/SauravDnj · linkedin.com/in/sauravdnj
1 / 12

Theme

Palette

Download

4K — sharpest, slowest
🎬 Video options
Preparing preview…
Live preview · loops the “none” effect
All rendering runs in your browser. No server, no cost, no upload. MP4/WebM = full motion + effects · GIF = lightweight loop · PNG/PDF = static for the Instagram & LinkedIn carousel.

Caption (tap to copy)

📖 Deep dive (full written explanation)

The slides stay clean and scannable. Here's the in-depth explanation behind each one — great for the blog version, show notes, or studying the topic properly.
Slide 1 · Env Mistakes to Avoid

This cover sets up the mistakes post with an honest observation: environment trouble is rarely intellectually hard. It's the same small set of errors, repeated, each quietly costing an afternoon. The failures are insidious because nothing crashes loudly — you're simply, silently, in the wrong place or using the wrong python.

The post is a field guide. For each common trap we name the symptom, explain the underlying cause, and give the habit that prevents it. The aim is to inoculate you against the mistakes that catch beginners and experienced developers alike.

Slide 2 · Installing into global Python

The first trap is installing into the global Python by accident. You run a bare 'pip install' before creating or activating an environment, and the package lands in your system interpreter. Now your project's dependencies are global, they collide with other projects, and the setup can't be reproduced from the project files.

The fix is twofold: always create the environment before installing anything, and prefer 'uv add' or 'uv run', which target the project's environment automatically rather than relying on you to have activated it. Making the project-scoped commands your default removes the chance to install globally by mistake.

Slide 3 · Committing the .venv folder

The second trap is committing the .venv folder to git. The directory is large, specific to one machine and operating system, and fully rebuildable, so it has no place in version control. Committing it bloats the repository and actively breaks for collaborators because the interpreter paths baked inside are absolute and machine-specific.

The correct approach is to add .venv to .gitignore and commit the lockfile instead. The lockfile is tiny, portable, and is the real source of truth — anyone can regenerate an identical .venv from it with 'uv sync'. Version the recipe, not the cooked meal.

Slide 4 · The .gitignore line

This .gitignore snippet is the concrete fix for the previous slide. It ignores the .venv directory along with the usual Python build noise — __pycache__ folders and compiled .pyc files. The comment then lists what you should actively commit: pyproject.toml, uv.lock, and .python-version.

The pairing is the whole lesson in a few lines. Exclude the large, regenerable, machine-specific artifacts; include the small, portable files that let anyone reconstruct the environment. Getting this .gitignore right on day one prevents a class of repository hygiene problems.

Slide 5 · Forgetting which env is active

The third trap is losing track of which environment is active. Activation lives in a single shell session, so a freshly opened terminal won't have it, and editors frequently launch with their own configured interpreter that may differ from your terminal's. You install a package in one place and then an import fails somewhere else.

The misleading part is the error message. Python says 'No module named X', which sounds like the package is missing, when in fact the package is installed — just in a different environment than the one currently running. Recognizing this category of error saves you from chasing the wrong fix.

Slide 6 · Check which python you're on

This code slide gives the one-line diagnostic for the previous trap. Printing sys.executable inside Python shows the absolute path of the running interpreter; in a correctly set-up project it should point inside your project's .venv. If it points at the system Python or some other location, you've found your problem.

The shell equivalents are 'where python' on Windows and 'which python' on Unix, which show which executable the shell would run. Making this check your reflex when imports misbehave turns a confusing multi-minute hunt into a five-second confirmation.

Slide 7 · Not committing the lockfile

The fourth trap is declaring dependencies but never committing the lockfile. pyproject.toml typically specifies ranges like '>=2.32', which is a constraint, not a decision. Without uv.lock, two people running 'uv sync' at different times can resolve those ranges to different exact versions, and your hard-won reproducibility silently evaporates.

uv.lock is the frozen, exact answer to 'which versions, precisely.' Commit it, and treat changes to it as deliberate, reviewable events — a lockfile diff in a pull request is a signal that dependencies moved, which is exactly the kind of change you want visible.

Slide 8 · Range vs pinned

This comparison sharpens the lock lesson. With only pyproject.toml, you've specified ranges; resolution happens fresh each time, versions drift over months, and the build is not reproducible. With uv.lock committed alongside it, you get exact pins, the same version set on every sync, frozen until you deliberately relock — a reproducible build.

The mental shift is to see pyproject.toml and uv.lock as answering different questions. The manifest says what versions are acceptable; the lockfile says which acceptable versions you actually committed to. You need both, and the lockfile is the one people forget.

Slide 9 · Mixing pip and uv blindly

The fifth trap is mixing raw pip and uv carelessly. Running plain 'pip install' inside a uv-managed project can place a package in the environment without updating pyproject.toml or uv.lock. Now your declared state and your actual state have diverged, which defeats the entire point of having a manifest.

If you genuinely need pip's behavior, use 'uv pip install' so uv remains aware of what's happening. The better default, though, is to standardize on 'uv add' for everything, so the manifest is always an accurate description of the environment and never silently out of date.

Slide 10 · The habits that prevent all of this

These bullets gather the preventive habits into one place: keep one environment per project; use 'uv add' and 'uv run' rather than reaching for raw pip; gitignore .venv while committing the lockfile; check sys.executable the moment something seems off; and treat the lockfile as the authoritative source of truth for your dependencies.

None of these habits is hard, and adopting them as defaults is what separates people who occasionally lose afternoons to environment confusion from those who essentially never do. The mistakes are predictable, which means they're preventable.

Slide 11 · Confused? Decide here

This decision tree is a quick triage for the most common confusion. If an import fails or you're getting an unexpected version, first check whether sys.executable points inside your .venv. If it does, the environment is right but its contents are stale or incomplete — run 'uv sync' to align it with the lock. If it doesn't, you're in the wrong environment entirely, so use 'uv run' to execute within the project's env. If neither symptom applies, nothing is wrong and you can carry on.

Keeping this two-question flow in mind turns most environment incidents into a quick, deterministic fix rather than an open-ended debugging session.

Slide 12 · Save this. Follow for Day 24.

This closes Day 23 and the topic of environments. With the concept, the rationale, the mechanics, a full worked example, and the common mistakes covered, you have a complete working command of virtual environments and uv. The CTA points to Day 24, which begins a new topic, so following keeps the series going.

🎨 AI image prompt (matches this theme + palette)

Paste into Midjourney, DALL·E, Ideogram, etc. to generate an on-brand image, then upload it on the Edit content page. The prompt updates automatically with the selected theme + palette.