You just broke your system Python
You cloned a repository, ran pip install -r requirements.txt, and suddenly your system tools stopped working. dnf complains about a missing Python module. firewall-cmd throws an import error. You accidentally ran pip install without activating an environment, and the system Python interpreter is now tangled with project dependencies. This happens more often than you think. Fedora ships with a carefully curated system Python that powers core utilities. Mixing project packages into that global space breaks things fast. The fix is isolation. You create a self-contained directory that holds its own interpreter, its own pip, and its own package cache. When you step into that directory, your shell points to the isolated environment. When you step out, the system returns to normal.
What isolation actually does
Python does not isolate packages by default. Every pip install writes wheels and metadata to a single global directory. That design made sense when Python was a scripting language for a single user. It breaks down when your laptop runs both a web scraper and a desktop environment that relies on python3-gobject. Virtual environments solve this by copying the Python executable into a local folder and redirecting the sys.prefix and sys.exec_prefix paths. The interpreter still runs from the system, but it looks for libraries inside the environment folder first. Think of it like a sandboxed container that only shares the kernel. The environment gets its own bin/, lib/, and include/ directories. Nothing leaks out unless you explicitly copy it.
Fedora treats the system Python as a protected resource. The package manager manages it. Your projects should never touch it. The python3 package in the Fedora repositories is split into runtime and development components. The runtime package provides the interpreter and standard library. The development package provides headers for compiling C extensions. When you create a virtual environment, venv reads the system Python's configuration and generates a pyvenv.cfg file inside the new directory. That file tells the interpreter to treat the environment root as the new prefix. The import system checks site-packages inside the environment before falling back to /usr/lib/python3.x/site-packages. This fallback is intentional. It lets you use system-installed libraries like dnf or systemd bindings without reinstalling them. You only install project-specific dependencies inside the environment.
Setting up the default environment with venv
The built-in venv module is the standard. It ships with the python3 package and requires no extra dependencies. Create a project folder and initialize the environment in one step.
Here is how to create and activate a standard virtual environment.
mkdir ~/my_project && cd ~/my_project
# Create the isolated environment in a hidden directory
python3 -m venv .venv
# Activate the environment for the current shell session
source .venv/bin/activate
# Install packages into the isolated environment, not the system
pip install requests
The source command runs the activation script, which prepends .venv/bin to your $PATH. Your shell prompt changes to show the environment name. Every subsequent python or pip command targets the isolated directory. The python3 -m venv syntax is preferred over calling venv directly because it guarantees you are using the exact Python interpreter that matches your system version. If you skip the -m flag and type venv, you might accidentally invoke a user-installed wrapper that points to a different Python release. Stick to the module invocation. It is deterministic.
You do not need sudo for any of this. Virtual environments live in your home directory or project root. Running them as root breaks ownership tracking and triggers unnecessary permission errors later. Keep the environment unprivileged. Fedora's packaging model expects user-space tools to run without elevated privileges. The system handles /usr/lib. You handle ~/.local and project directories. Respect that boundary.
Verifying the isolation
Confirmation takes two commands. Check where the interpreter lives and verify that pip points to the correct package directory.
Run these checks to confirm isolation is active.
# Show the full path of the running Python executable
which python
# List installed packages and verify they live inside .venv
pip list
The output of which python must point to ~/my_project/.venv/bin/python. If it points to /usr/bin/python3, the environment is not active. The pip list output should show only the packages you installed inside the environment. setuptools and pip themselves will appear, which is normal. They are bundled by venv to bootstrap the environment. When you are finished working, run deactivate to restore your original $PATH. The prompt returns to normal. The system Python is untouched.
Export your dependencies before closing the session. This creates a reproducible snapshot of the environment.
Capture the exact package versions for later restoration.
# Write installed packages and their pinned versions to a text file
pip freeze > requirements.txt
# Exit the virtual environment and restore the system path
deactivate
Commit requirements.txt to version control. Do not commit the .venv directory. Add .venv/ to your .gitignore. The environment is reproducible. The requirements file is the source of truth. Future you will thank you when you clone the repository on a fresh machine and run a single install command.
When to reach for virtualenv or pipenv
You will encounter virtualenv and pipenv in tutorials and older project documentation. They solve different problems. Choose the right tool based on your workflow.
Use venv when you want a lightweight, dependency-free environment that matches the system Python exactly. Use virtualenv when you need to create environments for Python versions that are not installed on the host system. Use pipenv when you want automatic environment creation combined with a Pipfile and lock file for reproducible dependency resolution. Use conda or mamba when you are working with scientific computing stacks that require compiled C or Fortran libraries outside the Python ecosystem.
virtualenv is faster than venv because it uses symlinks instead of copying files. It also supports creating environments for Python interpreters that live outside the default /usr/bin path. Install it through the package manager and invoke it with the -p flag to target a specific version.
Here is how to create an environment with virtualenv targeting a specific interpreter.
# Install the virtualenv package from Fedora repositories
sudo dnf install python3-virtualenv
# Create an environment using a specific Python version
virtualenv -p python3.11 my_env
# Activate the newly created environment
source my_env/bin/activate
pipenv wraps pip and virtualenv into a single command. It generates a Pipfile for human-readable dependencies and a Pipfile.lock for exact version pinning. This matches the workflow of tools like npm or cargo. Install it globally and run pipenv install to trigger automatic environment creation.
Here is how to initialize a project with pipenv.
# Install pipenv from the Fedora package manager
sudo dnf install python3-pipenv
# Install a package and automatically create the virtual environment
pipenv install flask
# Drop into the managed shell session
pipenv shell
The lock file prevents dependency drift across machines. If you commit Pipfile.lock to version control, every developer gets the exact same package versions. venv leaves dependency tracking to you. You manage requirements.txt manually. Pick the tool that matches your team's expectations.
Common pitfalls and what the errors look like
Isolation fails when paths leak or permissions block execution. The most common error appears when you try to run a script inside the environment and the system refuses to execute it.
bash: .venv/bin/python: Permission denied
This usually means the environment was created with sudo, which changed the ownership of the bin/ directory to root. Your regular user account cannot execute the files. Delete the .venv folder and recreate it without sudo. Never run virtual environment commands as root. The package manager handles system-level Python. Your user account handles project-level Python.
Another frequent issue involves missing development headers. You run pip install psycopg2 or pip install cryptography and the build process crashes with a compiler error. The error mentions Python.h or openssl/ssl.h. Fedora splits Python into runtime and development packages. The python3 package provides the interpreter. The python3-devel package provides the headers required to compile C extensions.
Install the development package before building native extensions.
# Install headers and static libraries required for compiling Python C extensions
sudo dnf install python3-devel
# Retry the package installation inside the activated environment
pip install cryptography
SELinux occasionally blocks execution if you move an environment to a non-standard location like /srv or /opt. The security context expects Python scripts to live in user home directories or standard project paths. If you see an avc: denied message in the audit log, check the context with ls -Z. The files should carry user_home_t or usr_t. If you must store environments in a custom directory, apply the correct context recursively.
Apply the correct SELinux context to a custom environment directory.
# Restore default security contexts for the environment directory
sudo restorecon -Rv /opt/my_project/.venv
# Verify the context matches standard user project files
ls -Z /opt/my_project/.venv/bin/python
Do not disable SELinux to fix virtual environment errors. The denial is protecting the system from untrusted scripts. Adjust the context or move the environment to your home directory. The system Python remains secure.
Fedora updates the system Python regularly through dnf upgrade --refresh. This command pulls the latest security patches and bug fixes from the repositories. Your virtual environments do not automatically inherit these updates. They are frozen at the time of creation. If a critical Python security patch drops, recreate the environment with python3 -m venv .venv and reinstall your dependencies. The old environment stays on disk until you delete it. You can keep it as a fallback while you verify the new one.
Deactivate before you commit. Leaving an environment active while running git or make can cause accidental path pollution. Trust the package manager. Manual file edits drift, snapshots stay.