How to automatically activate virtualenvs when cd'ing into a directory

后端 未结 12 1937
北海茫月
北海茫月 2020-12-24 06:27

I have a bunch of projects in my ~/Documents. I work almost exclusively in python, so these are basically all python projects. Each one, e.g. ~/Documents/

相关标签:
12条回答
  • 2020-12-24 06:45

    Based on @MS_'s solution:

    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
    }
    
    0 讨论(0)
  • 2020-12-24 06:48

    Add following in your .bashrc or .zshrc

    function cd() {
      builtin cd "$@"
    
      if [[ -z "$VIRTUAL_ENV" ]] ; then
        ## If env folder is found then activate the vitualenv
          if [[ -d ./.env ]] ; then
            source ./.env/bin/activate
          fi
      else
        ## 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
    }
    

    This code will not deactivate the virtualenv even if someone goes into subfolder. Inspired by answers of @agnul and @Gilles.

    If the virtualenv is made by pipenv, then please consider this wiki page.

    Furthermore, for added security please consider direnv.

    0 讨论(0)
  • 2020-12-24 06:50

    This is my solution, which:

    • checks if already at the currently active venv, and do nothing in that case
    • if there is a venv folder, deactivate the active one if there is one
    • activate the new venv whatever if there was an old one or not.

    In my 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
    }
    
    0 讨论(0)
  • 2020-12-24 06:52

    Rather than writing a custom script you could use direnv. It's not a zsh specific solution (for that you could try zsh-autoenv), but is well-maintained and easy to use with zsh. Once you've installed it, you'd want to put eval "$(direnv hook zsh)" at the end of your .zshrc. At that point you can do:

    $ 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
    

    Now you should be in your virtualenv. You can test by running pip freeze to see that your virtualenv specific packages are installed. To deactivate

    $ cd ..
    direnv: unloading
    
    0 讨论(0)
  • 2020-12-24 06:52

    For posterity: I used @MS_'s solution but ran into the problem where cding directly from one project to another deactivates the old virtualenv but doesn't activate the new one. This is a slightly modified version of that solution which solves this problem:

    # 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
    }
    
    0 讨论(0)
  • 2020-12-24 06:57

    Here is (yet) another solution to automatically activate a virtual environment; it's based on a number of the answers already posted here.

    This will work for any Virtual Environment name or directory (not just ./env, ./venv, etc.). Also supports subdirectories, as well as cd-ing into symlinks of virtual environment (parent) folders.

    This code searches for a pyvenv.cfg file instead of a particular named directory. If one is found within a subdirectory of the current folder, the environment is automatically activated. Once inside a virtual environment, that state is retained until you move out of the parent virtual environment directory, at which point the environment is deactivated.

    Place this inside your .bashrc or .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
    }
    

    Personally I think it's an improvement on a lot of the solutions here, since it should work for any virtual environment

    0 讨论(0)
提交回复
热议问题