128

I want to activate a virtualenv instance from a Python script.

I know it's quite easy to do, but all the examples I've seen use it to run commands within the env and then close the subprocess.

I simply want to activate the virtualenv and return to the shell, the same way that bin/activate does.

Something like this:

$me: my-script.py -d env-name
$(env-name)me:

Is this possible?

Relevant:

virtualenv › Invoking an env from a script

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
h3.
  • 10,688
  • 15
  • 51
  • 54

10 Answers10

118

If you want to run a Python subprocess under the virtualenv, you can do that by running the script using the Python interpreter that lives inside virtualenv's bin/ directory:

import subprocess

# Path to a Python interpreter that runs any Python script
# under the virtualenv /path/to/virtualenv/
python_bin = "/path/to/virtualenv/bin/python"

# Path to the script that must run under the virtualenv
script_file = "must/run/under/virtualenv/script.py"

subprocess.Popen([python_bin, script_file])

However, if you want to activate the virtualenv under the current Python interpreter instead of a subprocess, you can call exec passing the activate_this.py script, like this:

# Doing exec() on this file will alter the current interpreter's
# environment so you can import libraries in the virtualenv
activate_this_file = "/path/to/virtualenv/bin/activate_this.py"

exec(open(activate_this_file).read(), {'__file__': activate_this_file})

Note that you need to use the virtualenv library, not venv, for the above.

If you use venv, you can copy the implementation of virtualenv's activate_this.py, it should still more or less work with venv with just a few minor changes.

Lie Ryan
  • 62,238
  • 13
  • 100
  • 144
  • 1
    // , Shouldn't that last line in the first code block on this answer read as follows: `subprocess.Popen([venv_python_file, script_file])` ? – Nathan Basanese Aug 28 '15 at 21:56
  • 1
    // , Also, is there a way to run the `script_file` from an arbitrary location, or does it have to be in the `virtualenv` directory? – Nathan Basanese Aug 28 '15 at 21:57
  • Fixed, thanks for noticing the error. As to for your second question, no `script_file` doesn't have to be in virtualenv directory, it can be anywhere. – Lie Ryan Aug 28 '15 at 22:36
  • How can I deactivate the virtual env, if I'm using the second option? – falsePockets Apr 18 '17 at 01:22
  • @falsePockets: [XY Problem](https://meta.stackexchange.com/q/66377/148108), why do you ever want to do that? – Lie Ryan Apr 18 '17 at 02:12
  • To solve [this problem](http://stackoverflow.com/questions/43462260/runnning-python-nose-tests-in-virtual-env). I have a bunch of 'modules' which will each be uploaded to AWS as a AWS 'lambda function' (where lambda in an AWS context has a slightly different meaning to a python context). They each use different libraries, so they each need different virtual envs. I have a python script that runs unit tests and uploads each module to AWS. Each test needs to be done in it's respective virtual env. – falsePockets Apr 18 '17 at 03:50
  • 1
    How do you do this using the second option and python3? Looks like exec has replaced execfile in python3, but I'm not able to get it to work. – djsosofresh Jun 19 '18 at 18:28
  • @djsosofresh I was also investigating this and in the comments of this answer https://stackoverflow.com/a/33637414/8691571 I got the info from ShadowRanger that it is not possible. I guess we have not understood Lie Ryan's answer well enough. – Paloha Nov 26 '21 at 13:38
  • The third party module `virtualenv` still works for Python 3, if you just want things to work, use that instead of the built-in `venv` or `pyvenv` to create your virtual environment. The ShadowRanger answer that you linked also pointed out a workaround if you insist on using the built-in version of the module, you can just copy the `activate_this.py` from the third party `virtualenv` module into your project. It's not impossible to make it work in `venv`, though it may be a bit involved. – Lie Ryan Nov 26 '21 at 14:05
  • 2
    @djsosofresh This worked for me in Python 3.6 apparently: `exec(compile(open(activate_this_file, "rb").read(), activate_this_file, 'exec'), dict(__file__=activate_this_file))` – Calimo Dec 15 '21 at 11:51
76

The simplest solution to run your script under virtualenv's interpreter is to replace the default shebang line with path to your virtualenv's interpreter like so at the beginning of the script:

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

Make the script executable:

chmod u+x script.py

Run the script:

./script.py

Voila!

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
nafooesi
  • 1,097
  • 12
  • 18
  • 3
    +1 for elegance. Note on windows this requires a posix compliant environment that understands shebang lines like cygwin or msys – qneill Feb 01 '17 at 16:07
  • 1
    Works for python 3.6.3 and windows 10! – toonarmycaptain Nov 28 '17 at 15:26
  • Think I might have misunderstood the original question. He wants to activate the virtual environment with a script and return to shell with the activated environment. My answer runs script in the virtual environment but the returned shell does not retain the environment. The modern day solution is virtualenvwrapper: http://virtualenvwrapper.readthedocs.io/en/latest/#. It allows one to activate and switch between different virtualenvs. – nafooesi Dec 08 '17 at 05:39
  • This works like magic! – quantum Mar 30 '22 at 18:22
  • Could anyone please post an working example for this? Its quite confusing since you are using the commands like those in a command prompt and not a python script. – Pycoder Oct 23 '22 at 08:30
26

To run another Python environment according to the official Virtualenv documentation, in the command line you can specify the full path to the executable Python binary, just that (no need to active the virtualenv before):

/path/to/virtualenv/bin/python

The same applies if you want to invoke a script from the command line with your virtualenv. You don't need to activate it before:

me$ /path/to/virtualenv/bin/python myscript.py

The same for a Windows environment (whether it is from the command line or from a script):

> \path\to\env\Scripts\python.exe myscript.py
Mariano Ruiz
  • 4,314
  • 2
  • 38
  • 34
  • 7
    Question is: Activate a virtualenv with a python script (NOT from Shell) – Zaheer Oct 20 '17 at 06:25
  • 5
    Yes, my point is that you can just call the python runtime from a virtual environment without the need to activate it before, from the console or from a script. I will clarify the answer, thanks! – Mariano Ruiz Oct 20 '17 at 14:54
  • Oh my goodness! I didn't think about it. this is the only solution that worked for me :). Now, When I am executing python script from php, I am using: "path/to/virtualenv/bin/python mypythonscript.py" – Zaheer Oct 21 '17 at 18:31
25

It turns out that, yes, the problem is not simple, but the solution is.

First I had to create a shell script to wrap the "source" command. That said I used the "." instead, because I've read that it's better to use it than source for Bash scripts.

#!/bin/bash
. /path/to/env/bin/activate

Then from my Python script I can simply do this:

import os
os.system('/bin/bash --rcfile /path/to/myscript.sh')

The whole trick lies within the --rcfile argument.

When the Python interpreter exits it leaves the current shell in the activated environment.

Win!

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
h3.
  • 10,688
  • 15
  • 51
  • 54
  • 5
    I really don't get it. Why don't you just do that : `os.system('/bin/bash --rcfile path/to/env/activate')` You know, when an instance of bash is started, it takes .bashrc as an argument for the --rcfile. So just specify that the rcfile is your activate file... No ? – Depado Aug 03 '13 at 22:09
  • @Depado I just tried your solution and this will activate the shell within python. at least when I try it in the shell. >>> os.system('/bin/bash --rcfile /var/envs/test/bin/activate') (test)tcraig@tallis-desktop:~$ (test)tcraig@tallis-desktop:~$ ls -l total 706288 – Trenton Aug 09 '13 at 12:29
  • Maybe but this works in a script. The only inconvenient with this technique is that you don't get all your aliases and everything you had in your ~/.bashrc. But I'm fine with it. For example the "ls" command has no color. But everything works for me. When I want to leave, I just Ctrl+D – Depado Aug 09 '13 at 12:51
  • 11
    "When the python interpreter exits it leave the current shell in the activated environment" What? It spawns a totally new shell as a subprocess and waits until it finishes. – Kos Nov 01 '13 at 15:43
  • 1
    In order to avoid creating more new files on my repository and to also replicate the current bash config, I did this: `cat ~/.bashrc env/bin/activate > env/bin/activate2 && /bin/bash --rcfile env/bin/activate2` – WhyWhat Feb 08 '16 at 14:28
8

Just a simple solution that works for me. I don't know why you need the Bash script which basically does a useless step (am I wrong ?)

import os
os.system('/bin/bash  --rcfile flask/bin/activate')

Which basically does what you need:

[hellsing@silence Foundation]$ python2.7 pythonvenv.py
(flask)[hellsing@silence Foundation]$

Then instead of deactivating the virtual environment, just Ctrl + D or exit. Is that a possible solution or isn't that what you wanted?

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Depado
  • 4,811
  • 3
  • 41
  • 63
8

The top answer only works for Python 2.x

For Python 3.x, use this:

activate_this_file = "/path/to/virtualenv/bin/activate_this.py"

exec(compile(open(activate_this_file, "rb").read(), activate_this_file, 'exec'), dict(__file__=activate_this_file))

Reference: What is an alternative to execfile in Python 3?

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Asaad
  • 81
  • 1
  • 2
  • 1
    what is activate_this.py – randy Pen Aug 27 '19 at 07:45
  • 1
    @randyPen, the activate_this.py file is automatically added when you build the virtualenv in your project directory. (i.e. /project/directory/venv/bin/activate_this.py) – TheoreticallyNick Nov 19 '19 at 04:02
  • 1
    note that Python does not use the same dir structure on all operating systems, so this is not a universal solution (neither are any of the other questions, but it'd be nice if it were updated to "just work(tm)" instead of not working on any windows machine) – Mike 'Pomax' Kamermans Mar 26 '22 at 17:18
2

The child process environment is lost in the moment it ceases to exist, and moving the environment content from there to the parent is somewhat tricky.

You probably need to spawn a shell script (you can generate one dynamically to /tmp) which will output the virtualenv environment variables to a file, which you then read in the parent Python process and put in os.environ.

Or you simply parse the activate script in using for the line in open("bin/activate"), manually extract stuff, and put in os.environ. It is tricky, but not impossible.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Mikko Ohtamaa
  • 82,057
  • 50
  • 264
  • 435
1

For python2/3, Using below code snippet we can activate virtual env.

activate_this = "/home/<--path-->/<--virtual env name -->/bin/activate_this.py" #for ubuntu
activate_this = "D:\<-- path -->\<--virtual env name -->\Scripts\\activate_this.py" #for windows
with open(activate_this) as f:
    code = compile(f.read(), activate_this, 'exec')
    exec(code, dict(__file__=activate_this))
1

I had the same issue and there was no activate_this.py in the Scripts directory of my environment.

activate_this.py

"""By using execfile(this_file, dict(__file__=this_file)) you will
activate this virtualenv environment.
This can be used when you must use an existing Python interpreter, not
the virtualenv bin/python
"""

try:
    __file__
except NameError:
    raise AssertionError(
        "You must run this like execfile('path/to/active_this.py', dict(__file__='path/to/activate_this.py'))")
import sys
import os

base = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
if(sys.platform=='win32'):
     site_packages = os.path.join(base, 'Lib', 'site-packages')
else:
     site_packages = os.path.join(base, 'lib', 'python%s' % sys.version[:3], 'site-packages')
prev_sys_path = list(sys.path)
import site
site.addsitedir(site_packages)
sys.real_prefix = sys.prefix
sys.prefix = base
# Move the added items to the front of the path:
new_sys_path = []
for item in list(sys.path):
    if item not in prev_sys_path:
        new_sys_path.append(item)
        sys.path.remove(item)
sys.path[:0] = new_sys_path

Copy the file to the Scripts directory of your environment and use it like this:

def activate_virtual_environment(environment_root):
    """Configures the virtual environment starting at ``environment_root``."""
    activate_script = os.path.join(
        environment_root, 'Scripts', 'activate_this.py')
    execfile(activate_script, {'__file__': activate_script})

activate_virtual_environment('path/to/your/venv')

Refrence: https://github.com/dcreager/virtualenv/blob/master/virtualenv_support/activate_this.py

rahul_5409
  • 71
  • 1
  • 1
  • 5
-1

You should create all your virtualenvs in one folder, such as virt.

Assuming your virtualenv folder name is virt, if not change it

cd
mkdir custom

Copy the below lines...

#!/usr/bin/env bash
ENV_PATH="$HOME/virt/$1/bin/activate"
bash --rcfile $ENV_PATH -i

Create a shell script file and paste the above lines...

touch custom/vhelper
nano custom/vhelper

Grant executable permission to your file:

sudo chmod +x custom/vhelper

Now export that custom folder path so that you can find it on the command-line by clicking tab...

export PATH=$PATH:"$HOME/custom"

Now you can use it from anywhere by just typing the below command...

vhelper YOUR_VIRTUAL_ENV_FOLDER_NAME

Suppose it is abc then...

vhelper abc
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Smit Mehta
  • 91
  • 9