Automatic environment loading for Python projects


python
general


The cookiecutter project structure is quite popular with Python-based data science projects, which relies on virtual environments to work properly. This is due to the project’s re-usable code being kept in the src/ folder, and thus accessed as a Python module named src. This is fine as long as you only have one project, but if you have multiple, the modules will begin to clash. Hence, the need for virtual environments.

Although setting up the virtual environments is not an issue, constantly activating and de-activating them can be a pain. This is where direnv comes in, a great little tool to automate activating / deactivating environments depending on the folder you’re currently in.

Installation

direnv’s website provides a variety of ways to install it. On Linux, your package manager should work, so sudo apt-get install direnv, for example will work. If you’re on macOS, Homebrew is a quick way to install it by typing brew install direnv.

Once installed, you’ll need to add the following to your ~/.bashrc file:

eval "$(direnv hook bash)"

The precise command differs depending on your shell, so refer to the website for more details.

Setup (Anaconda)

If you’re using Anaconda, you’ll need to add support for it by making a file called ~/.direnvrc with the following inside:

layout_anaconda() {
  local ANACONDA_HOME="${HOME}/miniconda3/"
  PATH_add "$ANACONDA_HOME"/bin

  if [ -n "$1" ]; then
    # Explicit environment name from layout command.
    local env_name="$1"
    source activate ${env_name}
  elif (grep -q name: environment.yml); then
    # Detect environment name from `environment.yml` file in `.envrc` directory
    source activate `grep name: environment.yml | sed -e 's/name: //' | cut -d "'" -f 2 | cut -d '"' -f 2`
  else
    (>&2 echo No environment specified);
    exit 1;
  fi;
}

For vanilla Python installations or otherwise, refer to their wiki.

Then, in your ~/.bashrc, add the following lines to ensure the environment name is printed before your PS1 (the > or $ before your commands) at the terminal:

show_virtual_env() {
  if [ -n "$CONDA_DEFAULT_ENV" ]; then
    echo "($(basename $CONDA_DEFAULT_ENV))"
  fi
}
export show_virtual_env
PS1='$(show_virtual_env)'$PS1

The official wiki lists the export command as export -f show_virtual_env, the -f flag being for specifying a function rather than a variable. Despite it being a function, that flag leads to the function contents being printed to the terminal every time the terminal is loaded. Without it, the function still works and the function isn’t printed to the terminal.

Usage (Anaconda)

In your project folder, you’ll need two files, an .envrc and an environment.yml. The .envrc should contain the following:

layout anaconda

The environment.yml file can be generated by running conda env export > environment.yml from the terminal, assuming you’ve activated the appropriate environment for this project. Alternatively, you can create this file yourself, as only one line is important:

name: environment_name

To reload your ~/.bashrc, type source ~/.bashrc. You should then be able to cd into various project directories and have your Python virtual environments loading and unloaded according to your project!


Comments