Starting with pyenv-virtualenv in macOS

There are a few plugins and programs available to support development in virtual environments with Python in macOS, but I've had most success with a combination of pyenv and pyenv-virtualenv.

Here's the approach I take. I'll assume you have Homebrew installed on your system and are running zsh for your shell. If you're in another shell, you'd at least have to replace the shell configuration file names as appropriate.


Installing pyenv and pyenv-virtualenv

Here's how I use Homebrew to install pyenv and pyenv-virtualenv:

% brew install pyenv pyenv-virtualenv

To configure your shell to use pyenv automatically as you navigate directories, you need to initialize both pyenv and pyenv-virtualenv each time you start a shell. Here's how I configured my .zshrc config file:

% echo 'eval "$(pyenv init -)"' >> ~/.zshrc
% echo 'eval "$(pyenv virtualenv-init -)"' >> ~/.zshrc

Setting the global Python version

You'll want to install the latest version of Python and set it as your global Python installation. When I wrote this, the latest Python stable release was 3.8.3:

pyenv install '3.8.3'
pyenv global '3.8.3'

Creating a new pyenv virtual environment

To create a new virtual environment, use the following syntax:

% pyenv virtualenv $(version) $(venv_name)

The version parameter is optional, if ommitted pyenv will use the global version.


Setting the virtual environment for a directory

To set the virtual environment to be used in a particular directory, simply run:

% pyenv local $(venv_name)

This command will create a .python-version file in your current working directory containing the name of the virtual environment to use.

If you're using GitHub on a solo project, consider not instinctively putting .python-version in your .gitignore file. It won't work for collaborators, who will still have to install your project requirements from a pip frozen requirements.txt file or some other setup script, but as long as your environment is still available on your machine, cloning the repository with the .python-version file already set up will make your own workflow easier.


Cleaning up a Python installation.

Your default Python installation may have gotten ugly if you haven't been using pyenv appropriately. This following shell command can help:

% pip uninstall -y -r <(pip freeze)

Using pyenv to manage PATH priority.

What about your global Python? I like to keep my system installation of python clean for macOS to use, and I like to automatically use the latest stable version of Python 3 in all my directories where I haven't set a virtual environment, which I also like to keep clean.

For my virtual environments, for production I like to use specific projects for specific environments, that way I can dump a pip freeze file with minimal fuss to distribute a Python project. However, when hacking around I keep various toolsets. One for django projects, one for flask projects, one with numpy and pandas, one with Pelican (that I use to develop this website you're on now).

If you want these various tools to be available to you in your day-to-day work flow outside of project environments, you can set your global environment to multiple pyenv environments like so:

% pyenv global 3.8.3 numpy pandas flask pelican django misc-tools system

When calling for Python modules, pyenv will look in the directories for these virtual environments in the order you've specified.