Skip to content

Instantly share code, notes, and snippets.

@liamcryan
Created May 7, 2021 20:26
Show Gist options
  • Save liamcryan/70c68aa7700309b674178cf8b04be019 to your computer and use it in GitHub Desktop.
Save liamcryan/70c68aa7700309b674178cf8b04be019 to your computer and use it in GitHub Desktop.
create venv within venv (with_pip=True)
"""
Normally to create a virtual environment, we can do so from the command prompt with::
C:\Users\me>python -m venv venv
This doesn't work when we are within a virtual environment though::
(venv) C:Users\me>python -m venv venv2
Error: Command '['C:\\Users\\me\\venv2\\Scripts\\python.exe', '-Im', 'ensurepip', '--upgrade', '--default-pip']' returned non-zero exit status 3221226505.
The issue seems to stem from the home variable in the pyvenv.cfg created from creating the virtual environment within the virtual environment::
home = C:\Users\me\venv\Scripts
include-system-site-packages = false
version = 3.7.0
We need to override this home variable so that it points to a non-virtual enviroment Python.
Below is a shows how to create a virtual environment even if you have a virtual environment activated.
"""
import os
import re
import subprocess
import venv
class EnvB(venv.EnvBuilder):
""" Subclassing venv.EnvBuilder so we can customize the pyvenv.cfg file """
def create_configuration(self, context: SimpleNamespace) -> None:
"""
Create a configuration file indicating where the environment's Python
was copied from, and whether the system site-packages should be made
available in the environment.
:param context: The information for the environment creation request
being processed.
"""
context.cfg_path = path = os.path.join(context.env_dir, 'pyvenv.cfg')
try: # this part is different from the superclass
# we want the correct home python rather than the one from within a potential virtual environment
with open(os.path.join(os.path.dirname(context.python_dir), 'pyvenv.cfg'), 'r', encoding='utf-8') as f:
context.python_dir = re.search(r'home\s=\s(.+)', f.read().split('\n')[0]).group(1)
except FileNotFoundError:
pass # the rest is the same
with open(path, 'w', encoding='utf-8') as f:
f.write('home = %s\n' % context.python_dir)
if self.system_site_packages:
incl = 'true'
else:
incl = 'false'
f.write('include-system-site-packages = %s\n' % incl)
f.write('version = %d.%d.%d\n' % sys.version_info[:3])
def create_env(venv_dir_):
venv_py = os.path.join(venv_dir_, 'Scripts', 'python.exe')
v = EnvB()
v.create(venv_dir_)
r = subprocess.run([venv_py, '-c', 'import ensurepip;ensurepip.bootstrap(upgrade=True,default_pip=True)'],
capture_output=True)
if r.stderr and not r.stdout:
raise Exception(r.stderr.decode('utf-8'))
if __name__ == '__main__':
# activate your virtual environment before running
create_env(r'C:\Users\me\venv2')
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment