You cloned a project and pip broke your system
You cloned a repository from GitHub. The README says "Run pip install -r requirements.txt." You type the command. pip starts downloading packages. Then it stops. The terminal prints error: externally-managed-environment. You add sudo to force it. The command succeeds. A week later, you run dnf upgrade and it crashes with an import error. You broke the system.
Fedora uses Python for core utilities. dnf, NetworkManager, SELinux tools, and firewall-cmd all run on Python. These tools expect specific versions of libraries. If you install a project dependency globally, you might upgrade cryptography or urllib3 to a version the system tools do not support. The system breaks. You need isolation.
What's actually happening
Python packages live in a directory called site-packages. The system Python has its own site-packages under /usr/lib/python3.x/site-packages. Your project has its own dependencies. If they share the same directory, a project upgrade can overwrite a library that system tools rely on. This is namespace pollution.
Virtual environments solve this by creating a separate directory tree. The tree contains a copy of the Python executable and a private site-packages. When you activate the environment, your shell modifies the PATH so that python and pip commands point to the private tree. The system Python remains untouched.
Fedora enforces this protection. The system Python is marked as externally managed. pip refuses to install packages there by default. This is PEP 668. The error message is a safety feature, not a bug. It prevents you from breaking system utilities.
Convention aside: Fedora's package manager handles system Python packages. User modifications belong in /etc/ or ~/.local/. Project modifications belong in .venv/. Never mix them. Edit /etc/ for configuration. Use .venv/ for development. Leave /usr/lib/ alone.
Read the error message. If pip complains about an externally managed environment, it is doing its job. Create a virtual environment instead of fighting the protection.
The fix
Install the Python runtime and the tools needed to manage virtual environments. Fedora provides these via dnf.
Here's how to ensure you have the Python interpreter and the virtual environment module installed.
sudo dnf install python3 python3-venv python3-pip # WHY: dnf manages system packages. python3 provides the interpreter. python3-venv adds the standard library venv module. python3-pip ensures pip is available for the system and can be copied into venvs.
Create the virtual environment in your project directory. The standard convention is to name the directory .venv. The dot prefix hides the folder from casual ls output and signals to editors and version control that this is a hidden build artifact.
Here's how to create the isolated environment and activate it.
python3 -m venv .venv # WHY: Invokes the venv module to create a directory named .venv. This directory contains a private copy of Python, pip, and a site-packages folder.
source .venv/bin/activate # WHY: Runs the activation script. This prepends .venv/bin to your PATH so python and pip commands resolve to the virtual environment binaries.
Your shell prompt usually changes to show ( .venv ) or similar. This visual cue confirms the environment is active.
Install the project dependencies. The requirements.txt file lists the packages and versions the project needs. pip reads this file and installs the packages into the virtual environment's site-packages.
Here's how to install the dependencies listed in the project's requirements file.
pip install -r docs/requirements.txt # WHY: Reads the list of packages from the file. pip downloads and installs them into the .venv directory. The system Python remains untouched.
Run pip install inside the activated environment. Never use sudo with pip in a virtual environment. The environment is owned by your user account. sudo is unnecessary and dangerous.
Verify it worked
Check that your shell is using the correct Python executable. The path must point to the .venv directory, not /usr/bin.
Here's how to confirm the active Python path and verify a dependency is installed.
which python # WHY: Prints the path to the python executable. The output should be /path/to/project/.venv/bin/python. If it shows /usr/bin/python3, the environment is not active.
pip list | grep requests # WHY: Lists installed packages and filters for requests. This confirms the dependency is present in the local environment.
If which python returns /usr/bin/python3, your environment is not active. Run source .venv/bin/activate again.
Check the path. If which python returns /usr/bin/python3, your environment is not active.
Common pitfalls
Permission denied
You see Permission denied: '/usr/lib/python3.12/site-packages'. This happens when you run pip install without a virtual environment and without --user. pip tries to write to the system directory. Your user account does not have write access.
The fix is to activate the virtual environment. If you are installing a package for personal use outside a project, use pip install --user. This installs to ~/.local/lib/python3.x/site-packages. Do not use sudo.
Externally managed environment
You see this error:
error: externally-managed-environment
This environment is externally managed.
This is PEP 668 in action. pip detects the EXTERNALLY-MANAGED file in the system Python directory. It refuses to install packages to prevent conflicts.
The fix is to create a virtual environment. Do not delete the EXTERNALLY-MANAGED file. That file protects your system.
Module not found
You run your script and see ModuleNotFoundError: No module named 'requests'. This usually means you forgot to activate the virtual environment. You installed the package in .venv, but you are running the system Python.
Run source .venv/bin/activate and try again. Alternatively, run the script using the environment's Python directly: .venv/bin/python script.py.
If you see ModuleNotFoundError, check your activation status. The error usually means you are running the system Python, not the project Python.
Multiple Python versions
Fedora provides multiple Python versions via modules. If a project requires Python 3.11 and your system defaults to 3.12, you might need to switch versions.
Run dnf module list python3 to see available streams. You can enable a different stream with dnf module enable python3:3.11. This changes the system default. Be careful. Some system tools might depend on the default version.
For development, it is often safer to install the specific version alongside the default. Run dnf install python311. Then create the environment with python3.11 -m venv .venv. This leaves the system default unchanged.
Deactivate the environment when you are done. Leaving a venv active in your shell causes confusion when you switch to a different project.
When to use this vs alternatives
Use python3 -m venv when you are developing a project with specific dependencies that might conflict with system packages.
Use pipx when you want to install a standalone Python CLI tool like black or ruff without polluting your global environment.
Use dnf install python3-<package> when you need a Python library available to system services or other system tools.
Use pip install --user when you need a package available in your shell but do not want to create a virtual environment for a single script.
Pick the tool that matches your goal. Isolation protects the system. Global tools require discipline.