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

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.

Related

Different $PATH in Virtual Environments

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.

Is there a way to automatically load environment variables when activating venv?

I am using python venv to create virtual environments. But, since I am working with several projects with different virtual environments, I don't want to manualy set environment variables every time I switch to a different project.
Is there a way to set venv environment variables automatically when activating the venv?
What is the best practice for this problem?
A good practice is to use dotenv. You can load your environment by placing your environment variables into a file named .env, and whenever you would like to load an environment, just use the lines:
from dotenv import load_dotenv
load_dotenv()
This has the nicety that it only exists within the scope of you running a single script, since it essentially works like calling os.environ['variable'] = 'value' a number of times.
Activating a virtual environment is nothing more than sourcing a shell script. You can edit that script to set whatever variables you like. You will probably also want to edit the definition of deactivate to clear or roll back whatever changes you made to the environment.
you need to write a bash scirpt (in case you are using bash shell), where you specified a particular command which will activate the project python environment and add the project specific envrionment variable in the system environment. and remove the environment variable when you exit the project python environment.
but i don't this is good/correct way to do things. #mz solution will be correct, where you define a .env file and define env variable in it. and use load_env to read the env variable when project runs
This concept is based on Two Scoops of Django. I have implemented it using venv.
Open the Windows PowerShell Script in your virtual environment generated by venv.
The script is located at venv/Scripts/Activate.ps1
At the bottom of the file, you will see this line of code:
$env:VIRTUAL_ENV = $VenvDir
Below that code, enter your environment variable as follow:
$env:VARIABLE_NAME = 'variable_value'
Same concept goes if you are using the Command Prompt to activate the environment, you will need to place environment variables in venv/Scripts/activate.bat

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.

Where to put a virtualenv directory on Mac OS X?

I am transferring a Python based development system from PC to Mac. I need to create a virtualenv / directory to store this system. Where is a good place to put the directory (somewhere easily accessible from a terminal window)? I am not so savvy on the Mac as the PC, although I could probably write a bash script to change directory and activate the virtualenv. I am running OS X Mountain Lion (v10.8) and I'm the only user on the system.
If the virtualenvs are only to be used by you, you can take advantage of the ~ (tilde) shortcut which links to your home directory.
mkdir ~/venvs
Creating a virtual environment
You can then create a virtual environment with this command from any dir in the terminal
virtualenv ~/venvs/VENV_NAME
Activating a virtual environment
You can then source a virtual environment with this command
source ~/venvs/VENV_NAME/bin/activate
You can have as many as you like and put them where it's convenient. A common arrangement is to have a dedicated environment for each project; then if each project is in ~/projects/<project> you could have a virtualenv directory in each project's respective root directory. So ~/projects/foo/.env for the virtualenv for project foo, ~/projects/bar/.env for the one for bar, etc. (The use of .env is just a convention; again, you can name them any way you like.)

Save virtualenv variable on linux

I use Linux (Ubuntu 14). I need to save a variable to my virtualenv, so I write on the bash shell with the virtualenv activated:
$ export SECRET_KEY='asdgladfkga....'
and then I can do (using python):
import os
key = os.environ["SECRET_KEY"]
Everything works fine until I restart the computer, then, the variable is erased. How do I truly save it? can I do this without installing virtualenvwrapper?
If you want the SECRET_KEY variable to be defined only when you activate your virtualenv, then you could modify the preactivate script in your virtualenv bin directory by adding
export SECRET_KEY='asdgladfkga....'
This isn't really a virtualenv issue. virtualenv is meant to sandbox your Python environment. Running the activate script, which you source, does change some environment variables at the OS level, but those are not saved/sandboxed, and are not connected to the virtualenv itself other than in the current instance of the shell in which you ran activate.
When you reboot, your .bashrc will load your bash environment back up based on the contents of that file.
If you wanted to keep a "secret key" -- offhand, I'm not sure I get why you want to do this; what are you trying to accomplish? -- you could have a wrapper script that:
Set the key in the current shell via EXPORT
echos the key to a file in your home directory with the same EXPORT command
Then, you could modify your .bashrc to source that file if it exists, so it would get loaded on startup, and therefore survive reboots.
When the virtualenv wrapper was run again, the process would repeat (and not change anything functionally if the key didn't change; you could optimize it to not bother setting the variable again nor write out the file if the key is the same).

Categories

Resources