Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions news/8355.feature
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Add option ``--format`` to subcommand ``list`` of ``pip cache``, with ``abspath`` choice to output the full path of a wheel file.
33 changes: 32 additions & 1 deletion src/pip/_internal/commands/cache.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,11 +37,25 @@ class CacheCommand(Command):
usage = """
%prog dir
%prog info
%prog list [<pattern>]
%prog list [<pattern>] [--format=[human, abspath]]
%prog remove <pattern>
%prog purge
"""

def add_options(self):
# type: () -> None

self.cmd_opts.add_option(
'--format',
action='store',
dest='list_format',
default="human",
choices=('human', 'abspath'),
help="Select the output format among: human (default) or abspath"
)

self.parser.insert_option_group(0, self.cmd_opts)

def run(self, options, args):
# type: (Values, List[Any]) -> int
handlers = {
Expand Down Expand Up @@ -116,7 +130,13 @@ def list_cache_items(self, options, args):
pattern = '*'

files = self._find_wheels(options, pattern)
if options.list_format == 'human':
self.format_for_human(files)
else:
self.format_for_abspath(files)

def format_for_human(self, files):
# type: (List[str]) -> None
if not files:
logger.info('Nothing cached.')
return
Expand All @@ -129,6 +149,17 @@ def list_cache_items(self, options, args):
logger.info('Cache contents:\n')
logger.info('\n'.join(sorted(results)))

def format_for_abspath(self, files):
# type: (List[str]) -> None
if not files:
return

results = []
for filename in files:
results.append(filename)

logger.info('\n'.join(sorted(results)))

def remove_cache_items(self, options, args):
# type: (Values, List[Any]) -> None
if len(args) > 1:
Expand Down
59 changes: 59 additions & 0 deletions tests/functional/test_cache.py
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,19 @@ def list_matches_wheel(wheel_name, result):
return any(map(lambda l: l.startswith(expected), lines))


def list_matches_wheel_abspath(wheel_name, result):
"""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`.

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 = '{}-py3-none-any.whl'.format(wheel_name)
return any(map(lambda l: os.path.basename(l).startswith(expected)
and os.path.exists(l), lines))


@pytest.fixture
def remove_matches_wheel(wheel_cache_dir):
"""Returns True if any line in `result`, which should be the output of
Expand Down Expand Up @@ -132,6 +145,18 @@ def test_cache_list(script):
assert list_matches_wheel('zzz-7.8.9', result)


@pytest.mark.usefixtures("populate_wheel_cache")
def test_cache_list_abspath(script):
"""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')

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):
"""Running `pip cache list` with an empty cache should print
Expand All @@ -140,6 +165,14 @@ def test_cache_list_with_empty_cache(script):
assert result.stdout == "Nothing cached.\n"


@pytest.mark.usefixtures("empty_wheel_cache")
def test_cache_list_with_empty_cache_abspath(script):
"""Running `pip cache list --format=abspath` with an empty cache should not
print anything and exit."""
result = script.pip('cache', 'list', '--format=abspath')
assert result.stdout.strip() == ""


def test_cache_list_too_many_args(script):
"""Passing `pip cache list` too many arguments should cause an error."""
script.pip('cache', 'list', 'aaa', 'bbb',
Expand All @@ -158,6 +191,19 @@ def test_cache_list_name_match(script):
assert list_matches_wheel('zzz-7.8.9', result)


@pytest.mark.usefixtures("populate_wheel_cache")
def test_cache_list_name_match_abspath(script):
"""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')

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):
"""Running `pip cache list zzz-4.5.6` should list zzz-4.5.6, but
Expand All @@ -170,6 +216,19 @@ def test_cache_list_name_and_version_match(script):
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):
"""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')

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):
"""Running `pip cache remove` with no arguments should cause an error."""
Expand Down