19

If I have python script which activates the virtualenv like this:

#!/path/to/venv/bin/python

How can I set variables for this script without modifying this script?

I want this environment variable to be active for all scripts which use this virtualenv.

This means modifying this script is not a solution, since there are twenty scripts, and I don't want to modify twenty scripts.

Writing a shell wrapper-script around the python scripts would work, but I would like to avoid this.

In the past I thought a custom sitecustomize.py can be used for start-up code. But Ubuntu (AFAIK the only distribution which does this) comes with its own sitecustomize.py file, with the effect that my sitecustomize.py does not get called. See https://bugs.launchpad.net/ubuntu/+source/python2.5/+bug/197219

Here are some ways how I want to use the virtualenv:

(I have thought about this again. I guess it setting the variables is not the job of python or virtualenv. I need a unified way to set environment variables. And in my case I would like to do this without using a shell wrapper).

guettli
  • 25,042
  • 81
  • 346
  • 663
  • 2
    Is this relevant?: https://stackoverflow.com/questions/9554087/setting-an-environment-variable-in-virtualenv – OliverRadini Sep 24 '18 at 10:42
  • 1
    The activate script (in the bin directory of the virtual env) which is used to activate the virtualenv might be a possible place to set the environment variables. All python scripts should inherit those, but from maintenance point of view it might not be a great option because if you set up a new virtualenv you would have to remember to modify the activate script again. – Abhinav Upadhyay Sep 24 '18 at 10:50
  • @AbhinavUpadhyay If I call the interpreter like in the code line in the question, then the activate shell script does not get executed. – guettli Sep 24 '18 at 11:05
  • 1
    @OliverRadini the question you mention does not apply. AFAIK these question solve this by setting the environment variables in a (shell) script which gets executed before the python interpreter starts. In my question the interpreter gets called like this "#!/path/to/venv/bin/python" I can't write a wrapping shell script. – guettli Sep 24 '18 at 11:09
  • Ah, I see, thanks; sorry for the confusion. I'll leave my comment there for now in case anyone wants a bit more information about what _won't_ solve the problem – OliverRadini Sep 24 '18 at 11:32
  • *If I have python script which activates the virtualenv like this:*: that just selects the Python binary, the venv is not 'activated'. Activating a venv is mostly just an update to your PATH variable by the `bin/activate` shell script, but that's not a requirement to use the Python binary. – Martijn Pieters Sep 27 '18 at 17:38
  • Is not a bug in Ubuntu, is a feature because [ENABLE_USER_SITE is set to False](https://docs.python.org/3/library/site.html#site.ENABLE_USER_SITE) try to get it enabled. – Rutrus Feb 06 '21 at 11:09

5 Answers5

38

while writing sitecustomize.py file and changing bin/python all are feasible solutions, I would suggest another method that does not involve directly change contents inside virutalenv, by simply install a .pth file:

./venv/lib/python2.7/site-packages/_set_envs.pth

with content:

import os; os.environ['FOO'] = 'bar'

test:

$ ./venv/bin/python -c "import os; print os.getenv('FOO')"
bar

the trick is, python will load every .pth file on startup, and if there is a line starts with import, this line will be get executed, allowing inject arbitrary code.

the advantage is, you could simply write a python package to install this .pth file with setuptools, install to the virtualenv you want to change.

georgexsh
  • 15,984
  • 2
  • 37
  • 62
  • 1
    This way does not work in ubuntu neither. Also, python 2.x is outdated. You can get this path with `site.USER_SITE` importing [site module](https://docs.python.org/3/library/site.html). – Rutrus Feb 06 '21 at 11:01
4

From what I have tried, it seems if you create a sitecustomize.py file inside the virtual environment, it will take precedence over the global sitecustomize.pyinstalled in /usr/lib/python2.7 directory. Here is what I did:

Create a sitecustomize.py in the virtual environment

$ echo "import os; os.environ['FOO'] = 'BAR'" > ~/venvs/env_test/lib/python2.7/sitecustomize.py

Verify that it is getting imported and executed when running the Python binary from the virtual environment

$ ~/venvs/env_test/bin/python
Python 2.7.15rc1 (default, Apr 15 2018, 21:51:34)
[GCC 7.3.0] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> import sitecustomize
>>> sitecustomize.__file__
'/home/abhinav/venvs/env_test/lib/python2.7/sitecustomize.py'
>>> import os
>>> os.environ['FOO']
'BAR'
>>>

Just to verify that FOO is set even without explicitly importing sitecustomize:

$ ~/venvs/env_test/bin/python
Python 2.7.15rc1 (default, Apr 15 2018, 21:51:34)
[GCC 7.3.0] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> import os
>>> os.environ['FOO']
'BAR'
>>>
georgexsh
  • 15,984
  • 2
  • 37
  • 62
Abhinav Upadhyay
  • 2,477
  • 20
  • 32
  • This not work for me in Ubuntu 20.04.2 LTS with python 3.8.5 because [ENABLE_USER_SITE](https://docs.python.org/3/library/site.html#site.ENABLE_USER_SITE) is set to False – Rutrus Feb 06 '21 at 11:23
2

After trying dotenv package as well as the .pth method, I discovered they didn't work for me. So, I just modified the venv/bin/activate script, and exported the variables there.

Here's the idea.

$ cat venv/bin/activate

deactivate () {
    unset FOO
    unset BAR
    ...
}

...

export FOO='xxx'
export BAR='xxx'
1

Bit hackish, but should work.

  1. Rename python link in virtual environment bin to something like python.lnk
  2. In bin folder create file python that looks like

    #!/bin/sh
    
    export TEST='It works!'
    
    "$0.lnk" "$@"
  3. Make it executable

    chmod +x python

Then if you run a script like

#!/work/venv/bin/python
import os

print 'Virtualenv variable TEST="{}"'.format(os.environ['TEST'])

as follows:

./myscript.py

it prints out:

Virtualenv variable TEST="It works!"

Vader
  • 3,675
  • 23
  • 40
  • This is the correct answer. Only this way tweaks **his** python _sheebang_ that is the real problem in his question. – Rutrus Feb 06 '21 at 11:26
0

How to do in Ubuntu

The problem with Ubuntu it seems that python package comes with PYTHONNOUSERSITE as cPython compilation flag. You can find it with site module and see that site.ENABLE_USER_SITE is set to False.

Specific problem with the question

tl;dr #!/path/to/venv/bin/python is not enough to execute your virtual environment.

Although the rest of the answers seems to be correct in some contexts, the problem with the question is that he forces the execution with #!/path/to/venv/bin/python but hi is not providing any contextual virtual environment in his question, so I suppose he is not activating his virtual environment previous to run his script.

That is useless because that command usually links to your system python executable[^1] and does anything more. Also, by default you will use your system environment variables if you don't activate the virtual environment with source /path/to/venv/bin/activate or configure apache or nginx to manage your venv.

Solution for environment vars in venv

Then, is possible to add a specific line in your venv/bin/activate script that adds a environment value in bash language:

export FOO=BAR

and then activate it with source command.


[^1]: Probably you will prefer a generic #!/usr/bin/env python3 (python2 is deprecated). The environment will take properly your exectuable.

Rutrus
  • 1,367
  • 15
  • 27