I have a Heroku project that uses environment variables to get its configuration, but I use virtualenv to test my app locally first.
Is there a way to set the environment variables defined on the remote machine inside virtualenv?
In case you're using virtualenvwrapper (I highly recommend doing so), you can define different hooks (preactivate, postactivate, predeactivate, postdeactivate) using the scripts with the same names in $VIRTUAL_ENV/bin/
. You need the postactivate hook.
$ workon myvenv
$ cat $VIRTUAL_ENV/bin/postactivate
#!/bin/bash
# This hook is run after this virtualenv is activated.
export DJANGO_DEBUG=True
export S3_KEY=mykey
export S3_SECRET=mysecret
$ echo $DJANGO_DEBUG
True
If you want to keep this configuration in your project directory, simply create a symlink from your project directory to $VIRTUAL_ENV/bin/postactivate
.
$ rm $VIRTUAL_ENV/bin/postactivate
$ ln -s .env/postactivate $VIRTUAL_ENV/bin/postactivate
You could even automate the creation of the symlinks each time you use mkvirtualenv.
Remember that this wont clean up after itself. When you deactivate the virtualenv, the environment variable will persist. To clean up symmetrically you can add to $VIRTUAL_ENV/bin/predeactivate
.
$ cat $VIRTUAL_ENV/bin/predeactivate
#!/bin/bash
# This hook is run before this virtualenv is deactivated.
unset DJANGO_DEBUG
$ deactivate
$ echo $DJANGO_DEBUG
Remember that if using this for environment variables that might already be set in your environment then the unset will result in them being completely unset on leaving the virtualenv. So if that is at all probable you could record the previous value somewhere temporary then read it back in on deactivate.
Setup:
$ cat $VIRTUAL_ENV/bin/postactivate
#!/bin/bash
# This hook is run after this virtualenv is activated.
if [[ -n $SOME_VAR ]]
then
export SOME_VAR_BACKUP=$SOME_VAR
fi
export SOME_VAR=apple
$ cat $VIRTUAL_ENV/bin/predeactivate
#!/bin/bash
# This hook is run before this virtualenv is deactivated.
if [[ -n $SOME_VAR_BACKUP ]]
then
export SOME_VAR=$SOME_VAR_BACKUP
unset SOME_VAR_BACKUP
else
unset SOME_VAR
fi
Test:
$ echo $SOME_VAR
banana
$ workon myenv
$ echo $SOME_VAR
apple
$ deactivate
$ echo $SOME_VAR
banana
ln -s .env/postactivate $VIRTUAL_ENV/bin/postactivate
did not work for me. ln
wants a full path, so I had to do ln -s `pwd`/.env/postactivate $VIRTUAL_ENV/bin/postactivate
ln
.
Commented
Aug 16, 2013 at 8:44
ln
likes full paths so I tried that and it worked. When I tried to cat
the symlink with relative path it said No such file or directory
.
Using only virtualenv (without virtualenvwrapper), setting environment variables is easy through the activate
script you're sourcing in order to activate the virtualenv.
On unix, run:
nano YOUR_ENV/bin/activate
or if you're on windows:
nano YOUR_ENV/Scripts/activate.bat
Then, add the environment variables to the end of the file. If you're on unix:
export KEY=VALUE
or if you're on windows:
set KEY=VALUE
You can also set a similar hook to unset the environment variable as suggested by Danilo Bargen in his excellent answer above.
cd
just to have environment variables? shudder
Commented
May 22, 2014 at 8:25
YOUR_ENV/Scripts/activate.bat
and set KEY=VALUE
.
Commented
Jan 27, 2022 at 10:40
While there are a lot of nice answers here, I didn't see a solution posted that both includes unsetting environment variables on deactivate and doesn't require additional libraries beyond virtualenv
, so here's my solution that just involves editing /bin/activate, using the variables MY_SERVER_NAME
and MY_DATABASE_URL
as examples:
There should be a definition for deactivate in the activate script, and you want to unset your variables at the end of it:
deactivate () {
...
# Unset My Server's variables
unset MY_SERVER_NAME
unset MY_DATABASE_URL
}
Then at the end of the activate script, set the variables:
# Set My Server's variables
export MY_SERVER_NAME="<domain for My Server>"
export MY_DATABASE_URL="<url for database>"
This way you don't have to install anything else to get it working, and you don't end up with the variables being left over when you deactivate
the virtualenv.
You could try:
export ENVVAR=value
in virtualenv_root/bin/activate. Basically the activate script is what is executed when you start using the virtualenv so you can put all your customization in there.
deactivate
function defined virtualenv_root/bin/activate to balance setting and unsetting
Locally within an virtualenv there are two methods you could use to test this. The first is a tool which is installed via the Heroku toolbelt (https://toolbelt.heroku.com/). The tool is foreman. It will export all of your environment variables that are stored in a .env file locally and then run app processes within your Procfile.
The second way if you're looking for a lighter approach is to have a .env file locally then run:
export $(cat .env)
To activate virtualenv in env
directory and export envinroment variables stored in .env
use :
source env/bin/activate && set -a; source .env; set +a
Or just the following line for pyenv
:
set -a; source .env; set +a
echo 'alias e=". env/bin/activate && set -a; source .env; set +a"' >> ~/.bash_aliases
set -a
/set +a
is equivalent to set -o allexport
/set +o allexport
, which I find more descriptive
Commented
Jan 15 at 15:50
Concerning the standard venv package, here is a solution that:
SOLUTION:
python -m venv MY_ENV
activate
script in any text editor (e.g vim).vim MY_ENV/bin/activate
deactivate
function.These lines are executed when you deactivate the virtual environment. They restore the previous value of the ENV_VARIABLE
.
deactivate () {
... # Already existing code
# Restore the previous value of the ENV_VARIABLE on deactivation
# This code is executed when `deactivate` alias is called.
if [ ! "${1:-}" = "nondestructive" ] ; then
if [ -n "${_OLD_ENV_VARIABLE:-}" ] ; then
ENV_VARIABLE="${_OLD_ENV_VARIABLE:-}"
export ENV_VARIABLE
unset _OLD_ENV_VARIABLE
else
unset ENV_VARIABLE
fi
fi
}
"new value of the ENV_VARIABLE"
.These lines are executed when you activate the virtual environment.
# Update or set a ENV_VARIABLE on activation
if [ -n "${ENV_VARIABLE:-}" ] ; then
_OLD_ENV_VARIABLE="${ENV_VARIABLE:-}"
fi
export ENV_VARIABLE="new value of the ENV_VARIABLE"
OUTCOME:
Result of setting a new environment variable:
:~$ echo $ENV_VARIABLE
:~$
:~$ source MY_ENV/bin/activate
(MY_ENV):~$
(MY_ENV):~$ echo $ENV_VARIABLE
new value of the ENV_VARIABLE
:~$
(MY_ENV):~$ deactivate
:~$
:~$ echo $ENV_VARIABLE
:~$
Result of updating already existing environment variable:
:~$ export ENV_VARIABLE = "old value of the ENV_VARIABLE"
:~$
:~$ echo $ENV_VARIABLE
old value of the ENV_VARIABLE
:~$
:~$ source MY_ENV/bin/activate
(MY_ENV):~$
(MY_ENV):~$ echo $ENV_VARIABLE
new value of the ENV_VARIABLE
:~$
(MY_ENV):~$ deactivate
:~$
:~$ echo $ENV_VARIABLE
old value of the ENV_VARIABLE
:~$
Install autoenv either by
$ pip install autoenv
(or)
$ brew install autoenv
And then create .env
file in your virtualenv project folder
$ echo "source bin/activate" > .env
Now everything works fine.
If you're already using Heroku, consider running your server via Foreman. It supports a .env
file which is simply a list of lines with KEY=VAL
that will be exported to your app before it runs.
Another way to do it that's designed for django, but should work in most settings, is to use django-dotenv.