Search code examples
shellpyenv

Changing python virtual environment when calling a script from a python program


I have a script, foo that changes pyenv virtual environment and runs a python program.

#!/bin/bash

pyenv activate my_env
python main.py

I call the script by

. foo

or, equivalently

source foo

and it changes the virtualenv and works perfectly.

I now want to invoke the script from a python program. I have investigated the solutions given in answers to this question and my coded looks like this

import os
import subprocess


def main() -> None:
    script_path = 'scripts/foo'
    shell_source(script_path)


def shell_source(script):
    pipe = subprocess.Popen(
        ". %s && env -0" % script,
        stdout=subprocess.PIPE,
        shell=True
        )
    output = pipe.communicate()[0].decode('utf-8')
    output = output[:-1]

    env = {}
    for line in output.split('\x00'):
        line = line.split('=', 1)
        env[line[0]] = line[1]

        os.environ.update(env)


if __name__ == '__main__':
    main()

but when I run the program I get the error

Failed to activate virtualenv. Perhaps pyenv-virtualenv has not been loaded into your shell properly. Please restart current shell and try again.

What should I do?


Solution

  • I now realise that the question is worded incorrectly; it should have said

    How to run a Python program in a virtualenv from a bash script

    The solution is not activate the virtualenv and then call the program with bare python; e.g.

    pyenv activate my_env
    python main.py
    

    but to call it from the python version in the virtualenv; e.g.

    ~/.pyenv/versions//my_env/bin/python main.py
    

    and delete the line pyenv activate my_env from the script