如何在进入目录时自动激活virtualenvs

时间:2017-07-20 13:48:00

标签: virtualenv zsh virtualenvwrapper oh-my-zsh

我的~/Documents中有很多项目。我几乎只在python中工作,所以这些基本上都是python项目。每一个,例如~/Documents/foo有自己的virtualenv,~/Documents/foo/venv(他们总是被称为venv)。每当我在项目之间切换时,每天约10次,我就

deactivate
cd ..
cd foo
source venv/bin/activate

我已经到了忘记输入deactivatesource venv/bin/activate的地步。 我正在寻找一种只需cd ../foo的方法,并为我处理virtualenv操作。

  • 我很熟悉VirtualEnvWrapper,在我看来这有点笨拙。它似乎将你所有的virtualenvs移动到其他地方,并且据我所知,增加了一些复杂程度。 (欢迎反对意见!)

  • 我对shell脚本不太熟悉。如果你可以推荐一个低维护的脚本添加到我的~/.zshrc来完成这个,那就足够了,但是从一些快速的谷歌搜索,我还没有找到这样的脚本。

  • 我是zsh / oh-my-zsh用户。 oh-my-zsh似乎没有插件。这个问题的最佳答案是有人提供oh-my-zsh插件来执行此操作。 (如果这里的答案黯淡无光,我可能会这样做。

14 个答案:

答案 0 :(得分:8)

在.bashrc或.zshrc中添加以下内容

const myObjectArray = template.map(t => new t(model));

即使有人进入子文件夹,此代码也不会停用virtualenv。灵感来自@agnul@Gilles的答案。

此外,为了增加安全性,请考虑direnv

答案 1 :(得分:5)

在你的.zshrc

中加入这样的东西
function cd() {
  if [[ -d ./venv ]] ; then
    deactivate
  fi

  builtin cd $1

  if [[ -d ./venv ]] ; then
    . ./venv/bin/activate
  fi
}

修改:正如评论cd中所述 - 进入当前虚拟环境的子文件夹会停用它。一个想法可能是仅在cd成为新的env时停用当前的env,例如

function cd() {
  builtin cd $1

  if [[ -n "$VIRTUAL_ENV" && -d ./venv ]] ; then
    deactivate
    . ./venv/bin/activate
  fi
}

仍然可以改进,可能会把它变成一个“提示命令”或文件夹名称上的attempting some prefix matching来检查路径上的某个虚拟环境,但我的shell-fu还不够好。 / p>

答案 2 :(得分:3)

您可以使用direnv而不是编写自定义脚本。它不是特定于zsh的解决方案(为此,您可以尝试zsh-autoenv),但是维护良好且易于与zsh一起使用。安装后,您需要将eval "$(direnv hook zsh)"放在.zshrc的末尾。此时,您可以执行以下操作:

$ source ~/.zshrc
$ cd foo
$ echo "layout python" > .envrc
direnv: error .envrc is blocked. Run `direnv allow` to approve its content.
$ direnv allow
direnv: loading .envrc
direnv: export +VIRTUAL_ENV ~PATH

现在您应该在virtualenv中。您可以通过运行pip freeze进行测试以查看是否已安装特定于virtualenv的软件包。停用

$ cd ..
direnv: unloading

答案 3 :(得分:2)

如果没有autoenv,则应尝试类似direnv的操作。

第一个是“ 轻量级”,而第二个是“ 简单,高质量的软件”,分别听取每个作者的意见,并讨论另一个人的项目。因此,在我看来,它们都是不错的选择,两者都可以尝试!

无论如何,两者均已在zsh外壳上进行了测试。 特别是,autoenv在安装后非常易于使用:

$ git clone git://github.com/inishchith/autoenv.git ~/.autoenv
$ echo 'source ~/.autoenv/activate.sh' >> ~/.bashrc

只是“ 跟随白兔子”并尝试例如

$ mkdir project
$ echo "echo 'whoa'" > project/.env
$ cd project
whoa

”如果目录包含.env文件,则当您cd进入目录时,它将自动执行。启用后(将AUTOENV_ENABLE_LEAVE设置为非空字符串),如果目录包含一个.env.leave文件,当您离开该文件时,它将自动执行。”

请查看https://github.com/inishchith/autoenv以获得更详细的说明!...

答案 4 :(得分:1)

最远的一种选择(在2019年以后)是在您的virtualenvwrapper ~/.zshrc

中添加plugins

例如:

plugins=(
  git pip python brew virtualenvwrapper
)

答案 5 :(得分:1)

对于任何使用(或考虑使用)pyenv 的人来说,使用 pyenv-virtualenv 中描述的 here 插件可以非常方便地实现这一点。

基本上,您只需将 .python-version 文件添加到指定 virtualenv 名称的目录中。

答案 6 :(得分:0)

这是我的解决方案,

  • 检查是否已经在当前处于活动状态的venv上,在这种情况下什么也不做
  • 如果有一个venv文件夹,如果有一个,则停用活动文件夹
  • 激活新的venv(无论是否存在旧版本)。

在我的bash_aliases中:

function cd() {
    builtin cd "$@"

    if [ $(dirname "$VIRTUAL_ENV") == $(pwd) ] ; then
        # Already at the active virtual env
        return
    fi

    if [[ -d ./venv ]] ; then
        if type deactivate > /dev/null 2>&1 ; then
            printf "Deactivating virtualenv %s\n" "$VIRTUAL_ENV"
            deactivate
        fi

        source ./venv/bin/activate
        printf "Setting up   virtualenv %s\n" "$VIRTUAL_ENV"
    fi
}

答案 7 :(得分:0)

为后人:我使用@MS_的解决方案,但遇到了一个问题,其中cd直接从一个项目迁移到另一个项目会停用旧的virtualenv,但不会激活新的virtualenv。这是解决此问题的解决方案的稍作修改的版本:

# auto activate virtualenv
# Modified solution based on https://stackoverflow.com/questions/45216663/how-to-automatically-activate-virtualenvs-when-cding-into-a-directory/56309561#56309561
function cd() {
  builtin cd "$@"

  ## Default path to virtualenv in your projects
  DEFAULT_ENV_PATH="./env"

  ## If env folder is found then activate the vitualenv
  function activate_venv() {
    if [[ -f "${DEFAULT_ENV_PATH}/bin/activate" ]] ; then 
      source "${DEFAULT_ENV_PATH}/bin/activate"
      echo "Activating ${VIRTUAL_ENV}"
    fi
  }

  if [[ -z "$VIRTUAL_ENV" ]] ; then
    activate_venv
  else
    ## check the current folder belong to earlier VIRTUAL_ENV folder
    # if yes then do nothing
    # else deactivate then run a new env folder check
      parentdir="$(dirname ${VIRTUAL_ENV})"
      if [[ "$PWD"/ != "$parentdir"/* ]] ; then
        echo "Deactivating ${VIRTUAL_ENV}"
        deactivate
        activate_venv
      fi
  fi
}

答案 8 :(得分:0)

这是没有 cd'的解决方案,并且zsh设置为setop auto_cd,您将能够在没有cd的情况下更改目录,只需键入目录名称并按Enter。 它是上述解决方案的一部分:

    # auto activate virtualenv
# Modified solution based on https://stackoverflow.com/questions/45216663/how-to-automatically-activate-virtualenvs-when-cding-into-a-directory/56309561#56309561
function auto_active_env() {

  ## Default path to virtualenv in your projects
  DEFAULT_ENV_PATH="./env"

  ## If env folder is found then activate the vitualenv
  function activate_venv() {
    if [[ -f "${DEFAULT_ENV_PATH}/bin/activate" ]] ; then 
      source "${DEFAULT_ENV_PATH}/bin/activate"
      echo "Activating ${VIRTUAL_ENV}"
    fi
  }

  if [[ -z "$VIRTUAL_ENV" ]] ; then
    activate_venv
  else
    ## check the current folder belong to earlier VIRTUAL_ENV folder
    # if yes then do nothing
    # else deactivate then run a new env folder check
      parentdir="$(dirname ${VIRTUAL_ENV})"
      if [[ "$PWD"/ != "$parentdir"/* ]] ; then
        echo "Deactivating ${VIRTUAL_ENV}"
        deactivate
        activate_venv
      fi
  fi
}
chpwd_functions=(${chpwd_functions[@]} "auto_active_env")

答案 9 :(得分:0)

(这里)是(另一个)自动激活虚拟环境的解决方案;它基于此处已经发布的许多答案。

这将适用于任何虚拟环境名称或目录(不仅仅是./env./venv等)。还支持子目录以及cd-进入虚拟环境(父)文件夹的符号链接。

此代码搜索pyvenv.cfg文件,而不是特定的命名目录。如果在当前文件夹的子目录中找到一个,则环境将自动激活。进入虚拟环境后,该状态将保留,直到您移出父虚拟环境目录为止,此时该环境将被停用。

将其放置在.bashrc.bash_profile内。

function cd() {
  builtin cd "$@"

  if [[ -z "$VIRTUAL_ENV" ]] ; then
      # If config file is found -> activate the vitual environment
      venv_cfg_filepath=$(find . -maxdepth 2 -type f -name 'pyvenv.cfg' 2> /dev/null)
      if [[ -z "$venv_cfg_filepath" ]]; then
        return # no config file found
      fi

      venv_filepath=$(cut -d '/' -f -2 <<< ${venv_cfg_filepath})
      if [[ -d "$venv_filepath" ]] ; then
        source "${venv_filepath}"/bin/activate
      fi
  else
    # If the current directory is not contained 
    # within the venv parent directory -> deactivate the venv.
      cur_dir=$(pwd -P)
      venv_dir="$(dirname "$VIRTUAL_ENV")"
      if [[ "$cur_dir"/ != "$venv_dir"/* ]] ; then
        deactivate
      fi
  fi
}

我个人认为这是对许多解决方案的改进,因为它适用于任何虚拟环境

答案 10 :(得分:0)

这是我的解决方案:

  1. 如果未设置VIRTUAL_ENV,则:
    1. 检查我们是否在虚拟环境中
    2. 如果是,则将其激活
  2. 其他(已定义VIRTUAL_ENV),请检查当前文件夹是否以$ VIRTUAL_ENV开头(删除/venv部分)并验证deactivate命令是否存在
    1. 停用环境

这是脚本:

function cd() {
  builtin cd $1

  if [[ -z "${VIRTUAL_ENV}" ]]; then
    if [[ -d ./venv && -f ./venv/bin/activate ]]; then
      source ./venv/bin/activate
    fi
  elif [[ ! "$(pwd)" == ${VIRTUAL_ENV:0:n-5}* && ! -z "$(command -v deactivate)" ]]; then
    deactivate
  fi
}

注意:您需要将其添加到.bashrc。如果不起作用,请检查您的.profile是否没有覆盖您的命令(发生在我身上)

答案 11 :(得分:0)

基于@MS_的解决方案:

function cd() {
  builtin cd "$@"

  ## If env folder is found then activate the vitualenv
  if [[ -d ./venv ]] ; then
    source ./venv/bin/activate
  fi

  if [[ -n "$VIRTUAL_ENV" ]] ; then
    ## check the current folder belong to earlier VIRTUAL_ENV folder
    # if yes then do nothing
    # else deactivate
      parentdir="$(dirname "$VIRTUAL_ENV")"
      if [[ "$PWD"/ != "$parentdir"/* ]] ; then
        deactivate
      fi
  fi
}

答案 12 :(得分:0)

这是仅zsh的解决方案。

这是对daveruinseverything's answer的改进,也是对MS_'s answer的改进。

我们使用precmd挂钩而不是覆盖cd

我们添加了另一个额外功能。假设目录结构是

├── .venv
│   ├── bin
│   │   └── activate
├── subdir
│   ├── subdir1
│   │   ├── subdir2
│   │   │   └── test2.txt
│   │   └── test1.txt
│   └── test.txt
└── testing.py

如果您现在在subdir2中打开新终端,或者直接从其他地方cd到subdir2,它将激活venv。

解决方案是:

autoload -Uz add-zsh-hook
add-zsh-hook precmd automatically_activate_python_venv

function automatically_activate_python_env() {
  if [[ -z $VIRTUAL_ENV ]] ; then
    activate_venv
  else
    parentdir="$(dirname ${VIRTUAL_ENV})"
    if [[ "$PWD"/ != "$parentdir"/* ]] ; then
      deactivate
      activate_venv
    fi
  fi
}

function activate_venv() {  
  local d n
  d=$PWD
  
  until false 
  do 
  if [[ -f $d/.venv/bin/activate ]] ; then 
    source $d/.venv/bin/activate
    break
  fi
    d=${d%/*}
    # d="$(dirname "$d")"
    [[ $d = *\/* ]] || break
  done
}

答案 13 :(得分:0)

对于像我这样的 python 开发人员,我使用 this plugin 来创建、激活 python 虚拟环境,当 cd 进入 python 项目时,它也会在 cd 进入另一个目录后停用。

目前它有一个小错误,您的 ZSH 主题在停用后会恢复为默认值,并且有一个修补程序。