(root)/
Python-3.11.7/
Lib/
test/
test_venv.py
       1  """
       2  Test harness for the venv module.
       3  
       4  Copyright (C) 2011-2012 Vinay Sajip.
       5  Licensed to the PSF under a contributor agreement.
       6  """
       7  
       8  import contextlib
       9  import ensurepip
      10  import os
      11  import os.path
      12  import pathlib
      13  import re
      14  import shutil
      15  import struct
      16  import subprocess
      17  import sys
      18  import sysconfig
      19  import tempfile
      20  from test.support import (captured_stdout, captured_stderr, requires_zlib,
      21                            skip_if_broken_multiprocessing_synchronize, verbose,
      22                            requires_subprocess, is_emscripten, is_wasi,
      23                            requires_venv_with_pip, TEST_HOME_DIR,
      24                            requires_resource, copy_python_src_ignore)
      25  from test.support.os_helper import (can_symlink, EnvironmentVarGuard, rmtree)
      26  import unittest
      27  import venv
      28  from unittest.mock import patch, Mock
      29  
      30  try:
      31      import ctypes
      32  except ImportError:
      33      ctypes = None
      34  
      35  # Platforms that set sys._base_executable can create venvs from within
      36  # another venv, so no need to skip tests that require venv.create().
      37  requireVenvCreate = unittest.skipUnless(
      38      sys.prefix == sys.base_prefix
      39      or sys._base_executable != sys.executable,
      40      'cannot run venv.create from within a venv on this platform')
      41  
      42  if is_emscripten or is_wasi:
      43      raise unittest.SkipTest("venv is not available on Emscripten/WASI.")
      44  
      45  @requires_subprocess()
      46  def check_output(cmd, encoding=None):
      47      p = subprocess.Popen(cmd,
      48          stdout=subprocess.PIPE,
      49          stderr=subprocess.PIPE,
      50          encoding=encoding)
      51      out, err = p.communicate()
      52      if p.returncode:
      53          if verbose and err:
      54              print(err.decode('utf-8', 'backslashreplace'))
      55          raise subprocess.CalledProcessError(
      56              p.returncode, cmd, out, err)
      57      return out, err
      58  
      59  class ESC[4;38;5;81mBaseTest(ESC[4;38;5;149munittestESC[4;38;5;149m.ESC[4;38;5;149mTestCase):
      60      """Base class for venv tests."""
      61      maxDiff = 80 * 50
      62  
      63      def setUp(self):
      64          self.env_dir = os.path.realpath(tempfile.mkdtemp())
      65          if os.name == 'nt':
      66              self.bindir = 'Scripts'
      67              self.lib = ('Lib',)
      68              self.include = 'Include'
      69          else:
      70              self.bindir = 'bin'
      71              self.lib = ('lib', 'python%d.%d' % sys.version_info[:2])
      72              self.include = 'include'
      73          executable = sys._base_executable
      74          self.exe = os.path.split(executable)[-1]
      75          if (sys.platform == 'win32'
      76              and os.path.lexists(executable)
      77              and not os.path.exists(executable)):
      78              self.cannot_link_exe = True
      79          else:
      80              self.cannot_link_exe = False
      81  
      82      def tearDown(self):
      83          rmtree(self.env_dir)
      84  
      85      def run_with_capture(self, func, *args, **kwargs):
      86          with captured_stdout() as output:
      87              with captured_stderr() as error:
      88                  func(*args, **kwargs)
      89          return output.getvalue(), error.getvalue()
      90  
      91      def get_env_file(self, *args):
      92          return os.path.join(self.env_dir, *args)
      93  
      94      def get_text_file_contents(self, *args, encoding='utf-8'):
      95          with open(self.get_env_file(*args), 'r', encoding=encoding) as f:
      96              result = f.read()
      97          return result
      98  
      99  class ESC[4;38;5;81mBasicTest(ESC[4;38;5;149mBaseTest):
     100      """Test venv module functionality."""
     101  
     102      def isdir(self, *args):
     103          fn = self.get_env_file(*args)
     104          self.assertTrue(os.path.isdir(fn))
     105  
     106      def test_defaults_with_str_path(self):
     107          """
     108          Test the create function with default arguments and a str path.
     109          """
     110          rmtree(self.env_dir)
     111          self.run_with_capture(venv.create, self.env_dir)
     112          self._check_output_of_default_create()
     113  
     114      def test_defaults_with_pathlib_path(self):
     115          """
     116          Test the create function with default arguments and a pathlib.Path path.
     117          """
     118          rmtree(self.env_dir)
     119          self.run_with_capture(venv.create, pathlib.Path(self.env_dir))
     120          self._check_output_of_default_create()
     121  
     122      def _check_output_of_default_create(self):
     123          self.isdir(self.bindir)
     124          self.isdir(self.include)
     125          self.isdir(*self.lib)
     126          # Issue 21197
     127          p = self.get_env_file('lib64')
     128          conditions = ((struct.calcsize('P') == 8) and (os.name == 'posix') and
     129                        (sys.platform != 'darwin'))
     130          if conditions:
     131              self.assertTrue(os.path.islink(p))
     132          else:
     133              self.assertFalse(os.path.exists(p))
     134          data = self.get_text_file_contents('pyvenv.cfg')
     135          executable = sys._base_executable
     136          path = os.path.dirname(executable)
     137          self.assertIn('home = %s' % path, data)
     138          self.assertIn('executable = %s' %
     139                        os.path.realpath(sys.executable), data)
     140          copies = '' if os.name=='nt' else ' --copies'
     141          cmd = f'command = {sys.executable} -m venv{copies} --without-pip {self.env_dir}'
     142          self.assertIn(cmd, data)
     143          fn = self.get_env_file(self.bindir, self.exe)
     144          if not os.path.exists(fn):  # diagnostics for Windows buildbot failures
     145              bd = self.get_env_file(self.bindir)
     146              print('Contents of %r:' % bd)
     147              print('    %r' % os.listdir(bd))
     148          self.assertTrue(os.path.exists(fn), 'File %r should exist.' % fn)
     149  
     150      def test_config_file_command_key(self):
     151          attrs = [
     152              (None, None),
     153              ('symlinks', '--copies'),
     154              ('with_pip', '--without-pip'),
     155              ('system_site_packages', '--system-site-packages'),
     156              ('clear', '--clear'),
     157              ('upgrade', '--upgrade'),
     158              ('upgrade_deps', '--upgrade-deps'),
     159              ('prompt', '--prompt'),
     160          ]
     161          for attr, opt in attrs:
     162              rmtree(self.env_dir)
     163              if not attr:
     164                  b = venv.EnvBuilder()
     165              else:
     166                  b = venv.EnvBuilder(
     167                      **{attr: False if attr in ('with_pip', 'symlinks') else True})
     168              b.upgrade_dependencies = Mock() # avoid pip command to upgrade deps
     169              b._setup_pip = Mock() # avoid pip setup
     170              self.run_with_capture(b.create, self.env_dir)
     171              data = self.get_text_file_contents('pyvenv.cfg')
     172              if not attr:
     173                  for opt in ('--system-site-packages', '--clear', '--upgrade',
     174                          '--upgrade-deps', '--prompt'):
     175                      self.assertNotRegex(data, rf'command = .* {opt}')
     176              elif os.name=='nt' and attr=='symlinks':
     177                  pass
     178              else:
     179                  self.assertRegex(data, rf'command = .* {opt}')
     180  
     181      def test_prompt(self):
     182          env_name = os.path.split(self.env_dir)[1]
     183  
     184          rmtree(self.env_dir)
     185          builder = venv.EnvBuilder()
     186          self.run_with_capture(builder.create, self.env_dir)
     187          context = builder.ensure_directories(self.env_dir)
     188          data = self.get_text_file_contents('pyvenv.cfg')
     189          self.assertEqual(context.prompt, '(%s) ' % env_name)
     190          self.assertNotIn("prompt = ", data)
     191  
     192          rmtree(self.env_dir)
     193          builder = venv.EnvBuilder(prompt='My prompt')
     194          self.run_with_capture(builder.create, self.env_dir)
     195          context = builder.ensure_directories(self.env_dir)
     196          data = self.get_text_file_contents('pyvenv.cfg')
     197          self.assertEqual(context.prompt, '(My prompt) ')
     198          self.assertIn("prompt = 'My prompt'\n", data)
     199  
     200          rmtree(self.env_dir)
     201          builder = venv.EnvBuilder(prompt='.')
     202          cwd = os.path.basename(os.getcwd())
     203          self.run_with_capture(builder.create, self.env_dir)
     204          context = builder.ensure_directories(self.env_dir)
     205          data = self.get_text_file_contents('pyvenv.cfg')
     206          self.assertEqual(context.prompt, '(%s) ' % cwd)
     207          self.assertIn("prompt = '%s'\n" % cwd, data)
     208  
     209      def test_upgrade_dependencies(self):
     210          builder = venv.EnvBuilder()
     211          bin_path = 'Scripts' if sys.platform == 'win32' else 'bin'
     212          python_exe = os.path.split(sys.executable)[1]
     213          with tempfile.TemporaryDirectory() as fake_env_dir:
     214              expect_exe = os.path.normcase(
     215                  os.path.join(fake_env_dir, bin_path, python_exe)
     216              )
     217              if sys.platform == 'win32':
     218                  expect_exe = os.path.normcase(os.path.realpath(expect_exe))
     219  
     220              def pip_cmd_checker(cmd, **kwargs):
     221                  cmd[0] = os.path.normcase(cmd[0])
     222                  self.assertEqual(
     223                      cmd,
     224                      [
     225                          expect_exe,
     226                          '-m',
     227                          'pip',
     228                          'install',
     229                          '--upgrade',
     230                          'pip',
     231                          'setuptools'
     232                      ]
     233                  )
     234  
     235              fake_context = builder.ensure_directories(fake_env_dir)
     236              with patch('venv.subprocess.check_output', pip_cmd_checker):
     237                  builder.upgrade_dependencies(fake_context)
     238  
     239      @requireVenvCreate
     240      def test_prefixes(self):
     241          """
     242          Test that the prefix values are as expected.
     243          """
     244          # check a venv's prefixes
     245          rmtree(self.env_dir)
     246          self.run_with_capture(venv.create, self.env_dir)
     247          envpy = os.path.join(self.env_dir, self.bindir, self.exe)
     248          cmd = [envpy, '-c', None]
     249          for prefix, expected in (
     250              ('prefix', self.env_dir),
     251              ('exec_prefix', self.env_dir),
     252              ('base_prefix', sys.base_prefix),
     253              ('base_exec_prefix', sys.base_exec_prefix)):
     254              cmd[2] = 'import sys; print(sys.%s)' % prefix
     255              out, err = check_output(cmd)
     256              self.assertEqual(out.strip(), expected.encode(), prefix)
     257  
     258      @requireVenvCreate
     259      def test_sysconfig(self):
     260          """
     261          Test that the sysconfig functions work in a virtual environment.
     262          """
     263          rmtree(self.env_dir)
     264          self.run_with_capture(venv.create, self.env_dir, symlinks=False)
     265          envpy = os.path.join(self.env_dir, self.bindir, self.exe)
     266          cmd = [envpy, '-c', None]
     267          for call, expected in (
     268              # installation scheme
     269              ('get_preferred_scheme("prefix")', 'venv'),
     270              ('get_default_scheme()', 'venv'),
     271              # build environment
     272              ('is_python_build()', str(sysconfig.is_python_build())),
     273              ('get_makefile_filename()', sysconfig.get_makefile_filename()),
     274              ('get_config_h_filename()', sysconfig.get_config_h_filename())):
     275              with self.subTest(call):
     276                  cmd[2] = 'import sysconfig; print(sysconfig.%s)' % call
     277                  out, err = check_output(cmd)
     278                  self.assertEqual(out.strip(), expected.encode(), err)
     279  
     280      @requireVenvCreate
     281      @unittest.skipUnless(can_symlink(), 'Needs symlinks')
     282      def test_sysconfig_symlinks(self):
     283          """
     284          Test that the sysconfig functions work in a virtual environment.
     285          """
     286          rmtree(self.env_dir)
     287          self.run_with_capture(venv.create, self.env_dir, symlinks=True)
     288          envpy = os.path.join(self.env_dir, self.bindir, self.exe)
     289          cmd = [envpy, '-c', None]
     290          for call, expected in (
     291              # installation scheme
     292              ('get_preferred_scheme("prefix")', 'venv'),
     293              ('get_default_scheme()', 'venv'),
     294              # build environment
     295              ('is_python_build()', str(sysconfig.is_python_build())),
     296              ('get_makefile_filename()', sysconfig.get_makefile_filename()),
     297              ('get_config_h_filename()', sysconfig.get_config_h_filename())):
     298              with self.subTest(call):
     299                  cmd[2] = 'import sysconfig; print(sysconfig.%s)' % call
     300                  out, err = check_output(cmd)
     301                  self.assertEqual(out.strip(), expected.encode(), err)
     302  
     303      if sys.platform == 'win32':
     304          ENV_SUBDIRS = (
     305              ('Scripts',),
     306              ('Include',),
     307              ('Lib',),
     308              ('Lib', 'site-packages'),
     309          )
     310      else:
     311          ENV_SUBDIRS = (
     312              ('bin',),
     313              ('include',),
     314              ('lib',),
     315              ('lib', 'python%d.%d' % sys.version_info[:2]),
     316              ('lib', 'python%d.%d' % sys.version_info[:2], 'site-packages'),
     317          )
     318  
     319      def create_contents(self, paths, filename):
     320          """
     321          Create some files in the environment which are unrelated
     322          to the virtual environment.
     323          """
     324          for subdirs in paths:
     325              d = os.path.join(self.env_dir, *subdirs)
     326              os.mkdir(d)
     327              fn = os.path.join(d, filename)
     328              with open(fn, 'wb') as f:
     329                  f.write(b'Still here?')
     330  
     331      def test_overwrite_existing(self):
     332          """
     333          Test creating environment in an existing directory.
     334          """
     335          self.create_contents(self.ENV_SUBDIRS, 'foo')
     336          venv.create(self.env_dir)
     337          for subdirs in self.ENV_SUBDIRS:
     338              fn = os.path.join(self.env_dir, *(subdirs + ('foo',)))
     339              self.assertTrue(os.path.exists(fn))
     340              with open(fn, 'rb') as f:
     341                  self.assertEqual(f.read(), b'Still here?')
     342  
     343          builder = venv.EnvBuilder(clear=True)
     344          builder.create(self.env_dir)
     345          for subdirs in self.ENV_SUBDIRS:
     346              fn = os.path.join(self.env_dir, *(subdirs + ('foo',)))
     347              self.assertFalse(os.path.exists(fn))
     348  
     349      def clear_directory(self, path):
     350          for fn in os.listdir(path):
     351              fn = os.path.join(path, fn)
     352              if os.path.islink(fn) or os.path.isfile(fn):
     353                  os.remove(fn)
     354              elif os.path.isdir(fn):
     355                  rmtree(fn)
     356  
     357      def test_unoverwritable_fails(self):
     358          #create a file clashing with directories in the env dir
     359          for paths in self.ENV_SUBDIRS[:3]:
     360              fn = os.path.join(self.env_dir, *paths)
     361              with open(fn, 'wb') as f:
     362                  f.write(b'')
     363              self.assertRaises((ValueError, OSError), venv.create, self.env_dir)
     364              self.clear_directory(self.env_dir)
     365  
     366      def test_upgrade(self):
     367          """
     368          Test upgrading an existing environment directory.
     369          """
     370          # See Issue #21643: the loop needs to run twice to ensure
     371          # that everything works on the upgrade (the first run just creates
     372          # the venv).
     373          for upgrade in (False, True):
     374              builder = venv.EnvBuilder(upgrade=upgrade)
     375              self.run_with_capture(builder.create, self.env_dir)
     376              self.isdir(self.bindir)
     377              self.isdir(self.include)
     378              self.isdir(*self.lib)
     379              fn = self.get_env_file(self.bindir, self.exe)
     380              if not os.path.exists(fn):
     381                  # diagnostics for Windows buildbot failures
     382                  bd = self.get_env_file(self.bindir)
     383                  print('Contents of %r:' % bd)
     384                  print('    %r' % os.listdir(bd))
     385              self.assertTrue(os.path.exists(fn), 'File %r should exist.' % fn)
     386  
     387      def test_isolation(self):
     388          """
     389          Test isolation from system site-packages
     390          """
     391          for ssp, s in ((True, 'true'), (False, 'false')):
     392              builder = venv.EnvBuilder(clear=True, system_site_packages=ssp)
     393              builder.create(self.env_dir)
     394              data = self.get_text_file_contents('pyvenv.cfg')
     395              self.assertIn('include-system-site-packages = %s\n' % s, data)
     396  
     397      @unittest.skipUnless(can_symlink(), 'Needs symlinks')
     398      def test_symlinking(self):
     399          """
     400          Test symlinking works as expected
     401          """
     402          for usl in (False, True):
     403              builder = venv.EnvBuilder(clear=True, symlinks=usl)
     404              builder.create(self.env_dir)
     405              fn = self.get_env_file(self.bindir, self.exe)
     406              # Don't test when False, because e.g. 'python' is always
     407              # symlinked to 'python3.3' in the env, even when symlinking in
     408              # general isn't wanted.
     409              if usl:
     410                  if self.cannot_link_exe:
     411                      # Symlinking is skipped when our executable is already a
     412                      # special app symlink
     413                      self.assertFalse(os.path.islink(fn))
     414                  else:
     415                      self.assertTrue(os.path.islink(fn))
     416  
     417      # If a venv is created from a source build and that venv is used to
     418      # run the test, the pyvenv.cfg in the venv created in the test will
     419      # point to the venv being used to run the test, and we lose the link
     420      # to the source build - so Python can't initialise properly.
     421      @requireVenvCreate
     422      def test_executable(self):
     423          """
     424          Test that the sys.executable value is as expected.
     425          """
     426          rmtree(self.env_dir)
     427          self.run_with_capture(venv.create, self.env_dir)
     428          envpy = os.path.join(os.path.realpath(self.env_dir),
     429                               self.bindir, self.exe)
     430          out, err = check_output([envpy, '-c',
     431              'import sys; print(sys.executable)'])
     432          self.assertEqual(out.strip(), envpy.encode())
     433  
     434      @unittest.skipUnless(can_symlink(), 'Needs symlinks')
     435      def test_executable_symlinks(self):
     436          """
     437          Test that the sys.executable value is as expected.
     438          """
     439          rmtree(self.env_dir)
     440          builder = venv.EnvBuilder(clear=True, symlinks=True)
     441          builder.create(self.env_dir)
     442          envpy = os.path.join(os.path.realpath(self.env_dir),
     443                               self.bindir, self.exe)
     444          out, err = check_output([envpy, '-c',
     445              'import sys; print(sys.executable)'])
     446          self.assertEqual(out.strip(), envpy.encode())
     447  
     448      @unittest.skipUnless(os.name == 'nt', 'only relevant on Windows')
     449      def test_unicode_in_batch_file(self):
     450          """
     451          Test handling of Unicode paths
     452          """
     453          rmtree(self.env_dir)
     454          env_dir = os.path.join(os.path.realpath(self.env_dir), 'ϼўТλФЙ')
     455          builder = venv.EnvBuilder(clear=True)
     456          builder.create(env_dir)
     457          activate = os.path.join(env_dir, self.bindir, 'activate.bat')
     458          envpy = os.path.join(env_dir, self.bindir, self.exe)
     459          out, err = check_output(
     460              [activate, '&', self.exe, '-c', 'print(0)'],
     461              encoding='oem',
     462          )
     463          self.assertEqual(out.strip(), '0')
     464  
     465      @requireVenvCreate
     466      def test_multiprocessing(self):
     467          """
     468          Test that the multiprocessing is able to spawn.
     469          """
     470          # bpo-36342: Instantiation of a Pool object imports the
     471          # multiprocessing.synchronize module. Skip the test if this module
     472          # cannot be imported.
     473          skip_if_broken_multiprocessing_synchronize()
     474  
     475          rmtree(self.env_dir)
     476          self.run_with_capture(venv.create, self.env_dir)
     477          envpy = os.path.join(os.path.realpath(self.env_dir),
     478                               self.bindir, self.exe)
     479          out, err = check_output([envpy, '-c',
     480              'from multiprocessing import Pool; '
     481              'pool = Pool(1); '
     482              'print(pool.apply_async("Python".lower).get(3)); '
     483              'pool.terminate()'])
     484          self.assertEqual(out.strip(), "python".encode())
     485  
     486      @requireVenvCreate
     487      def test_multiprocessing_recursion(self):
     488          """
     489          Test that the multiprocessing is able to spawn itself
     490          """
     491          skip_if_broken_multiprocessing_synchronize()
     492  
     493          rmtree(self.env_dir)
     494          self.run_with_capture(venv.create, self.env_dir)
     495          envpy = os.path.join(os.path.realpath(self.env_dir),
     496                               self.bindir, self.exe)
     497          script = os.path.join(TEST_HOME_DIR, '_test_venv_multiprocessing.py')
     498          subprocess.check_call([envpy, script])
     499  
     500      @unittest.skipIf(os.name == 'nt', 'not relevant on Windows')
     501      def test_deactivate_with_strict_bash_opts(self):
     502          bash = shutil.which("bash")
     503          if bash is None:
     504              self.skipTest("bash required for this test")
     505          rmtree(self.env_dir)
     506          builder = venv.EnvBuilder(clear=True)
     507          builder.create(self.env_dir)
     508          activate = os.path.join(self.env_dir, self.bindir, "activate")
     509          test_script = os.path.join(self.env_dir, "test_strict.sh")
     510          with open(test_script, "w") as f:
     511              f.write("set -euo pipefail\n"
     512                      f"source {activate}\n"
     513                      "deactivate\n")
     514          out, err = check_output([bash, test_script])
     515          self.assertEqual(out, "".encode())
     516          self.assertEqual(err, "".encode())
     517  
     518  
     519      @unittest.skipUnless(sys.platform == 'darwin', 'only relevant on macOS')
     520      def test_macos_env(self):
     521          rmtree(self.env_dir)
     522          builder = venv.EnvBuilder()
     523          builder.create(self.env_dir)
     524  
     525          envpy = os.path.join(os.path.realpath(self.env_dir),
     526                               self.bindir, self.exe)
     527          out, err = check_output([envpy, '-c',
     528              'import os; print("__PYVENV_LAUNCHER__" in os.environ)'])
     529          self.assertEqual(out.strip(), 'False'.encode())
     530  
     531      def test_pathsep_error(self):
     532          """
     533          Test that venv creation fails when the target directory contains
     534          the path separator.
     535          """
     536          rmtree(self.env_dir)
     537          bad_itempath = self.env_dir + os.pathsep
     538          self.assertRaises(ValueError, venv.create, bad_itempath)
     539          self.assertRaises(ValueError, venv.create, pathlib.Path(bad_itempath))
     540  
     541      @unittest.skipIf(os.name == 'nt', 'not relevant on Windows')
     542      @requireVenvCreate
     543      def test_zippath_from_non_installed_posix(self):
     544          """
     545          Test that when create venv from non-installed python, the zip path
     546          value is as expected.
     547          """
     548          rmtree(self.env_dir)
     549          # First try to create a non-installed python. It's not a real full
     550          # functional non-installed python, but enough for this test.
     551          platlibdir = sys.platlibdir
     552          non_installed_dir = os.path.realpath(tempfile.mkdtemp())
     553          self.addCleanup(rmtree, non_installed_dir)
     554          bindir = os.path.join(non_installed_dir, self.bindir)
     555          os.mkdir(bindir)
     556          shutil.copy2(sys.executable, bindir)
     557          libdir = os.path.join(non_installed_dir, platlibdir, self.lib[1])
     558          os.makedirs(libdir)
     559          landmark = os.path.join(libdir, "os.py")
     560          stdlib_zip = "python%d%d.zip" % sys.version_info[:2]
     561          zip_landmark = os.path.join(non_installed_dir,
     562                                      platlibdir,
     563                                      stdlib_zip)
     564          additional_pythonpath_for_non_installed = []
     565  
     566          # Copy stdlib files to the non-installed python so venv can
     567          # correctly calculate the prefix.
     568          for eachpath in sys.path:
     569              if eachpath.endswith(".zip"):
     570                  if os.path.isfile(eachpath):
     571                      shutil.copyfile(
     572                          eachpath,
     573                          os.path.join(non_installed_dir, platlibdir))
     574              elif os.path.isfile(os.path.join(eachpath, "os.py")):
     575                  names = os.listdir(eachpath)
     576                  ignored_names = copy_python_src_ignore(eachpath, names)
     577                  for name in names:
     578                      if name in ignored_names:
     579                          continue
     580                      if name == "site-packages":
     581                          continue
     582                      fn = os.path.join(eachpath, name)
     583                      if os.path.isfile(fn):
     584                          shutil.copy(fn, libdir)
     585                      elif os.path.isdir(fn):
     586                          shutil.copytree(fn, os.path.join(libdir, name),
     587                                          ignore=copy_python_src_ignore)
     588              else:
     589                  additional_pythonpath_for_non_installed.append(
     590                      eachpath)
     591          cmd = [os.path.join(non_installed_dir, self.bindir, self.exe),
     592                 "-m",
     593                 "venv",
     594                 "--without-pip",
     595                 self.env_dir]
     596          # Our fake non-installed python is not fully functional because
     597          # it cannot find the extensions. Set PYTHONPATH so it can run the
     598          # venv module correctly.
     599          pythonpath = os.pathsep.join(
     600              additional_pythonpath_for_non_installed)
     601          # For python built with shared enabled. We need to set
     602          # LD_LIBRARY_PATH so the non-installed python can find and link
     603          # libpython.so
     604          ld_library_path = sysconfig.get_config_var("LIBDIR")
     605          if not ld_library_path or sysconfig.is_python_build():
     606              ld_library_path = os.path.abspath(os.path.dirname(sys.executable))
     607          if sys.platform == 'darwin':
     608              ld_library_path_env = "DYLD_LIBRARY_PATH"
     609          else:
     610              ld_library_path_env = "LD_LIBRARY_PATH"
     611          subprocess.check_call(cmd,
     612                                env={"PYTHONPATH": pythonpath,
     613                                     ld_library_path_env: ld_library_path})
     614          envpy = os.path.join(self.env_dir, self.bindir, self.exe)
     615          # Now check the venv created from the non-installed python has
     616          # correct zip path in pythonpath.
     617          cmd = [envpy, '-S', '-c', 'import sys; print(sys.path)']
     618          out, err = check_output(cmd)
     619          self.assertTrue(zip_landmark.encode() in out)
     620  
     621  @requireVenvCreate
     622  class ESC[4;38;5;81mEnsurePipTest(ESC[4;38;5;149mBaseTest):
     623      """Test venv module installation of pip."""
     624      def assert_pip_not_installed(self):
     625          envpy = os.path.join(os.path.realpath(self.env_dir),
     626                               self.bindir, self.exe)
     627          out, err = check_output([envpy, '-c',
     628              'try:\n import pip\nexcept ImportError:\n print("OK")'])
     629          # We force everything to text, so unittest gives the detailed diff
     630          # if we get unexpected results
     631          err = err.decode("latin-1") # Force to text, prevent decoding errors
     632          self.assertEqual(err, "")
     633          out = out.decode("latin-1") # Force to text, prevent decoding errors
     634          self.assertEqual(out.strip(), "OK")
     635  
     636  
     637      def test_no_pip_by_default(self):
     638          rmtree(self.env_dir)
     639          self.run_with_capture(venv.create, self.env_dir)
     640          self.assert_pip_not_installed()
     641  
     642      def test_explicit_no_pip(self):
     643          rmtree(self.env_dir)
     644          self.run_with_capture(venv.create, self.env_dir, with_pip=False)
     645          self.assert_pip_not_installed()
     646  
     647      def test_devnull(self):
     648          # Fix for issue #20053 uses os.devnull to force a config file to
     649          # appear empty. However http://bugs.python.org/issue20541 means
     650          # that doesn't currently work properly on Windows. Once that is
     651          # fixed, the "win_location" part of test_with_pip should be restored
     652          with open(os.devnull, "rb") as f:
     653              self.assertEqual(f.read(), b"")
     654  
     655          self.assertTrue(os.path.exists(os.devnull))
     656  
     657      def do_test_with_pip(self, system_site_packages):
     658          rmtree(self.env_dir)
     659          with EnvironmentVarGuard() as envvars:
     660              # pip's cross-version compatibility may trigger deprecation
     661              # warnings in current versions of Python. Ensure related
     662              # environment settings don't cause venv to fail.
     663              envvars["PYTHONWARNINGS"] = "ignore"
     664              # ensurepip is different enough from a normal pip invocation
     665              # that we want to ensure it ignores the normal pip environment
     666              # variable settings. We set PIP_NO_INSTALL here specifically
     667              # to check that ensurepip (and hence venv) ignores it.
     668              # See http://bugs.python.org/issue19734
     669              envvars["PIP_NO_INSTALL"] = "1"
     670              # Also check that we ignore the pip configuration file
     671              # See http://bugs.python.org/issue20053
     672              with tempfile.TemporaryDirectory() as home_dir:
     673                  envvars["HOME"] = home_dir
     674                  bad_config = "[global]\nno-install=1"
     675                  # Write to both config file names on all platforms to reduce
     676                  # cross-platform variation in test code behaviour
     677                  win_location = ("pip", "pip.ini")
     678                  posix_location = (".pip", "pip.conf")
     679                  # Skips win_location due to http://bugs.python.org/issue20541
     680                  for dirname, fname in (posix_location,):
     681                      dirpath = os.path.join(home_dir, dirname)
     682                      os.mkdir(dirpath)
     683                      fpath = os.path.join(dirpath, fname)
     684                      with open(fpath, 'w') as f:
     685                          f.write(bad_config)
     686  
     687                  # Actually run the create command with all that unhelpful
     688                  # config in place to ensure we ignore it
     689                  with self.nicer_error():
     690                      self.run_with_capture(venv.create, self.env_dir,
     691                                            system_site_packages=system_site_packages,
     692                                            with_pip=True)
     693          # Ensure pip is available in the virtual environment
     694          envpy = os.path.join(os.path.realpath(self.env_dir), self.bindir, self.exe)
     695          # Ignore DeprecationWarning since pip code is not part of Python
     696          out, err = check_output([envpy, '-W', 'ignore::DeprecationWarning',
     697                 '-W', 'ignore::ImportWarning', '-I',
     698                 '-m', 'pip', '--version'])
     699          # We force everything to text, so unittest gives the detailed diff
     700          # if we get unexpected results
     701          err = err.decode("latin-1") # Force to text, prevent decoding errors
     702          self.assertEqual(err, "")
     703          out = out.decode("latin-1") # Force to text, prevent decoding errors
     704          expected_version = "pip {}".format(ensurepip.version())
     705          self.assertEqual(out[:len(expected_version)], expected_version)
     706          env_dir = os.fsencode(self.env_dir).decode("latin-1")
     707          self.assertIn(env_dir, out)
     708  
     709          # http://bugs.python.org/issue19728
     710          # Check the private uninstall command provided for the Windows
     711          # installers works (at least in a virtual environment)
     712          with EnvironmentVarGuard() as envvars:
     713              with self.nicer_error():
     714                  # It seems ensurepip._uninstall calls subprocesses which do not
     715                  # inherit the interpreter settings.
     716                  envvars["PYTHONWARNINGS"] = "ignore"
     717                  out, err = check_output([envpy,
     718                      '-W', 'ignore::DeprecationWarning',
     719                      '-W', 'ignore::ImportWarning', '-I',
     720                      '-m', 'ensurepip._uninstall'])
     721          # We force everything to text, so unittest gives the detailed diff
     722          # if we get unexpected results
     723          err = err.decode("latin-1") # Force to text, prevent decoding errors
     724          # Ignore the warning:
     725          #   "The directory '$HOME/.cache/pip/http' or its parent directory
     726          #    is not owned by the current user and the cache has been disabled.
     727          #    Please check the permissions and owner of that directory. If
     728          #    executing pip with sudo, you may want sudo's -H flag."
     729          # where $HOME is replaced by the HOME environment variable.
     730          err = re.sub("^(WARNING: )?The directory .* or its parent directory "
     731                       "is not owned or is not writable by the current user.*$", "",
     732                       err, flags=re.MULTILINE)
     733          self.assertEqual(err.rstrip(), "")
     734          # Being fairly specific regarding the expected behaviour for the
     735          # initial bundling phase in Python 3.4. If the output changes in
     736          # future pip versions, this test can likely be relaxed further.
     737          out = out.decode("latin-1") # Force to text, prevent decoding errors
     738          self.assertIn("Successfully uninstalled pip", out)
     739          self.assertIn("Successfully uninstalled setuptools", out)
     740          # Check pip is now gone from the virtual environment. This only
     741          # applies in the system_site_packages=False case, because in the
     742          # other case, pip may still be available in the system site-packages
     743          if not system_site_packages:
     744              self.assert_pip_not_installed()
     745  
     746      @contextlib.contextmanager
     747      def nicer_error(self):
     748          """
     749          Capture output from a failed subprocess for easier debugging.
     750  
     751          The output this handler produces can be a little hard to read,
     752          but at least it has all the details.
     753          """
     754          try:
     755              yield
     756          except subprocess.CalledProcessError as exc:
     757              out = (exc.output or b'').decode(errors="replace")
     758              err = (exc.stderr or b'').decode(errors="replace")
     759              self.fail(
     760                  f"{exc}\n\n"
     761                  f"**Subprocess Output**\n{out}\n\n"
     762                  f"**Subprocess Error**\n{err}"
     763              )
     764  
     765      @requires_venv_with_pip()
     766      @requires_resource('cpu')
     767      def test_with_pip(self):
     768          self.do_test_with_pip(False)
     769          self.do_test_with_pip(True)
     770  
     771  
     772  if __name__ == "__main__":
     773      unittest.main()