61

I'm using virtualenvwrapper with a django project that has a management task that automatically writes some config files, so the user just has to

./manage.py generate_configuration > much_nice.conf

And then move the file elsewhere. One of the generated config files is a task for supervisord that launches a celery worker. The problem I'm getting is that I don't know how to output the path of the celery executable that is within the bin folder of the virtualenv. Essentially, I'd like to have the output of the command

which celery

One option is using sys.executable, get the folder (which seems to be the bin folder of the virtualenv) and that's it... but I'm not sure.

Doesn't virtualenv have any kind of method to get the path itself?

José Tomás Tocino
  • 9,873
  • 5
  • 44
  • 78

4 Answers4

135

The path to the virtual env is in the environment variable VIRTUAL_ENV

echo $VIRTUAL_ENV
Brad Culberson
  • 1,409
  • 1
  • 10
  • 2
  • 11
    That's it, thanks. I managed to get the value in python using `os.environ['VIRTUAL_ENV']`. – José Tomás Tocino Feb 25 '14 at 14:38
  • 11
    Note that `VIRTUAL_ENV` is set by the virtualenv's `activate` script, and it's possible to use the virtualenv python without activating the virtualenv. See: http://stackoverflow.com/a/1883251/1286571 – ForeverWintr Dec 15 '16 at 22:46
  • 1
    Also, conda do not use this variable. This will beak for users using CONDA or any other ways to manage their python distributions. I don't think this is a robust approach. Using `sys.executable` as proposed by @laurent-laporte seems more reliable. – Christian O'Reilly Nov 28 '19 at 15:18
23

The VIRTUAL_ENV environment variable is only available if the virtual environment is activated.

For instance:

$ python3 -m venv myapp
$ source myapp/bin/activate
(myapp) $ python  -c "import os; print(os.environ['VIRTUAL_ENV'])"
/path/to/virtualenv/myapp

If not activated, you have an exception:

(myapp) $ deactivate
$ myapp/bin/python -c "import os; print(os.environ['VIRTUAL_ENV'])"
Traceback (most recent call last):
  File "<string>", line 1, in <module>
  File "/usr/lib64/python3.4/os.py", line 635, in __getitem__
    raise KeyError(key) from None
KeyError: 'VIRTUAL_ENV'

IMO, you should use sys.executable to get the path of your Python executable, and then build the path to celery:

import sys
import os

celery_name = {'linux': 'celery', 'win32': 'celery.exe'}[sys.platform]
celery_path = os.path.join(os.path.dirname(sys.executable), celery_name)
Laurent LAPORTE
  • 21,958
  • 6
  • 58
  • 103
6

How about referencing sys.prefix? It always outputs a result regardless of a virtualenv is activated or not, and also it's more convenient than getting grand parent position of sys.executable.

$ python -c 'import sys;print(sys.prefix)'
/usr
$ . venv/bin/activate
(venv) $ python -c 'import sys;print(sys.prefix)'
path/to/venv
Lyle
  • 1,238
  • 14
  • 16
0

You can use fabric to do such things from python

>>> from fabric.api import local
>>> local('which celery')
glmvrml
  • 1,612
  • 2
  • 14
  • 31
  • 1
    This will probably not work. A sub-shell started is not going to have the virtual env on $PATH so `which` won't work. – Tyler Eaves Aug 06 '14 at 18:43