From fd93dd79be89b21e6e9d43ca2dd1b02b811f6d6f Mon Sep 17 00:00:00 2001 From: chrysle Date: Fri, 28 Apr 2023 01:36:03 +0200 Subject: 3.12 support and no setuptools/wheel on 3.12+ (#2558) --- .github/workflows/check.yml | 1 + docs/changelog/2487.feature.rst | 6 +++ docs/changelog/2558.feature.rst | 1 + docs/render_cli.py | 10 +--- docs/user_guide.rst | 5 +- pyproject.toml | 6 ++- src/virtualenv/activation/python/__init__.py | 3 +- src/virtualenv/seed/embed/base_embed.py | 17 ++++--- src/virtualenv/util/path/_sync.py | 4 +- tests/conftest.py | 31 ++++++------- tests/integration/test_run_int.py | 6 ++- tests/unit/config/test___main__.py | 5 +- tests/unit/create/test_creator.py | 26 +++++++++-- tests/unit/discovery/py_info/test_py_info.py | 2 +- tests/unit/discovery/windows/conftest.py | 2 +- tests/unit/seed/embed/test_base_embed.py | 13 ++++++ .../seed/embed/test_bootstrap_link_via_app_data.py | 8 ++-- tests/unit/seed/wheels/test_acquire.py | 13 +++++- tests/unit/seed/wheels/test_periodic_update.py | 53 ++++++++++++++-------- 19 files changed, 140 insertions(+), 72 deletions(-) create mode 100644 docs/changelog/2487.feature.rst create mode 100644 docs/changelog/2558.feature.rst diff --git a/.github/workflows/check.yml b/.github/workflows/check.yml index 19b37fc..81916ad 100644 --- a/.github/workflows/check.yml +++ b/.github/workflows/check.yml @@ -19,6 +19,7 @@ jobs: fail-fast: false matrix: py: + - "3.12.0-alpha.7" - "3.11" - "3.10" - "3.9" diff --git a/docs/changelog/2487.feature.rst b/docs/changelog/2487.feature.rst new file mode 100644 index 0000000..12cc896 --- /dev/null +++ b/docs/changelog/2487.feature.rst @@ -0,0 +1,6 @@ +Do not install ``wheel`` and ``setuptools`` seed packages for Python 3.12+. To restore the old behaviour use: + +- for ``wheel`` use ``VIRTUALENV_WHEEL=bundle`` environment variable or ``--wheel=bundle`` CLI flag, +- for ``setuptools`` use ``VIRTUALENV_SETUPTOOLS=bundle`` environment variable or ``--setuptools=bundle`` CLI flag. + +By :user:`chrysle`. diff --git a/docs/changelog/2558.feature.rst b/docs/changelog/2558.feature.rst new file mode 100644 index 0000000..58b627a --- /dev/null +++ b/docs/changelog/2558.feature.rst @@ -0,0 +1 @@ +3.12 support - by :user:`gaborbernat`. diff --git a/docs/render_cli.py b/docs/render_cli.py index 5e76611..76cecd1 100644 --- a/docs/render_cli.py +++ b/docs/render_cli.py @@ -180,15 +180,7 @@ class CliTable(SphinxDirective): content = row.help[: row.help.index("(") - 1] else: content = row.help - if name in ("--setuptools", "--pip", "--wheel"): - text = row.help - at = text.index(" bundle ") - help_body = n.paragraph("") - help_body += n.Text(text[: at + 1]) - help_body += n.literal(text="bundle") - help_body += n.Text(text[at + 7 :]) - else: - help_body = n.paragraph("", "", n.Text(content)) + help_body = n.paragraph("", "", n.Text(content)) if row.choices is not None: help_body += n.Text("; choice of: ") first = True diff --git a/docs/user_guide.rst b/docs/user_guide.rst index 3215ed6..9a2c26f 100644 --- a/docs/user_guide.rst +++ b/docs/user_guide.rst @@ -118,8 +118,9 @@ at the moment has two types of virtual environments: Seeders ------- These will install for you some seed packages (one or more of: :pypi:`pip`, :pypi:`setuptools`, :pypi:`wheel`) that -enables you to install additional python packages into the created virtual environment (by invoking pip). There are two -main seed mechanism available: +enables you to install additional python packages into the created virtual environment (by invoking pip). Installing +:pypi:`setuptools` and :pypi:`wheel` is disabled by default on Python 3.12+ environments. There are two +main seed mechanisms available: - ``pip`` - this method uses the bundled pip with virtualenv to install the seed packages (note, a new child process needs to be created to do this, which can be expensive especially on Windows). diff --git a/pyproject.toml b/pyproject.toml index 92f4b18..5a883da 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -57,10 +57,12 @@ optional-dependencies.test = [ "packaging>=23.1", "pytest>=7.3.1", "pytest-env>=0.8.1", - "pytest-freezegun>=0.4.2", + 'pytest-freezegun>=0.4.2; platform_python_implementation == "PyPy"', "pytest-mock>=3.10", "pytest-randomly>=3.12", "pytest-timeout>=2.1", + "setuptools>=67.7.1", + 'time-machine>=2.9; platform_python_implementation == "CPython"', ] urls.Documentation = "https://virtualenv.pypa.io" urls.Homepage = "https://github.com/pypa/virtualenv" @@ -116,7 +118,7 @@ ignore = [ [tool.pytest.ini_options] markers = ["slow"] timeout = 600 -addopts = "--tb=auto -ra --showlocals --no-success-flaky-report" +addopts = "--showlocals --no-success-flaky-report" env = ["PYTHONIOENCODING=utf-8"] [tool.coverage] diff --git a/src/virtualenv/activation/python/__init__.py b/src/virtualenv/activation/python/__init__.py index 28861f9..ed220dc 100644 --- a/src/virtualenv/activation/python/__init__.py +++ b/src/virtualenv/activation/python/__init__.py @@ -13,9 +13,10 @@ class PythonActivator(ViaTemplateActivator): def replacements(self, creator, dest_folder): replacements = super().replacements(creator, dest_folder) lib_folders = OrderedDict((os.path.relpath(str(i), str(dest_folder)), None) for i in creator.libs) + lib_folders = os.pathsep.join(lib_folders.keys()).replace("\\", "\\\\") # escape Windows path characters replacements.update( { - "__LIB_FOLDERS__": os.pathsep.join(lib_folders.keys()), + "__LIB_FOLDERS__": lib_folders, "__DECODE_PATH__": "", }, ) diff --git a/src/virtualenv/seed/embed/base_embed.py b/src/virtualenv/seed/embed/base_embed.py index 65f2b97..80a3364 100644 --- a/src/virtualenv/seed/embed/base_embed.py +++ b/src/virtualenv/seed/embed/base_embed.py @@ -30,18 +30,18 @@ class BaseEmbed(Seeder, metaclass=ABCMeta): self.enabled = False @classmethod - def distributions(cls): + def distributions(cls) -> dict[str, Version]: return { "pip": Version.bundle, "setuptools": Version.bundle, "wheel": Version.bundle, } - def distribution_to_versions(self): + def distribution_to_versions(self) -> dict[str, str]: return { distribution: getattr(self, f"{distribution}_version") for distribution in self.distributions() - if getattr(self, f"no_{distribution}") is False + if getattr(self, f"no_{distribution}") is False and getattr(self, f"{distribution}_version") != "none" } @classmethod @@ -71,11 +71,13 @@ class BaseEmbed(Seeder, metaclass=ABCMeta): default=[], ) for distribution, default in cls.distributions().items(): + if interpreter.version_info[:2] >= (3, 12) and distribution in {"wheel", "setuptools"}: + default = "none" parser.add_argument( f"--{distribution}", dest=distribution, metavar="version", - help=f"version of {distribution} to install as seed: embed, bundle or exact version", + help=f"version of {distribution} to install as seed: embed, bundle, none or exact version", default=default, ) for distribution in cls.distributions(): @@ -94,7 +96,7 @@ class BaseEmbed(Seeder, metaclass=ABCMeta): default=not PERIODIC_UPDATE_ON_BY_DEFAULT, ) - def __repr__(self): + def __repr__(self) -> str: result = self.__class__.__name__ result += "(" if self.extra_search_dir: @@ -103,7 +105,10 @@ class BaseEmbed(Seeder, metaclass=ABCMeta): for distribution in self.distributions(): if getattr(self, f"no_{distribution}"): continue - ver = f"={getattr(self, f'{distribution}_version', None) or 'latest'}" + version = getattr(self, f"{distribution}_version", None) + if version == "none": + continue + ver = f"={version or 'latest'}" result += f" {distribution}{ver}," return result[:-1] + ")" diff --git a/src/virtualenv/util/path/_sync.py b/src/virtualenv/util/path/_sync.py index f0e0173..a81f82b 100644 --- a/src/virtualenv/util/path/_sync.py +++ b/src/virtualenv/util/path/_sync.py @@ -3,6 +3,7 @@ from __future__ import annotations import logging import os import shutil +import sys from stat import S_IWUSR @@ -58,7 +59,8 @@ def safe_delete(dest): else: raise - shutil.rmtree(str(dest), ignore_errors=True, onerror=onerror) + kwargs = {"onexc" if sys.version_info >= (3, 12) else "onerror": onerror} + shutil.rmtree(str(dest), ignore_errors=True, **kwargs) class _Debug: diff --git a/tests/conftest.py b/tests/conftest.py index 72db0d5..800861e 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -12,7 +12,7 @@ import pytest from virtualenv.app_data import AppDataDiskFolder from virtualenv.discovery.py_info import PythonInfo -from virtualenv.info import IS_WIN, fs_supports_symlink +from virtualenv.info import IS_PYPY, IS_WIN, fs_supports_symlink from virtualenv.report import LOGGER @@ -144,22 +144,6 @@ def _ignore_global_config(tmp_path_factory): yield -@pytest.fixture(autouse=True, scope="session") -def _pip_cert(tmp_path_factory): - # workaround for https://github.com/pypa/pip/issues/8984 - if the certificate is explicitly set no error can happen - key = "PIP_CERT" - if key in os.environ: - yield - else: - cert = tmp_path_factory.mktemp("folder") / "cert" - import pkgutil - - cert_data = pkgutil.get_data("pip._vendor.certifi", "cacert.pem") - cert.write_bytes(cert_data) - with change_os_environ(key, str(cert)): - yield - - @pytest.fixture(autouse=True) def _check_os_environ_stable(): old = os.environ.copy() @@ -368,3 +352,16 @@ def _skip_if_test_in_system(session_app_data): current = PythonInfo.current(session_app_data) if current.system_executable is not None: pytest.skip("test not valid if run under system") + + +if IS_PYPY: + + @pytest.fixture() + def time_freeze(freezer): + return freezer.move_to + +else: + + @pytest.fixture() + def time_freeze(time_machine): + return lambda s: time_machine.move_to(s, tick=False) diff --git a/tests/integration/test_run_int.py b/tests/integration/test_run_int.py index 36aaf4f..8f4cc16 100644 --- a/tests/integration/test_run_int.py +++ b/tests/integration/test_run_int.py @@ -1,5 +1,7 @@ from __future__ import annotations +from pathlib import Path + import pytest from virtualenv import cli_run @@ -8,8 +10,8 @@ from virtualenv.util.subprocess import run_cmd @pytest.mark.skipif(IS_PYPY, reason="setuptools distutils patching does not work") -def test_app_data_pinning(tmp_path): - version = "19.3.1" +def test_app_data_pinning(tmp_path: Path) -> None: + version = "23.0" result = cli_run([str(tmp_path), "--pip", version, "--activators", "", "--seeder", "app-data"]) code, out, _ = run_cmd([str(result.creator.script("pip")), "list", "--disable-pip-version-check"]) assert not code diff --git a/tests/unit/config/test___main__.py b/tests/unit/config/test___main__.py index 76c9dfa..a850415 100644 --- a/tests/unit/config/test___main__.py +++ b/tests/unit/config/test___main__.py @@ -2,6 +2,7 @@ from __future__ import annotations import re import sys +from pathlib import Path from subprocess import PIPE, Popen, check_output import pytest @@ -59,8 +60,8 @@ def test_fail_with_traceback(raise_on_session_done, tmp_path, capsys): @pytest.mark.usefixtures("session_app_data") -def test_session_report_full(tmp_path, capsys): - run_with_catch([str(tmp_path)]) +def test_session_report_full(tmp_path: Path, capsys: pytest.CaptureFixture[str]) -> None: + run_with_catch([str(tmp_path), "--setuptools", "bundle", "--wheel", "bundle"]) out, err = capsys.readouterr() assert err == "" lines = out.splitlines() diff --git a/tests/unit/create/test_creator.py b/tests/unit/create/test_creator.py index 54e8896..8b33729 100644 --- a/tests/unit/create/test_creator.py +++ b/tests/unit/create/test_creator.py @@ -364,7 +364,19 @@ def test_create_long_path(tmp_path): @pytest.mark.parametrize("creator", sorted(set(PythonInfo.current_system().creators().key_to_class) - {"builtin"})) @pytest.mark.usefixtures("session_app_data") def test_create_distutils_cfg(creator, tmp_path, monkeypatch): - result = cli_run([str(tmp_path / "venv"), "--activators", "", "--creator", creator]) + result = cli_run( + [ + str(tmp_path / "venv"), + "--activators", + "", + "--creator", + creator, + "--setuptools", + "bundle", + "--wheel", + "bundle", + ], + ) app = Path(__file__).parent / "console_app" dest = tmp_path / "console_app" @@ -417,7 +429,9 @@ def list_files(path): def test_zip_importer_can_import_setuptools(tmp_path): """We're patching the loaders so might fail on r/o loaders, such as zipimporter on CPython<3.8""" - result = cli_run([str(tmp_path / "venv"), "--activators", "", "--no-pip", "--no-wheel", "--copies"]) + result = cli_run( + [str(tmp_path / "venv"), "--activators", "", "--no-pip", "--no-wheel", "--copies", "--setuptools", "bundle"], + ) zip_path = tmp_path / "site-packages.zip" with zipfile.ZipFile(str(zip_path), "w", zipfile.ZIP_DEFLATED) as zip_handler: lib = str(result.creator.purelib) @@ -451,6 +465,7 @@ def test_no_preimport_threading(tmp_path): out = subprocess.check_output( [str(session.creator.exe), "-c", r"import sys; print('\n'.join(sorted(sys.modules)))"], text=True, + encoding="utf-8", ) imported = set(out.splitlines()) assert "threading" not in imported @@ -467,6 +482,7 @@ def test_pth_in_site_vs_python_path(tmp_path): out = subprocess.check_output( [str(session.creator.exe), "-c", r"import sys; print(sys.testpth)"], text=True, + encoding="utf-8", ) assert out == "ok\n" # same with $PYTHONPATH pointing to site_packages @@ -479,6 +495,7 @@ def test_pth_in_site_vs_python_path(tmp_path): [str(session.creator.exe), "-c", r"import sys; print(sys.testpth)"], text=True, env=env, + encoding="utf-8", ) assert out == "ok\n" @@ -492,6 +509,7 @@ def test_getsitepackages_system_site(tmp_path): out = subprocess.check_output( [str(session.creator.exe), "-c", r"import site; print(site.getsitepackages())"], text=True, + encoding="utf-8", ) site_packages = ast.literal_eval(out) @@ -506,6 +524,7 @@ def test_getsitepackages_system_site(tmp_path): out = subprocess.check_output( [str(session.creator.exe), "-c", r"import site; print(site.getsitepackages())"], text=True, + encoding="utf-8", ) site_packages = [str(Path(i).resolve()) for i in ast.literal_eval(out)] @@ -531,6 +550,7 @@ def test_get_site_packages(tmp_path): out = subprocess.check_output( [str(session.creator.exe), "-c", r"import site; print(site.getsitepackages())"], text=True, + encoding="utf-8", ) site_packages = ast.literal_eval(out) @@ -569,7 +589,7 @@ def test_python_path(monkeypatch, tmp_path, python_path_on): if flag: cmd.append(flag) cmd.extend(["-c", "import json; import sys; print(json.dumps(sys.path))"]) - return [i if case_sensitive else i.lower() for i in json.loads(subprocess.check_output(cmd))] + return [i if case_sensitive else i.lower() for i in json.loads(subprocess.check_output(cmd, encoding="utf-8"))] monkeypatch.delenv("PYTHONPATH", raising=False) base = _get_sys_path() diff --git a/tests/unit/discovery/py_info/test_py_info.py b/tests/unit/discovery/py_info/test_py_info.py index 639fbaa..f839e22 100644 --- a/tests/unit/discovery/py_info/test_py_info.py +++ b/tests/unit/discovery/py_info/test_py_info.py @@ -291,7 +291,7 @@ def test_discover_exe_on_path_non_spec_name_not_match(mocker): assert CURRENT.satisfies(spec, impl_must_match=True) is False -@pytest.mark.skipif(IS_PYPY, reason="setuptools distutil1s patching does not work") +@pytest.mark.skipif(IS_PYPY, reason="setuptools distutils patching does not work") def test_py_info_setuptools(): from setuptools.dist import Distribution diff --git a/tests/unit/discovery/windows/conftest.py b/tests/unit/discovery/windows/conftest.py index 21ed61b..08c72fd 100644 --- a/tests/unit/discovery/windows/conftest.py +++ b/tests/unit/discovery/windows/conftest.py @@ -11,7 +11,7 @@ def _mock_registry(mocker): from virtualenv.discovery.windows.pep514 import winreg loc, glob = {}, {} - mock_value_str = (Path(__file__).parent / "winreg-mock-values.py").read_text() + mock_value_str = (Path(__file__).parent / "winreg-mock-values.py").read_text(encoding="utf-8") exec(mock_value_str, glob, loc) enum_collect = loc["enum_collect"] value_collect = loc["value_collect"] diff --git a/tests/unit/seed/embed/test_base_embed.py b/tests/unit/seed/embed/test_base_embed.py index e9d61f3..a249e47 100644 --- a/tests/unit/seed/embed/test_base_embed.py +++ b/tests/unit/seed/embed/test_base_embed.py @@ -1,5 +1,8 @@ from __future__ import annotations +import sys +from pathlib import Path + import pytest from virtualenv.run import session_via_cli @@ -12,3 +15,13 @@ from virtualenv.run import session_via_cli def test_download_cli_flag(args, download, tmp_path): session = session_via_cli(args + [str(tmp_path)]) assert session.seeder.download is download + + +def test_embed_wheel_versions(tmp_path: Path) -> None: + session = session_via_cli([str(tmp_path)]) + expected = ( + {"pip": "bundle"} + if sys.version_info[:2] >= (3, 12) + else {"pip": "bundle", "setuptools": "bundle", "wheel": "bundle"} + ) + assert session.seeder.distribution_to_versions() == expected diff --git a/tests/unit/seed/embed/test_bootstrap_link_via_app_data.py b/tests/unit/seed/embed/test_bootstrap_link_via_app_data.py index 610aaa2..fac9ac6 100644 --- a/tests/unit/seed/embed/test_bootstrap_link_via_app_data.py +++ b/tests/unit/seed/embed/test_bootstrap_link_via_app_data.py @@ -3,11 +3,13 @@ from __future__ import annotations import contextlib import os import sys +from pathlib import Path from stat import S_IWGRP, S_IWOTH, S_IWUSR from subprocess import Popen, check_call from threading import Thread import pytest +from pytest_mock import MockerFixture from virtualenv.discovery import cached_py_info from virtualenv.discovery.py_info import PythonInfo @@ -202,7 +204,7 @@ def test_populated_read_only_cache_and_copied_app_data(tmp_path, current_fastest @pytest.mark.parametrize("pkg", ["pip", "setuptools", "wheel"]) @pytest.mark.usefixtures("session_app_data", "current_fastest", "coverage_env") def test_base_bootstrap_link_via_app_data_no(tmp_path, pkg): - create_cmd = [str(tmp_path), "--seeder", "app-data", f"--no-{pkg}"] + create_cmd = [str(tmp_path), "--seeder", "app-data", f"--no-{pkg}", "--wheel", "bundle", "--setuptools", "bundle"] result = cli_run(create_cmd) assert not (result.creator.purelib / pkg).exists() for key in {"pip", "setuptools", "wheel"} - {pkg}: @@ -216,7 +218,7 @@ def test_app_data_parallel_ok(tmp_path): @pytest.mark.usefixtures("temp_app_data") -def test_app_data_parallel_fail(tmp_path, mocker): +def test_app_data_parallel_fail(tmp_path: Path, mocker: MockerFixture) -> None: mocker.patch("virtualenv.seed.embed.via_app_data.pip_install.base.PipInstall.build_image", side_effect=RuntimeError) exceptions = _run_parallel_threads(tmp_path) assert len(exceptions) == 2 @@ -230,7 +232,7 @@ def _run_parallel_threads(tmp_path): def _run(name): try: - cli_run(["--seeder", "app-data", str(tmp_path / name), "--no-pip", "--no-setuptools"]) + cli_run(["--seeder", "app-data", str(tmp_path / name), "--no-pip", "--no-setuptools", "--wheel", "bundle"]) except Exception as exception: as_str = str(exception) exceptions.append(as_str) diff --git a/tests/unit/seed/wheels/test_acquire.py b/tests/unit/seed/wheels/test_acquire.py index 7f88f6a..dc471a1 100644 --- a/tests/unit/seed/wheels/test_acquire.py +++ b/tests/unit/seed/wheels/test_acquire.py @@ -5,8 +5,11 @@ import sys from datetime import datetime from pathlib import Path from subprocess import CalledProcessError +from typing import Callable +from unittest.mock import MagicMock import pytest +from pytest_mock import MockerFixture from virtualenv.app_data import AppDataDiskFolder from virtualenv.seed.wheels.acquire import download_wheel, get_wheel, pip_wheel_env_run @@ -113,8 +116,14 @@ def test_get_wheel_download_not_called(mocker, for_py_version, session_app_data, assert write.call_count == 0 -@pytest.mark.usefixtures("freezer") -def test_get_wheel_download_cached(tmp_path, mocker, for_py_version, downloaded_wheel): +def test_get_wheel_download_cached( + tmp_path: Path, + mocker: MockerFixture, + for_py_version: str, + downloaded_wheel: tuple[Wheel, MagicMock], + time_freeze: Callable[[datetime], None], +) -> None: + time_freeze(datetime.now()) from virtualenv.app_data.via_disk_folder import JSONStoreDisk app_data = AppDataDiskFolder(folder=str(tmp_path)) diff --git a/tests/unit/seed/wheels/test_periodic_update.py b/tests/unit/seed/wheels/test_periodic_update.py index 82c86e3..d4a5e09 100644 --- a/tests/unit/seed/wheels/test_periodic_update.py +++ b/tests/unit/seed/wheels/test_periodic_update.py @@ -68,7 +68,7 @@ def test_manual_upgrade(session_app_data, caplog, mocker, for_py_version): @pytest.mark.usefixtures("session_app_data") def test_pick_periodic_update(tmp_path, mocker, for_py_version): - embed, current = get_embed_wheel("setuptools", "3.5"), get_embed_wheel("setuptools", for_py_version) + embed, current = get_embed_wheel("setuptools", "3.6"), get_embed_wheel("setuptools", for_py_version) mocker.patch("virtualenv.seed.wheels.bundle.load_embed_wheel", return_value=embed) completed = datetime.now() - timedelta(days=29) u_log = UpdateLog( @@ -79,7 +79,20 @@ def test_pick_periodic_update(tmp_path, mocker, for_py_version): ) read_dict = mocker.patch("virtualenv.app_data.via_disk_folder.JSONStoreDisk.read", return_value=u_log.to_dict()) - result = cli_run([str(tmp_path), "--activators", "", "--no-periodic-update", "--no-wheel", "--no-pip"]) + result = cli_run( + [ + str(tmp_path), + "--activators", + "", + "--no-periodic-update", + "--no-wheel", + "--no-pip", + "--setuptools", + "bundle", + "--wheel", + "bundle", + ], + ) assert read_dict.call_count == 1 installed = [i.name for i in result.creator.purelib.iterdir() if i.suffix == ".dist-info"] @@ -208,8 +221,8 @@ _UPDATE_SKIP = { @pytest.mark.parametrize("u_log", list(_UPDATE_SKIP.values()), ids=list(_UPDATE_SKIP.keys())) -def test_periodic_update_skip(u_log, mocker, for_py_version, session_app_data, freezer): - freezer.move_to(_UP_NOW) +def test_periodic_update_skip(u_log, mocker, for_py_version, session_app_data, time_freeze): + time_freeze(_UP_NOW) mocker.patch("virtualenv.app_data.via_disk_folder.JSONStoreDisk.read", return_value=u_log.to_dict()) mocker.patch("virtualenv.seed.wheels.periodic_update.trigger_update", side_effect=RuntimeError) @@ -235,8 +248,8 @@ _UPDATE_YES = { @pytest.mark.parametrize("u_log", list(_UPDATE_YES.values()), ids=list(_UPDATE_YES.keys())) -def test_periodic_update_trigger(u_log, mocker, for_py_version, session_app_data, freezer): - freezer.move_to(_UP_NOW) +def test_periodic_update_trigger(u_log, mocker, for_py_version, session_app_data, time_freeze): + time_freeze(_UP_NOW) mocker.patch("virtualenv.app_data.via_disk_folder.JSONStoreDisk.read", return_value=u_log.to_dict()) write = mocker.patch("virtualenv.app_data.via_disk_folder.JSONStoreDisk.write") trigger_update_ = mocker.patch("virtualenv.seed.wheels.periodic_update.trigger_update") @@ -343,8 +356,8 @@ def test_trigger_update_debug(for_py_version, session_app_data, tmp_path, mocker assert process.communicate.call_count == 1 -def test_do_update_first(tmp_path, mocker, freezer): - freezer.move_to(_UP_NOW) +def test_do_update_first(tmp_path, mocker, time_freeze): + time_freeze(_UP_NOW) wheel = get_embed_wheel("pip", "3.9") app_data_outer = AppDataDiskFolder(str(tmp_path / "app")) extra = tmp_path / "extra" @@ -421,8 +434,8 @@ def test_do_update_first(tmp_path, mocker, freezer): } -def test_do_update_skip_already_done(tmp_path, mocker, freezer): - freezer.move_to(_UP_NOW + timedelta(hours=1)) +def test_do_update_skip_already_done(tmp_path, mocker, time_freeze): + time_freeze(_UP_NOW + timedelta(hours=1)) wheel = get_embed_wheel("pip", "3.9") app_data_outer = AppDataDiskFolder(str(tmp_path / "app")) extra = tmp_path / "extra" @@ -535,8 +548,8 @@ def mock_download(mocker, pip_version_remote): ) -def test_download_stop_with_embed(tmp_path, mocker, freezer): - freezer.move_to(_UP_NOW) +def test_download_stop_with_embed(tmp_path, mocker, time_freeze): + time_freeze(_UP_NOW) wheel = get_embed_wheel("pip", "3.9") app_data_outer = AppDataDiskFolder(str(tmp_path / "app")) pip_version_remote = [wheel_path(wheel, (0, 0, 2)), wheel_path(wheel, (0, 0, 1)), wheel_path(wheel, (-1, 0, 0))] @@ -558,8 +571,8 @@ def test_download_stop_with_embed(tmp_path, mocker, freezer): assert write.call_count == 1 -def test_download_manual_stop_after_one_download(tmp_path, mocker, freezer): - freezer.move_to(_UP_NOW) +def test_download_manual_stop_after_one_download(tmp_path, mocker, time_freeze): + time_freeze(_UP_NOW) wheel = get_embed_wheel("pip", "3.9") app_data_outer = AppDataDiskFolder(str(tmp_path / "app")) pip_version_remote = [wheel_path(wheel, (0, 1, 1))] @@ -580,8 +593,8 @@ def test_download_manual_stop_after_one_download(tmp_path, mocker, freezer): assert write.call_count == 1 -def test_download_manual_ignores_pre_release(tmp_path, mocker, freezer): - freezer.move_to(_UP_NOW) +def test_download_manual_ignores_pre_release(tmp_path, mocker, time_freeze): + time_freeze(_UP_NOW) wheel = get_embed_wheel("pip", "3.9") app_data_outer = AppDataDiskFolder(str(tmp_path / "app")) pip_version_remote = [wheel_path(wheel, (0, 0, 1))] @@ -613,8 +626,8 @@ def test_download_manual_ignores_pre_release(tmp_path, mocker, freezer): ] -def test_download_periodic_stop_at_first_usable(tmp_path, mocker, freezer): - freezer.move_to(_UP_NOW) +def test_download_periodic_stop_at_first_usable(tmp_path, mocker, time_freeze): + time_freeze(_UP_NOW) wheel = get_embed_wheel("pip", "3.9") app_data_outer = AppDataDiskFolder(str(tmp_path / "app")) pip_version_remote = [wheel_path(wheel, (0, 1, 1)), wheel_path(wheel, (0, 1, 0))] @@ -641,8 +654,8 @@ def test_download_periodic_stop_at_first_usable(tmp_path, mocker, freezer): assert write.call_count == 1 -def test_download_periodic_stop_at_first_usable_with_previous_minor(tmp_path, mocker, freezer): - freezer.move_to(_UP_NOW) +def test_download_periodic_stop_at_first_usable_with_previous_minor(tmp_path, mocker, time_freeze): + time_freeze(_UP_NOW) wheel = get_embed_wheel("pip", "3.9") app_data_outer = AppDataDiskFolder(str(tmp_path / "app")) pip_version_remote = [wheel_path(wheel, (0, 1, 1)), wheel_path(wheel, (0, 1, 0)), wheel_path(wheel, (0, -1, 0))] -- cgit v1.2.1