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

22

97

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/foo has its own virtualenv, ~/Documents/foo/venv (they're always called venv). Whenever I switch between projects, which is ~10 times a day, I do

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

I've reached the point where I'm sick of typing deactivate and source venv/bin/activate. I'm looking for a way to just cd ../foo and have the virtualenv operations handled for me.

  • I'm familiar with VirtualEnvWrapper which is a little heavy-handed in my opinion. It seems to move all your virtualenvs somewhere else, and adds a little more complexity than it removes, as far as I can tell. (Dissenting opinions welcome!)

  • I am not too familiar with shell scripting. If you can recommend a low-maintenance script to add to my ~/.zshrc that accomplishes this, that would be more than enough, but from some quick googling, I haven't found such a script.

  • I'm a zsh/oh-my-zsh user. oh-my-zsh doesn't seem to have a plugin for this. The best answer to this question would be someone contributing an oh-my-zsh plugin which does this. (Which I might do if the answers here are lackluster.

Southwick answered 20/7, 2017 at 13:47 Comment(1)
It is not a good idea to overload "cd", the most basic executable. I recommend creating a function called cdd or ccd... that way you keep the original functionality of cd unchanged and you add the funcitonality you want at the cost of pressing twice the 'c' button (ccd) or the 'd' button (cdd).Flem
M
19

Put something like this in your .zshrc

function cd() {
  if [[ -d ./venv ]] ; then
    deactivate
  fi

  builtin cd $1

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

Edit: As noted in comments cd-ing into a subfolder of the current virtual env would deactivate it. One idea could be to deactivate the current env only if cd-ing into a new one, like

function cd() {
  builtin cd $1

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

that could still be improved, maybe turning it into a "prompt command" or attempting some prefix matching on the folder names to check there's a virtual env somewhere up the path, but my shell-fu is not good enough.

Motivate answered 20/7, 2017 at 14:14 Comment(10)
Hi @agnul. Thanks for this answer! Why . ./venv/bin/activate instead of source venv/bin/activate/ ?Southwick
"." is equivalent to "source", at least for zsh and bashMotivate
[[ -d ./venv ]] works only if current directory is the root of the project. Better test for env var: [ -n "$VIRTUAL_ENV" ].Ecosphere
As phd points out, if I cd into a subdirectory of a project with a virtualenv, I step out of the virtualenv. However, @phd's solution isn't working for me at all. Would one of you be willing to help with this? How do I stay in the virtualenv when I'm in a directory with a virtualenv anywhere above?Southwick
Still looking for an answer to this one!Southwick
is there any reason at all to run deactivate? e.g. if you exit the shell with ctr+d then won't the session be automatically closed?Cymophane
I think it should be: function cd() { builtin cd $1 if [[ -d venv ]] ; then if [[ -n "$VIRTUAL_ENV" ]] ; then deactivate fi source venv/bin/activate fi }Dafodil
This will also not switch environments when you cd from one env to another; it will only deactivate the new one, but not activate the new one.Davies
@AlexLenail this is because you cannot fix it in a couple of lines, within your .zshrc, but you need something more...look at the autoenv and direnv solutions, I provided in my answer here below ;)Schiffman
checking on $PWD value?Schiffman
C
63

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.

Chitchat answered 13/6, 2018 at 6:42 Comment(14)
just saw this doesn't work if you're in a project with venv and do cd ../other_projGantz
@Gantz For clarification: Are the names of virtual environment folder in both the projects are .env? This code assumes the folder name for virtual environment folder to be .env.Chitchat
I believe you meant ./env instead of .env in your previous comment, other than that your solution is exactly what I needed.Vishinsky
@Vishinsky I mean ./.env, i.e., .env folder in the current python project folder. So you current project virtualenv folder should be a hidden folder with name .env. Hope that helps.Chitchat
right, but your code snippet references ./env (not to be pedantic though, I was just pointing it out for clarity and to avoid confusions between the posted code and your comment)Vishinsky
@Vishinsky Thanks for pointing that out. I have the updated the code accordingly.Chitchat
note that this snippet works for virtual folders that have been named .env. If you named your folder any other name, change it in the line that says source ./.env/bin/activate. The folder name is what you specified when running mkvirtualenv venv -p python3. You can also ls your current directory to see if you can recognize what you named it.Nashom
It looks to me that cd-ing from a dir with venv to another dir with venv would run deactivate, then nothing? I expect the script to deactivate the old one, and activate the new one.Menorrhagia
@Menorrhagia simply grab the first block between the if and else (not inclusive), and put it after the second last fi.Dominick
@Dominick Yeah, I formulated it as a question, but it was more a comment. Check out my own answer.Menorrhagia
You should consider using the function chpwd instead of cd. That will work with AUTOCD too.Ilsa
I created a plugin for zsh following your reasoning, @MS_. See here: github.com/DanielAtKrypton/viper-envMaher
Is there a way to make it recognize switching between two different projects with two different virtual env names?Arsenault
Probably want to use .venv consistently to not conflict with .env files or directories for python-dotenv. Also recommended in official docs: docs.python.org/3/library/…Dolora
S
23

You should try something like autoenv if not direnv.

The first one is considered to be "lightweight", while the second one "simply, higher quality software", listening respectively to each one's author, talking about the other one's project. Thus, they seem to me fairly good options, to try both!

Anyway, both have been tested on zsh shells. In particular, autoenv is really simple to use, after installing it:

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

just "follow the white rabbit " and try for example

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

"If a directory contains a .env file, it will automatically be executed when you cd into it. When enabled (set AUTOENV_ENABLE_LEAVE to a non-null string), if a directory contains a .env.leave file, it will automatically be executed when you leave it."

Have a look at https://github.com/inishchith/autoenv for more detailed instructions!...

Schiffman answered 18/5, 2020 at 0:17 Comment(2)
Thank you for not simply recommending a library, but additionally including both an explanation as well as command line syntax. That’s a best practice on Stack Overflow, but one that many newer contributors fail to adhere to.Ephraim
I strongly agree with you (this was my very first answer, though!), with a bit more explanations, this is something similar to what @mc_kaiser already pointed out.Schiffman
M
19

Put something like this in your .zshrc

function cd() {
  if [[ -d ./venv ]] ; then
    deactivate
  fi

  builtin cd $1

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

Edit: As noted in comments cd-ing into a subfolder of the current virtual env would deactivate it. One idea could be to deactivate the current env only if cd-ing into a new one, like

function cd() {
  builtin cd $1

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

that could still be improved, maybe turning it into a "prompt command" or attempting some prefix matching on the folder names to check there's a virtual env somewhere up the path, but my shell-fu is not good enough.

Motivate answered 20/7, 2017 at 14:14 Comment(10)
Hi @agnul. Thanks for this answer! Why . ./venv/bin/activate instead of source venv/bin/activate/ ?Southwick
"." is equivalent to "source", at least for zsh and bashMotivate
[[ -d ./venv ]] works only if current directory is the root of the project. Better test for env var: [ -n "$VIRTUAL_ENV" ].Ecosphere
As phd points out, if I cd into a subdirectory of a project with a virtualenv, I step out of the virtualenv. However, @phd's solution isn't working for me at all. Would one of you be willing to help with this? How do I stay in the virtualenv when I'm in a directory with a virtualenv anywhere above?Southwick
Still looking for an answer to this one!Southwick
is there any reason at all to run deactivate? e.g. if you exit the shell with ctr+d then won't the session be automatically closed?Cymophane
I think it should be: function cd() { builtin cd $1 if [[ -d venv ]] ; then if [[ -n "$VIRTUAL_ENV" ]] ; then deactivate fi source venv/bin/activate fi }Dafodil
This will also not switch environments when you cd from one env to another; it will only deactivate the new one, but not activate the new one.Davies
@AlexLenail this is because you cannot fix it in a couple of lines, within your .zshrc, but you need something more...look at the autoenv and direnv solutions, I provided in my answer here below ;)Schiffman
checking on $PWD value?Schiffman
M
18

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
Malinowski answered 10/9, 2018 at 17:25 Comment(1)
This is the best solution IMO. One thing to note is that adding "layout python" requires the project to conform to a particular structure. See direnv.net/man/direnv-stdlib.1.html. If you structure your project slightly differently (perhaps your virtualenv lives under .venv), you could instead add the line: "PATH_add .venv/bin".Sizeable
N
14

By far the easiest option (in 2019+) is to add virtualenvwrapper into your ~/.zshrc plugins

For example:

plugins=(
  git pip python brew virtualenvwrapper
)
Nadiya answered 13/2, 2020 at 20:42 Comment(1)
github.com/ohmyzsh/ohmyzsh/tree/master/plugins/… documentation is here.Hercules
T
11

For anyone using (or considering to use) pyenv this can be achieved very conveniently using the pyenv-virtualenv plugin as described here.

Basically you simply add a .python-version file to the directory in which the name of the virtualenv is specified.

Torras answered 18/3, 2021 at 15:38 Comment(1)
I think this only works for virtualenvs that are created and managed by pyenv-virtualenv. Unless I'm mistaken, this mechanism isn't designed to pick up a local venv/ subdirectory, only venvs that are in the managed venv directory $(pyenv root)/versions, and thus were created by pyenv-virtualenv itself.Ouidaouija
S
7

This is a zsh only solution.

This is an improvement over daveruinseverything's answer which is an improvement over MS_'s answer.

We are using precmd hook instead of overwriting cd.

We have added another extra feature. Suppose the directory structure is

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

If you now open a new terminal in subdir2, or directly cd to subdir2 from other place, it will activate the venv.

The solution is:

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

function automatically_activate_python_venv() {
  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
}
Sixpack answered 18/9, 2020 at 12:37 Comment(3)
it would be great if you could evaluate the functionality of the plugin I created based on your answer. More information here. Pull requests are welcome!Maher
@DanielKaminskideSouza I am glad that someone found the code useful enough to make a plugin out of it. I am feeling very good. Thank you very much.Sixpack
your research led to I believe the best solution so far. The plugin is a continuation of your research... I just added a feature to work with any environment name and made some speed optimizations.Maher
T
5

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://mcmap.net/q/217451/-how-to-automatically-activate-virtualenvs-when-cd-39-ing-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
}
Tailrace answered 25/5, 2019 at 23:40 Comment(0)
B
4

that is the solution without cd'ing, with zsh set to setop auto_cd w'll be able to change directories without cd, just type directory name and hit enter. it is anhence of above solution:

    # auto activate virtualenv
# Modified solution based on https://mcmap.net/q/217451/-how-to-automatically-activate-virtualenvs-when-cd-39-ing-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")
Buddleia answered 15/8, 2019 at 21:34 Comment(0)
A
2

Similar to Jake's answer but supports cding from one virtualenv to another. In this case it deactivates the old virtualenv then activates the new one.

function cd() {
  builtin cd "$@"

  if [[ ! -z "$VIRTUAL_ENV" ]] ; then
    # 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

  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
  fi
}
Ascites answered 20/11, 2021 at 10:52 Comment(0)
G
2

Self promotion warning!

If you use oh-my-zsh I've forked and greatly improved (imo) a plugin that works for both bash and zsh and I included instructions for installing with oh-my-zsh

https://github.com/RobertDeRose/virtualenv-autodetect

Guanaco answered 19/3, 2023 at 4:40 Comment(0)
P
1

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

Panoptic answered 10/10, 2019 at 23:34 Comment(0)
T
1

I tried direnv as suggested by others but found it a bit too opinionated and it didn't exactly do what I wanted.

The solution below is for fish shell users only. Also, it assumes a pyproject.toml file and stdlib's venv, but that can be easily changed.

The fish shell has the concept of event handlers so you can easily define a function that gets run whenever an "event" gets triggered (Unix signals, environment variables changing, etc). See this a blog post for a quick introduction.

Add the following to your ~/.config/fish/config.fish (and modify as needed):

function venv_activate --on-variable PWD
    if test ! -e pyproject.toml
        if test -n "$VIRTUAL_ENV"
            deactivate
        end
        return
    end

    # echo "Found pyproject.toml"
    if test ! -d .venv
        # echo "Creating $(python -V) venv"
        python -m venv .venv --prompt (basename (pwd))
    end

    source .venv/bin/activate.fish
end

As a side note, the above works nicely with pyenv's .python-version files as well.

Tovatovar answered 13/7, 2022 at 9:9 Comment(1)
This only activates the venv at the directory where pyproject.toml is. It won't work on subdirectories, but can be modified if needed.Tovatovar
M
1

You can use a zsh hook function that runs whenever you change directories. For example, you could add this to your ~/.zshrc:

# Define a function to activate/deactivate virtualenvs based on the current directory
function venv_cd() {
  # Check if the current directory has a venv subdirectory
  if [[ -d venv ]]; then
    # If yes, activate it if it's not already active
    if [[ "$VIRTUAL_ENV" != "$PWD/venv" ]]; then
      source venv/bin/activate
    fi
  else
    # If no, deactivate the current virtualenv if any
    if [[ -n "$VIRTUAL_ENV" ]]; then
      deactivate
    fi
  fi
}

Add the function to the chpwd hook, which runs after every cd

add-zsh-hook chpwd venv_cd

Optionally, run the function once at the start of the session

venv_cd

This should automatically activate the virtualenv in the current directory if it exists, or deactivate it if you move to a directory without one.

Moribund answered 5/1, 2023 at 12:50 Comment(1)
Thanks for the answer! where is the 'chpwd` hook found? Is that another entry in the .zshrc?Submicroscopic
S
1

Here is an alternative which sets an env variable when cd'ing into a virtualenv directory and checks if an active subdir is a child-directory of said virtualenv.

This will also deactivate when exiting or cd'ing to another directory.

This assumes you're using Pyenv to manage your Python installations, however you can change the pyvenv.cfg notation to anything else.

function cd() {

  builtin cd "$@"

    if [[ -f ./pyvenv.cfg ]] ; then
        export VENV_CURRENT=$PWD
        source ./bin/activate
    else
        if [[ $(env | fgrep VENV_CURRENT) ]]; then
            if ! [[ $(pwd | fgrep $VENV_CURRENT) ]]; then
                unset VENV_CURRENT
                deactivate
            fi
        fi
    fi
}
Secund answered 7/2, 2023 at 13:11 Comment(0)
M
0

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
}
Menorrhagia answered 24/4, 2019 at 14:26 Comment(3)
Hi @Gauthier. This code only work if you enter in the root directory of target virtual environment. However, if you cd into any sub-directory of the target virtual environment, it still keeps the old virtual environment active.Chitchat
@Chitchat that's correct, it's not something I need. I guess it wouldn't be too hard to cd up all the way to / or until you find a dir venv? I considered it but will do it only when I have the need. More than that, it puts expectations on the name of the dir, whereas it should really try to be smarter and detect if a dir is a virtualenv environment by checking its content. But your answer doesn't do any of that either, am I wrong?Menorrhagia
This doesn't deactivate when going into a non project directory (not necessarily important but I think it's nice to do).Triphthong
A
0

This is my solution:

  1. If VIRTUAL_ENV is not set then:
    1. Check if we're inside a virtual env
    2. If yes, then activate it
  2. Else (VIRTUAL_ENV is defined), check that the current folder starts with $VIRTUAL_ENV (removing the /venv part) and verify that the deactivate command exists
    1. Deactivate teh environment

This is the script:

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
}

Note: You need to add this to .bashrc. If it doesn't work, check if your .profile is not overriding your command (it happened to me)

Ashraf answered 21/12, 2019 at 14:36 Comment(1)
This doesn't support moving from one venv directory to anotherTriphthong
T
0

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
}
Triphthong answered 15/1, 2020 at 17:31 Comment(0)
J
0

I've used direnv in the past, as others have mentioned. Lyft use aactivator for this exact scenario.

Once the venv is built it must be activated (added to $PATH). We use aactivator to automatically activate the venv each time a user enters the service directory and deactivates as they leave.

Joslin answered 5/1, 2022 at 14:8 Comment(0)
O
0

You don't have to execute deactivate on the directory where venv exists. When virtual environment is active you can deactivate anywhere.

So, say you have 2 venvs, <somepath>/project1/venv and <somepath>/project2/venv, and currently project1/venv is active. If you want to switch project2/venv, do below.

cd project2
deactivate && source ./venv/bin/activate

It will deactivate previous one and activate current one.

Now the above you can just make an alias, or shell function in ~/.zshrc as below:

function avenv(){
  deactivate
  source ./venv/bin/activate 
}

go the path where you want to activate the venv and just run avenv.

Python venv has a feature called --prompt, while creating venv you can mention the prompt, so that in the terminal you will understand which venv is active.

python3 -m venv venv --prompt PROJECT1_VENV

Now in terminal, it will come as (PROJECT1_VENV) -> ~

Obsess answered 5/1, 2023 at 10:6 Comment(0)
M
0

pyenv-virtualenv + pyenv local

$ pyenv virtualenv 3.10.9 my-project
$ pyenv local my-project

That's is.

Every time you cd into that project directory pyenv automatically:

  • checks the .python-version file made by pyenv local
  • activates the virtual env from $HOME/.pyenv/versions/3.10.9/envs/my-project

Reference

Merino answered 25/4, 2023 at 1:6 Comment(0)
U
0

The most upvoted answer didn't work for me. But adding this to my .bashrc did

# Automatically activate Python venv if it exists
auto_activate_venv() {
    if [ -e ".venv/bin/activate" ]; then
        source .venv/bin/activate
    elif [ "$VIRTUAL_ENV" != "" ] && [ ! -e "$PWD/.venv" ]; then
        deactivate
    fi
}

# Override the 'cd' command to call our function
cd() {
    builtin cd "$@" && auto_activate_venv
}

# If you use pushd/popd, you can override them too.
pushd() {
    builtin pushd "$@" && auto_activate_venv
}

popd() {
    builtin popd "$@" && auto_activate_venv
}
Ugo answered 22/9, 2023 at 21:35 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.