def test_py_info_cached_symlink_error(mocker, tmp_path, session_app_data): spy = mocker.spy(cached_py_info, "_run_subprocess") with pytest.raises(RuntimeError): PythonInfo.from_exe(str(tmp_path), session_app_data) symlinked = tmp_path / "a" symlinked.symlink_to(tmp_path) with pytest.raises(RuntimeError): PythonInfo.from_exe(str(symlinked), session_app_data) assert spy.call_count == 2
def test_py_info_cache_clear(mocker, tmp_path, session_app_data): spy = mocker.spy(cached_py_info, "_run_subprocess") result = PythonInfo.from_exe(sys.executable, session_app_data) assert result is not None count = 1 if result.executable == sys.executable else 2 # at least two, one for the venv, one more for the host assert spy.call_count >= count PythonInfo.clear_cache(session_app_data) assert PythonInfo.from_exe(sys.executable, session_app_data) is not None assert spy.call_count >= 2 * count
def test_py_info_cached_symlink(mocker, tmp_path): spy = mocker.spy(cached_py_info, "_run_subprocess") first_result = PythonInfo.from_exe(sys.executable) assert first_result is not None assert spy.call_count == 2 # at least two, one for the venv, one more for the host new_exe = tmp_path / "a" new_exe.symlink_to(sys.executable) new_exe_str = str(new_exe) second_result = PythonInfo.from_exe(new_exe_str) assert second_result.executable == new_exe_str assert spy.call_count == 3 # no longer needed the host invocation, but the new symlink is must
def test_cross_major(cross_python, coverage_env, tmp_path, current_fastest, session_app_data): cmd = [ "-v", "-v", "-p", ensure_text(cross_python.executable), ensure_text(str(tmp_path)), "--no-setuptools", "--no-wheel", "--activators", "", "--creator", current_fastest, ] result = cli_run(cmd) pip_scripts = { i.name.replace(".exe", "") for i in result.creator.script_dir.iterdir() if i.name.startswith("pip") } major, minor = cross_python.version_info[0:2] assert pip_scripts == { "pip", "pip-{}.{}".format(major, minor), "pip{}".format(major) } coverage_env() env = PythonInfo.from_exe(str(result.creator.exe), session_app_data) assert env.version_info.major != CURRENT.version_info.major
def test_base_bootstrap_via_pip_invoke(tmp_path, coverage_env, current_fastest): bundle_ver = BUNDLE_SUPPORT[ PythonInfo.current_system().version_release_str] create_cmd = [ "--seeder", "pip", str(tmp_path / "env"), "--download", "--pip", bundle_ver["pip"].split("-")[1], "--setuptools", bundle_ver["setuptools"].split("-")[1], "--creator", current_fastest, ] result = run_via_cli(create_cmd) coverage_env() assert result site_package = result.creator.purelib pip = site_package / "pip" setuptools = site_package / "setuptools" wheel = site_package / "wheel" files_post_first_create = list(site_package.iterdir()) assert pip in files_post_first_create assert setuptools in files_post_first_create assert wheel in files_post_first_create
def test_failed_to_find_implementation(of_id, mocker): mocker.patch("virtualenv.run.plugin.creators.CreatorSelector._OPTIONS", return_value={}) with pytest.raises(RuntimeError) as context: cli_run(["-p", of_id]) assert repr(context.value) == repr( RuntimeError("No virtualenv implementation for {}".format(PythonInfo.current_system())) )
def __init__(self, options, interpreter): self.describe = options.describe super(Venv, self).__init__(options, interpreter) self.can_be_inline = ( interpreter is PythonInfo.current() and interpreter.executable == interpreter.system_executable ) self._context = None
def test_base_bootstrap_via_pip_invoke(tmp_path, coverage_env, current_fastest, no): bundle_ver = BUNDLE_SUPPORT[PythonInfo.current_system().version_release_str] create_cmd = [ "--seeder", "pip", str(tmp_path / "env"), "--download", "--pip", bundle_ver["pip"].split("-")[1], "--setuptools", bundle_ver["setuptools"].split("-")[1], "--creator", current_fastest, ] if no: create_cmd.append("--no-{}".format(no)) result = cli_run(create_cmd) coverage_env() assert result site_package = result.creator.purelib pip = site_package / "pip" setuptools = site_package / "setuptools" wheel = site_package / "wheel" files_post_first_create = list(site_package.iterdir()) if no: no_file = locals()[no] assert no not in files_post_first_create for key in ("pip", "setuptools", "wheel"): if key == no: continue assert locals()[key] in files_post_first_create
def test_relative_path(tmp_path, session_app_data, monkeypatch): sys_executable = Path(PythonInfo.current_system(app_data=session_app_data).system_executable) cwd = sys_executable.parents[1] monkeypatch.chdir(str(cwd)) relative = str(sys_executable.relative_to(cwd)) result = get_interpreter(relative, session_app_data) assert result is not None
def test_py_info_cached_symlink(mocker, tmp_path, session_app_data): spy = mocker.spy(cached_py_info, "_run_subprocess") first_result = PythonInfo.from_exe(sys.executable, session_app_data) assert first_result is not None count = spy.call_count # at least two, one for the venv, one more for the host exp_count = 1 if first_result.executable == sys.executable else 2 assert count >= exp_count # at least two, one for the venv, one more for the host new_exe = tmp_path / "a" new_exe.symlink_to(sys.executable) pyvenv = Path(sys.executable).parents[1] / "pyvenv.cfg" if pyvenv.exists(): (tmp_path / pyvenv.name).write_text(pyvenv.read_text()) new_exe_str = str(new_exe) second_result = PythonInfo.from_exe(new_exe_str, session_app_data) assert second_result.executable == new_exe_str assert spy.call_count == count + 1 # no longer needed the host invocation, but the new symlink is must
def test_py_info_to_system_raises(session_app_data, mocker, caplog): caplog.set_level(logging.DEBUG) mocker.patch.object(PythonInfo, "_find_possible_folders", return_value=[]) result = PythonInfo.from_exe(sys.executable, app_data=session_app_data, raise_on_error=False) assert result is None log = caplog.records[-1] assert log.levelno == logging.INFO expected = "ignore {} due cannot resolve system due to RuntimeError('failed to detect ".format(sys.executable) assert expected in log.message
def test_base_bootstrap_via_pip_invoke(tmp_path, coverage_env, mocker, current_fastest, no): bundle_ver = BUNDLE_SUPPORT[ PythonInfo.current_system().version_release_str] extra_search_dir = tmp_path / "extra" extra_search_dir.mkdir() original = PipInvoke._execute def _execute(cmd, env): assert set(cmd[-4:]) == { "--find-links", str(extra_search_dir), str(BUNDLE_FOLDER) } return original(cmd, env) run = mocker.patch.object(PipInvoke, "_execute", side_effect=_execute) create_cmd = [ "--seeder", "pip", str(tmp_path / "env"), "--download", "--pip", bundle_ver["pip"].split("-")[1], "--setuptools", bundle_ver["setuptools"].split("-")[1], "--creator", current_fastest, "--extra-search-dir", str(extra_search_dir), ] if no: create_cmd.append("--no-{}".format(no)) result = cli_run(create_cmd) coverage_env() assert result assert run.call_count == 1 site_package = result.creator.purelib pip = site_package / "pip" setuptools = site_package / "setuptools" wheel = site_package / "wheel" files_post_first_create = list(site_package.iterdir()) if no: no_file = locals()[no] assert no not in files_post_first_create for key in ("pip", "setuptools", "wheel"): if key == no: continue assert locals()[key] in files_post_first_create
def test_bad_exe_py_info_no_raise(tmp_path, caplog, capsys, session_app_data): caplog.set_level(logging.NOTSET) exe = str(tmp_path) result = PythonInfo.from_exe(exe, session_app_data, raise_on_error=False) assert result is None out, _ = capsys.readouterr() assert not out messages = [r.message for r in caplog.records if r.filename != "filelock.py"] assert len(messages) == 2 msg = messages[0] assert "get interpreter info via cmd: " in msg msg = messages[1] assert str(exe) in msg assert "code" in msg
def test_py_info_ignores_distutils_config(monkeypatch, tmp_path): (tmp_path / "setup.cfg").write_text( dedent(""" [install] prefix={0}{1}prefix install_purelib={0}{1}purelib install_platlib={0}{1}platlib install_headers={0}{1}headers install_scripts={0}{1}scripts install_data={0}{1}data """.format(tmp_path, os.sep))) monkeypatch.chdir(tmp_path) py_info = PythonInfo.from_exe(sys.executable) distutils = py_info.distutils_install for key, value in distutils.items(): assert not value.startswith(str(tmp_path)), "{}={}".format(key, value)
def test_cross_major(cross_python, coverage_env, tmp_path, current_fastest): cmd = [ "-v", "-v", "-p", ensure_text(cross_python.executable), ensure_text(str(tmp_path)), "--no-seed", "--activators", "", "--creator", current_fastest, ] result = cli_run(cmd) coverage_env() env = PythonInfo.from_exe(str(result.creator.exe)) assert env.version_info.major != CURRENT.version_info.major
def test_pyc_only(tmp_path, mocker, session_app_data): """Ensure that creation can succeed if os.pyc exists (even if os.py has been deleted)""" interpreter = PythonInfo.from_exe(sys.executable, session_app_data) host_pyc, _, host_pyc_exists = Python2.from_stdlib(Python2.mappings(interpreter), "os.pyc") if not host_pyc_exists: pytest.skip("missing system os.pyc at {}".format(host_pyc)) previous = Python2.from_stdlib def from_stdlib(mappings, name): path, to, exists = previous(mappings, name) if name.endswith(".py"): exists = False return path, to, exists mocker.patch.object(Python2, "from_stdlib", side_effect=from_stdlib) result = cli_run([ensure_text(str(tmp_path)), "--without-pip", "--activators", ""]) assert not (result.creator.stdlib / "os.py").exists() assert (result.creator.stdlib / "os.pyc").exists() assert "os.pyc" in result.creator.debug["os"]
import pytest from virtualenv.discovery.builtin import Builtin, get_interpreter from virtualenv.discovery.py_info import PythonInfo from virtualenv.info import fs_supports_symlink from virtualenv.util.path import Path from virtualenv.util.six import ensure_text @pytest.mark.skipif(not fs_supports_symlink(), reason="symlink not supported") @pytest.mark.parametrize("case", ["mixed", "lower", "upper"]) def test_discovery_via_path(monkeypatch, case, tmp_path, caplog, session_app_data): caplog.set_level(logging.DEBUG) current = PythonInfo.current_system(session_app_data) core = "somethingVeryCryptic{}".format(".".join( str(i) for i in current.version_info[0:3])) name = "somethingVeryCryptic" if case == "lower": name = name.lower() elif case == "upper": name = name.upper() exe_name = "{}{}{}".format(name, current.version_info.major, ".exe" if sys.platform == "win32" else "") target = tmp_path / current.distutils_install["scripts"] target.mkdir(parents=True) executable = target / exe_name os.symlink(sys.executable, ensure_text(str(executable))) pyvenv_cfg = Path(sys.executable).parents[1] / "pyvenv.cfg" if pyvenv_cfg.exists():
from itertools import product from threading import Thread import pytest from virtualenv.__main__ import run, run_with_catch from virtualenv.create.creator import DEBUG_SCRIPT, Creator, get_env_debug_info from virtualenv.discovery.builtin import get_interpreter from virtualenv.discovery.py_info import PythonInfo from virtualenv.info import IS_PYPY, fs_supports_symlink from virtualenv.pyenv_cfg import PyEnvCfg from virtualenv.run import cli_run, session_via_cli from virtualenv.util.path import Path from virtualenv.util.six import ensure_text CURRENT = PythonInfo.current_system() def test_os_path_sep_not_allowed(tmp_path, capsys): target = str(tmp_path / "a{}b".format(os.pathsep)) err = _non_success_exit_code(capsys, target) msg = ( "destination {!r} must not contain the path separator ({}) as this" " would break the activation scripts".format(target, os.pathsep) ) assert msg in err, err def _non_success_exit_code(capsys, target): with pytest.raises(SystemExit) as context: run_with_catch(args=[target])
def ensure_py_info_cache_empty(): PythonInfo.clear_cache() yield PythonInfo.clear_cache()
def current_creators(): return PythonInfo.current_system().creators()
from __future__ import absolute_import, unicode_literals import sys from uuid import uuid4 import pytest from virtualenv.discovery.py_info import PythonInfo from virtualenv.run import cli_run @pytest.mark.slow def test_failed_to_find_bad_spec(): of_id = uuid4().hex with pytest.raises(RuntimeError) as context: cli_run(["-p", of_id]) msg = repr(RuntimeError("failed to find interpreter for Builtin discover of python_spec={!r}".format(of_id))) assert repr(context.value) == msg @pytest.mark.parametrize("of_id", [sys.executable, PythonInfo.current_system().implementation]) def test_failed_to_find_implementation(of_id, mocker): mocker.patch("virtualenv.run.plugin.creators.CreatorSelector._OPTIONS", return_value={}) with pytest.raises(RuntimeError) as context: cli_run(["-p", of_id]) assert repr(context.value) == repr( RuntimeError("No virtualenv implementation for {}".format(PythonInfo.current_system())) )
from __future__ import absolute_import, unicode_literals import logging import os import pytest from virtualenv.discovery.py_info import EXTENSIONS, PythonInfo from virtualenv.info import IS_WIN, fs_is_case_sensitive, fs_supports_symlink from virtualenv.util.path import Path CURRENT = PythonInfo.current() def test_discover_empty_folder(tmp_path, monkeypatch, session_app_data): with pytest.raises(RuntimeError): CURRENT.discover_exe(session_app_data, prefix=str(tmp_path)) BASE = (CURRENT.distutils_install["scripts"], ".") @pytest.mark.skipif(not fs_supports_symlink(), reason="symlink is not supported") @pytest.mark.parametrize("suffix", sorted({".exe", ".cmd", ""} & set(EXTENSIONS) if IS_WIN else [""])) @pytest.mark.parametrize("into", BASE) @pytest.mark.parametrize("arch", [CURRENT.architecture, ""]) @pytest.mark.parametrize("version", [".".join(str(i) for i in CURRENT.version_info[0:i]) for i in range(3, 0, -1)]) @pytest.mark.parametrize("impl", [CURRENT.implementation, "python"]) def test_discover_ok(tmp_path, monkeypatch, suffix, impl, version, arch, into, caplog, session_app_data): caplog.set_level(logging.DEBUG) folder = tmp_path / into
import logging import os import random import sys from collections import OrderedDict from pathlib import Path from shlex import quote from string import ascii_lowercase, ascii_uppercase, digits from subprocess import Popen from virtualenv.app_data import AppDataDisabled from virtualenv.discovery.py_info import PythonInfo from virtualenv.util.subprocess import subprocess _CACHE = OrderedDict() _CACHE[Path(sys.executable)] = PythonInfo() def from_exe(cls, app_data, exe, env=None, raise_on_error=True, ignore_cache=False): env = os.environ if env is None else env result = _get_from_cache(cls, app_data, exe, env, ignore_cache=ignore_cache) if isinstance(result, Exception):
def test_seed_link_via_app_data(tmp_path, coverage_env, current_fastest, copies): current = PythonInfo.current_system() bundle_ver = BUNDLE_SUPPORT[current.version_release_str] create_cmd = [ ensure_text( str(tmp_path / "en v") ), # space in the name to ensure generated scripts work when path has space "--seeder", "app-data", "--extra-search-dir", ensure_text(str(BUNDLE_FOLDER)), "--download", "--pip", bundle_ver["pip"].split("-")[1], "--setuptools", bundle_ver["setuptools"].split("-")[1], "--clear-app-data", "--creator", current_fastest, "-vv", ] if not copies: create_cmd.append("--symlink-app-data") result = cli_run(create_cmd) coverage_env() assert result # uninstalling pip/setuptools now should leave us with a ensure_safe_to_do env site_package = result.creator.purelib pip = site_package / "pip" setuptools = site_package / "setuptools" files_post_first_create = list(site_package.iterdir()) assert pip in files_post_first_create assert setuptools in files_post_first_create for pip_exe in [ result.creator.script_dir / "pip{}{}".format(suffix, result.creator.exe.suffix) for suffix in ( "", "{}".format(current.version_info.major), "{}.{}".format(current.version_info.major, current.version_info.minor), "-{}.{}".format(current.version_info.major, current.version_info.minor), ) ]: assert pip_exe.exists() process = Popen([ ensure_text(str(pip_exe)), "--version", "--disable-pip-version-check" ]) _, __ = process.communicate() assert not process.returncode remove_cmd = [ str(result.creator.script("pip")), "--verbose", "--disable-pip-version-check", "uninstall", "-y", "setuptools", ] process = Popen(remove_cmd) _, __ = process.communicate() assert not process.returncode assert site_package.exists() files_post_first_uninstall = list(site_package.iterdir()) assert pip in files_post_first_uninstall assert setuptools not in files_post_first_uninstall # check we can run it again and will work - checks both overwrite and reuse cache result = cli_run(create_cmd) coverage_env() assert result files_post_second_create = list(site_package.iterdir()) assert files_post_first_create == files_post_second_create # Windows does not allow removing a executable while running it, so when uninstalling pip we need to do it via # python -m pip remove_cmd = [str(result.creator.exe), "-m", "pip"] + remove_cmd[1:] process = Popen(remove_cmd + ["pip", "wheel"]) _, __ = process.communicate() assert not process.returncode # pip is greedy here, removing all packages removes the site-package too if site_package.exists(): purelib = result.creator.purelib patch_files = { purelib / "{}.{}".format("_virtualenv", i) for i in ("py", "pyc", "pth") } patch_files.add(purelib / "__pycache__") post_run = set(site_package.iterdir()) - patch_files assert not post_run, "\n".join(str(i) for i in post_run) if sys.version_info[0:2] == (3, 4) and os.environ.get( str("PIP_REQ_TRACKER")): os.environ.pop(str("PIP_REQ_TRACKER"))
def read_fixture(fixture_name): fixture_json = fixture_file(fixture_name).read_text() return PythonInfo._from_json(fixture_json)
def test_py_info_setuptools(): from setuptools.dist import Distribution assert Distribution PythonInfo()
def test_create_no_seed(python, creator, isolated, system, coverage_env, special_name_dir): dest = special_name_dir creator_key, method = creator cmd = [ "-v", "-v", "-p", ensure_text(python), ensure_text(str(dest)), "--without-pip", "--activators", "", "--creator", creator_key, "--{}".format(method), ] if isolated == "global": cmd.append("--system-site-packages") result = cli_run(cmd) creator = result.creator coverage_env() if IS_PYPY: # pypy cleans up file descriptors periodically so our (many) subprocess calls impact file descriptor limits # force a close of these on system where the limit is low-ish (e.g. MacOS 256) gc.collect() purelib = creator.purelib patch_files = { purelib / "{}.{}".format("_virtualenv", i) for i in ("py", "pyc", "pth") } patch_files.add(purelib / "__pycache__") content = set(creator.purelib.iterdir()) - patch_files assert not content, "\n".join(ensure_text(str(i)) for i in content) assert creator.env_name == ensure_text(dest.name) debug = creator.debug assert "exception" not in debug, "{}\n{}\n{}".format( debug.get("exception"), debug.get("out"), debug.get("err")) sys_path = cleanup_sys_path(debug["sys"]["path"]) system_sys_path = cleanup_sys_path(system["sys"]["path"]) our_paths = set(sys_path) - set(system_sys_path) our_paths_repr = "\n".join(ensure_text(repr(i)) for i in our_paths) # ensure we have at least one extra path added assert len(our_paths) >= 1, our_paths_repr # ensure all additional paths are related to the virtual environment for path in our_paths: msg = "\n{}\ndoes not start with {}\nhas:\n{}".format( ensure_text(str(path)), ensure_text(str(dest)), "\n".join(ensure_text(str(p)) for p in system_sys_path), ) assert str(path).startswith(str(dest)), msg # ensure there's at least a site-packages folder as part of the virtual environment added assert any(p for p in our_paths if p.parts[-1] == "site-packages"), our_paths_repr # ensure the global site package is added or not, depending on flag global_sys_path = system_sys_path[-1] if isolated == "isolated": msg = "global sys path {} is in virtual environment sys path:\n{}".format( ensure_text(str(global_sys_path)), "\n".join(ensure_text(str(j)) for j in sys_path), ) assert global_sys_path not in sys_path, msg else: common = [] for left, right in zip(reversed(system_sys_path), reversed(sys_path)): if left == right: common.append(left) else: break def list_to_str(iterable): return [ensure_text(str(i)) for i in iterable] assert common, "\n".join( difflib.unified_diff(list_to_str(sys_path), list_to_str(system_sys_path))) # test that the python executables in the bin directory are either: # - files # - absolute symlinks outside of the venv # - relative symlinks inside of the venv if sys.platform == "win32": exes = ("python.exe", ) else: exes = ("python", "python{}".format(*sys.version_info), "python{}.{}".format(*sys.version_info)) if creator_key == "venv": # for venv some repackaging does not includes the pythonx.y exes = exes[:-1] for exe in exes: exe_path = creator.bin_dir / exe assert exe_path.exists(), "\n".join( str(i) for i in creator.bin_dir.iterdir()) if not exe_path.is_symlink(): # option 1: a real file continue # it was a file link = os.readlink(str(exe_path)) if not os.path.isabs(link): # option 2: a relative symlink continue # option 3: an absolute symlink, should point outside the venv assert not link.startswith(str(creator.dest)) if IS_WIN and CURRENT.implementation == "CPython": python_w = creator.exe.parent / "pythonw.exe" assert python_w.exists() assert python_w.read_bytes() != creator.exe.read_bytes() if CPython3Posix.pyvenv_launch_patch_active( PythonInfo.from_exe(python)) and creator_key != "venv": result = subprocess.check_output( [ str(creator.exe), "-c", 'import os; print(os.environ.get("__PYVENV_LAUNCHER__"))' ], universal_newlines=True, ).strip() assert result == "None" if isinstance(creator, CPython2PosixBase): make_file = debug["makefile_filename"] assert os.path.exists(make_file) git_ignore = (dest / ".gitignore").read_text() assert git_ignore.splitlines() == [ "# created by virtualenv automatically", "*" ]
from textwrap import dedent from threading import Thread import pytest from virtualenv.__main__ import run, run_with_catch from virtualenv.create.creator import DEBUG_SCRIPT, Creator, get_env_debug_info from virtualenv.discovery.builtin import get_interpreter from virtualenv.discovery.py_info import PythonInfo from virtualenv.info import IS_PYPY, IS_WIN, PY3, fs_is_case_sensitive, fs_supports_symlink from virtualenv.pyenv_cfg import PyEnvCfg from virtualenv.run import cli_run, session_via_cli from virtualenv.util.path import Path from virtualenv.util.six import ensure_str, ensure_text CURRENT = PythonInfo.current_system() def test_os_path_sep_not_allowed(tmp_path, capsys): target = str(tmp_path / "a{}b".format(os.pathsep)) err = _non_success_exit_code(capsys, target) msg = ("destination {!r} must not contain the path separator ({}) as this" " would break the activation scripts".format(target, os.pathsep)) assert msg in err, err def _non_success_exit_code(capsys, target): with pytest.raises(SystemExit) as context: run_with_catch(args=[target]) assert context.value.code != 0 out, err = capsys.readouterr()
from threading import Thread import pytest from virtualenv.__main__ import run, run_with_catch from virtualenv.create.creator import DEBUG_SCRIPT, Creator, get_env_debug_info from virtualenv.create.via_global_ref.builtin.python2.python2 import Python2 from virtualenv.discovery.builtin import get_interpreter from virtualenv.discovery.py_info import PythonInfo from virtualenv.info import IS_PYPY, IS_WIN, PY2, PY3, fs_is_case_sensitive from virtualenv.pyenv_cfg import PyEnvCfg from virtualenv.run import cli_run, session_via_cli from virtualenv.util.path import Path from virtualenv.util.six import ensure_str, ensure_text CURRENT = PythonInfo.current_system() def test_os_path_sep_not_allowed(tmp_path, capsys): target = str(tmp_path / "a{}b".format(os.pathsep)) err = _non_success_exit_code(capsys, target) msg = ( "destination {!r} must not contain the path separator ({}) as this" " would break the activation scripts".format(target, os.pathsep) ) assert msg in err, err def _non_success_exit_code(capsys, target): with pytest.raises(SystemExit) as context: run_with_catch(args=[target])
def test_base_bootstrap_link_via_app_data(tmp_path, coverage_env, current_fastest): current = PythonInfo.current_system() bundle_ver = BUNDLE_SUPPORT[current.version_release_str] create_cmd = [ six.ensure_text(str(tmp_path / "env")), "--seeder", "app-data", "--extra-search-dir", six.ensure_text(str(BUNDLE_FOLDER)), "--download", "--pip", bundle_ver["pip"].split("-")[1], "--setuptools", bundle_ver["setuptools"].split("-")[1], "--clear-app-data", "--creator", current_fastest, "-vv", ] result = run_via_cli(create_cmd) coverage_env() assert result # uninstalling pip/setuptools now should leave us with a ensure_safe_to_do env site_package = result.creator.purelib pip = site_package / "pip" setuptools = site_package / "setuptools" files_post_first_create = list(site_package.iterdir()) assert pip in files_post_first_create assert setuptools in files_post_first_create for pip_exe in [ result.creator.script_dir / "pip{}{}".format(suffix, result.creator.exe.suffix) for suffix in ( "", "{}".format(current.version_info.major), "-{}.{}".format(current.version_info.major, current.version_info.minor), ) ]: assert pip_exe.exists() process = Popen([ six.ensure_text(str(pip_exe)), "--version", "--disable-pip-version-check" ]) _, __ = process.communicate() assert not process.returncode remove_cmd = [ str(result.creator.exe), "-m", "pip", "--verbose", "--disable-pip-version-check", "uninstall", "-y", "setuptools", ] process = Popen(remove_cmd) _, __ = process.communicate() assert not process.returncode assert site_package.exists() files_post_first_uninstall = list(site_package.iterdir()) assert pip in files_post_first_uninstall assert setuptools not in files_post_first_uninstall # check we can run it again and will work - checks both overwrite and reuse cache result = run_via_cli(create_cmd) coverage_env() assert result files_post_second_create = list(site_package.iterdir()) assert files_post_first_create == files_post_second_create process = Popen(remove_cmd + ["pip", "wheel"]) _, __ = process.communicate() assert not process.returncode # pip is greedy here, removing all packages removes the site-package too if site_package.exists(): post_run = list(site_package.iterdir()) assert not post_run, "\n".join(str(i) for i in post_run) if sys.version_info[0:2] == (3, 4) and os.environ.get( str("PIP_REQ_TRACKER")): os.environ.pop(str("PIP_REQ_TRACKER"))