wouter bolsterlee edited this page Aug 17, 2018 · 26 revisions

virtualenv

The default python layout uses virtualenv to sandbox a project's dependencies.

Add this to the .envrc:

layout python

The first time the .envrc is loaded it will automatically create the virtualenv under .direnv/python-$python_version. The sandbox is also automatically activated whenever direnv loads the .envrc file (although the prompt won't change).

Restoring the PS1

The PS1 is not modified during activation as it does when doing it by hand. To restore that functionality it's possible to add something like this in your .zshrc/.bashrc:

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

If you do not add this export show_virtual_env line, when you entering a sub-bash process, the function will not be seen and some error will occur.

If using Conda instead of virtualenv, replace $VIRTUAL_ENV with $CONDA_DEFAULT_ENV.

Selecting python versions

The layout python directive will look for a python executable on the path. It's possible to specify another executable if the virtualenv needs to be created with a different one. For example: layout python ~/.pyenv/versions/2.7.6/bin/python

For python3 there is a shortcut layout python3

venv (stdlib module)

Python 3.3 and later provide built-in support for virtual environments via the venv module in the standard library. This means the virtualenv tool is no longer needed. To use venv to automatically create and activate virtual environments, add this snippet to your ~/.config/direnv/direnvrc:

layout_python-venv() {
    local python=${1:-python3}
    [[ $# -gt 0 ]] && shift
    unset PYTHONHOME
    if [[ -n $VIRTUAL_ENV ]]; then
        VIRTUAL_ENV=$(realpath "${VIRTUAL_ENV}")
    else
        local python_version
        python_version=$("$python" -c "import platform; print(platform.python_version())")
        if [[ -z $python_version ]]; then
            log_error "Could not detect Python version"
            return 1
        fi
        VIRTUAL_ENV=$PWD/.direnv/python-venv-$python_version
    fi
    export VIRTUAL_ENV
    if [[ ! -d $VIRTUAL_ENV ]]; then
        log_status "no venv found; creating $VIRTUAL_ENV"
        "$python" -m venv "$VIRTUAL_ENV"
    fi
    PATH_add "$VIRTUAL_ENV/bin"
}

Now you can use it like this in your .envrc:

layout python-venv

To specify the Python executable to use, use:

layout python-venv python3.6

(This works similar to the layout python ... that ships with direnv itself.)

To use a different directory for the virtualenv, set the $VIRTUAL_ENV variable to the desired path, which may be relative:

export VIRTUAL_ENV=.venv
layout python-venv python3.6

pyenv

It's possible to use pyenv to manage python versions and direnv to load them. For this add the following in the ~/.direnvrc file:

use_python() {
  local python_root=$PYENV_ROOT/versions/$1
  load_prefix "$python_root"
  if [[ -x "$python_root/bin/python" ]]; then
    layout python "$python_root/bin/python"
  else
    echo "Error: $python_root/bin/python can't be executed."
    exit
  fi
}

Using pyenv, install a couple of versions.

Then in any project's .envrc: use python 2.6.7

pyenv-virtualenv

It's possible to use pyenv-virtualenv to manage python versions and virtualenvs, and rely on direnv to load them. For this add the following in the ~/.direnvrc (or ~/.config/direnv/direnvrc) file:

# use a certain pyenv version
use_python() {
    if [ -n "$(which pyenv)" ]; then
        local pyversion=$1
        pyenv local ${pyversion}
    fi
}

layout_virtualenv() {
    local pyversion=$1
    local pvenv=$2
    if [ -n "$(which pyenv virtualenv)" ]; then
        pyenv virtualenv --force --quiet ${pyversion} ${pvenv}-${pyversion}
    fi
    pyenv local --unset
}

layout_activate() {
    if [ -n "$(which pyenv)" ]; then
        source $PYENV_ROOT/versions/$1/bin/activate
    fi
}

Using pyenv, install a couple of versions.

Then in any project's .envrc:

# -*- mode: sh; -*-
# (rootdir)/.envrc : direnv configuration file
# see https://direnv.net/
# pyversion=$(head .python-version)
# pvenv=$(head     .python-virtualenv)
pyversion=2.7.14
pvenv=myproject

use python ${pyversion}
# Create the virtualenv if not yet done
layout virtualenv ${pyversion} ${pvenv}
# activate it
layout activate ${pvenv}-${pyversion}

You can replace your myproject above with: pvenv=$(basename $PWD) to default to the base name of the current path. I use a BASH function to drop the contents of this into the .envrc in $CWD so I have less setup/editing files.

virtualenvwrapper

You can define a new layouts in your ~/.direnvrc file to activate a virtual environment automatically.

Add this to your ~/.direnvrc file:

layout_virtualenv() {
  local venv_path="$1"
  source ${venv_path}/bin/activate
}

layout_virtualenvwrapper() {
  local venv_path="${WORKON_HOME}/$1"
  layout_virtualenv $venv_path
}

and use it like this in .envrc of project folder:

layout virtualenv /path/to/my-awesome-project

or

layout virtualenvwrapper my-awesome-project

pipenv

$ echo layout_pipenv >> .envrc

Or more generally, in the .envrc:

layout_pipenv

anaconda

It's possible to use anaconda for virtual environments. For this add the following in the ~/.direnvrc (or ~/.config/direnv/direnvrc) file:

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;
}

Then specify anaconda in your .envrc with:

layout anaconda root

or

layout anaconda

to activate an environment specified in environment.yml.

pycharm editor support

Using direnv with Pycharm explained...

You can use direnv to create your local virtualenv following normal means: echo "layout python3" > .envrc

But certain editors that look for local .env, env or venv will not find .direnv/python-x.x.x/. You can however create a soft link. Pycharm will automatically find and use the local environment.

echo "ln -s .direnv/\$(basename \$VIRTUAL_ENV)/ .env" >> .envrc

Shared my entire setup for this in a gist.

You can’t perform that action at this time.
You signed in with another tab or window. Reload to refresh your session. You signed out in another tab or window. Reload to refresh your session.
Press h to open a hovercard with more details.