Pyenv and VirtualEnv
pyenv allows you to install and switch between multiple Python versions on the same machine without touching the system Python. pyenv-virtualenv extends this with virtual environment management, so each project can have its own isolated set of packages.
Installation
% which pyenv
pyenv not found
% brew install pyenv pyenv-virtualenv
Updating Homebrew...
...
To enable auto-activation add to your profile:
if which pyenv-virtualenv-init > /dev/null; then eval "$(pyenv virtualenv-init -)"; fi
% which pyenv
/usr/local/bin/pyenv
% pyenv --version
pyenv 2.0.0
Shell Configuration
pyenv works by placing shim executables at the front of $PATH. When we run "python", the shim intercepts the call and delegates to whichever Python version pyenv has been told to use. For this to work, pyenv directories must appear before system directories in $PATH, and pyenv must initialise on every shell startup.
Let's run pyenv init to see what it recommends:
% pyenv init
# Load pyenv automatically by appending the following to ~/.zprofile (for login shells) and ~/.zshrc (for interactive shells) :
export PYENV_ROOT="$HOME/.pyenv"
command -v pyenv >/dev/null || export PATH="$PYENV_ROOT/bin:$PATH"
eval "$(pyenv init -)"
# Restart your shell for the changes to take effect.
We can add these lines to both ~/.zprofile (login shells) and ~/.zshrc (interactive shells) using echo command. We also add eval "$(pyenv virtualenv-init -) to ~/.zshrc for auto-activation of virtualenv whenever we enter respective directories:
% echo 'export PYENV_ROOT="$HOME/.pyenv"' >> ~/.zprofile
% echo '[[ -d $PYENV_ROOT/bin ]] && export PATH="$PYENV_ROOT/bin:$PATH"' >> ~/.zprofile
% echo 'eval "$(pyenv init - zsh)"' >> ~/.zprofile
% 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
% echo 'eval "$(pyenv virtualenv-init -)"' >> ~/.zshrc
After Closing and reopening the terminal (or running exec zsh):
% echo $PATH
/Users/username/.pyenv/shims:/Users/username/.pyenv/bin:/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin
The pyenv directories now appear before system directories — pyenv-managed Pythons will take priority.
Note: If pyenv paths are not at the front of $PATH, we need to ensure the configuration was added to ~/.zprofile (not just ~/.zshrc) and that we have closed and opened a new terminal window.
