3.2pip, virtual environments (venv) & dependency management
The essentials in 30 seconds
- Global mixes everything: two projects requiring two versions of the same package are impossible together — each project deserves its isolated environment.
- The venv + pip ritual: python -m venv .venv, activate, pip install, pip freeze > requirements.txt — the interpreter and pip then point to the venv.
- The .venv is never committed, requirements always is: pinned versions, rebuild proven by pip install -r — the project is portable.
Running mini-case — Nabil escapes version hell
Nabil, junior data analyst in Algiers, installs everything globally: his sales analysis requires a recent version of a library, but a colleague's reporting breaks as soon as he upgrades. He creates one venv per project (python -m venv .venv), activates, installs, pins with pip freeze > requirements.txt, adds .venv to .gitignore. Deleted then rebuilt via pip install -r, each project recovers exactly its versions.
This same case returns in the lesson, the diagram, the script and the 48h challenge.
1. Global chaos and the venv bubble
Python's strength is its PyPI catalogue, installed via pip (pip install pandas). But installing everything globally mixes the dependencies of all projects: project A requires one version, B another — impossible together, that is dependency hell. From the second project on, isolation is non-negotiable.
The solution is the virtual environment (venv): an isolated folder with its own Python and packages, untouched by other projects. Create it (python -m venv .venv), activate it (Windows: .venv\Scripts\activate; macOS/Linux: source .venv/bin/activate) — the prompt changes, python and pip then point to the venv. Nabil creates one venv for sales analysis, another for reporting: each lives its own life.
2. Pin, share, rebuild: requirements.txt
A venv alone is not enough: you need the contract of versions. pip freeze > requirements.txt exports dependencies and pinned versions; pip install -r requirements.txt reinstalls them identically elsewhere. The .venv folder is NEVER committed (bulky, machine-specific, via .gitignore); requirements.txt ALWAYS is (light, shareable).
Nabil's truth test: delete the .venv and rebuild it with one command — if the analysis runs, the project is portable. Check with pip list that the library is indeed in THIS venv, and select the .venv interpreter in the editor. After each addition, re-pin to keep the contract up to date.
🔎 Concrete example — Full ritual of the isolated project
Nabil isolates his sales analysis, then rebuilds it elsewhere.
python -m venv .venv
.venv\Scripts\activate
pip install requests
pip freeze > requirements.txt
deactivate
Reading: create, activate, install, pin — requirements becomes the contract.
Lesson: elsewhere, recreate the venv then pip install -r requirements.txt restores identically.
Section vocabulary
- pip
- Python's package manager: pip install name downloads and installs a library from PyPI into the active environment.
Simple example: Nabil's pip install requests in his analysis venv.
What it is not: downloading a ZIP and placing it by hand.
Reflex: always check the active venv before pip install.
- PyPI
- Central repository of third-party Python libraries: hundreds of thousands of installable packages.
Simple example: The catalogue where Nabil finds requests and pandas.
What it is not: the standard library shipped by default.
Reflex: standard first, PyPI next.
- Virtual environment (venv)
- Isolated folder with its own Python and packages, specific to one project, not interfering with others.
Simple example: Nabil's .venv sales analysis, separate from reporting.
What it is not: a global install shared by all projects.
Reflex: one venv per project, from the start.
- Activation
- Making a venv active in the terminal so python and pip point to it (modified prompt).
Simple example: Nabil's activate before each analysis session.
What it is not: working while forgetting to activate, hence in global.
Reflex: activate first, install next.
- requirements.txt
- List of dependencies and versions: pip freeze exports it, pip install -r reinstalls it identically.
Simple example: The versioned contract Nabil shares in Algiers.
What it is not: the .venv folder committed to Git.
Reflex: pin after each addition, rebuild to prove.
In practice — Isolate a project with venv and pip
- Create a venv (python -m venv .venv) then activate it; check that the terminal prompt has changed.
- Install a library (pip install requests) and check with pip list that it is in THIS venv, not global.
- Pin with pip freeze > requirements.txt; open the file and observe the pinned versions.
- Deactivate (deactivate), delete the venv, recreate it and reinstall via pip install -r requirements.txt.
Ready-to-say script — presenting your environment (30 s)
“Each project has its venv: created with python -m venv .venv, activated before any install, dependencies pinned with pip freeze into a versioned requirements.txt, .venv ignored by Git. Tested by deleting then pip install -r: identical rebuild.”
Say in review; show the activated prompt and the requirements.
Copy-paste template — venv + requirements ritual
python -m venv .venv
.venv\Scripts\activate
pip install requests
pip list
pip freeze > requirements.txt
deactivate
python -m venv .venv
.venv\Scripts\activate
pip install -r requirements.txt
Independent
One venv + one pinned requirements is enough to share the analysis friction-free.
SME in Algiers
Nabil duplicates the ritual: one sales venv, one reporting venv, zero conflicts.
Product team
Enforce ignored .venv + versioned requirements for identical installs everywhere.
Beginner
This week: one venv, one install, one freeze, one rebuild.
✓ Best practices
- Create one venv per project from the first pip install.
- Pin after each addition (freeze) and keep requirements versioned.
- Rebuild (delete + install -r) to prove reproducibility.
✗ Common pitfalls
- Installing everything globally (guaranteed version conflicts).
- Committing the .venv (useless megabytes, machine-specific).
- Sharing requirements with no pinned versions (silent drift).
Key takeaways
- pip INSTALLS from PyPI into the ACTIVE environment — check activation first.
- One VENV isolates dependencies PER PROJECT: no more version conflicts.
- requirements.txt (freeze / install -r) makes the project REPRODUCIBLE everywhere.
- .venv NEVER committed (.gitignore); requirements ALWAYS versioned, rebuilt as proof.
48h challenge — apply tomorrow
Create 1 venv, install 1 package, pin the requirements, then rebuild via install -r.
- Each project has its venv activated before install.
- My requirements pins the exact versions.
- My .venv is ignored, my rebuild works.
Frequently asked questions
Why not install everything globally, it is simpler?
Because two projects will soon require incompatible versions of the same library: that is dependency hell. One venv per project gives each exactly what it needs and makes the project shareable identically via requirements.txt.
Should the .venv folder be committed to Git?
No, never: bulky and machine-specific. Exclude it via .gitignore and share only requirements.txt — each teammate recreates their venv with pip install -r.
What do you share in Git to reproduce the environment?