Tmux And Venv

23 Feb 2020   software

I spent the better part of this morning learning about Python package management:

Some useful links:

After a few hours of research, here are the commands I ran to configure a new project:

# Install Python3.8 and venv - one time thing
sudo apt-get install python3.8 python3.8-venv

# Initialize a new project folder
mkdir ~/project
cd ~/project
git init

# Call the venv module to create a new virtual
# environment in a subdirectory called 'venv'
python3.8 -m venv venv

# Don't track the virtual environment
echo venv >> .gitignore

With everything set up, installing dependencies is as easy as:

source venv/bin/activate
pip install ...

And export dependencies is just:

pip freeze > requirements.txt

One last thing: I noticed that new tmux panes and windows don’t inherit the virtual environment from the parent shell. Since I frequently create new panes and windows, it quickly became inconvenient to activate the virtual environment every time I did. So I added the following lines to my .bashrc:

# Activate virtual env and save the path as a tmux variable,
# so that new panes/windows can re-activate as necessary
function sv() {
    source venv/bin/activate &&
    tmux set-environment VIRTUAL_ENV $VIRTUAL_ENV
}
if [ -n "$VIRTUAL_ENV" ]; then
    source $VIRTUAL_ENV/bin/activate;
fi

Assuming I always name my project-specific virtual environments “venv” and use sv to activate them, tmux will pass the virtual environment path to new panes and windows, source my bashrc, and automatically activate - nice!

Worth mentioning: there are other solutions to the activation problem. For example, direnv lets you configure environment variables on a per-directory basis. You could use it to run activate whenever you change into project directory, and deactivate whenever you leave. For now though, the lines above are good enough for me.


25 Jan 2021

With some fiddling, I figured out how to unset the VIRTUAL_ENV variable when deactivate is run, but unfortunately it only works if it’s run from the same shell as the original command:

function sv() {
    source venv/bin/activate &&
    tmux set-environment VIRTUAL_ENV $VIRTUAL_ENV &&
    alias deactivate='\deactivate && tmux set-environment -u VIRTUAL_ENV && unalias deactivate'
}