def test_pick_periodic_update(tmp_path, session_app_data, mocker, for_py_version): embed, current = get_embed_wheel("setuptools", "3.4"), 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( started=datetime.now() - timedelta(days=30), completed=completed, versions=[ NewVersion(filename=current.path, found_date=completed, release_date=completed) ], periodic=True, ) 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" ]) assert read_dict.call_count == 1 installed = list(i.name for i in result.creator.purelib.iterdir() if i.suffix == ".dist-info") assert "setuptools-{}.dist-info".format(current.version) in installed
def test_download_stop_with_embed(tmp_path, mocker, freezer): freezer.move_to(_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))] at = {"index": 0} def download(): while True: path = pip_version_remote[at["index"]] at["index"] += 1 yield Wheel(Path(path)) do = download() download_wheel = mocker.patch("virtualenv.seed.wheels.acquire.download_wheel", side_effect=lambda *a, **k: next(do)) url_o = mocker.patch("virtualenv.seed.wheels.periodic_update.urlopen", side_effect=URLError("unavailable")) last_update = _UP_NOW - timedelta(days=14) u_log = UpdateLog(started=last_update, completed=last_update, versions=[], periodic=True) read_dict = 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") do_update("pip", "3.9", str(wheel.path), str(app_data_outer), [], True) assert download_wheel.call_count == 3 assert url_o.call_count == 2 assert read_dict.call_count == 1 assert write.call_count == 1
def test_trigger_update_debug(for_py_version, session_app_data, tmp_path, mocker, monkeypatch): monkeypatch.setenv(str("_VIRTUALENV_PERIODIC_UPDATE_INLINE"), str("1")) current = get_embed_wheel("pip", for_py_version) process = mocker.MagicMock() process.communicate.return_value = None, None Popen = mocker.patch("virtualenv.seed.wheels.periodic_update.Popen", return_value=process) trigger_update("pip", for_py_version, current, [tmp_path / "a", tmp_path / "b"], session_app_data, os.environ, False) assert Popen.call_count == 1 args, kwargs = Popen.call_args cmd = (dedent( """ from virtualenv.report import setup_report, MAX_LEVEL from virtualenv.seed.wheels.periodic_update import do_update setup_report(MAX_LEVEL, show_pid=True) do_update({!r}, {!r}, {!r}, {!r}, {!r}, {!r}) """, ).strip().format( "pip", for_py_version, str(current.path), str(session_app_data), [str(tmp_path / "a"), str(tmp_path / "b")], False, )) assert args == ([sys.executable, "-c", cmd], ) expected = {"stdout": None, "stderr": None} assert kwargs == expected assert process.communicate.call_count == 1
def test_manual_upgrade(session_app_data, caplog, mocker, for_py_version): wheel = get_embed_wheel("pip", for_py_version) new_version = NewVersion(wheel.path, datetime.now(), datetime.now() - timedelta(days=20)) def _do_update(distribution, for_py_version, embed_filename, app_data, search_dirs, periodic): # noqa if distribution == "pip": return [new_version] return [] do_update_mock = mocker.patch( "virtualenv.seed.wheels.periodic_update.do_update", side_effect=_do_update) manual_upgrade(session_app_data, os.environ) assert "upgrade pip" in caplog.text assert "upgraded pip" in caplog.text assert " no new versions found" in caplog.text assert " new entries found:\n" in caplog.text assert "\tNewVersion(" in caplog.text packages = defaultdict(list) for i in do_update_mock.call_args_list: packages[i[1]["distribution"]].append(i[1]["for_py_version"]) packages = {key: sorted(value) for key, value in packages.items()} versions = list(sorted(BUNDLE_SUPPORT.keys())) expected = {"setuptools": versions, "wheel": versions, "pip": versions} assert packages == expected
def test_find_less_than(for_py_version): latest = get_embed_wheel("setuptools", MAX) result = find_compatible_in_house("setuptools", "<{}".format(latest.version), MAX, BUNDLE_FOLDER) assert result is not None assert result.path != latest.path
def next_pip_wheel(for_py_version): wheel = get_embed_wheel("pip", for_py_version) new_version = list(wheel.version_tuple) new_version[-1] += 1 new_name = wheel.name.replace(wheel.version, ".".join(str(i) for i in new_version)) return Wheel.from_path(Path(new_name))
def test_download_manual_stop_after_one_download(tmp_path, mocker, freezer): freezer.move_to(_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))] download_wheel = mock_download(mocker, pip_version_remote) url_o = mocker.patch("virtualenv.seed.wheels.periodic_update.urlopen", side_effect=URLError("unavailable")) last_update = _UP_NOW - timedelta(days=14) u_log = UpdateLog(started=last_update, completed=last_update, versions=[], periodic=True) read_dict = 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") do_update("pip", "3.9", str(wheel.path), str(app_data_outer), [], False) assert download_wheel.call_count == 1 assert url_o.call_count == 2 assert read_dict.call_count == 1 assert write.call_count == 1
def test_manual_update_honored(mocker, session_app_data, for_py_version): current = get_embed_wheel("setuptools", for_py_version) expected_path = wheel_path(current, (0, 1, 1)) now = datetime.now() completed = now u_log = UpdateLog( started=completed, completed=completed, periodic=True, versions=[ NewVersion(wheel_path(current, (0, 1, 2)), completed, completed, "periodic"), NewVersion(expected_path, completed, now - timedelta(days=10), "manual"), NewVersion(wheel_path(current, (0, 1, 0)), completed, now - timedelta(days=11), "periodic"), NewVersion(str(current.path), completed, now - timedelta(days=12), "manual"), ], ) mocker.patch("virtualenv.app_data.via_disk_folder.JSONStoreDisk.read", return_value=u_log.to_dict()) result = periodic_update("setuptools", None, for_py_version, current, [], session_app_data, False, os.environ) assert str(result.path) == expected_path
def test_periodic_update_stops_at_current(mocker, session_app_data, for_py_version): current = get_embed_wheel("setuptools", for_py_version) now, completed = datetime.now(), datetime.now() - timedelta(days=29) u_log = UpdateLog( started=completed, completed=completed, versions=[ NewVersion(wheel_path(current, (1, )), completed, now - timedelta(days=1)), NewVersion(filename=current.path, found_date=completed, release_date=now - timedelta(days=2)), NewVersion(wheel_path(current, (-1, )), completed, now - timedelta(days=30)), ], periodic=True, ) mocker.patch("virtualenv.app_data.via_disk_folder.JSONStoreDisk.read", return_value=u_log.to_dict()) result = periodic_update("setuptools", for_py_version, current, [], session_app_data, False, os.environ) assert result.path == current.path
def test_do_update_skip_already_done(tmp_path, mocker, freezer): freezer.move_to(_UP_NOW + timedelta(hours=1)) wheel = get_embed_wheel("pip", "3.9") app_data_outer = AppDataDiskFolder(str(tmp_path / "app")) extra = tmp_path / "extra" extra.mkdir() def _download_wheel(distribution, version_spec, for_py_version, search_dirs, app_data, to_folder, env): # noqa return wheel.path download_wheel = mocker.patch( "virtualenv.seed.wheels.acquire.download_wheel", side_effect=_download_wheel) url_o = mocker.patch("virtualenv.seed.wheels.periodic_update.urlopen", side_effect=RuntimeError) released = _UP_NOW - timedelta(days=30) u_log = UpdateLog( started=_UP_NOW - timedelta(days=31), completed=released, versions=[ NewVersion(filename=wheel.path.name, found_date=released, release_date=released) ], periodic=True, ) read_dict = 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") versions = do_update("pip", "3.9", str(wheel.path), str(app_data_outer), [str(extra)], False) assert download_wheel.call_count == 1 assert read_dict.call_count == 1 assert not url_o.call_count assert versions == [] assert write.call_count == 1 wrote_json = write.call_args[0][0] assert wrote_json == { "started": dump_datetime(_UP_NOW + timedelta(hours=1)), "completed": dump_datetime(_UP_NOW + timedelta(hours=1)), "periodic": False, "versions": [ { "filename": wheel.path.name, "release_date": dump_datetime(released), "found_date": dump_datetime(released), }, ], }
def test_wheel_support_no_python_requires(mocker): wheel = get_embed_wheel("setuptools", for_py_version=None) zip_mock = mocker.MagicMock() mocker.patch("virtualenv.seed.wheels.util.ZipFile", new=zip_mock) zip_mock.return_value.__enter__.return_value.read = lambda name: b"" supports = wheel.support_py("3.8") assert supports is True
def test_get_wheel_download_not_called(mocker, for_py_version, session_app_data, downloaded_wheel, version): distribution = "setuptools" expected = get_embed_wheel(distribution, for_py_version) if version == "pinned": version = expected.version write = mocker.patch( "virtualenv.app_data.via_disk_folder.JSONStoreDisk.write") wheel = get_wheel(distribution, version, for_py_version, [], True, session_app_data, False, os.environ) assert wheel is not None assert wheel.name == expected.name assert downloaded_wheel[1].call_count == 0 assert write.call_count == 0
def test_download_wheel_bad_output(mocker, for_py_version, session_app_data): """if the download contains no match for what wheel was downloaded, pick one that matches from target""" distribution = "setuptools" p_open = mocker.MagicMock() mocker.patch("virtualenv.seed.wheels.acquire.Popen", return_value=p_open) p_open.communicate.return_value = "", "" p_open.returncode = 0 embed = get_embed_wheel(distribution, for_py_version) as_path = mocker.MagicMock() available = discover_wheels(BUNDLE_FOLDER, "setuptools", None, for_py_version) as_path.iterdir.return_value = [i.path for i in available] result = download_wheel(distribution, "=={}".format(embed.version), for_py_version, [], session_app_data, as_path) assert result.path == embed.path
def test_download_manual_ignores_pre_release(tmp_path, mocker, freezer): freezer.move_to(_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))] pip_version_pre = NewVersion( Path(wheel_path(wheel, (0, 1, 0), "b1")).name, _UP_NOW, None, "downloaded") download_wheel = mock_download(mocker, pip_version_remote) url_o = mocker.patch("virtualenv.seed.wheels.periodic_update.urlopen", side_effect=URLError("unavailable")) last_update = _UP_NOW - timedelta(days=14) u_log = UpdateLog(started=last_update, completed=last_update, versions=[pip_version_pre], periodic=True) read_dict = 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") do_update("pip", "3.9", str(wheel.path), str(app_data_outer), [], False) assert download_wheel.call_count == 1 assert url_o.call_count == 2 assert read_dict.call_count == 1 assert write.call_count == 1 wrote_json = write.call_args[0][0] assert wrote_json["versions"] == [ { "filename": Path(pip_version_remote[0]).name, "release_date": None, "found_date": dump_datetime(_UP_NOW), "source": "manual", }, pip_version_pre.to_dict(), ]
def test_download_periodic_stop_at_first_usable(tmp_path, mocker, freezer): freezer.move_to(_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)) ] rel_date_remote = [ _UP_NOW - timedelta(days=1), _UP_NOW - timedelta(days=30) ] download_wheel = mock_download(mocker, pip_version_remote) rel_date_gen = iter(rel_date_remote) release_date = mocker.patch( "virtualenv.seed.wheels.periodic_update.release_date_for_wheel_path", side_effect=lambda *a, **k: next(rel_date_gen), ) last_update = _UP_NOW - timedelta(days=14) u_log = UpdateLog(started=last_update, completed=last_update, versions=[], periodic=True) read_dict = 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") do_update("pip", "3.9", str(wheel.path), str(app_data_outer), [], True) assert download_wheel.call_count == 2 assert release_date.call_count == 2 assert read_dict.call_count == 1 assert write.call_count == 1
def test_trigger_update_no_debug(for_py_version, session_app_data, tmp_path, mocker, monkeypatch): monkeypatch.delenv(str("_VIRTUALENV_PERIODIC_UPDATE_INLINE"), raising=False) current = get_embed_wheel("setuptools", for_py_version) process = mocker.MagicMock() process.communicate.return_value = None, None Popen = mocker.patch("virtualenv.seed.wheels.periodic_update.Popen", return_value=process) trigger_update("setuptools", for_py_version, current, [tmp_path / "a", tmp_path / "b"], session_app_data, True) assert Popen.call_count == 1 args, kwargs = Popen.call_args cmd = ( dedent( """ from virtualenv.report import setup_report, MAX_LEVEL from virtualenv.seed.wheels.periodic_update import do_update setup_report(MAX_LEVEL, show_pid=True) do_update({!r}, {!r}, {!r}, {!r}, {!r}, {!r}) """, ) .strip() .format( "setuptools", for_py_version, str(current.path), str(session_app_data), [str(tmp_path / "a"), str(tmp_path / "b")], True, ) ) assert args == ([sys.executable, "-c", cmd],) expected = {"stdout": subprocess.PIPE, "stderr": subprocess.PIPE} if sys.platform == "win32": expected["creationflags"] = DETACHED_PROCESS assert kwargs == expected assert process.communicate.call_count == 0
def test_version_pinned_is_embed(app_data, for_py_version): expected_wheel = get_embed_wheel("pip", for_py_version) wheel = from_bundle("pip", expected_wheel.version, for_py_version, [], app_data, False, os.environ) assert wheel is not None assert wheel.name == expected_wheel.name
def test_version_embed(app_data, for_py_version): wheel = from_bundle("pip", Version.embed, for_py_version, [], app_data, False, os.environ) assert wheel is not None assert wheel.name == get_embed_wheel("pip", for_py_version).name
def test_find_latest(for_py_version): result = find_compatible_in_house("setuptools", None, for_py_version, BUNDLE_FOLDER) expected = get_embed_wheel("setuptools", for_py_version) assert result.path == expected.path
def test_find_exact(for_py_version): expected = get_embed_wheel("setuptools", for_py_version) result = find_compatible_in_house("setuptools", f"=={expected.version}", for_py_version, BUNDLE_FOLDER) assert result.path == expected.path
def test_download_periodic_stop_at_first_usable_with_previous_minor( tmp_path, mocker, freezer): freezer.move_to(_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)) ] rel_date_remote = [ _UP_NOW - timedelta(days=1), _UP_NOW - timedelta(days=30), _UP_NOW - timedelta(days=40) ] downloaded_versions = [ NewVersion( Path(pip_version_remote[2]).name, rel_date_remote[2], None, "download"), NewVersion( Path(pip_version_remote[0]).name, rel_date_remote[0], None, "download"), ] download_wheel = mock_download(mocker, pip_version_remote) rel_date_gen = iter(rel_date_remote) release_date = mocker.patch( "virtualenv.seed.wheels.periodic_update.release_date_for_wheel_path", side_effect=lambda *a, **k: next(rel_date_gen), ) last_update = _UP_NOW - timedelta(days=14) u_log = UpdateLog( started=last_update, completed=last_update, versions=downloaded_versions, periodic=True, ) read_dict = 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") do_update("pip", "3.9", str(wheel.path), str(app_data_outer), [], True) assert download_wheel.call_count == 2 assert release_date.call_count == 2 assert read_dict.call_count == 1 assert write.call_count == 1 wrote_json = write.call_args[0][0] assert wrote_json["versions"] == [ { "filename": Path(pip_version_remote[0]).name, "release_date": dump_datetime(rel_date_remote[0]), "found_date": dump_datetime(_UP_NOW), "source": "periodic", }, { "filename": Path(pip_version_remote[1]).name, "release_date": dump_datetime(rel_date_remote[1]), "found_date": dump_datetime(_UP_NOW), "source": "periodic", }, downloaded_versions[0].to_dict(), ]
def test_wheel_not_support(): wheel = get_embed_wheel("setuptools", MAX) assert wheel.support_py("3.3") is False
def test_wheel_repr(): wheel = get_embed_wheel("setuptools", MAX) assert str(wheel.path) in repr(wheel)
def test_do_update_first(tmp_path, mocker, freezer): freezer.move_to(_UP_NOW) wheel = get_embed_wheel("pip", "3.9") app_data_outer = AppDataDiskFolder(str(tmp_path / "app")) extra = tmp_path / "extra" extra.mkdir() pip_version_remote = [ (wheel_path(wheel, (1, 0, 0)), None), (wheel_path(wheel, (0, 1, 0)), _UP_NOW - timedelta(days=1)), (wheel_path(wheel, (0, 0, 1)), _UP_NOW - timedelta(days=2)), (wheel.path, _UP_NOW - timedelta(days=3)), (wheel_path(wheel, (-1, 0, 0)), _UP_NOW - timedelta(days=30)), ] download_wheels = (Wheel(Path(i[0])) for i in pip_version_remote) def _download_wheel(distribution, version_spec, for_py_version, search_dirs, app_data, to_folder, env): assert distribution == "pip" assert for_py_version == "3.9" assert [str(i) for i in search_dirs] == [str(extra)] assert isinstance(app_data, AppDataDiskFolder) assert to_folder == app_data_outer.house return next(download_wheels) download_wheel = mocker.patch( "virtualenv.seed.wheels.acquire.download_wheel", side_effect=_download_wheel) releases = { Wheel(Path(wheel)).version: [ { "upload_time": datetime.strftime(release_date, "%Y-%m-%dT%H:%M:%S") if release_date is not None else None }, ] for wheel, release_date in pip_version_remote } pypi_release = json.dumps({"releases": releases}) @contextmanager def _release(of, context): assert of == "https://pypi.org/pypi/pip/json" assert context is None yield StringIO(pypi_release) url_o = mocker.patch("virtualenv.seed.wheels.periodic_update.urlopen", side_effect=_release) last_update = _UP_NOW - timedelta(days=14) u_log = UpdateLog(started=last_update, completed=last_update, versions=[], periodic=True) read_dict = 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") copy = mocker.patch("virtualenv.seed.wheels.periodic_update.copy2") versions = do_update("pip", "3.9", str(pip_version_remote[-1][0]), str(app_data_outer), [str(extra)], True) assert download_wheel.call_count == len(pip_version_remote) assert url_o.call_count == 1 assert copy.call_count == 1 expected = [ NewVersion( Path(wheel).name, _UP_NOW, None if release is None else release.replace(microsecond=0)) for wheel, release in pip_version_remote ] assert versions == expected assert read_dict.call_count == 1 assert write.call_count == 1 wrote_json = write.call_args[0][0] assert wrote_json == { "started": dump_datetime(last_update), "completed": dump_datetime(_UP_NOW), "periodic": True, "versions": [e.to_dict() for e in expected], }
def get_embedded_wheel(self, distribution): return get_embed_wheel( distribution, "{}.{}".format(self.version_info[0], self.version_info[1])).path