Benjamin Patch

Guides for Building Ethical & Impactful AI Software

Simple Python Virtual Environments: Linux and Mac

Written by Benjamin Patch

Published:

Last updated:


Python is the most widely used programming language for projects involving artificial intelligence and machine learning. But regardless of what you use Python for, virtual environments are critical to essentially all development workflows. In this guide, you will learn why virtual environments are important and how to create and manage them.

Specifically, we will cover the installation, configuration, and basic use of pyenv to manage numerous versions of Python on your system. We will also explain how to use venv to create, activate, deactivate, and remove virtual Python environments. Finally, we will cover the management of external dependencies with pip.

The combination of these three tools will help us create simple, clean, and flexible virtual environments for a wide range of Python projects. Let’s walk through the process together.

Why Virtual Environments?

It is best practice to create virtual environments to isolate project dependencies from the global Python installation and other projects. Imagine a situation where you are working on one project that is targeting the most recent version of Python and external packages. But you also inherited another project from other developers who wrote the code years ago for a much older version of Python and external packages.

By isolating the development environments for each of these projects, you can prevent conflicts between them and ensure each project runs with the specific version of Python and external packages it requires. Plus, you can quickly swap out versions of Python and dependencies to see if it leads to any problems.

Perhaps that old project only needs a few minor tweaks to run in modern environments. Maybe it will become more performant and secure with the upgrade. Virtual development environments can help you find out.

A Note for My Windows Friends

This guide is written for setting up virtual environments on Linux and macOS because that is where I spend most of my time. While some of these tools will work on Windows, it is not recommended. As noted in the documentation for the first tool we will be discussing, pyenv:

pyenv does not officially support Windows and does not work in Windows outside the Windows Subsystem for Linux. Moreover, even there, the Pythons it installs are not native Windows versions but rather Linux versions running in a virtual machine -- so you won't get Windows-specific functionality.

If you're in Windows, we recommend using @kirankotari's pyenv-win fork -- which does install native Windows Python versions.

After pyenv-win is installed and running Python on your Windows machine, you should be able to join us later in this guide in the Use venv to Create Virtual Environments section since everything after that is done within Python itself.

Just keep in mind the syntax differences between running Python commands on Windows as compared to Linux and macOS. For example:

python3 --version # run Python commands on Linux and macOS
py --version      # run the same Python command on Windows

Install pyenv

pyenv is the gold standard for managing multiple Python versions on your system. It allows you to easily install and switch between different Python interpreters globally or on a per-project level. It is simple, unobtrusive, and follows the UNIX tradition of single-purpose tools that do one thing well. Let's start by getting pyenv installed.

Linux

On your Linux distro of choice, run the following terminal command:

curl -fsSL <https://pyenv.run> | bash

macOS

On macOS, the Linux command above should work but using the Homebrew package manager is recommended by the developers of pyenv.

If you don't already have Homebrew running on your Mac, then please follow the installation instructions from Homebrew's documentation.

With Homebrew installed on your Mac, run the following terminal commands to update Homebrew itself and install pyenv:

brew update
brew install pyenv

Windows

As noted above, this guide is written for Linux and macOS. Windows users are encouraged to use pyenv-win instead. Detailed installation and usage instructions can be found in that project's documentation.


Shell Configurations

With pyenv installed, it now needs to be configured for your terminal’s shell. This guide covers the three most common shells: Bash, Zsh, and Fish. If you are not sure which shell your system is using, run:

echo $0

And it will tell you. Then follow the steps outlined in the appropriate section below.

To learn more about shells, please see this informative article from TheLinuxCode: Linux Shells for Beginners – Bash, Zsh, and Fish Explained and Compared.

Bash

Bash (Bourne Again SHell) ships as the default shell on most Linux distros and older Macs.

If you are not using Bash, please skip this section.

Stock Bash startup files vary widely between Linux distributions. So, the most reliable way to get pyenv working in all environments is to append configuration commands to both .bashrc (for interactive shells) and the profile file that Bash would use (for login shells).

First, add the following commands to ~/.bashrc by running the following in your terminal:

echo 'export PYENV_ROOT="$HOME/.pyenv"' >> ~/.bashrc
echo '[[ -d $PYENV_ROOT/bin ]] && export PATH="$PYENV_ROOT/bin:$PATH"' >> ~/.bashrc
echo 'eval "$(pyenv init - bash)"' >> ~/.bashrc

Then, if you have ~/.profile, ~/.bash_profile or ~/.bash_login, add the commands there as well. If you have none of these, create a ~/.profile and add the commands there.

Run for ~/.profile:

echo 'export PYENV_ROOT="$HOME/.pyenv"' >> ~/.profile
echo '[[ -d $PYENV_ROOT/bin ]] && export PATH="$PYENV_ROOT/bin:$PATH"' >> ~/.profile
echo 'eval "$(pyenv init - bash)"' >> ~/.profile

Run for ~/.bash_profile:

echo 'export PYENV_ROOT="$HOME/.pyenv"' >> ~/.bash_profile
echo '[[ -d $PYENV_ROOT/bin ]] && export PATH="$PYENV_ROOT/bin:$PATH"' >> ~/.bash_profile
echo 'eval "$(pyenv init - bash)"' >> ~/.bash_profile

Zsh

Zsh (Z SHell) ships as the default shell on newer Macs and a few Linux distros. But if desired, virtually any Linux distro can be configured to run Zsh.

If you are not using Zsh, please skip this section.

For Zsh shells, run:

  echo 'export PYENV_ROOT="$HOME/.pyenv"' >> ~/.zshrc
  echo '[[ -d $PYENV_ROOT/bin ]] && export PATH="$PYENV_ROOT/bin:$PATH"' >> ~/.zshrc
  echo 'eval "$(pyenv init - zsh)"' >> ~/.zshrc

Fish

As far as I know, Fish (Friendly Interactive Shell) does not ship as the default shell on any major Linux distros or macOS. It must be installed manually.

If you are not using Fish, please skip this section.

If you have Fish 3.2.0 or newer, execute this interactively:

set -Ux PYENV_ROOT $HOME/.pyenv
fish_add_path $PYENV_ROOT/bin

Otherwise, execute this snippet:

set -Ux PYENV_ROOT $HOME/.pyenv
set -U fish_user_paths $PYENV_ROOT/bin $fish_user_paths

Finally, add this to ~/.config/fish/config.fish:

pyenv init - fish | source

Restart Your Shell

Regardless of which shell you are using, for the PATH changes to take effect, the shell must restart:

exec "$SHELL"

Install Python Build Dependencies

pyenv will try its best to download and compile the desired Python version. Still, sometimes the compilation fails because of unmet system dependencies, or the compilation succeeds but the new Python version exhibits strange failures at runtime. The following instructions are the developer's recommendations for a sane build environment.

Please only apply the following instructions for your OS and skip the others.

macOS

If you haven't already done so, please install Xcode Command Line Tools (xcode-select --install) and Homebrew. Then run:

brew update
brew install openssl readline sqlite3 xz zlib tcl-tk@8

Fedora 22+

sudo dnf install make gcc patch zlib-devel bzip2 bzip2-devel readline-devel sqlite sqlite-devel openssl-devel tk-devel libffi-devel xz-devel libuuid-devel gdbm-libs libnsl2

Fedora Silverblue

toolbox enter
sudo dnf update vte-profile  # <https://github.com/containers/toolbox/issues/390>
sudo dnf install "@Development Tools" zlib-devel bzip2 bzip2-devel readline-devel sqlite \\
sqlite-devel openssl-devel xz xz-devel libffi-devel findutils tk-devel

Ubuntu / Debian / Mint

sudo apt update; sudo apt install build-essential libssl-dev zlib1g-dev \\
libbz2-dev libreadline-dev libsqlite3-dev curl git \\
libncursesw5-dev xz-utils tk-dev libxml2-dev libxmlsec1-dev libffi-dev liblzma-dev

If your OS is not listed here, please see the complete documentation of suggested build environments from the developers of pyenv itself.


List and Install Python Versions with pyenv

With your shell configured and Python build dependencies installed, let’s now ask pyenv to list all Python versions it knows about. This is a long list, so you might want to use a regular expression to narrow it down.

In this case, we are asking for a list of all available Python versions from 3.12 to 3.14:

pyenv install --list | grep "3\\.1[234]"

Once you have found your desired version(s) of Python, it/they can be installed with a single command:

pyenv install 3.13.1 # installs Python version 3.13.1
pyenv install 3.9.17 # installs Python version 3.9.17

Allow the installation(s) to complete.

Repeat for additional Python versions if needed.

Verify Installation(s)

This command will list the versions of Python pyenv has access to on your system. It also tells you which version is currently used by default.

pyenv versions

The * indicates which version is set to run by default. For example:

* system (set by /path/to/your/.pyenv/version)
  3.13.1
  3.9.17

Set a Global or Local Python Version

If desired, you can make this new version of Python the global or local default.

pyenv global 3.13.1  # set a global default
# OR
pyenv local 3.9.17   # set for a specific project directory

Run pyenv versions again, and you will see the output has changed to your selected version of Python. For example:

  system
* 3.13.1 (set by /path/to/your/.pyenv/version)
  3.9.17

Return to System Python

If you want to return to your system's stock version of Python, just run:

pyenv global system

Uninstall a Particular Python Version

To remove a specific version of Python from pyenv, simply run:

pyenv uninstall 3.9.17 # to uninstall Python version 3.9.17

Use venv to Create Virtual Environments

Advantages of venv over the older virtualenv option:

To create the virtual environment, navigate to your project directory:

cd /path/to/your/project

The command to create a new environment is as follows. This command will use the Python interpreter that pyenv has made active (either globally or locally) to create the environment.

For Linux and macOS, run:

python3 -m venv .venv[-optional-python-version-number]

This creates a new directory called .venv-3.13.1 (for example) at the top level of your project. I like to add the Python version number after .venv so it is clear exactly which version of Python this virtual environment runs.

You can choose to name this directory anything you would like. But some variant of .venv is recommended.


Activate the Virtual Environment

From the project's root directory, run:

source [your-venv-directory]/bin/activate

And your terminal should indicate the environment is now active.

Install Python Packages

With your virtual environment activated, install any Python packages your project requires:

pip install # packages required for your project

As you install Python packages, they will only run while this virtual environment is active, effectively isolating your project dependencies from the rest of your system.

Proceed to build and test your Python program as normal.

Deactivate the Virtual Environment

When you are finished with your coding session, deactivate the virtual environment with this simple command:

deactivate

If needed, you can then switch to another virtual environment running a different version of Python and/or packages to see how these new environments affect your program.

Remove a Virtual Environment

Since we created the environment in a sub-directory of our project, simply delete the .venv directory to remove the virtual environment. For example:

rm -rf /path/to/your/project/.venv-3.9.17

Go Further with venv

For more information about using venv, I recommend starting with the official documentation: venv - Creation of Virtual Environments - docs.python.org


Basic Dependency Declaration with pip

Most Python programs make use of external packages and modules. To ensure your program has the correct version of everything it needs to run properly, it’s a good idea to formally declare all dependencies in a way that can easily be updated and reproduced on another system or new virtual environment.

Fortunately, Python’s standard package manager pip makes this easy.

Generate a requirements.txt File

After our packages are installed, all we need to do is use pip to generate a requirements.txt file. This file lists all the installed packages and their versions. To do this, run:

pip freeze > requirements.txt

Anytime your dependencies change, simply re-run the command above, and requirements.txt will update.

requirements.txt can then be used to install the correct version of all dependencies in a new virtual environment or on an entirely new system by running:

pip install -r requirements.txt

Unfortunately, pip does not record the version of Python running in this environment. I recommend adding this as a note on your project’s README or other documentation so you and others have a record of the exact environment variables of when the program was built and tested.


In Summary

For managing multiple Python versions on your system while creating isolated development environments, using pyenv along with venv is the recommended and most straightforward approach. Once the virtual environment is running, using pip to create and update the requirements.txt file is a simple way to ensure all dependencies can easily be reproduced.

This guide has helped us create a simple, clean, and flexible virtual development environment.

If you found this helpful and would like me to write guides for more advanced dependency management with tools like Pipenv or Poetry, please contact me on Bluesky @benjaminpatch.com.

Thanks for reading and I wish you the best in creating and managing all of your Python virtual environments!

Additional Information and Sources