Skip to content

Instantly share code, notes, and snippets.

@scbedd
Last active February 9, 2024 02:38
Show Gist options
  • Save scbedd/194a998b36b3ccb30573db217415cc47 to your computer and use it in GitHub Desktop.
Save scbedd/194a998b36b3ccb30573db217415cc47 to your computer and use it in GitHub Desktop.

Notice that pip freeze for the invoking environment remains clean.

image

And this is what it looks like on disk:

image

import sys
import uuid
import subprocess
import os
from subprocess import CalledProcessError
from typing import List
class RunContext:
# venv_folder is the directory in which the venv dir will be created
# python_executable is the python executable to use to create the venv, defaults to _invoking_ python executable
def __init__(self, venv_folder: str, python_executable: str = sys.executable):
random_guid = str(uuid.uuid4())
self.venv_dir = os.path.join(venv_folder, random_guid)
# create venv
subprocess.run([python_executable, "-m", "venv", self.venv_dir], check=True) # this will throw CalledProcessError if it fails
# now save the python executable path
if os.name == "nt":
self.executable = os.path.join(self.venv_dir, "Scripts", f"python.exe")
else:
self.executable = os.path.abspath(os.path.join(self.venv_dir, "bin", f"python"))
# probably should double check the path assumption on macs
def run_command(self, command: List[str]):
command.insert(0, self.executable)
subprocess.run(command, check=True) # again, if anything goes wrong, we'll know. wrapper should handle CalledProcessError on failure
if __name__ == "__main__":
target_dir = "venv_dir" # this is bad, but for the sake of example this is just going to create a venv in the current directory/venv_dir
run1 = RunContext(target_dir)
try:
run1.run_command(["-m", "pip", "install", "requests"])
except CalledProcessError as e:
print(f"Failed to install requests into environment {run1.venv_dir} using executable {run1.executable}: {e}")
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment