4

I have this script (this is the beginning of a wsgi script for openshift applications). This script activates a virtualenv using the in-python system environment.

#!/usr/bin/python
import os

virtenv = os.environ['OPENSHIFT_PYTHON_DIR'] + '/virtenv/'
virtualenv = os.path.join(virtenv, 'bin/activate_this.py')
try:
    execfile(virtualenv, dict(__file__=virtualenv))
except IOError:
    pass

What's the opposite? i.e.: is there an analogous way to do a "deactivate_this"? (a file like that does not seem to exist in any of my created virtualenvs)

This means: I don't want to reinvent the wheel. I'm asking if there's a prepared command line for that.

Luis Masuelli
  • 12,079
  • 10
  • 49
  • 87
  • have you tried subprocess? – Padraic Cunningham Aug 28 '14 at 22:41
  • Actually, no. Does that let me alter the environment variables as well? – Luis Masuelli Aug 28 '14 at 23:10
  • you just want to deactivate the virtualenv yes? – Padraic Cunningham Aug 28 '14 at 23:11
  • yes. this script (activate_this) alters the environment and the underlying shell. is there an already-made way to do the opposite? – Luis Masuelli Aug 28 '14 at 23:15
  • What specifically is the activation setting that is causing a problem? There are other ways of activating a virtual environment if using mod_wsgi. So helping us to understand what the original problem is would be better than asking us what you think is the solution. – Graham Dumpleton Aug 28 '14 at 23:30
  • I'm having some problems using openshift, and have to run nested commands. Simple calls to `os.system` passing 'bin/activate' and 'deactivate' did not work for me (they produced no effect). So I wanted to embed both activation and deactivation in the interpreter itself. – Luis Masuelli Aug 28 '14 at 23:51
  • Note the reason running `bin/activate` and `deactivate` had no (visible) effect is because they run the sub-shell in a new subprocess, and then exit. So they have no (direct) effect on the running process. You'd need to do something like `os.system("bin/activate; my_program.py")` – Tom Dalton Aug 29 '14 at 14:55
  • Yes, that's a good alternative. But I would need a way to share actual data (python objects) with the executed script. that's the reason why I did not took that way. – Luis Masuelli Aug 29 '14 at 15:01

2 Answers2

3

I believe the short answer is No.

The medium answer is "Not unless you have saved the state of the environment before executing activate_this.py".

Perhaps a way to achieve what you want is to separate the parts of your app that need to run in the venv from those that don't. Then use a subprocess to activate the venv and run whatever you want, when the subprocess terminates, your original process (in the original environment) can resume.

NB This post (How to leave/exit/deactivate a python virtualenv?) suggests the activation may provide a shell function to put-everything-back. You'd need to check if your activate_this.py script provides anything similar, though it sounds like you have already checked this.

Community
  • 1
  • 1
Tom Dalton
  • 6,122
  • 24
  • 35
2

This is a complement to the answer @TomDalton gave. Althought there's no an automatically provided way to do this, there are means provided by the activate_this script.

First, it is important to remember that this line:

execfile(virtualenv, dict(__file__=virtualenv))

is calling the function without passing a dictionary for globals nor a dictionary for locals. This will imply that the execution context will be the current globals (i.e. the one from the calling line) and locals objects. such line will alter the variables we currently have -- will override the calling environment See here for docs about.

In that way, since variables are overriden, activate_this gives us some variables like:

old_os_path = os.environ['PATH']
#the previous PATH

prev_sys_path = list(sys.path)
#the old Python Path

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)
#site_packages is the extended venv's packages dir.
#sys.path is affected here

sys.real_prefix = sys.prefix
#the old system prefix

So we can restore such variables if we want a manual deactivation:

import sys, os, site
sys.path[:0] = prev_sys_path #will also revert the added site-packages
sys.prefix = sys.real_prefix
os.setenv('PATH', old_os_path)
Luis Masuelli
  • 12,079
  • 10
  • 49
  • 87
  • Nice. It's a shame activate_this.py doesn't provide a function to do this automatically, but I think it wasn't designed for this job. – Tom Dalton Aug 28 '14 at 23:54
  • activate_this was designed for, specifically, that purpose (otherwise the script would not exist). I think it would be wise to recommend the patch (it's a nonbreaking patch) with such function. I'm trying that now. – Luis Masuelli Aug 29 '14 at 14:23
  • Sorry, I meant for being able to deactivate the environment. If it was designed for that, then expecting you to use the commands found above is non-obvious and it doesn't seem to be documented anywhere. – Tom Dalton Aug 29 '14 at 14:53
  • I did not express myself correctly. `activate_this` was designed to act in the same python path. extending it to create a `deactivate` function is straightforward. It is a pity these variables are not documented and so are able to change without prior notice. – Luis Masuelli Aug 29 '14 at 15:03