1

I have a Python 3.9 script running in a virtual environment. The host environment is set up with Python 3.6 and many installed packages. I need to be able to run a shell script that only functions properly if it's run in the host environment.

It's not possible for me to make the 3.9 virtual environment work for this shell script, nor is it possible to update the shell script to work in Python 3.9.

When I run the script at the command line, I need to call deactivate, run the shell script, and then reactivate the virtual environment.

I'd like to be able to do the equivalent of that from within a Python program running in my 3.9 venv. But since I'm trying to run a shell script and not a Python program, I can't simply call the Python 3.6 interpreter directly to solve the problem.

I can think of two solutions:

  1. Create a temporary shell script that deactivates the venv and calls the target shell script. Then run that temporary shell script from my Py3.9 program. I assume the deactivation will only apply to the scope I create when I run the shell script.
  2. Create an alias for every program I want to run that first runs deactivate, e.g. alias run_myprog = "deactivate; myprog", although it would be kind of tedious to have to create one of these for every program I need to run.

Are there better solutions than the above two?

(This is related to this question. The difference is that question is asking about running a Python 3.6 program instead of a shell script that depends on Python 3.6.)

5
  • Hi @Amadan, I don't quite follow. There's no new venv to activate. Py3.6 is in the host environment, so once I deactivate the Py3.9 venv, then Py3.6 will be available. Apart from that, are you basically saying my option 1 is how you'd do it? Commented Apr 12, 2024 at 2:15
  • 1
    My bad — I both misunderstood, and then gave a suggestion that does not work (since deactivate is not exported). This being said, does this answer your question? How can I temporary bypass python virtual environment from inside a bash script? Commented Apr 12, 2024 at 7:04
  • 1
    That link seems to address what to do in the temporary shell script. It doesn't address my real question of whether that shell script is the right way to go in the first place. It sounds like you think it is; namely, that you think my Py3.9 program should create a temporary shell script that follows instructions from your linked question, run it, and then when control returns, continue with my Py3.9 script. Commented Apr 12, 2024 at 11:23
  • I've read your answers several times -- nowhere did you said a temporary shell script is not what you meant. I asked you if you thought option 1 was right, and you didn't answer that. Then I assumed a temporary shell script must be what you were talking about because I thought it was clear that I cannot modify the target script, so I couldn't see what other script you would be talking about. Since that's apparently not what you meant, I do not understand what you're suggesting I do. Commented Apr 15, 2024 at 16:54
  • Never mind. You seem to have gotten an answer that works for you. Commented Apr 16, 2024 at 1:07

1 Answer 1

2

Activation of venv in a nutshell is just adding a few environment variables.

  • VIRTUAL_ENV
  • VIRTUAL_ENV_PROMPT

and modification of few other environment variables:

  • PS1
  • PATH

VIRTUAL_ENV variable points to the root of the venv. Depending on the OS you are running, what activation does is that it adds the value of ${VIRTUAL_ENV}/Scripts on windows and ${VIRTUAL_ENV}/bin on others like linux and mac to be the first element of your active PATH env.

Removing that will essentially be same as running without activation of venv - even thought its still activated for the parent process.

How to do that, depends on how you are calling your shell script. But for example, if you are using subprocess. Most if not all of its calling methods allow you to pass a new environment for the process and you can construct that with following snippet:

import os

deactivated_env = os.environ.copy()
venv_root = deactivated_env.pop("VIRTUAL_ENV")
paths = deactivated_env["PATH"].split(os.pathsep)

deactivated_path = os.pathsep.join([x for x in paths if not x.startswith(venv_root)])
deactivated_env["PATH"] = deactivated_path
deactivated_env.pop("VIRTUAL_ENV_PROMPT")

# subprocess.run( ...., env=deactivated_env)

with that, your shellscript should fall back into using the system wide python and its settings..

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.