← All 133 books pip and venv, at work
One concept per page

pip and venv, at work

Twenty-eight lessons on Python packaging, one concept per page: pip itself and PyPI; what pip install resolves and the four sources it installs from; the venv module, what activation changes in PATH, one script per shell, and deactivate; the EXTERNALLY-MANAGED marker, the PEP 668 refusal, the break-system-packages bypass and virtualenv beside the stdlib's venv; the pin set of pip list, pip show, pip freeze and requirements.txt replayed into a second environment; wheels, sdists and the build backend, pip download, editable installs; the pip cache, offline installs, upgrading pip itself and pip uninstall; then pyproject.toml, pip check, publishing to PyPI, and the wider field.


Steve Hodgkiss 7 lessons

One concept, one page, one real capture. That's the rhythm.

pip and venv, at work

Twenty-eight lessons on Python packaging, one concept per page: pip itself and PyPI; what pip install resolves and the four sources it installs from; the venv module, what activation changes in PATH, one script per shell, and deactivate; the EXTERNALLY-MANAGED marker, the PEP 668 refusal, the break-system-packages bypass and virtualenv beside the stdlib's venv; the pin set of pip list, pip show, pip freeze and requirements.txt replayed into a second environment; wheels, sdists and the build backend, pip download, editable installs; the pip cache, offline installs, upgrading pip itself and pip uninstall; then pyproject.toml, pip check, publishing to PyPI, and the wider field.


Set in Space Grotesk, Inter and JetBrains Mono (SIL Open Font License).

Every fact in this book is as the official source states it, fetched and read during this build: the pip user guide, CLI reference, pip install page and pip freeze page from pip.pypa.io; the Python venv and installing documentation (docs.python.org); the Python Packaging User Guide (packaging.python.org); PEP 668, Marking Python base environments as externally managed (peps.python.org); the virtualenv documentation (virtualenv.pypa.io); and the Wikipedia article on pip. No facts are sourced from Reddit, Stack Overflow or vendor blogs. Every command and output pair on every page was run on this machine (Python 3.14.9, pip 26.2.2, Debian system Python 3.12.3 marked EXTERNALLY-MANAGED) and confirmed before printing; every install went into throwaway virtual environments under a scratch directory, never into a system or shared interpreter. The --break-system-packages option and publishing to PyPI were never run, and are stated from the sources instead. An independent guide, not affiliated with or endorsed by the Python Software Foundation, the Python Packaging Authority, the pip developers, or the Wikimedia Foundation.

Your purchase is for personal use only. You do not have redistribution rights: please do not share, resell, or republish this book or its pages.

© 2026 Steve Hodgkiss. All rights reserved. Personal use only; no redistribution rights.

Edition 1.0 · stevehodgkiss.net

Contents

Contents


Part 1 · The installer and its index
pip, the installer4
Part 2 · The environment
python -m venv5
Part 3 · The border
The PEP 668 refusal6
Part 4 · The pin set
pip freeze7
Part 5 · What pip installs
Wheels8
Part 6 · The working machine
The pip cache9
Part 7 · The project and beyond
Publishing to PyPI10

Per the Wikipedia pip article, pip is a package manager written in Python, used to install and manage software packages, Python 3.4 and later include pip by default, and the name is a recursive acronym, Pip Installs Packages. This machine's capture: the venv's own interpreter reported pip 26.2.2 from the venv's site-packages, bound to python 3.14.

pip and venv companion · No. 01
pip

pip, the installer

What it is, whose it is

the installer, named and versioned$ python3 -m pip --versionpip 26.2.2 from.../demo1/.../site-packages/pip(python 3.14)Python 3.4+ includes pipby default, says Wikipediapip installs and managesPython packages; the nameis a recursive acronym,Pip Installs Packages. Itis a package manager in Pythonpython -m pip names the interpreter; a bare pip can be a stranger

pip installs and manages packages, and Python 3.4+ ships it by default, says the Wikipedia article. The name is a recursive acronym: Pip Installs Packages.

Whose pip answered? Our capture: pip 26.2.2 from the venv's own site-packages, on python 3.14. Running python -m pip names the interpreter, so you always know.

A bare pip can belong to anyone. The habit this book builds: one venv per project, and its python -m pip does everything.

RUN IT THIS WEEK

Run python -m pip --version in two different venvs and watch the paths differ.

Per the Python venv documentation, the venv module supports creating lightweight virtual environments, each with their own independent set of Python packages installed in their site directories; creating one places a pyvenv.cfg file with a home key pointing to the Python installation from which the command was run, a bin (Scripts on Windows) subdirectory containing a copy or symlink of the interpreter, and a lib/pythonX.Y/site-packages subdirectory. This machine's capture: python3 -m venv created demo1 in seconds, unprivileged.

pip and venv companion · No. 02
venv

python -m venv

An environment in one line

an environment beside the interpreter$ python3 -m venv demo1demo1/ bin/ python, pip, activate* lib/pythonX.Y/ site-packages/ pyvenv.cfglightweight virtualenvironments, each with anindependent set of packagesin its own site directory,per the Python venv docspyvenv.cfg's home key points at the interpreter it came from

python -m venv demo1 builds a whole private environment: bin/ with python and pip, lib/.../site-packages/, and pyvenv.cfg.

The docs call it lightweight: each venv holds an independent set of packages in its own site directory. Our capture created one in seconds, no root, no apt.

pyvenv.cfg's home key names the base interpreter, so the venv is a thin profile over a real Python, not a copy of the language.

RUN IT THIS WEEK

Create a throwaway venv, list its three parts, and read its pyvenv.cfg top to bottom.

Per PEP 668, Marking Python base environments as externally managed, a distribution marks its Python with an EXTERNALLY-MANAGED marker file so installers refuse to install packages into it outside the system package manager. Per the Python installing documentation, ensurepip bootstraps pip into an environment. This machine's capture: venv creation under the system Python refused with ensurepip is not available, advising apt install python3.12-venv, and the marker file /usr/lib/python3.12/EXTERNALLY-MANAGED is present.

pip and venv companion · No. 03
PEP 668

The PEP 668 refusal

externally managed

the marker that says hands off$ /usr/bin/python3 -m venv tensurepip is not availableapt install python3.12-venvThe virtual environment wasnot created successfullyls: /usr/lib/python3.12/EXTERNALLY-MANAGEDPEP 668: Marking Pythonbase environments asexternally managed; pipsees the marker and refusesto install over the distro'scarefully versioned setthe refusal is protection; the next page shows the bypass and its cost

PEP 668 marks distro Pythons as externally managed: a marker file tells installers to keep their hands off.

Our machine shows both edges: the marker at /usr/lib/python3.12/EXTERNALLY-MANAGED, and a venv attempt refused with ensurepip is not available, pointing at apt.

That error you may have met, externally-managed-environment, is this policy in pip's voice. It is protection, not obstruction.

RUN IT THIS WEEK

Look for an EXTERNALLY-MANAGED file under your system Python's lib directory; read its note.

Per the pip freeze page, pip freeze outputs installed packages in requirements format. This machine's capture: pip freeze in the venv printed exactly one line, six==1.17.0, the name, a double equals and the exact installed version.

pip and venv companion · No. 04
freeze

pip freeze

The exact set, as pins

the exact set, as pins$ pip freezesix==1.17.0pip freeze > requirements.txtoutput installed packagesin requirements format, oneexact pin per line, no rangesthe pip freeze page says itplainly: requirements format.Name, double equals, exactversion: the set can bereplayed whole, later, anywherefreeze records what IS installed, not what SHOULD be

pip freeze prints installed packages in requirements format: name, double equals, exact version. Our whole capture: six==1.17.0.

One line per package, no ranges, no comments on your behalf. What was installed, precisely, is what gets written.

Freeze records what IS, not what SHOULD be. Edit requirements by hand when you mean to change the plan; freeze only ever photographs it.

RUN IT THIS WEEK

Freeze a real project's venv, read every line, and check each pin against what you intended.

Per the Python Packaging User Guide specification on the wheel binary distribution format, a wheel is a ZIP-format archive with a specially formatted file name and the .whl extension, containing a single distribution nearly as it would be installed, with the file name carrying the distribution, version, python tag, abi tag and platform tag. This machine's capture: pip download saved six-1.17.0-py2.py3-none-any.whl, the py2.py3-none-any tags marking a pure-Python wheel.

pip and venv companion · No. 05
wheels

Wheels

Finished goods, ready to copy

a zip whose name carries its tags$ pip download --no-deps sixSaved .../dl/six-1.17.0-py2.py3-none-any.whla ZIP-format archive witha specially formatted filename and the .whl extension,says the wheel specificationsix-1.17.0-py2.py3-none-anydistribution, version, thenpython, abi and platformtags; py2.py3-none-any ispure Python: runs anywhereno build step, no compiler: a wheel is finished goods

A wheel is a ZIP-format archive with a specially formatted name and the .whl extension, says the specification: a single distribution, nearly as it would be installed.

The name is a passport: six-1.17.0-py2.py3-none-any is distribution, version, then python, abi and platform tags. none-any means pure Python, runs everywhere.

No build step, no compiler, no setup dance: a wheel is finished goods, and pip's favorite currency.

RUN IT THIS WEEK

Download one wheel and one tar.gz of the same package; unzip the wheel and read its top level.

Per the pip CLI reference, pip cache is the subcommand for managing pip's local caches. This machine's captures: pip cache dir printed /root/.cache/pip, and pip cache info reported the http-v2 index page cache at 226.8 MB across 500 HTTP files, and locally built wheels at 926 kB, 2 of them.

pip and venv companion · No. 06
cache

The pip cache

Wheels remembered locally

wheels remembered between runs$ pip cache dir; cache info/root/.cache/piphttp-v2: 226.8 MB, 500 fileswheels: 926 kB, 2 built heredownloads and locally builtwheels are kept between runsthe second install saidUsing cached: no network,no rebuild; the CLI has apip cache subcommand toinspect and purge itthe cache serves wheels; the pins still decide versions

pip keeps what it earns: /root/.cache/pip in our capture, holding an http-v2 index cache (226.8 MB, 500 files) and locally built wheels (926 kB).

That is why round two printed Using cached: no network, no rebuild. The pip cache subcommand inspects and purges it.

The cache serves bytes, never versions: your pins still decide what is right, the cache only makes it fast.

RUN IT THIS WEEK

Run pip cache info, note the two sizes, and purge it once to feel what a cold install costs.

Per the Python Packaging User Guide packaging tutorial, publishing means learning how to build the package and how to upload it to the Python Package Index, generating distribution archives and running twine upload dist/*, with TestPyPI recommended for trying the flow first and a package name chosen that does not conflict with packages uploaded by other people. Publishing was not run on this machine during this build.

pip and venv companion · No. 07
publish

Publishing to PyPI

Build, then twine upload

build, then uploadpyproject.tomlbuilddist/twine upload dist/*PyPItry TestPyPI first,the tutorial advisesdistribution archives built from one pyproject.toml, then uploaded oncepick a package name that does not conflict with other people's uploadsnot run on this machine: publishing needs an account, and we have noneeverything this book taught in reverse: become the index for a day

The tutorial's arc: build distribution archives from your project, then twine upload dist/* to the index.

Its two cautions: try TestPyPI first, and pick a name that does not conflict with other people's uploads.

Honesty note: not run here, no account exists on this machine. Every step shown is quoted from the tutorial, not improvised.

RUN IT THIS WEEK

Walk the tutorial once against TestPyPI with a throwaway name; delete nothing, learn everything.

Index

Index


pip freeze7
pip, the installer4
Publishing to PyPI10
python -m venv5
The PEP 668 refusal6
The pip cache9
Wheels8