Stage 3 of 6 · Lab, on the Pi over SSH · about 15 minutes
Environments
Week 3 promised the apt-versus-pip answer; here it is. The operating system has a Python of its own, and it defends it. Your projects get their own instead: a virtual environment, created once per project, activated in two keystrokes per session.
Why bare pip is refused
Try to install a library the naive way on the Pi and the system says no:
$ pip install gpiozero
error: externally-managed-environment
× This environment is externally managed
╰─> To install Python packages system-wide, try apt install python3-xyz...
If you wish to install a non-Debian-packaged Python package, create a
virtual environment using python3 -m venv path/to/venv...
This is protection, not obstruction. The OS itself is partly written in Python: system tools import from the system's package set, which apt manages with tested, matched versions. If pip could overwrite those libraries freely, one project's upgrade could break the desktop, the updater, or another project. Debian therefore marks its Python as externally managed: apt tends the system's packages, and pip is told to work inside project environments. The rule of thumb from Week 3 completes itself:
| You want | Tool | Example |
|---|---|---|
| System software, for every user | apt | sudo apt install htop |
| A Python library, for one project | pip, inside that project's venv | pip install paho-mqtt (Week 9's messaging library) |
What a venv actually is
Concretely, python3 -m venv .venv creates a folder .venv holding a copy of the interpreter's entry points and an empty site-packages for libraries. Activating it edits your current terminal's PATH so that python and pip mean this project's python and pip. Nothing is virtualized in the machine sense; delete the folder and the environment is gone, your code untouched.
Create and activate
On the Pi, over SSH. One flag matters on Raspberry Pi OS: --system-site-packages gives the venv a read-only window onto the apt-installed packages, which is where gpiozero and its pin driver already live. The official Raspberry Pi documentation recommends exactly this for GPIO work.
$ mkdir -p ~/iot/week4 && cd ~/iot/week4
$ python3 -m venv --system-site-packages .venv
$ source .venv/bin/activate
(.venv) username@lastname-pi:~/iot/week4 $ which python
/home/username/iot/week4/.venv/bin/python
- The
(.venv)prefix on the prompt is the tell: this terminal now uses the project toolbox. No prefix, no environment. - Per session: creation happens once per project;
source .venv/bin/activatehappens every time you open a new terminal to work. Forgetting it is this week's most common error, and the troubleshoot table starts there. deactivate(a command the activation added) returns the terminal to normal.
Install with pip
Inside the activated environment, pip works and installs into the project:
(.venv) $ pip list # what this environment can import (system window included)
(.venv) $ pip install cowsay # a harmless test package
(.venv) $ python -c "import cowsay; cowsay.cow('environments work')"
(.venv) $ pip uninstall -y cowsay
gpiozero needs no install today, the system window provides it; check with python -c "import gpiozero; print(gpiozero.__version__)". The habit pays off in Week 9, when pip install paho-mqtt goes into the project instead of fighting the OS.
Reproducing an environment: requirements.txt
pip freeze > requirements.txt writes the installed libraries and versions to a file; on any other machine, pip install -r requirements.txt rebuilds the set. Commit the file, not the environment: it is the environment's recipe, and the project's documentation standard ("a third party could rebuild it") will require one.
Environments and Git
The Week 1 .gitignore promise comes due. The .venv folder is large, machine-specific and entirely regenerable, so it never enters history; the recipe file does:
$ nano .gitignore
.venv/
__pycache__/
*.pyc
__pycache__ and *.pyc are byte-code caches Python drops beside your files as it runs; harmless, regenerable, ignored. Commit the .gitignore, then check git status stays clean of environment noise for the rest of the semester.
Read more
The mechanism in the standard library's words: the venv documentation. The workflow, pip included: the Python Packaging Guide's virtual environments and pip guide. The Pi-specific policy and the --system-site-packages advice: the Raspberry Pi OS documentation, Python section.
Checklist for this stage
Check yourself
Why does the Pi refuse pip install outside an environment?
What physically is a virtual environment, and what does activating change?
.venv) holding a private interpreter setup and its own installed libraries. Activation edits this terminal's PATH so python and pip resolve there. Deleting the folder removes the environment and nothing else.Why did our venv get --system-site-packages?
ModuleNotFoundError: No module named 'paho' in Week 9. First two things to check?
(.venv) in the prompt)? If yes, was the library installed in this environment (pip list)? Nine times out of ten it is a forgotten activation.Which of these belongs in Git: .venv/, requirements.txt, __pycache__/?
requirements.txt: the environment's recipe. The environment itself and Python's byte-code caches are regenerable machine artifacts, listed in .gitignore.