Your venv Is Not the Python You Think It Is

SarbatDaBhalla  · October 4, 2026

You create a virtual environment called py_venv310, activate it, and get this:

$ which python
/usr/bin/python
$ python --version
Python 3.8.10

A folder named for 3.10. An interpreter that is 3.8. And a path pointing outside the venv completely.

Nothing you pip install goes where you expect, and pytest runs against a different set of packages than you think. Here is how to find out what is wrong, fix it on either platform, and stop it happening again.

Versions and package availability checked on 2026-10-04.


1. Check it in one command

Do not guess. Run this:

python -c "import sys; print(sys.prefix); print(sys.base_prefix)"

Two different paths means you are inside a venv. Two identical paths means you are not — whatever your prompt says.

For the full picture:

echo "VIRTUAL_ENV: ${VIRTUAL_ENV:-<unset>}"
command -v python
python --version

PowerShell:

$env:VIRTUAL_ENV
(Get-Command python).Source
python --version

Read it like this:

What you see What it means
VIRTUAL_ENV is empty Not activated. Fix that first.
VIRTUAL_ENV set, but python is /usr/bin/python Activated, but something else is ahead on PATH
sys.prefix same as sys.base_prefix You are not in a venv at all
Both paths differ, but the version is wrong The venv is fine. It was built on the wrong Python.

That last row is the interesting one, and it is the example above.


2. Why it happens

It was built on the wrong Python. This is the common one, and people misread it as “activation is broken”.

A venv is not a Python version. It is a small folder that points at the interpreter that created it — permanently. When you run:

python -m venv py_venv310

you get whatever python meant at that moment. On Ubuntu 20.04 that is 3.8. The name py_venv310 is just a folder name. It does not ask for a version, and nothing checks it.

You can see this for yourself:

cat py_venv310/pyvenv.cfg
home = /usr/bin
version = 3.8.10
executable = /usr/bin/python3.8

There it is, in writing. A venv’s Python version cannot be changed afterwards. Delete it and make a new one — there is no repair.

The shell remembered the old path. If you deleted and recreated the venv and it still looks wrong, bash may be caching the old location:

hash -r

3. Fix it on Ubuntu

deactivate 2>/dev/null || true
cd ~/projects/my-tests          # your project folder, NOT inside the venv
rm -rf py_venv310

python3.12 -m venv .venv        # name the version — this is the whole point
source .venv/bin/activate

python --version                # should say 3.12.x

Watch step 2. If you delete a venv while your shell is sitting inside it, you end up in a folder that no longer exists, which causes its own strange errors.

If you get “ensurepip is not available”, Ubuntu ships venv separately:

sudo apt install python3.12-venv

The advice that does not work on Ubuntu 20.04

Nearly every guide says this:

sudo apt install python3.10 python3.10-venv    # fails on 20.04

Ubuntu 20.04 has no python3.10 package. I checked the Ubuntu package archive for focal on 2026-10-04: searching for python3.10 returns “Sorry, your search gave no results”. The command fails with Unable to locate package, and people assume their apt sources are broken. They are not.

The old answer was the deadsnakes PPA. That no longer covers 20.04 either — as of 2026-10-04 it publishes for jammy (22.04), noble (24.04) and resolute (26.04) only. Focal was dropped.

What each Ubuntu release ships by default:

Ubuntu Codename Default Python
20.04 Focal Fossa 3.8
22.04 Jammy Jellyfish 3.10
24.04 Noble Numbat 3.12

What works on 20.04 today

Use uv. It downloads a ready-made interpreter. No apt, no PPA, no compiler, no root:

curl -LsSf https://astral.sh/uv/install.sh | sh
uv python install 3.12
uv venv --python 3.12 .venv
source .venv/bin/activate
uv pip install -r requirements.txt

The useful part: uv venv --python 3.12 fails loudly if it cannot get 3.12, instead of quietly handing you 3.8. That one behaviour removes this whole class of bug. (uv was 0.12.23 when I wrote this.)

Or use pyenv, which builds from source — slower, and you need the build dependencies first:

curl -fsSL https://pyenv.run | bash
pyenv install 3.12
pyenv local 3.12
python -m venv .venv

Or upgrade the machine. Ubuntu 20.04 is old, and its default Python 3.8 stopped getting fixes in October 2024. If you can move to 24.04, that is the fix that stops costing you time.

Either tool puts a modern Python on an old box without touching the system one. That matters: Ubuntu’s own tools depend on /usr/bin/python3. Never apt remove it, and never repoint it.


4. Fix it on Windows

Same idea, different commands:

deactivate
Remove-Item -Recurse -Force .venv

py -V:3.12 -m venv .venv
.\.venv\Scripts\Activate.ps1
python --version

Note the activate path is .\.venv\Scripts\Activate.ps1 — one dot, then a backslash. Typing ..venv\... makes PowerShell look in the parent folder, and the error does not explain that.

If activation is blocked with “running scripts is disabled on this system”, that is the PowerShell execution policy. I covered that one, and the Microsoft Store python alias, in Setting Up Python on Windows 11.

Installing versions properly

Hardcoding C:\...\Python312\python.exe works but gets messy with several versions. Python now ships an Install Manager for Windows:

winget install 9NQ7512CXL7T -e     # or install "Python" from the Microsoft Store
py install 3.12                    # download and register 3.12
py list                            # what you have
py -V:3.12 -m venv .venv           # venv on a specific version

py -V:3.12 -m venv .venv is the payoff: an explicit version, no long paths, no PATH edits. In scripts, use pymanager instead of py — the docs suggest it, because an older launcher can take over the py command.

Do not follow the PATH tip in the install output. After py install you are told to add %LocalAppData%\Python\bin. Plenty of write-ups then tell you to also add the per-version folder like pythoncore-3.12-64. Do not.

Per the official Windows docs, adding bin is optional — it only makes aliases like python3.14.exe work, and py works fine without it. The per-version folder is that version’s scripts folder. Putting it on PATH pins bare python to one fixed version, which is the exact bug this post opened with, just created on purpose.

If py is not resolving, let the manager repair itself rather than editing PATH by hand:

py install --configure -y

5. The pytest version of this bug

pytest adds two twists.

pytest on PATH may belong to a different venv. The pytest command is a small script with the creating venv’s interpreter written into it. If an old one is earlier on PATH, your tests run under that Python with that set of packages — while python --version happily reports the right thing. Check both:

command -v pytest
python -c "import sys; print(sys.executable)"

python -m pytest is not the same as pytest. The pytest docs put it like this: calling via python “will also add the current directory to sys.path.”

That cuts both ways:

  • It guarantees you are using the Python you just checked, so it sidesteps the problem above.
  • It can hide a packaging mistake. A test that only imports your package because the current folder happens to be on sys.path will fail in CI, where the package is installed properly.

So: use python -m pytest while sorting out an environment, and pip install -e . with plain pytest as the real setup.

Install with python -m pip, not bare pip, so it goes to the Python you just verified:

python -m pip install -r requirements.txt
python -m pip -V        # check the path is inside your venv

6. Which version to pin

Support status on 2026-10-04:

Version Latest Supported until
3.14 3.14.8 Oct 2030
3.13 3.13.16 Oct 2029
3.12 3.12.15 Oct 2028
3.11 3.11.17 Oct 2027
3.10 3.10.22 ended 1 Oct 2026
3.9 3.9.25 ended Oct 2025
3.8 3.8.20 ended Oct 2024

Worth knowing before you spend an afternoon getting 3.10 onto an old machine: 3.10 is already end of life — support ran out on 1 October 2026. If you are picking a version now, rather than matching one a project already uses, pick 3.12 or newer.

Write the decision where tools can read it, not in a folder name:

# pyproject.toml
[project]
requires-python = ">=3.12"

7. The habit that prevents all of it

Never create a venv with a bare python -m venv. Name the version every time:

python3.12 -m venv .venv        # Linux and macOS
py -V:3.12 -m venv .venv        # Windows
uv venv --python 3.12 .venv     # anywhere — downloads it if missing

The difference is what happens when the version is missing. Bare python -m venv quietly gives you whatever it found. All three above fail straight away and tell you. That is a two-minute problem instead of a two-hour one.

Two more habits:

  • Call it .venv, not py_venv310. A version in the folder name is a comment nothing enforces, and it will eventually be wrong. .venv is what editors and most tools look for automatically.
  • Read pyvenv.cfg when anything looks odd. Three lines, and it cannot lie.

Quick reference

Symptom Cause Fix
which python is /usr/bin/python with venv “active” Not actually activated source .venv/bin/activate
Right venv, wrong version Built on the wrong Python Check pyvenv.cfg, delete, recreate with python3.12 -m venv
Unable to locate package python3.10 on 20.04 Not in the focal archive Use uv, or pyenv, or upgrade
ensurepip is not available Ubuntu ships venv separately sudo apt install python3.X-venv
Recreated the venv, still wrong Shell cached the old path hash -r
Activate.ps1 cannot be loaded PowerShell execution policy Set-ExecutionPolicy RemoteSigned -Scope CurrentUser
pip install works, import still fails pip belongs to another Python Use python -m pip; check python -m pip -V
Passes locally, ModuleNotFoundError in CI python -m pytest put cwd on sys.path pip install -e ., run plain pytest
python stuck on one version Per-version folder added to PATH Remove it; use py -V:3.12

Sources


Did this match what you hit, or was your venv broken in some new way? Tell me in the comments below — and if you are on Ubuntu 20.04, I would like to know which fix you went with.


Questions or comments?

Ask a question, share your experience, or add a correction below.

Loading comments...