Different $PATH in Virtual Environments - python

I'm on Mac using only terminal.
Running echo $PATH returns
/Library/Frameworks/Python.framework/Versions/3.10/bin:/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin:/Users/username/.cargo/bin:/Applications/Postgres.app/Contents/Versions/latest/bin:/Users/username/Venvs/default/bin:/opt/homebrew/bin:/opt/homebrew/sbin:/Users/username/.nvm/versions/node/v17.4.0/bin:usr/local/bin:/Users/username/.cargo/bin
After activating the venv, echo $PATH only returns
/Users/username/Venvs/default/bin:/opt/homebrew/bin:/opt/homebrew/sbin:/Users/username/.nvm/versions/node/v17.4.0/bin:/usr/bin:/bin:/usr/sbin:/sbin
How do I set i.e. /Users/username/.cargo/bin to be loaded by all venvs by default? (now it's set in .zshrc)
I can't find any documentation of how do Virtual environments set the $PATH and why. I can't even figure out where do most of the entries come from.
This is a related question, but does not address why the situation happens when I'm in the terminal the whole time:
Environment $PATH different when using venv
I have tried to append the PATH using all these places with no difference:
/etc/bashrc
/etc/profile
~/.bashrc
~/.bash_profile
~/.profile
~/.MacOSX/environment.plist
~/.zshrc
~/.zprofile

The whole point of a virtual environment is to configure your shell to use a specific Python installation.
While details might vary depending on the tool used to create the virtual environment, typically there is a shell script activate that you source which explicitly adds the virtual environment's bin directory to your PATH. (It also saves the old path, and defines a shell function deactivate which restores PATH to its previous value.)

The only way to make $PATH different seems to be to activate a virtual environment and then append to it.
I use a default venv that I'm setting in .zshrc, but I have also been setting it in .zshenv, which was loaded first. Removing the venv activation from .zshenv solved the issue.
So in case there's a difference between your $PATH in different venvs, make sure the order of activation and appending is correct.

Related

What is the VIRTUAL_ENV environment variable used for

Reading Python's virtualenv/bin/activate script, I noticed that besides the obvious manipulation of the PATH variable, it also sets and exports VIRTUAL_ENV. I wonder is this significant, and who or what uses this variable?
I'm asking because I assumed that you can instead of using the activate script also do something like:
$ venv/bin/python3 ...
or
$ venv/bin/flake8
to explicitly use the virtual environment for one-shot commands or in makefiles. Now I realize that it is not quite equivalent as the VIRTUAL_ENV variable would be missing.
People use it for anything, primary to detect if a virtualenv is activated at all; sometimes to find out its directory. Almost nobody needs it for a one-shot command because the environment kinda activated and deactivated immediately.
I use it to deactivate temporary environments created by virtualenvwrapper's mktmpenv in my ~/.bashrc:
# Clean up python virtual environment on exit
# See https://virtualenvwrapper.readthedocs.io/en/latest/tips.html#clean-up-environments-on-exit
trap '[ "$VIRTUAL_ENV" ] && deactivate' EXIT
Deactivated temporary environments are automatically self-destroyed and deleted from disk.
I also use it to re-activate a virtualenv in a subshell that inherited the variable from its parent shell:
if [ -n "$VIRTUAL_ENV" ] && ! type deactivate >/dev/null 2>&1; then
. "$VIRTUAL_ENV/bin/activate"
fi
I found the answer in the docs:
When a virtual environment is active, the VIRTUAL_ENV environment variable is set to the path of the virtual environment. This can be used to check if one is running inside a virtual environment.
further:
You don’t specifically need to activate an environment; activation just prepends the virtual environment’s binary directory to your path, so that “python” invokes the virtual environment’s Python interpreter and you can run installed scripts without having to use their full path. However, all scripts installed in a virtual environment should be runnable without activating it, and run with the virtual environment’s Python automatically.
So according to the docs, you don't have to activate the venv, but then you don't have the VIRTUAL_ENV variable set. This implies that the VIRTUAL_ENV is not a very reliable way of checking if you're running inside a venv.

How to display conda's environment in zsh (not using oh-my-zsh)?

I use zsh but not equipted with oh-my-zsh, since I cloned many git repos on my machine and oh-my-zsh's default theme or 'josh' theme makes it very slow, for cd and ls commands, etc.
Thus I delete oh-my-zsh and only use zsh's default recommended config, except adding some alias and path variables.
Now comes the question: I manage my python environment by conda, and no current enviroment name displayed in my prompt.
I have executed the command:
conda init zsh
And re-open my terminal (default shell is zsh), still not display "(base)" or "(py36)" stuffs.
How can I tell my terminal to show that stuff? The git branch does not matters for my work, but the current python version really matters, since DeepLearning related tools use many different python versions.
For those users with oh-my-zsh
I add anaconda element in ~/.zshrc config file
POWERLEVEL9K_LEFT_PROMPT_ELEMENTS=(anaconda ...ENVS)
and the conda env shows up
If you're not using oh-my-zsh and have not copy-pasted the relevant sections from there, then the correct answer is that when you do conda init zsh, the environment variable CONDA_PROMPT_MODIFIER is introduced. You want to add that to your PROMPT. You should do so as part of the precmd function, so that the an updated value of the environment variable is shown every time a prompt is printed.
This was caused due to this line in default zsh's config:
prompt adam1
Once delete that line, re-open terminal, conda environment are shown.
You can try,
# init your shell first
conda init zsh
source ~/.zshrc # refresh your shell
source activate base # (optional, on linux) activate base env

activating virtualenv with direnv doesn't activate virtualenv

I'm using direnv to source my virtualenv when I change into the directory.
/project
.envrc
/env <--- my virtualenv
.envrc
source env/bin/activate
When I change directory into /project I get the output:
direnv: loading .envrc
direnv: export +VIRTUAL_ENV -PS2 ~PATH
It prepends the env directory to my PATH environment variable so when I run which python and which pip both point to python and pip that's in my env directory
=> which python
/USER/project/env/bin/python
=> which pip
/USER/project/env/bin/pip
However it doesn't seem to run source env/bin/activate as I expect it to. I expect it to activate my virtualenv by adding the virtualenv name (env) to my CLI prompt and give access to the deactivate command, neither of that happens. Is there something I'm misunderstanding about how direnv and virtualenv work? I'm new to python so I'm not sure if there are existing tools to do something like this.
I think it's important to understand how direnv works to form a proper mental model first; direnv doesn't load the .envrc directly in the current shell. Instead, it starts a new bash shell, executes the .envrc in there, records the changes in environment and exports the diff bash into the current shell.
What is happening here is that:
virtualenv is using $PS1 to set the prompt. This is a local variable and thus not re-exported. direnv also filters PS1 because it causes segfaults on the old macOS bash when it's unset.
The deactivate() function is not exported from the bash sub-shell as it's not an environment variable.
In practice the activation worked as you noticed. python is in the right path and running pip or easy_install is going to install things in the virtualenv. deactivation is not necessary as direnv will automatically unload the environment when cd-ing out of the directory.
To restore the custom prompt, there is more info available on the wiki: https://github.com/direnv/direnv/wiki/Python#restoring-the-ps1
There is a "hidden" feature to do what you want in direnv. You have to take a look at the toolbox that is loaded by direnv for you to use in the .envrc files. You can use the layout command with python (layout python3) to activate a virtualenv on entering the dir, and deactivating it when exiting the directory. It will even take care of creating the virtualenv the first time.
Also take a look at source_up that keep loading .envrc files higher in the file system. I start all my projects by creating a .envrc file with the following:
layout python3
source_up
This will create, activate and deactivate a python virtualenv automatically, and keep on reading variables from higher-level .envrc files. Environement variables for the current project only will go in the local .envrc.

python virtualenv -- possible to augment $PATH or add other environment variables?

I'd like to alter my $PATH only in a Python virtual environment. Is it possible to have the $PATH change when I activate a virtual environment?
You can write an activation script that sources virtualenv's activate (on linux, or calls the bat file on windows) and then updates PATH, PYTHONPATH and other environment variables. Use the virtualenv bootstrap hooks to install the script when the virtualenv is created and call it instead of activate.
Depending on what operating system you are using you could edit the activate file and set an environment variable there. For example, a Windows virtualenv folder has a sub-folder called Scripts. Inside scripts is the activate.bat file. Edit activate.bat and alter the path variable. One thing to consider though, is you might want to save the original path variable in another temporary environment variable and restore from that temporary environment variable in the deactivate.bat file.

Why do you need to set the WORKON_HOME environment variable?

I haven't used my python/virtual environments in a while, but I do have virtualenvironment wrapper installed also.
My question is, in the doc page it says to do this:
export WORKON_HOME=~/Envs
$ mkdir -p $WORKON_HOME
$ source /usr/local/bin/virtualenvwrapper.sh
$ mkvirtualenv env1
I simply did this at my prompt:
source /usr/local/bin/virutalenvwrapper.sh
And now I can list and select an environment by doing:
>workon
>workon envtest1
My question is, since this works for me, I'm confused why I should be creating an environmental variable WORKON_HOME and point it to the ~/Envs folder? What does that do and how come mine works fine w/o it? I don't have that /Envs folder either (I know the script creates it).
Reference: http://virtualenvwrapper.readthedocs.org/en/latest/
If WORKON_HOME is not set, your default virtualenv folder will be set to ~/.virtualenvs
(see virtualenvwrapper.sh l.118)
You will also use WORKON_HOME to specify to pip which folder to use (export PIP_VIRTUALENV_BASE=$WORKON_HOME)
source : virtualenvwrapper.readthedocs.org : Tying to pip’s virtualenv support
I'm confused why I should be creating an environmental variable
WORKON_HOME and point it to the ~/Envs folder?
It's optional. You're confused (like I was) because the documentation is confusing.
What does that do and how come mine works fine w/o it?
It tells virtualenvwrapper which folder to search for Python environments. The command workon searches the path WORKON_HOME if it's defined, or ~/.virtualenvs if it's not, which is why it works by default.
A use case for defining a different WORKON_HOME directory would be if you have different environments you want to available to virtualenvwrapper. For example, if you save virtual env backups to a different folder or have multiple users who want to maintain their own environments.

Categories

Resources