From 8f14e3d9f0f200fa203eef54e4f62c7403dcec9d Mon Sep 17 00:00:00 2001 From: Ben Mares Date: Fri, 13 Sep 2024 01:27:58 +0200 Subject: [PATCH 1/2] Move clear_poetry_cache fixture to conftest.py --- tests/conftest.py | 37 ++++++++++++++++++++++++++++++++ tests/test_pip_repositories.py | 39 ---------------------------------- 2 files changed, 37 insertions(+), 39 deletions(-) diff --git a/tests/conftest.py b/tests/conftest.py index b29d7f94..8d8c227b 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -2,6 +2,8 @@ import pathlib import platform import re +import shutil +import sys import typing from pathlib import Path @@ -15,6 +17,7 @@ from docker.models.containers import Container from ensureconda.resolve import platform_subdir +from conda_lock._vendor.poetry.locations import DEFAULT_CACHE_DIR from conda_lock.invoke_conda import PathLike, _ensureconda @@ -179,3 +182,37 @@ def install_lock(): """Limit concurrent install operations.""" with filelock.FileLock(str(TESTS_DIR.joinpath("install.lock"))): yield + + +@pytest.fixture() +def cleared_poetry_cache(tmp_path_factory, testrun_uid: str): + """Ensure no concurrency for tests that rely on the cache being cleared""" + # testrun_uid comes from xdist + # The idea for using FileLock with the base temp directory comes from + # + root_tmp_dir = tmp_path_factory.getbasetemp().parent + testrun_lockfile = root_tmp_dir / f".conda_lock_pytest_{testrun_uid}.lock" + with filelock.FileLock(testrun_lockfile): + # Use `pytest -s` to see these messages + print( + f"Clearing {DEFAULT_CACHE_DIR} based on lock {testrun_lockfile}", + file=sys.stderr, + ) + clear_poetry_cache() + yield + print(f"Releasing lock {testrun_lockfile}", file=sys.stderr) + + +def clear_poetry_cache() -> None: + # We are going to rmtree the cache directory. Let's be extra careful to make + # sure we only delete a directory named "pypoetry-conda-lock" or one of its + # subdirectories. + to_delete = DEFAULT_CACHE_DIR.resolve() + assert to_delete.name == "pypoetry-conda-lock" or ( + to_delete.parent.name == "pypoetry-conda-lock" and to_delete.name == "Cache" + ) + # Do another independent check that triggers even if we're in optimized mode + if "pypoetry-conda-lock" in to_delete.parts: + shutil.rmtree(DEFAULT_CACHE_DIR, ignore_errors=True) + else: + raise RuntimeError(f"Refusing to delete {to_delete} as it does not look right") diff --git a/tests/test_pip_repositories.py b/tests/test_pip_repositories.py index 541120da..64e7c2a2 100644 --- a/tests/test_pip_repositories.py +++ b/tests/test_pip_repositories.py @@ -1,7 +1,5 @@ import base64 import os -import shutil -import sys import tarfile from io import BytesIO @@ -13,9 +11,6 @@ import requests import requests_mock -from filelock import FileLock - -from conda_lock._vendor.poetry.locations import DEFAULT_CACHE_DIR from conda_lock.conda_lock import DEFAULT_LOCKFILE_NAME, run_lock from conda_lock.lockfile import parse_conda_lock_file from tests.test_conda_lock import clone_test_dir @@ -135,25 +130,6 @@ def configure_auth(monkeypatch): monkeypatch.setenv("PIP_PASSWORD", _PRIVATE_REPO_PASSWORD) -@pytest.fixture() -def cleared_poetry_cache(tmp_path_factory, testrun_uid: str): - """Ensure no concurrency for tests that rely on the cache being cleared""" - # testrun_uid comes from xdist - # The idea for using FileLock with the base temp directory comes from - # - root_tmp_dir = tmp_path_factory.getbasetemp().parent - testrun_lockfile = root_tmp_dir / f".conda_lock_pytest_{testrun_uid}.lock" - with FileLock(testrun_lockfile): - # Use `pytest -s` to see these messages - print( - f"Clearing {DEFAULT_CACHE_DIR} based on lock {testrun_lockfile}", - file=sys.stderr, - ) - clear_poetry_cache() - yield - print(f"Releasing lock {testrun_lockfile}", file=sys.stderr) - - def test_it_uses_pip_repositories_with_env_var_substitution( monkeypatch: "pytest.MonkeyPatch", conda_exe: str, @@ -197,18 +173,3 @@ def test_it_uses_pip_repositories_with_env_var_substitution( "Password environment variable was not respected, See full lock-file:\n" + lockfile_content ) - - -def clear_poetry_cache() -> None: - # We are going to rmtree the cache directory. Let's be extra careful to make - # sure we only delete a directory named "pypoetry-conda-lock" or one of its - # subdirectories. - to_delete = DEFAULT_CACHE_DIR.resolve() - assert to_delete.name == "pypoetry-conda-lock" or ( - to_delete.parent.name == "pypoetry-conda-lock" and to_delete.name == "Cache" - ) - # Do another independent check that triggers even if we're in optimized mode - if "pypoetry-conda-lock" in to_delete.parts: - shutil.rmtree(DEFAULT_CACHE_DIR, ignore_errors=True) - else: - raise RuntimeError(f"Refusing to delete {to_delete} as it does not look right") From c53135d426f9e22eaaaa8e78a9e91f7a38339de7 Mon Sep 17 00:00:00 2001 From: Ben Mares Date: Fri, 13 Sep 2024 01:30:01 +0200 Subject: [PATCH 2/2] Ensure cache is not deleted during test_pip_full_whl_url --- tests/test_conda_lock.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/tests/test_conda_lock.py b/tests/test_conda_lock.py index 2f999fa5..17a92b97 100644 --- a/tests/test_conda_lock.py +++ b/tests/test_conda_lock.py @@ -2752,7 +2752,12 @@ def test_parse_environment_file_with_pip_and_platform_selector(): def test_pip_full_whl_url( - tmp_path: Path, conda_exe: str, monkeypatch: "pytest.MonkeyPatch" + tmp_path: Path, + conda_exe: str, + monkeypatch: "pytest.MonkeyPatch", + # If the cache is cleared under this test, it can cause an error message: + # E FileNotFoundError: [Errno 2] No such file or directory: '/Users/runner/Library/Caches/pypoetry-conda-lock/artifacts/5a/51/bb/896565e2c84dc024b41e43536c67cef3618b17b0daa532d87a72054dca/requests-2.31.0-py3-none-any.whl' + cleared_poetry_cache: None, ): """Ensure that we can specify full wheel URL in the environment file."""