diff options
Diffstat (limited to 'tests/functional/test_cache.py')
-rw-r--r-- | tests/functional/test_cache.py | 330 |
1 files changed, 186 insertions, 144 deletions
diff --git a/tests/functional/test_cache.py b/tests/functional/test_cache.py index 0dc791081..7d20f5e31 100644 --- a/tests/functional/test_cache.py +++ b/tests/functional/test_cache.py @@ -1,38 +1,41 @@ import os import shutil from glob import glob +from typing import Callable, List, Tuple import pytest +from tests.lib import PipTestEnvironment, TestPipResult + @pytest.fixture -def cache_dir(script): +def cache_dir(script: PipTestEnvironment) -> str: result = script.run( - 'python', '-c', - 'from pip._internal.locations import USER_CACHE_DIR;' - 'print(USER_CACHE_DIR)' + "python", + "-c", + "from pip._internal.locations import USER_CACHE_DIR;print(USER_CACHE_DIR)", ) return result.stdout.strip() @pytest.fixture -def http_cache_dir(cache_dir): - return os.path.normcase(os.path.join(cache_dir, 'http')) +def http_cache_dir(cache_dir: str) -> str: + return os.path.normcase(os.path.join(cache_dir, "http")) @pytest.fixture -def wheel_cache_dir(cache_dir): - return os.path.normcase(os.path.join(cache_dir, 'wheels')) +def wheel_cache_dir(cache_dir: str) -> str: + return os.path.normcase(os.path.join(cache_dir, "wheels")) @pytest.fixture -def http_cache_files(http_cache_dir): - destination = os.path.join(http_cache_dir, 'arbitrary', 'pathname') +def http_cache_files(http_cache_dir: str) -> List[str]: + destination = os.path.join(http_cache_dir, "arbitrary", "pathname") if not os.path.exists(destination): return [] - filenames = glob(os.path.join(destination, '*')) + filenames = glob(os.path.join(destination, "*")) files = [] for filename in filenames: files.append(os.path.join(destination, filename)) @@ -40,13 +43,13 @@ def http_cache_files(http_cache_dir): @pytest.fixture -def wheel_cache_files(wheel_cache_dir): - destination = os.path.join(wheel_cache_dir, 'arbitrary', 'pathname') +def wheel_cache_files(wheel_cache_dir: str) -> List[str]: + destination = os.path.join(wheel_cache_dir, "arbitrary", "pathname") if not os.path.exists(destination): return [] - filenames = glob(os.path.join(destination, '*.whl')) + filenames = glob(os.path.join(destination, "*.whl")) files = [] for filename in filenames: files.append(os.path.join(destination, filename)) @@ -54,60 +57,60 @@ def wheel_cache_files(wheel_cache_dir): @pytest.fixture -def populate_http_cache(http_cache_dir): - destination = os.path.join(http_cache_dir, 'arbitrary', 'pathname') +def populate_http_cache(http_cache_dir: str) -> List[Tuple[str, str]]: + destination = os.path.join(http_cache_dir, "arbitrary", "pathname") os.makedirs(destination) files = [ - ('aaaaaaaaa', os.path.join(destination, 'aaaaaaaaa')), - ('bbbbbbbbb', os.path.join(destination, 'bbbbbbbbb')), - ('ccccccccc', os.path.join(destination, 'ccccccccc')), + ("aaaaaaaaa", os.path.join(destination, "aaaaaaaaa")), + ("bbbbbbbbb", os.path.join(destination, "bbbbbbbbb")), + ("ccccccccc", os.path.join(destination, "ccccccccc")), ] for _name, filename in files: - with open(filename, 'w'): + with open(filename, "w"): pass return files @pytest.fixture -def populate_wheel_cache(wheel_cache_dir): - destination = os.path.join(wheel_cache_dir, 'arbitrary', 'pathname') +def populate_wheel_cache(wheel_cache_dir: str) -> List[Tuple[str, str]]: + destination = os.path.join(wheel_cache_dir, "arbitrary", "pathname") os.makedirs(destination) files = [ - ('yyy-1.2.3', os.path.join(destination, 'yyy-1.2.3-py3-none-any.whl')), - ('zzz-4.5.6', os.path.join(destination, 'zzz-4.5.6-py3-none-any.whl')), - ('zzz-4.5.7', os.path.join(destination, 'zzz-4.5.7-py3-none-any.whl')), - ('zzz-7.8.9', os.path.join(destination, 'zzz-7.8.9-py3-none-any.whl')), + ("yyy-1.2.3", os.path.join(destination, "yyy-1.2.3-py3-none-any.whl")), + ("zzz-4.5.6", os.path.join(destination, "zzz-4.5.6-py3-none-any.whl")), + ("zzz-4.5.7", os.path.join(destination, "zzz-4.5.7-py3-none-any.whl")), + ("zzz-7.8.9", os.path.join(destination, "zzz-7.8.9-py3-none-any.whl")), ] for _name, filename in files: - with open(filename, 'w'): + with open(filename, "w"): pass return files @pytest.fixture -def empty_wheel_cache(wheel_cache_dir): +def empty_wheel_cache(wheel_cache_dir: str) -> None: if os.path.exists(wheel_cache_dir): shutil.rmtree(wheel_cache_dir) -def list_matches_wheel(wheel_name, result): +def list_matches_wheel(wheel_name: str, result: TestPipResult) -> bool: """Returns True if any line in `result`, which should be the output of a `pip cache list` call, matches `wheel_name`. E.g., If wheel_name is `foo-1.2.3` it searches for a line starting with `- foo-1.2.3-py3-none-any.whl `.""" lines = result.stdout.splitlines() - expected = f' - {wheel_name}-py3-none-any.whl ' + expected = f" - {wheel_name}-py3-none-any.whl " return any(map(lambda l: l.startswith(expected), lines)) -def list_matches_wheel_abspath(wheel_name, result): +def list_matches_wheel_abspath(wheel_name: str, result: TestPipResult) -> bool: """Returns True if any line in `result`, which should be the output of a `pip cache list --format=abspath` call, is a valid path and belongs to `wheel_name`. @@ -115,13 +118,20 @@ def list_matches_wheel_abspath(wheel_name, result): E.g., If wheel_name is `foo-1.2.3` it searches for a line starting with `foo-1.2.3-py3-none-any.whl`.""" lines = result.stdout.splitlines() - expected = f'{wheel_name}-py3-none-any.whl' - return any(map(lambda l: os.path.basename(l).startswith(expected) - and os.path.exists(l), lines)) + expected = f"{wheel_name}-py3-none-any.whl" + return any( + map( + lambda l: os.path.basename(l).startswith(expected) and os.path.exists(l), + lines, + ) + ) + + +RemoveMatches = Callable[[str, TestPipResult], bool] @pytest.fixture -def remove_matches_http(http_cache_dir): +def remove_matches_http(http_cache_dir: str) -> RemoveMatches: """Returns True if any line in `result`, which should be the output of a `pip cache purge` call, matches `http_filename`. @@ -129,22 +139,25 @@ def remove_matches_http(http_cache_dir): `Removed <http files cache dir>/arbitrary/pathname/aaaaaaaaa`. """ - def _remove_matches_http(http_filename, result): + def _remove_matches_http(http_filename: str, result: TestPipResult) -> bool: lines = result.stdout.splitlines() # The "/arbitrary/pathname/" bit is an implementation detail of how # the `populate_http_cache` fixture is implemented. path = os.path.join( - http_cache_dir, 'arbitrary', 'pathname', http_filename, + http_cache_dir, + "arbitrary", + "pathname", + http_filename, ) - expected = f'Removed {path}' + expected = f"Removed {path}" return expected in lines return _remove_matches_http @pytest.fixture -def remove_matches_wheel(wheel_cache_dir): +def remove_matches_wheel(wheel_cache_dir: str) -> RemoveMatches: """Returns True if any line in `result`, which should be the output of a `pip cache remove`/`pip cache purge` call, matches `wheel_name`. @@ -152,214 +165,240 @@ def remove_matches_wheel(wheel_cache_dir): `Removed <wheel cache dir>/arbitrary/pathname/foo-1.2.3-py3-none-any.whl`. """ - def _remove_matches_wheel(wheel_name, result): + def _remove_matches_wheel(wheel_name: str, result: TestPipResult) -> bool: lines = result.stdout.splitlines() - wheel_filename = f'{wheel_name}-py3-none-any.whl' + wheel_filename = f"{wheel_name}-py3-none-any.whl" # The "/arbitrary/pathname/" bit is an implementation detail of how # the `populate_wheel_cache` fixture is implemented. path = os.path.join( - wheel_cache_dir, 'arbitrary', 'pathname', wheel_filename, + wheel_cache_dir, + "arbitrary", + "pathname", + wheel_filename, ) - expected = f'Removed {path}' + expected = f"Removed {path}" return expected in lines return _remove_matches_wheel -def test_cache_dir(script, cache_dir): - result = script.pip('cache', 'dir') +def test_cache_dir(script: PipTestEnvironment, cache_dir: str) -> None: + result = script.pip("cache", "dir") assert os.path.normcase(cache_dir) == result.stdout.strip() -def test_cache_dir_too_many_args(script, cache_dir): - result = script.pip('cache', 'dir', 'aaa', expect_error=True) +def test_cache_dir_too_many_args(script: PipTestEnvironment, cache_dir: str) -> None: + result = script.pip("cache", "dir", "aaa", expect_error=True) - assert result.stdout == '' + assert result.stdout == "" # This would be `result.stderr == ...`, but pip prints deprecation # warnings on Python 2.7, so we check if the _line_ is in stderr. - assert 'ERROR: Too many arguments' in result.stderr.splitlines() + assert "ERROR: Too many arguments" in result.stderr.splitlines() @pytest.mark.usefixtures("populate_http_cache", "populate_wheel_cache") def test_cache_info( - script, http_cache_dir, wheel_cache_dir, wheel_cache_files -): - result = script.pip('cache', 'info') - - assert ( - f'Package index page cache location: {http_cache_dir}' - in result.stdout - ) - assert f'Wheels location: {wheel_cache_dir}' in result.stdout + script: PipTestEnvironment, + http_cache_dir: str, + wheel_cache_dir: str, + wheel_cache_files: List[str], +) -> None: + result = script.pip("cache", "info") + + assert f"Package index page cache location: {http_cache_dir}" in result.stdout + assert f"Locally built wheels location: {wheel_cache_dir}" in result.stdout num_wheels = len(wheel_cache_files) - assert f'Number of wheels: {num_wheels}' in result.stdout + assert f"Number of locally built wheels: {num_wheels}" in result.stdout @pytest.mark.usefixtures("populate_wheel_cache") -def test_cache_list(script): +def test_cache_list(script: PipTestEnvironment) -> None: """Running `pip cache list` should return exactly what the populate_wheel_cache fixture adds.""" - result = script.pip('cache', 'list') + result = script.pip("cache", "list") - assert list_matches_wheel('yyy-1.2.3', result) - assert list_matches_wheel('zzz-4.5.6', result) - assert list_matches_wheel('zzz-4.5.7', result) - assert list_matches_wheel('zzz-7.8.9', result) + assert list_matches_wheel("yyy-1.2.3", result) + assert list_matches_wheel("zzz-4.5.6", result) + assert list_matches_wheel("zzz-4.5.7", result) + assert list_matches_wheel("zzz-7.8.9", result) @pytest.mark.usefixtures("populate_wheel_cache") -def test_cache_list_abspath(script): +def test_cache_list_abspath(script: PipTestEnvironment) -> None: """Running `pip cache list --format=abspath` should return full paths of exactly what the populate_wheel_cache fixture adds.""" - result = script.pip('cache', 'list', '--format=abspath') + result = script.pip("cache", "list", "--format=abspath") - assert list_matches_wheel_abspath('yyy-1.2.3', result) - assert list_matches_wheel_abspath('zzz-4.5.6', result) - assert list_matches_wheel_abspath('zzz-4.5.7', result) - assert list_matches_wheel_abspath('zzz-7.8.9', result) + assert list_matches_wheel_abspath("yyy-1.2.3", result) + assert list_matches_wheel_abspath("zzz-4.5.6", result) + assert list_matches_wheel_abspath("zzz-4.5.7", result) + assert list_matches_wheel_abspath("zzz-7.8.9", result) @pytest.mark.usefixtures("empty_wheel_cache") -def test_cache_list_with_empty_cache(script): +def test_cache_list_with_empty_cache(script: PipTestEnvironment) -> None: """Running `pip cache list` with an empty cache should print - "Nothing cached." and exit.""" - result = script.pip('cache', 'list') - assert result.stdout == "Nothing cached.\n" + "No locally built wheels cached." and exit.""" + result = script.pip("cache", "list") + assert result.stdout == "No locally built wheels cached.\n" @pytest.mark.usefixtures("empty_wheel_cache") -def test_cache_list_with_empty_cache_abspath(script): +def test_cache_list_with_empty_cache_abspath(script: PipTestEnvironment) -> None: """Running `pip cache list --format=abspath` with an empty cache should not print anything and exit.""" - result = script.pip('cache', 'list', '--format=abspath') + result = script.pip("cache", "list", "--format=abspath") assert result.stdout.strip() == "" -def test_cache_list_too_many_args(script): +@pytest.mark.usefixtures("empty_wheel_cache") +def test_cache_purge_with_empty_cache(script: PipTestEnvironment) -> None: + """Running `pip cache purge` with an empty cache should print a warning + and exit without an error code.""" + result = script.pip("cache", "purge", allow_stderr_warning=True) + assert result.stderr == "WARNING: No matching packages\n" + assert result.stdout == "Files removed: 0\n" + + +@pytest.mark.usefixtures("populate_wheel_cache") +def test_cache_remove_with_bad_pattern(script: PipTestEnvironment) -> None: + """Running `pip cache remove` with a bad pattern should print a warning + and exit without an error code.""" + result = script.pip("cache", "remove", "aaa", allow_stderr_warning=True) + assert result.stderr == 'WARNING: No matching packages for pattern "aaa"\n' + assert result.stdout == "Files removed: 0\n" + + +def test_cache_list_too_many_args(script: PipTestEnvironment) -> None: """Passing `pip cache list` too many arguments should cause an error.""" - script.pip('cache', 'list', 'aaa', 'bbb', - expect_error=True) + script.pip("cache", "list", "aaa", "bbb", expect_error=True) @pytest.mark.usefixtures("populate_wheel_cache") -def test_cache_list_name_match(script): +def test_cache_list_name_match(script: PipTestEnvironment) -> None: """Running `pip cache list zzz` should list zzz-4.5.6, zzz-4.5.7, zzz-7.8.9, but nothing else.""" - result = script.pip('cache', 'list', 'zzz', '--verbose') + result = script.pip("cache", "list", "zzz", "--verbose") - assert not list_matches_wheel('yyy-1.2.3', result) - assert list_matches_wheel('zzz-4.5.6', result) - assert list_matches_wheel('zzz-4.5.7', result) - assert list_matches_wheel('zzz-7.8.9', result) + assert not list_matches_wheel("yyy-1.2.3", result) + assert list_matches_wheel("zzz-4.5.6", result) + assert list_matches_wheel("zzz-4.5.7", result) + assert list_matches_wheel("zzz-7.8.9", result) @pytest.mark.usefixtures("populate_wheel_cache") -def test_cache_list_name_match_abspath(script): +def test_cache_list_name_match_abspath(script: PipTestEnvironment) -> None: """Running `pip cache list zzz --format=abspath` should list paths of zzz-4.5.6, zzz-4.5.7, zzz-7.8.9, but nothing else.""" - result = script.pip('cache', 'list', 'zzz', '--format=abspath', - '--verbose') + result = script.pip("cache", "list", "zzz", "--format=abspath", "--verbose") - assert not list_matches_wheel_abspath('yyy-1.2.3', result) - assert list_matches_wheel_abspath('zzz-4.5.6', result) - assert list_matches_wheel_abspath('zzz-4.5.7', result) - assert list_matches_wheel_abspath('zzz-7.8.9', result) + assert not list_matches_wheel_abspath("yyy-1.2.3", result) + assert list_matches_wheel_abspath("zzz-4.5.6", result) + assert list_matches_wheel_abspath("zzz-4.5.7", result) + assert list_matches_wheel_abspath("zzz-7.8.9", result) @pytest.mark.usefixtures("populate_wheel_cache") -def test_cache_list_name_and_version_match(script): +def test_cache_list_name_and_version_match(script: PipTestEnvironment) -> None: """Running `pip cache list zzz-4.5.6` should list zzz-4.5.6, but nothing else.""" - result = script.pip('cache', 'list', 'zzz-4.5.6', '--verbose') + result = script.pip("cache", "list", "zzz-4.5.6", "--verbose") - assert not list_matches_wheel('yyy-1.2.3', result) - assert list_matches_wheel('zzz-4.5.6', result) - assert not list_matches_wheel('zzz-4.5.7', result) - assert not list_matches_wheel('zzz-7.8.9', result) + assert not list_matches_wheel("yyy-1.2.3", result) + assert list_matches_wheel("zzz-4.5.6", result) + assert not list_matches_wheel("zzz-4.5.7", result) + assert not list_matches_wheel("zzz-7.8.9", result) @pytest.mark.usefixtures("populate_wheel_cache") -def test_cache_list_name_and_version_match_abspath(script): +def test_cache_list_name_and_version_match_abspath(script: PipTestEnvironment) -> None: """Running `pip cache list zzz-4.5.6 --format=abspath` should list path of zzz-4.5.6, but nothing else.""" - result = script.pip('cache', 'list', 'zzz-4.5.6', '--format=abspath', - '--verbose') + result = script.pip("cache", "list", "zzz-4.5.6", "--format=abspath", "--verbose") - assert not list_matches_wheel_abspath('yyy-1.2.3', result) - assert list_matches_wheel_abspath('zzz-4.5.6', result) - assert not list_matches_wheel_abspath('zzz-4.5.7', result) - assert not list_matches_wheel_abspath('zzz-7.8.9', result) + assert not list_matches_wheel_abspath("yyy-1.2.3", result) + assert list_matches_wheel_abspath("zzz-4.5.6", result) + assert not list_matches_wheel_abspath("zzz-4.5.7", result) + assert not list_matches_wheel_abspath("zzz-7.8.9", result) @pytest.mark.usefixtures("populate_wheel_cache") -def test_cache_remove_no_arguments(script): +def test_cache_remove_no_arguments(script: PipTestEnvironment) -> None: """Running `pip cache remove` with no arguments should cause an error.""" - script.pip('cache', 'remove', expect_error=True) + script.pip("cache", "remove", expect_error=True) -def test_cache_remove_too_many_args(script): +def test_cache_remove_too_many_args(script: PipTestEnvironment) -> None: """Passing `pip cache remove` too many arguments should cause an error.""" - script.pip('cache', 'remove', 'aaa', 'bbb', - expect_error=True) + script.pip("cache", "remove", "aaa", "bbb", expect_error=True) @pytest.mark.usefixtures("populate_wheel_cache") -def test_cache_remove_name_match(script, remove_matches_wheel): +def test_cache_remove_name_match( + script: PipTestEnvironment, remove_matches_wheel: RemoveMatches +) -> None: """Running `pip cache remove zzz` should remove zzz-4.5.6 and zzz-7.8.9, but nothing else.""" - result = script.pip('cache', 'remove', 'zzz', '--verbose') + result = script.pip("cache", "remove", "zzz", "--verbose") - assert not remove_matches_wheel('yyy-1.2.3', result) - assert remove_matches_wheel('zzz-4.5.6', result) - assert remove_matches_wheel('zzz-4.5.7', result) - assert remove_matches_wheel('zzz-7.8.9', result) + assert not remove_matches_wheel("yyy-1.2.3", result) + assert remove_matches_wheel("zzz-4.5.6", result) + assert remove_matches_wheel("zzz-4.5.7", result) + assert remove_matches_wheel("zzz-7.8.9", result) @pytest.mark.usefixtures("populate_wheel_cache") -def test_cache_remove_name_and_version_match(script, remove_matches_wheel): +def test_cache_remove_name_and_version_match( + script: PipTestEnvironment, remove_matches_wheel: RemoveMatches +) -> None: """Running `pip cache remove zzz-4.5.6` should remove zzz-4.5.6, but nothing else.""" - result = script.pip('cache', 'remove', 'zzz-4.5.6', '--verbose') + result = script.pip("cache", "remove", "zzz-4.5.6", "--verbose") - assert not remove_matches_wheel('yyy-1.2.3', result) - assert remove_matches_wheel('zzz-4.5.6', result) - assert not remove_matches_wheel('zzz-4.5.7', result) - assert not remove_matches_wheel('zzz-7.8.9', result) + assert not remove_matches_wheel("yyy-1.2.3", result) + assert remove_matches_wheel("zzz-4.5.6", result) + assert not remove_matches_wheel("zzz-4.5.7", result) + assert not remove_matches_wheel("zzz-7.8.9", result) @pytest.mark.usefixtures("populate_http_cache", "populate_wheel_cache") -def test_cache_purge(script, remove_matches_http, remove_matches_wheel): +def test_cache_purge( + script: PipTestEnvironment, + remove_matches_http: RemoveMatches, + remove_matches_wheel: RemoveMatches, +) -> None: """Running `pip cache purge` should remove all cached http files and wheels.""" - result = script.pip('cache', 'purge', '--verbose') + result = script.pip("cache", "purge", "--verbose") - assert remove_matches_http('aaaaaaaaa', result) - assert remove_matches_http('bbbbbbbbb', result) - assert remove_matches_http('ccccccccc', result) + assert remove_matches_http("aaaaaaaaa", result) + assert remove_matches_http("bbbbbbbbb", result) + assert remove_matches_http("ccccccccc", result) - assert remove_matches_wheel('yyy-1.2.3', result) - assert remove_matches_wheel('zzz-4.5.6', result) - assert remove_matches_wheel('zzz-4.5.7', result) - assert remove_matches_wheel('zzz-7.8.9', result) + assert remove_matches_wheel("yyy-1.2.3", result) + assert remove_matches_wheel("zzz-4.5.6", result) + assert remove_matches_wheel("zzz-4.5.7", result) + assert remove_matches_wheel("zzz-7.8.9", result) @pytest.mark.usefixtures("populate_http_cache", "populate_wheel_cache") def test_cache_purge_too_many_args( - script, http_cache_files, wheel_cache_files -): + script: PipTestEnvironment, + http_cache_files: List[str], + wheel_cache_files: List[str], +) -> None: """Running `pip cache purge aaa` should raise an error and remove no cached http files or wheels.""" - result = script.pip('cache', 'purge', 'aaa', '--verbose', - expect_error=True) - assert result.stdout == '' + result = script.pip("cache", "purge", "aaa", "--verbose", expect_error=True) + assert result.stdout == "" # This would be `result.stderr == ...`, but pip prints deprecation # warnings on Python 2.7, so we check if the _line_ is in stderr. - assert 'ERROR: Too many arguments' in result.stderr.splitlines() + assert "ERROR: Too many arguments" in result.stderr.splitlines() # Make sure nothing was deleted. for filename in http_cache_files + wheel_cache_files: @@ -367,12 +406,15 @@ def test_cache_purge_too_many_args( @pytest.mark.parametrize("command", ["info", "list", "remove", "purge"]) -def test_cache_abort_when_no_cache_dir(script, command): +def test_cache_abort_when_no_cache_dir( + script: PipTestEnvironment, command: str +) -> None: """Running any pip cache command when cache is disabled should abort and log an informative error""" - result = script.pip('cache', command, '--no-cache-dir', - expect_error=True) - assert result.stdout == '' + result = script.pip("cache", command, "--no-cache-dir", expect_error=True) + assert result.stdout == "" - assert ('ERROR: pip cache commands can not function' - ' since cache is disabled.' in result.stderr.splitlines()) + assert ( + "ERROR: pip cache commands can not function" + " since cache is disabled." in result.stderr.splitlines() + ) |