Kennisbank › Python › pip on Python: Installing, Pinning and Cleaning Up Packages
python starter 05 October 2026

pip on Python: Installing, Pinning and Cleaning Up Packages

pip on Python: Installing, Pinning and Cleaning Up Packages `pip --version` is the first command you run on a fresh Python install, and what it prints decides

This article covers pip as it behaves on a current Linux server: installing packages from PyPI, isolating them per project, pinning versions, and cleaning up when something breaks. It assumes you have shell access and Python 3 already on the box.

Requirements

  • Python 3.8 or newer. Python 2.7 is end-of-life since January 2020 and pip dropped support for it in version 21.0.
  • pip 23.1 or newer. The dependency resolver introduced in pip 20.3 is the one you want; older versions will happily install conflicting packages without warning.
  • Write access to the target Python environment, or `sudo` if you are installing system-wide.
  • Network access to `pypi.org` and `files.pythonhosted.org` over HTTPS.
Check what you have before touching anything:

```bash python3 --version pip3 --version ```

On Debian and Ubuntu, `pip` and `pip3` are separate binaries. `pip` historically pointed at Python 2, `pip3` at Python 3. Since Python 2 is gone from most current distros, `pip3` is the safe spelling. If both resolve to the same Python 3 interpreter on your system, that is fine — but do not assume it.

Why the system Python is the wrong place to install

Every package you `pip install` into the system interpreter lands in `/usr/lib/python3/dist-packages` or `/usr/local/lib/python3.x/site-packages`, shared by every script and service on the machine.

Two projects that need different versions of `requests` cannot coexist there. One of them breaks. On a server running multiple Python services, this is not a hypothetical — it is a Tuesday.

The fix is a virtual environment per project. It costs you an extra directory and one activation command. It buys you isolation, reproducibility, and the ability to delete a project by deleting a folder.

Steps

1. Verify pip is present and current

```bash python3 -m pip --version ```

Using `python3 -m pip` instead of bare `pip` guarantees you are talking to the pip that belongs to that Python interpreter. When multiple Pythons are installed, bare `pip` can point at a different one than `python3`, and you will spend twenty minutes wondering why your imports fail.

If pip is missing or too old:

```bash python3 -m ensurepip --upgrade python3 -m pip install --upgrade pip ```

`ensurepip` ships with CPython since 3.4, so it works offline. The upgrade pulls from PyPI and needs network access.

2. Create a virtual environment

```bash python3 -m venv /srv/myproject/venv source /srv/myproject/venv/bin/activate ```

The `venv` module is part of the standard library. You do not need `virtualenv` unless you are on Python 3.3 or older, or you need features like `--system-site-packages` handling that `venv` does not expose cleanly.

After activation, `which python` should point inside the venv. If it does not, the activation failed and every package you install from here goes to the system interpreter.

3. Upgrade pip inside the venv

```bash python -m pip install --upgrade pip ```

The pip that `venv` creates is whatever version was bundled with your Python build. On a Python 3.8 install from 2020, that is pip 20.x, which has the old resolver. Upgrading inside the venv is a separate step from step 1 because the venv starts with its own copy.

4. Install a package

```bash python -m pip install requests==2.31.0 ```

Pinning the version is not optional in production. `pip install requests` grabs whatever is newest at that moment. Tomorrow it grabs something else. Your build is now non-reproducible, and the failure will surface at the worst possible time.

pip reads the package metadata — `pyproject.toml` for modern packages, `setup.py` for older ones — resolves the dependency tree, downloads wheels or source distributions, and installs everything into `site-packages` of the active venv.

5. Install from a requirements file

```bash python -m pip install -r requirements.txt ```

A `requirements.txt` is a list of pinned packages. Generate it from a working environment:

```bash python -m pip freeze > requirements.txt ```

`pip freeze` outputs every installed package with its exact version, including transitive dependencies. That is what you want for reproducible builds. It is also noisy: it captures packages you installed for debugging and forgot about. Prune the file by hand before committing it.

6. Install from Git or a local path

```bash python -m pip install git+https://github.com/psf/requests.git@v2.31.0 python -m pip install -e /srv/myproject/src ```

The `git+https://` form clones the repository, builds the package, and installs it. Pin a tag or commit hash after the `@` — pointing at `main` means your build changes whenever upstream pushes.

The `-e` flag installs in editable mode: the package is linked, not copied, so edits to the source take effect without reinstalling. Useful during development, wrong for production.

7. Inspect what is installed

```bash python -m pip list python -m pip show requests python -m pip check ```

`pip list` gives you names and versions. `pip show requests` prints the version, dependencies, author, license, and install location for one package — the fastest way to confirm which copy of a library your code is actually importing.

`pip check` compares every installed package against its declared dependencies and reports version conflicts. Run it after any bulk install. It catches problems that `pip install` did not, because pip will happily leave an inconsistent environment alone if you did not ask it to change anything.

8. Uninstall and clean up

```bash python -m pip uninstall requests python -m pip uninstall -r requirements.txt -y ```

pip removes the package files but does not touch its dependencies. If `requests` pulled in `urllib3` and nothing else needs it, `urllib3` stays. There is no reliable automatic cleanup — pip cannot know which packages other tools depend on outside its own metadata.

The honest answer is that the cleanest way to remove a package and its orphaned dependencies is to delete the venv and rebuild it from `requirements.txt`. It takes thirty seconds and leaves no residue.

Verification

After installing, confirm the package imports in the interpreter you think you are using:

```bash python -c "import requests; print(requests.__version__)" ```

If that prints the version you pinned, the install landed in the right environment. If it raises `ModuleNotFoundError`, you installed into a different interpreter than the one running the command — check `which python` and `python -m pip --version` again.

For a full environment audit:

```bash python -m pip check python -m pip list --outdated ```

`pip check` should print nothing if the environment is consistent. `pip list --outdated` shows what has newer versions available; it does not change anything.

Common problems

`externally-managed-environment` error on Debian 12 or Ubuntu 23.04+

PEP 668 marks the system Python as externally managed. pip refuses to install into it.

```bash python3 -m venv /srv/myproject/venv source /srv/myproject/venv/bin/activate ```

Do not reach for `--break-system-packages`. It disables the guard that exists precisely to stop you from breaking `apt` and system tooling. The venv is the intended path.

Dependency resolver loops or takes minutes

pip 20.3 and later use a backtracking resolver. On large dependency graphs with conflicting constraints, it can churn. If it exceeds a minute, the constraints are probably unsatisfiable.

```bash python -m pip install --upgrade pip python -m pip install "packageA==1.2.3" "packageB==2.0.1" -v ```

The `-v` flag prints which candidates pip is trying and rejecting. That output tells you which two packages disagree. Loosen the pin on one of them, or find a version pair that works.

Installing a package fails to build from source

pip falls back to building from source when no wheel exists for your platform. That needs a compiler and headers.

```bash sudo apt install build-essential python3-dev ```

On RHEL-family systems: `sudo dnf groupinstall "Development Tools"` and `sudo dnf install python3-devel`. If the build still fails, check whether a newer version of the package ships a wheel — the maintainers may have fixed the build for your architecture.

PyPI is an open index. Anyone can upload a package, including one named `reqeusts` that looks close enough to `requests` to catch a typo. pip does not protect you from that. Pin your versions, read the package names before you hit enter, and keep your `requirements.txt` under version control — the file is the only record of what you actually meant to install.

← Terug naar kennisbank
← Terug naar kennisbank