← home

Conda Auto Env

If you grow tired of having to manually activate your conda environment every time you switch between Python projects. Since you’re reading this, you may even have started googling for a solution that automates this process. The following zsh script aimed satisfies this objective and has served me well for the last few months now. It’s a spin-off of Christine Doig’s conda-auto-env.

#!/bin/zsh

# Automatically activates conda environments when entering directories
# containing a conda environment file. The file must be named one of
#   - env(ironment).y(a)ml
#   - requirements.y(a)ml

# Deactivates env when exciting the directory. If the env doesn't exist yet,
# offer to create it from file.

# Installation: Copy chpwd() to .zshrc or save the whole script as a file and
# source it in .zshrc, e.g. by placing it in /usr/local/bin or by symlinking
# conda_auto_env there and then adding `source conda_auto_env`.

# chpwd is a zsh hook called whenever the working directory changes.
# (http://zsh.sourceforge.net/Doc/Release/Functions.html#Hook-Functions). When
# using bash, use the environment variable `PROMPT_COMMAND` instead. This might
# have performance implications since it runs on every prompt (even empty ones),
# not just directory changes. Plus PROMPT_COMMAND makes it impossible to change
# to a different conda env while you're in a directory with an env file since
# bash will always auto-change back to that file's env.
chpwd() {
  # On Linux replace `find -E` with `f -regextype posix-extended`.
  FILE="$(find -E . -maxdepth 1 -regex '.*(env(ironment)?|requirements).ya?ml' -print -quit)"
  if [[ -e $FILE ]]; then
    ENV=$(sed -n 's/name: //p' $FILE)
    # Check if env is already active.
    if [[ $CONDA_DEFAULT_ENV != $ENV ]]; then
      conda activate $ENV
      # If env activation is unsuccessful, prompt user whether to create conda env from file.
      if [ $? -ne 0 ]; then
        while true; do
          # Read user reply into variable YorN.
          read "YorN?[conda_auto_env] Environment '$ENV' doesn't exist. Would you like to create it now? (y/n)"$'\n'
          # $'\n' for newline. https://unix.stackexchange.com/a/126316/315020
          if [ "$YorN" = "" ]; then YorN='y'; fi # interpret enter as y
          case $YorN in
              [Yy] ) echo Proceeding...
                conda env create -f $FILE
                conda activate $ENV;;
              [Nn] ) echo Exiting...; break;;
              * ) echo "Enter y for yes or n for no.";;
          esac
        done
      fi
      CONDA_ENV_ROOT="$(pwd)"
    fi
  # Deactivate env when exciting the env file's directory.
  elif [[ $PATH = */envs/* ]]    && [[ $(pwd) != $CONDA_ENV_ROOT ]]    && [[ $(pwd) != $CONDA_ENV_ROOT/* ]]
  then
    CONDA_ENV_ROOT=""
    conda deactivate
  fi
}

# Execute chpwd on shell init in case the shell launches in a conda env directory.
chpwd

To install it, either copy it to .zshrc or .zprofile or — a little cleaner — source this script in either of those files. For instance, say you have a ~/scripts directory where you keep custom scripts like this, simply run

ln -s "~/scripts/conda_auto_env" /usr/local/bin

to add this script to your path. Then append the following line to your .zshrc.

source conda_auto_env

That’s it. Now, every time you open a shell prompt in a directory that contains a conda environment file named one of [env(ironment).y(a)ml, requirements.y(a)ml], conda_auto_env will automatically read the name of the corresponding environment from that file and activate it. Similarly, when you exit that directory, the environment will be deactivated. Lastly, if the environment doesn’t exist yet when you first enter the directory, conda_auto_env will offer to create it from file.