ChatGPT解决这个技术问题 Extra ChatGPT

Activate a virtualenv with a Python script

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


J
Jean-François Fabre

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 use the activate_this.py script:

# Doing execfile() 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"

execfile(activate_this_file, dict(__file__=activate_this_file))

// , Shouldn't that last line in the first code block on this answer read as follows: subprocess.Popen([venv_python_file, script_file]) ?
// , Also, is there a way to run the script_file from an arbitrary location, or does it have to be in the virtualenv directory?
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.
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 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))
P
Peter Mortensen

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!


+1 for elegance. Note on windows this requires a posix compliant environment that understands shebang lines like cygwin or msys
Works for python 3.6.3 and windows 10!
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: virtualenvwrapper.readthedocs.io/en/latest/#. It allows one to activate and switch between different virtualenvs.
This works like magic!
P
Peter Mortensen

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!


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 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
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
"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.
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
M
Mariano Ruiz

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

Question is: Activate a virtualenv with a python script (NOT from Shell)
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!
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"
P
Peter Mortensen

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?


P
Peter Mortensen

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?


what is activate_this.py
@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)
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)
P
Peter Mortensen

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.


R
Ronak Delvadiya

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))

surely it would make more sense to not have to guess, and just ask platform.system() which OS we're in, then set activate_this to what it needs to be?
r
rahul_5409

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


P
Peter Mortensen

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