1

Here's what I would like to do with my Python script:

  1. Create virtual environment
  2. Change directory into environment
  3. Activate environment
  4. Install django
  5. Do other stuff...

I've managed to create the environment and change directory with the following:

import subprocess
import os

env_name = "env_new"
subprocess.run(["py", "-m", "venv", env_name])
chdir(env_name)

But activating the environment is a different story:

subprocess.run(["source", "./Scripts/activate"])  # Also tried with activate.bat

Result:

FileNotFoundError: [WinError 2] The system cannot find the file specified

subprocess.run([".", "./Scripts/activate"])  # Also tried with activate.bat

Result:

PermissionError: [WinError 5] Access is denied

Just to clarify, I made sure I was in the correct directory by using print(os.getcwd()).

After this I'd then like to install django. I think it has to happen inside the same run() method like so:

subprocess.run([".", "./Scripts/activate", "&&", "pip", "install", "django"])  # Or something...

Is this even possible?

Sean
  • 192
  • 1
  • 1
  • 14
  • If you are on Windows, what is your shell? You can't usefully run `activate` in a subprocess because the result will disappear as soon as the subprocess exits. Also, without `shell=True`, you can't use `.` which is a Bash built-in. The usual solution is to `activate` before you start Python, but depending on what you want, you might also be able to run Python as a subprocess of Python; though this is often something you will want to avoid. – tripleee Aug 19 '21 at 12:35
  • I'm using git bash. I can't activate it before hand because automating the creation of the environment as well the creation of files inside of the environment need to all happen within the script. – Sean Aug 19 '21 at 12:44
  • path to the activate script is `/bin/activate`. `source` is a bash-built in, not a command, and you need to execute it in the same process that will then execute more steps. – alexis Aug 19 '21 at 12:45
  • I know its `/bin/activate` but I've been testing just the activation from within the environment. "`source` is a bash-built in", what about `.` – Sean Aug 19 '21 at 12:51

3 Answers3

3

There is a number of things wrong here. When you run a subprocess, the environment it creates disappears when the subprocess exits.

What you can do is wrap Python inside Python, something like

import subprocess

env_name = "env_new"
subprocess.run(["py", "-m", "venv", env_name])

subprocess.run(["%s/bin/python" % env_name, "-c", """
    the rest of your Python code here
    """])

which of course is just a rather pointless complication, and better written as a shell script.

#!/bin/bash

py -m venv env_new
. ./env_new/Scripts/activate
pip install -r requirements.txt
python ./your_real_script_here.py
tripleee
  • 175,061
  • 34
  • 275
  • 318
  • I'm not entirely sure `env_name/bin/python` runs the activated Python on Windows, too. This should work on properly Unix-compatible platforms at least (though then `activate` is in `bin` too, not in `Scripts`). – tripleee Aug 19 '21 at 12:51
  • Ok I suppose I forgot to add that I will be taking a command line argument when I run the script which will contain the name for the venv e.g. `django-setup env_django`. Is there a way to pass that information on to the shell script? – Sean Aug 19 '21 at 12:58
  • The first command-line argument to a shell script is `$1` (though you'll basically always want to quote it; `"$1"`). – tripleee Aug 19 '21 at 13:03
  • I tried doing the above suggested (not the shell but the run method with python script as an argument), didn't get any errors however It's installing django globally. Any idea why? – Sean Aug 19 '21 at 13:04
  • Sounds like virtualenv/bin/python doesn't work in Windows then. You can still embed the shell script and run it all as an external process but again, the Python wrapper to do that is pretty uniquely useless. – tripleee Aug 19 '21 at 13:09
  • Ok don't worry using the script worked. Thank you so much man, I was losing my mind. I was going to accept the answer but there is a little more I would like to add for anyone else who finds this. Is it possible for me to edit yours or make a new answer? – Sean Aug 19 '21 at 13:09
  • Feel free to edit, I'll revert the changes if I think it's too intrusive. – tripleee Aug 19 '21 at 13:10
  • (Calling people "man" when you can't know their gender is rather risky.) – tripleee Aug 19 '21 at 13:11
  • "Suggested edit queue is full" can't edit. Also I use "man" with everyone lol, sorry if I offended. – Sean Aug 19 '21 at 13:12
1

Original poster here. I just want to expand on triplee's answer above by displaying the full code required to achieve my desired result.

Python Script #1 - django-setup

#!/usr/bin/env python
import subprocess
import sys

if __name__ == '__main__':
    if len(sys.argv) > 1:
        subprocess.call(f"intermediary.sh {sys.argv[1]}", shell=True)
    else:
        print("No arguments given")

Shell Script - intermediary.sh

#!/bin/bash

py -m venv "env_$1"
cd "env_$1"
. ./Scripts/activate
pip install django
mkdir "$1"
cd "$1"
django-setup-2

Python Script #2 - django-setup-2

#!/usr/bin/env python

import subprocess

subprocess.run(['django-admin', 'startproject', 'config', '.'])
print("More code here!")

Executing the command django-setup blog would achieve the following result:

env_blog/
    Scripts/
    Include/
    Lib/
    blog/
        config/
        manage.py
    pyvenv.cfg
Sean
  • 192
  • 1
  • 1
  • 14
  • The `shell=True` is useless here, and easily avoided. `subprocess.call(["intermediary.sh", sys.argv[1]])` also avoids the need for interpolating the argument into a string. Perhaps see also [Actual meaning of `shell=True` in subprocess](https://stackoverflow.com/questions/3172470/actual-meaning-of-shell-true-in-subprocess) But as suggested before, the first level of Python wrapper is rather useless, too. (If you really want to keep it in Python, you can avoid the separate script file; just pass the entire script to `subprocess.call("""py -m venv "env_$1"; ...""", shell=True)`.) – tripleee Aug 30 '21 at 06:31
  • (The current script has no Bash features; but if you need the script to be executed by Bash, you can add `executable='/bin/bash'` after `shell=True`.) – tripleee Aug 30 '21 at 06:34
-2
  1. For the creation of a virtual environment and using it, follow here.

  2. Alternatively, you may use Conda to create and manage your virtual environments.