How does running source activate <env-name>
update the $PATH variable? I've been looking in the CONDA-INSTALLATION/bin/activate
script and do not understand how conda updates my $PATH variable to include the bin directory for the recently activated environment. No where can I find the code that conda uses to prepend my $PATH variable.
Question 1: do i have to activate the conda env every time i open command prompt? No, you do not have to activate conda every time you open CMD. This is simply a matter of choice for the developer.
Generally, you won't find too much of a difference between conda activate and the old source activate , except that it's meant to be faster, and work the same across different operating systems (the latter difference makes conda activate a huge improvement IMO).
Disclaimer: I am not a conda developer, and I'm not a Bash expert. The following explanation is based on me tracing through the code, and I hope I got it all right. Also, all of the links below are permalinks to the master commit at the time of writing this answer (7cb5f66
). Behavior/lines may change in future commits. Beware: Deep rabbit hole ahead!
Note that this explanation is for the command source activate env-name
, but in conda>=4.4, the recommended way to activate an environment is conda activate env-name
. I think if one uses conda activate env-name
, you should pick up the explanation around the part where we get into the cli.main
function.
For conda >=4.4,<4.5, looking at CONDA_INST_DIR/bin/activate
, we find on the second to last and last lines (GitHub link):
. "$_CONDA_ROOT/etc/profile.d/conda.sh" || return $?
_conda_activate "$@"
The first line sources the script conda.sh
in the $_CONDA_ROOT/etc/profile.d
directory, and that script defins the _conda_activate
bash function, to which we pass the arguments $@
which is basically all of the arguments that we passed to the activate
script.
Taking the next step down the rabbit hole, we look at $_CONDA_ROOT/etc/profile.d/conda.sh
and find (GitHub link):
_conda_activate() {
# Some code removed...
local ask_conda
ask_conda="$(PS1="$PS1" $_CONDA_EXE shell.posix activate "$@")" || return $?
eval "$ask_conda"
_conda_hashr
}
The key is that line ask_conda=...
, and particularly $_CONDA_EXE shell.posix activate "$@"
. Here, we are running the conda executable with the arguments shell.posix
, activate
, and then the rest of the arguments that got passed to this function (i.e., the environment name that we want to activate).
Another step into the rabbit hole... From here, the conda executable calls the cli.main
function and since the first argument starts with shell.
, it imports the main
function from conda.activate
. This function creates an instance of the Activator
class (defined in the same file) and runs the execute
method.
The execute
method processes the arguments and stores the passed environment name into an instance variable, then decides that the activate
command has been passed, so it runs the activate
method.
Another step into the rabbit hole... The activate
method calls the build_activate
method, which calls another function to process the environment name to find the environment prefix (i.e., which folder the environment is in). Finally, the build_activate
method adds the prefix
to the PATH
via the _add_prefix_to_path
method. Finally, the build_activate
method returns a dictionary of commands that need to be run to "activate" the environment.
And another step deeper... The dictionary returned from the build_activate
method gets processed into shell commands by the _yield_commands
method, which are passed into the _finalize
method. The activate
method returns the value from running the _finalize
method which returns the name of a temp file. The temp file has the commands required to set all of the appropriate environment variables.
Now, stepping back out, in the activate.main
function, the return value of the execute
method (i.e., the name of the temp file) is printed to stdout. This temp file name gets stored in the Bash variable ask_conda
back in the _conda_activate
Bash function, and finally, the temp file is executed by the eval
Bash function.
Phew! I hope I got everything right. As I said, I'm not a conda developer, and far from a Bash expert, so please excuse any explanation shortcuts I took that aren't 100% correct. Just leave a comment, I'll be happy to fix it!
I should also note that the recommended method to activate environments in conda >=4.4 is conda activate env-name
, which is one of the reasons this is so convoluted - the activation is mostly handled in Python now, whereas (I think) previously it was more-or-less handled directly in Bash/CMD.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With