A Beginner's Guide to UK GDPR for Web Developers: Cookies, Consent and Data Requests
October 07, 2026 - Web Development
You install a package, run your script, and everything works. A month later you open the same project and Python greets you with a wall of red text: ModuleNotFoundError, or worse, a version conflict that makes no sense. Nine times out of ten the culprit is not your code. It is where your packages ended up.
By default, pip install drops everything into one shared pile of libraries used by every Python project on your machine. Virtual environments give each project its own pile. They take about thirty seconds to set up, and they will save you hours of confusion later.
When you install a package without a virtual environment, it lands in the same folder as every other package that Python knows about. With one project on your laptop, that is fine. With four, it becomes a problem.
Suppose one project depends on an older release of a web framework, and a newer project needs the current one. There is only one copy installed, so one of them will break. You upgrade for project B and project A stops working. Downgrade for A and B falls over. This is the point at which people start blaming Python rather than their setup.
There is a second, quieter problem: you lose track of what a project actually needs. Looking at a shared package list tells you that something is installed, but not which version the project was built against, and not which packages were pulled in as dependencies of something else.
On macOS and most Linux distributions, there is a third reason to be careful. The Python that ships with the operating system is used by system tools. Modern distributions now refuse to let pip write to it at all, producing an externally managed environment error. That message is not a bug — it is the system protecting itself. The answer is a virtual environment.
Strip away the jargon and a virtual environment is just a folder. When you create one, Python sets up a directory containing its own interpreter, its own pip, and its own place to store packages. When the environment is active, the words python and pip in your terminal point at that folder instead of the system-wide installation.
Nothing is copied from your other projects. Nothing leaks out. If the environment becomes a mess, you delete the folder and build a fresh one — a genuinely useful escape hatch.
The standard tool ships with Python itself, so there is nothing to install. From your project folder:
Naming the folder .venv is a convention rather than a rule, but it is a good one: the leading dot signals that it is not source code, and the name is unlikely to clash with anything else.
A virtual environment contains thousands of files, many of them binaries built for your specific operating system. It should never go into Git. Add a line containing .venv/ to your .gitignore file before your first commit, and your collaborators will thank you.
With the environment active, pip behaves exactly as before — it just writes somewhere else. The safest habit is to call it through Python, which guarantees you are using the interpreter tied to your active environment:
python -m pip install requests
To see what is installed, use python -m pip list. To inspect a single package and its dependencies, python -m pip show requests is more informative than most people expect.
Version pinning is worth learning early. Writing python -m pip install "requests==2.31.0" installs one exact release rather than whatever is newest. For a quick experiment that does not matter. For anything you intend to deploy, it does.
If pip refuses to install and suggests adding sudo, stop. Running pip with administrator rights is how people break their system Python. Activate the environment instead, or create one if you have not.
Because the environment folder is not shared, you need another way to tell someone — or your future self — what the project needs. That is what a requirements file is for.
With the environment active, run:
python -m pip freeze > requirements.txt
This writes every installed package with its exact version into a plain text file. To rebuild the same environment elsewhere, create and activate a fresh virtual environment, then run python -m pip install -r requirements.txt. Within minutes you have a working setup, no guesswork involved.
A freeze captures everything, including packages you never asked for directly. That is excellent for reproducibility and noisy for reading. Hand-writing a short list of top-level packages — the ones you actually chose — gives a clearer picture but does not pin versions.
A common compromise is to commit a pinned requirements file for reproducibility and keep a short comment at the top explaining which packages are the direct dependencies. When you deliberately add or remove a package, regenerate the file rather than editing it by hand.
Make a folder. Run python -m venv .venv. Activate it. Install what you need with python -m pip install. Save the list with python -m pip freeze > requirements.txt. Write code, safe in the knowledge that nothing you install can disturb another project on the same machine.
That is the whole routine, and it is worth repeating until it becomes automatic. The first time a colleague clones your repository, runs a single install command and gets a working environment without asking you a single question, the effort pays for itself.
Photo: Innovalabs / Pixabay
Copyright © 2026 Wren Stack. All Right Reserved.