runtime
146 / 250
lesson 146 Packaging & Databases · advanced

Virtual environments: one project, its own packages

A virtual environment is a folder with its own site-packages, so each project installs the versions it needs without fighting the others. You create and activate it in a terminal; from Python you can inspect it.

You'll be able to
  • Say what python -m venv .venv, activation and python -m pip install each do, and where packages end up
  • Read the settings in a pyvenv.cfg file and turn them into a dictionary
  • Tell from sys.prefix and sys.base_prefix whether a program runs inside a virtual environment
The idea

Two projects on one computer rarely agree. The sales report needs pandas 2.2; an old invoice script only works with 1.5. If both install into the one Python that came with the computer, the second install replaces the first and one project breaks.

A virtual environment solves this with a folder. It has its own site-packages (where installed packages live), a bin/ folder (Scripts\ on Windows) with a python that uses that site-packages, and a small settings file, pyvenv.cfg, saying which Python it was made from. The commands, typed in a terminal on your own computer:

  • python -m venv .venv creates the folder .venv next to your project;
  • source .venv/bin/activate (macOS, Linux) or .venv\Scripts\activate (Windows) activates it: for that terminal only, python and pip now mean the ones inside .venv;
  • python -m pip install pandas installs into whichever environment that python belongs to;
  • deactivate goes back to the computer's own Python.

The Python in this page runs inside your browser, with no terminal and no pip, so these commands aren't run here. What a program *can* do anywhere is read the files an environment is made of, and ask its own interpreter where it lives. That's what the examples do.

Run each example to see what it prints. Running examples doesn't count toward progress.

example-1.py · Read pyvenv.cfg
cfg_text = """home = /usr/local/bin
include-system-site-packages = false
version = 3.12.4
executable = /usr/local/bin/python3.12
command = /usr/local/bin/python3.12 -m venv /home/ana/market-reports/.venv
"""

settings = {}
for line in cfg_text.splitlines():
    if "=" not in line:
        continue
    key, value = line.split("=", 1)
    settings[key.strip()] = value.strip()

print(settings["version"])
print(settings["include-system-site-packages"])
print(len(settings), "settings")

A running program can also check whether it is inside an environment. sys.base_prefix is the folder of the Python installation; sys.prefix is the environment's folder when one is active and the same folder otherwise. So sys.prefix != sys.base_prefix means *inside a virtual environment*.

Where pip puts a package follows a fixed layout, and pathlib's pure paths can build it for either operating system without touching the disk: PurePosixPath joins with /, PureWindowsPath with \.

example-2.py · Inside an environment? Where do packages go?
import sys
from pathlib import PurePosixPath, PureWindowsPath

def in_virtualenv(prefix, base_prefix):
    return prefix != base_prefix

def site_packages(env_dir, version, windows):
    if windows:
        return PureWindowsPath(env_dir) / "Lib" / "site-packages"
    major_minor = ".".join(version.split(".")[:2])
    return PurePosixPath(env_dir) / "lib" / f"python{major_minor}" / "site-packages"

print(in_virtualenv("/home/ana/market-reports/.venv", "/usr/local"))
print(in_virtualenv(sys.prefix, sys.base_prefix))
print(site_packages("/home/ana/market-reports/.venv", "3.12.4", False))
print(site_packages(r"C:\Users\ana\market-reports\.venv", "3.12.4", True))

When to use one: always, one environment per project. Make it once, activate it whenever you work on the project, and install with python -m pip so the pip you run belongs to the Python you mean.

Mistakes to avoid: running pip install in a terminal where the environment isn't active (the package lands in another Python, and import in your project still fails); committing .venv to git (it is big and machine-specific: list your dependencies instead, next lessons); and treating the text false in pyvenv.cfg as if it were False. Any non-empty text is true in an if.

Review
  • A virtual environment is a folder with its own site-packages and a pyvenv.cfg saying which Python made it.
  • python -m venv .venv, activate, then python -m pip install …: activation only affects that terminal.
  • sys.prefix != sys.base_prefix is true inside an environment; values in pyvenv.cfg are always text.
  • Next: pyproject.toml, the file that describes the project itself and the packages it needs.

Loading your progress…

To master this lesson, solve both challenges without hints or the answer, and pass the concept check.

Virtual environments: one project, its own packages — Packaging & Databases · Runtime