79

I am trying to make a python environment separate from the system one (using virtualenv) in a directory which is not under /home, because I need to use it to build other software that has to be accessible to multiple users. I can create and activate the virtualenv all right, but when I sudo some command (for example to make or compile other software), it is the system python that is used (I can tell because of the available modules).

Since on Ubuntu it is not a good thing to use the root user, is there a way to tell sudo to use a virtualenv? Or maybe this is not the correct approach, and I should make a completely new python installation?

I am using the 64bit version of Ubuntu 12.04 (and python 2.7).

1
  • 2
    Does the following work? sudo $(which python) <script> May 26, 2017 at 15:40

4 Answers 4

97

The issue is almost certainly that when you run sudo, the virtualenv environment variables, aliases, functions, etc aren't being carried over.

The solution would be to explicitly run the virtual environment's Python executable with sudo. For example if your virtualenv is ./AwesomeProject, then you could run sudo ./AwesomeProject/bin/python <script> to use the script with the virtualenv with root privileges.

4
  • 6
    You could also let the first line of your script point to the Python binary in your virtualenv. #!<virtualenv_dir>/bin/python.
    – OrangeTux
    Sep 17, 2013 at 14:04
  • Ugh, annoying that this is only solution so far. On Mac, sudo python uses python from the virtual env.
    – minou
    Oct 5, 2019 at 19:56
  • @OrangeTux I tried what you suggested and it does not work for me when running the script with sudo python3 my_script.py
    – belvederef
    Feb 17, 2020 at 17:50
  • @kenkinder @gaefan In my case, I get Command not found when using sudo ./home/pradan/.virtualenvs/sk/bin/python3 main.py where main.py is my script and sk is name of my virtual env.
    – Pe Dro
    May 22, 2020 at 17:40
14

Depending on your particular use-case this may or may not solve your problem, but this wasn't yet mentioned here. Say, you want to run a Python script that was installed in your virtual environment, and you need to setuid(0) it, i.e. you want to run it as superuser. Say, your script is called myscript.py, then, you can do it like this:

(.venv) $ sudo -E env PATH=$PATH ./myscript.py

Explanation

(.venv) $ is the shell's prompt, you don't need to type it, it just shows that you are currently using some virtual environment, and you are not a privileged user.

sudo -E will tell sudo that when starting a process, it needs to copy the environment variables from your current shell environment. So, if you have any extra variables defined in .venv/bin/activate script, they should stick around while you are root.

env PATH=$PATH when using sudo -E not all environment variables are preserved, specifically, and most importantly, the PATH may be removed. The specifics of this behavior will depend on your sudoers file. This, however, will circumvent whatever's written in sudoers file, as it will copy the PATH explicitly into environment sudo creates for the new process. This is important because when your system resolves shebang comment in your myscript.py, it will look in the PATH variable, and the first directory to match the requirement for interpreter will be used. venv on the other hand, sets up the shell environment in such a way that the directory containing the symlink to the chosen Python interpreter appears first, thus causing system to locate the desired Python before any other Pythons on system path.

4

Just stumbled across this and for others who may find the same issue, Ken is correct that the env variables are not being carried over. The solution I used was to add the following lines to my script. This has the added benefit of always loading the virtual environment directly from the script. (Meaning you can use the script with crontab or launchd without any other workarounds.)

base_dir = os.path.dirname(os.path.abspath(__file__))
activate_this = os.path.join(base_dir, 'venv/bin/activate_this.py')
execfile(activate_this, dict(__file__=activate_this))

More background here: https://virtualenv.pypa.io/en/latest/userguide.html#using-virtualenv-without-bin-python

4

Sometimes you need the $PATH updated because the script runs other programs. For example pypi-install needs py2dsc-deb in the PATH. This command works: sudo sh -c ". venv/bin/activate ; pypi-install $PACKAGE"

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .