We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
Unable to clean http cache with pip
<!--
If you're reporting an issue for `--use-feature=2020-resolver`, use the "Dependency resolver failures / errors" template instead.
-->

**Environment**

* pip version: pip 20.2.3
* Python version: Python 2.7 (32bit)
* OS: Windows 10 (64bit)

<!-- Feel free to add more information about your environment here -->

**Description**
<!-- A clear and concise description of what the bug is. -->
We noticed pip will cache the http response for future installation. However if the cached http response includes corruped data (network issue for example), installing the same package will result in pip cache error as follow: 

```
(venv2) H:\>pip install pyside
DEPRECATION: Python 2.7 reached the end of its life on January 1st, 2020. Please upgrade your Python as Python 2.7 is no longer maintained. pip 21.0 will drop support for Python 2.7 in January 2021. More details about Python 2 support in pip can be found at https://pip.pypa.io/en/latest/development/release-process/#python-2-support pip 21.0 will remove support for this functionality.
Collecting pyside
  Using cached PySide-1.2.4-cp27-none-win32.whl (41.0 MB)
ERROR: THESE PACKAGES DO NOT MATCH THE HASHES FROM THE REQUIREMENTS FILE. If you have updated the package versions, please update the hashes. Otherwise, examine the package contents carefully; someone may have tampered with them.
    pyside from https://files.pythonhosted.org/packages/39/78/2b5fcd3b4ff4fc891f1c3a8bee09616d59fa6d644b0dc6252d46d8fbb423/PySide-1.2.4-cp27-none-win32.whl#sha256=104c0f3aee597e92c43b60f31205cbbd57a4307fea0fae4bbaeeb58b61878908:
        Expected sha256 104c0f3aee597e92c43b60f31205cbbd57a4307fea0fae4bbaeeb58b61878908
             Got        9c9bdae0c8b07e8e834b3bd9f35ab93f3ddbae8365047b1596553eb70e996427
```


The symption of this issue has already been reported in https://github.com/pypa/warehouse/issues/8330. 

**Expected behavior**
<!-- A clear and concise description of what you expected to happen. -->
If the error is caused by the data corruption in http response cache then pip should invalidate the cache and try to re-download for best attempt. 

Currently `pip cache purge` will not clear http response cache. The only solution to this case is to remove http directory from the file system forcing pip to rebuild http cache. 

**How to Reproduce**
<!-- Describe the steps to reproduce this bug. -->

1. Create a Python 2 virtual environment
2. Download the example corruped file https://mega.nz/file/WsthyLTS#AWD7NmS-w9B62Q3Y8Lb4SvCalqCb1d83a5FniKPmFqY
3. Overwrite http folder in C:\Users\<account name>\AppData\Local\pip\cache\http
4. Uninstall pyside and install pyside by `pip install pyside`


**Output**

```
(venv2) H:\>pip install pyside
DEPRECATION: Python 2.7 reached the end of its life on January 1st, 2020. Please upgrade your Python as Python 2.7 is no longer maintained. pip 21.0 will drop support for Python 2.7 in January 2021. More details about Python 2 support in pip can be found at https://pip.pypa.io/en/latest/development/release-process/#python-2-support pip 21.0 will remove support for this functionality.
Collecting pyside
  Using cached PySide-1.2.4-cp27-none-win32.whl (41.0 MB)
ERROR: THESE PACKAGES DO NOT MATCH THE HASHES FROM THE REQUIREMENTS FILE. If you have updated the package versions, please update the hashes. Otherwise, examine the package contents carefully; someone may have tampered with them.
    pyside from https://files.pythonhosted.org/packages/39/78/2b5fcd3b4ff4fc891f1c3a8bee09616d59fa6d644b0dc6252d46d8fbb423/PySide-1.2.4-cp27-none-win32.whl#sha256=104c0f3aee597e92c43b60f31205cbbd57a4307fea0fae4bbaeeb58b61878908:
        Expected sha256 104c0f3aee597e92c43b60f31205cbbd57a4307fea0fae4bbaeeb58b61878908
             Got        9c9bdae0c8b07e8e834b3bd9f35ab93f3ddbae8365047b1596553eb70e996427
```


--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `src/pip/_internal/commands/cache.py`
Content:
```
1 from __future__ import absolute_import
2 
3 import logging
4 import os
5 import textwrap
6 
7 import pip._internal.utils.filesystem as filesystem
8 from pip._internal.cli.base_command import Command
9 from pip._internal.cli.status_codes import ERROR, SUCCESS
10 from pip._internal.exceptions import CommandError, PipError
11 from pip._internal.utils.typing import MYPY_CHECK_RUNNING
12 
13 if MYPY_CHECK_RUNNING:
14     from optparse import Values
15     from typing import Any, List
16 
17 
18 logger = logging.getLogger(__name__)
19 
20 
21 class CacheCommand(Command):
22     """
23     Inspect and manage pip's wheel cache.
24 
25     Subcommands:
26 
27     - dir: Show the cache directory.
28     - info: Show information about the cache.
29     - list: List filenames of packages stored in the cache.
30     - remove: Remove one or more package from the cache.
31     - purge: Remove all items from the cache.
32 
33     ``<pattern>`` can be a glob expression or a package name.
34     """
35 
36     ignore_require_venv = True
37     usage = """
38         %prog dir
39         %prog info
40         %prog list [<pattern>] [--format=[human, abspath]]
41         %prog remove <pattern>
42         %prog purge
43     """
44 
45     def add_options(self):
46         # type: () -> None
47 
48         self.cmd_opts.add_option(
49             '--format',
50             action='store',
51             dest='list_format',
52             default="human",
53             choices=('human', 'abspath'),
54             help="Select the output format among: human (default) or abspath"
55         )
56 
57         self.parser.insert_option_group(0, self.cmd_opts)
58 
59     def run(self, options, args):
60         # type: (Values, List[Any]) -> int
61         handlers = {
62             "dir": self.get_cache_dir,
63             "info": self.get_cache_info,
64             "list": self.list_cache_items,
65             "remove": self.remove_cache_items,
66             "purge": self.purge_cache,
67         }
68 
69         if not options.cache_dir:
70             logger.error("pip cache commands can not "
71                          "function since cache is disabled.")
72             return ERROR
73 
74         # Determine action
75         if not args or args[0] not in handlers:
76             logger.error(
77                 "Need an action (%s) to perform.",
78                 ", ".join(sorted(handlers)),
79             )
80             return ERROR
81 
82         action = args[0]
83 
84         # Error handling happens here, not in the action-handlers.
85         try:
86             handlers[action](options, args[1:])
87         except PipError as e:
88             logger.error(e.args[0])
89             return ERROR
90 
91         return SUCCESS
92 
93     def get_cache_dir(self, options, args):
94         # type: (Values, List[Any]) -> None
95         if args:
96             raise CommandError('Too many arguments')
97 
98         logger.info(options.cache_dir)
99 
100     def get_cache_info(self, options, args):
101         # type: (Values, List[Any]) -> None
102         if args:
103             raise CommandError('Too many arguments')
104 
105         num_packages = len(self._find_wheels(options, '*'))
106 
107         cache_location = self._wheels_cache_dir(options)
108         cache_size = filesystem.format_directory_size(cache_location)
109 
110         message = textwrap.dedent("""
111             Location: {location}
112             Size: {size}
113             Number of wheels: {package_count}
114         """).format(
115             location=cache_location,
116             package_count=num_packages,
117             size=cache_size,
118         ).strip()
119 
120         logger.info(message)
121 
122     def list_cache_items(self, options, args):
123         # type: (Values, List[Any]) -> None
124         if len(args) > 1:
125             raise CommandError('Too many arguments')
126 
127         if args:
128             pattern = args[0]
129         else:
130             pattern = '*'
131 
132         files = self._find_wheels(options, pattern)
133         if options.list_format == 'human':
134             self.format_for_human(files)
135         else:
136             self.format_for_abspath(files)
137 
138     def format_for_human(self, files):
139         # type: (List[str]) -> None
140         if not files:
141             logger.info('Nothing cached.')
142             return
143 
144         results = []
145         for filename in files:
146             wheel = os.path.basename(filename)
147             size = filesystem.format_file_size(filename)
148             results.append(' - {} ({})'.format(wheel, size))
149         logger.info('Cache contents:\n')
150         logger.info('\n'.join(sorted(results)))
151 
152     def format_for_abspath(self, files):
153         # type: (List[str]) -> None
154         if not files:
155             return
156 
157         results = []
158         for filename in files:
159             results.append(filename)
160 
161         logger.info('\n'.join(sorted(results)))
162 
163     def remove_cache_items(self, options, args):
164         # type: (Values, List[Any]) -> None
165         if len(args) > 1:
166             raise CommandError('Too many arguments')
167 
168         if not args:
169             raise CommandError('Please provide a pattern')
170 
171         files = self._find_wheels(options, args[0])
172         if not files:
173             raise CommandError('No matching packages')
174 
175         for filename in files:
176             os.unlink(filename)
177             logger.debug('Removed %s', filename)
178         logger.info('Files removed: %s', len(files))
179 
180     def purge_cache(self, options, args):
181         # type: (Values, List[Any]) -> None
182         if args:
183             raise CommandError('Too many arguments')
184 
185         return self.remove_cache_items(options, ['*'])
186 
187     def _wheels_cache_dir(self, options):
188         # type: (Values) -> str
189         return os.path.join(options.cache_dir, 'wheels')
190 
191     def _find_wheels(self, options, pattern):
192         # type: (Values, str) -> List[str]
193         wheel_dir = self._wheels_cache_dir(options)
194 
195         # The wheel filename format, as specified in PEP 427, is:
196         #     {distribution}-{version}(-{build})?-{python}-{abi}-{platform}.whl
197         #
198         # Additionally, non-alphanumeric values in the distribution are
199         # normalized to underscores (_), meaning hyphens can never occur
200         # before `-{version}`.
201         #
202         # Given that information:
203         # - If the pattern we're given contains a hyphen (-), the user is
204         #   providing at least the version. Thus, we can just append `*.whl`
205         #   to match the rest of it.
206         # - If the pattern we're given doesn't contain a hyphen (-), the
207         #   user is only providing the name. Thus, we append `-*.whl` to
208         #   match the hyphen before the version, followed by anything else.
209         #
210         # PEP 427: https://www.python.org/dev/peps/pep-0427/
211         pattern = pattern + ("*.whl" if "-" in pattern else "-*.whl")
212 
213         return filesystem.find_files(wheel_dir, pattern)
214
```
--- END FILES ---

Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.

Here is an example:

```diff
diff --git a/examples/server_async.py b/examples/server_async.py
--- a/examples/server_async.py
+++ b/examples/server_async.py
@@ -313,4 +313,4 @@
 
 
 if __name__ == "__main__":
-    asyncio.run(run_async_server("."), debug=True)
+    asyncio.run(run_async_server(), debug=True)
diff --git a/examples/server_sync.py b/examples/server_sync.py
--- a/examples/server_sync.py
+++ b/examples/server_sync.py
@@ -313,5 +313,5 @@
 
 
 if __name__ == "__main__":
-    server = run_sync_server(".")
+    server = run_sync_server()
     server.shutdown()

```

diff --git a/src/pip/_internal/commands/cache.py b/src/pip/_internal/commands/cache.py
--- a/src/pip/_internal/commands/cache.py
+++ b/src/pip/_internal/commands/cache.py
@@ -102,19 +102,30 @@
         if args:
             raise CommandError('Too many arguments')
 
+        num_http_files = len(self._find_http_files(options))
         num_packages = len(self._find_wheels(options, '*'))
 
-        cache_location = self._wheels_cache_dir(options)
-        cache_size = filesystem.format_directory_size(cache_location)
+        http_cache_location = self._cache_dir(options, 'http')
+        wheels_cache_location = self._cache_dir(options, 'wheels')
+        http_cache_size = filesystem.format_directory_size(http_cache_location)
+        wheels_cache_size = filesystem.format_directory_size(
+            wheels_cache_location
+        )
 
         message = textwrap.dedent("""
-            Location: {location}
-            Size: {size}
+            Package index page cache location: {http_cache_location}
+            Package index page cache size: {http_cache_size}
+            Number of HTTP files: {num_http_files}
+            Wheels location: {wheels_cache_location}
+            Wheels size: {wheels_cache_size}
             Number of wheels: {package_count}
         """).format(
-            location=cache_location,
+            http_cache_location=http_cache_location,
+            http_cache_size=http_cache_size,
+            num_http_files=num_http_files,
+            wheels_cache_location=wheels_cache_location,
             package_count=num_packages,
-            size=cache_size,
+            wheels_cache_size=wheels_cache_size,
         ).strip()
 
         logger.info(message)
@@ -169,6 +180,11 @@
             raise CommandError('Please provide a pattern')
 
         files = self._find_wheels(options, args[0])
+
+        # Only fetch http files if no specific pattern given
+        if args[0] == '*':
+            files += self._find_http_files(options)
+
         if not files:
             raise CommandError('No matching packages')
 
@@ -184,13 +200,18 @@
 
         return self.remove_cache_items(options, ['*'])
 
-    def _wheels_cache_dir(self, options):
-        # type: (Values) -> str
-        return os.path.join(options.cache_dir, 'wheels')
+    def _cache_dir(self, options, subdir):
+        # type: (Values, str) -> str
+        return os.path.join(options.cache_dir, subdir)
+
+    def _find_http_files(self, options):
+        # type: (Values) -> List[str]
+        http_dir = self._cache_dir(options, 'http')
+        return filesystem.find_files(http_dir, '*')
 
     def _find_wheels(self, options, pattern):
         # type: (Values, str) -> List[str]
-        wheel_dir = self._wheels_cache_dir(options)
+        wheel_dir = self._cache_dir(options, 'wheels')
 
         # The wheel filename format, as specified in PEP 427, is:
         #     {distribution}-{version}(-{build})?-{python}-{abi}-{platform}.whl

{"golden_diff": "diff --git a/src/pip/_internal/commands/cache.py b/src/pip/_internal/commands/cache.py\n--- a/src/pip/_internal/commands/cache.py\n+++ b/src/pip/_internal/commands/cache.py\n@@ -102,19 +102,30 @@\n         if args:\n             raise CommandError('Too many arguments')\n \n+        num_http_files = len(self._find_http_files(options))\n         num_packages = len(self._find_wheels(options, '*'))\n \n-        cache_location = self._wheels_cache_dir(options)\n-        cache_size = filesystem.format_directory_size(cache_location)\n+        http_cache_location = self._cache_dir(options, 'http')\n+        wheels_cache_location = self._cache_dir(options, 'wheels')\n+        http_cache_size = filesystem.format_directory_size(http_cache_location)\n+        wheels_cache_size = filesystem.format_directory_size(\n+            wheels_cache_location\n+        )\n \n         message = textwrap.dedent(\"\"\"\n-            Location: {location}\n-            Size: {size}\n+            Package index page cache location: {http_cache_location}\n+            Package index page cache size: {http_cache_size}\n+            Number of HTTP files: {num_http_files}\n+            Wheels location: {wheels_cache_location}\n+            Wheels size: {wheels_cache_size}\n             Number of wheels: {package_count}\n         \"\"\").format(\n-            location=cache_location,\n+            http_cache_location=http_cache_location,\n+            http_cache_size=http_cache_size,\n+            num_http_files=num_http_files,\n+            wheels_cache_location=wheels_cache_location,\n             package_count=num_packages,\n-            size=cache_size,\n+            wheels_cache_size=wheels_cache_size,\n         ).strip()\n \n         logger.info(message)\n@@ -169,6 +180,11 @@\n             raise CommandError('Please provide a pattern')\n \n         files = self._find_wheels(options, args[0])\n+\n+        # Only fetch http files if no specific pattern given\n+        if args[0] == '*':\n+            files += self._find_http_files(options)\n+\n         if not files:\n             raise CommandError('No matching packages')\n \n@@ -184,13 +200,18 @@\n \n         return self.remove_cache_items(options, ['*'])\n \n-    def _wheels_cache_dir(self, options):\n-        # type: (Values) -> str\n-        return os.path.join(options.cache_dir, 'wheels')\n+    def _cache_dir(self, options, subdir):\n+        # type: (Values, str) -> str\n+        return os.path.join(options.cache_dir, subdir)\n+\n+    def _find_http_files(self, options):\n+        # type: (Values) -> List[str]\n+        http_dir = self._cache_dir(options, 'http')\n+        return filesystem.find_files(http_dir, '*')\n \n     def _find_wheels(self, options, pattern):\n         # type: (Values, str) -> List[str]\n-        wheel_dir = self._wheels_cache_dir(options)\n+        wheel_dir = self._cache_dir(options, 'wheels')\n \n         # The wheel filename format, as specified in PEP 427, is:\n         #     {distribution}-{version}(-{build})?-{python}-{abi}-{platform}.whl\n", "issue": "Unable to clean http cache with pip\n<!--\r\nIf you're reporting an issue for `--use-feature=2020-resolver`, use the \"Dependency resolver failures / errors\" template instead.\r\n-->\r\n\r\n**Environment**\r\n\r\n* pip version: pip 20.2.3\r\n* Python version: Python 2.7 (32bit)\r\n* OS: Windows 10 (64bit)\r\n\r\n<!-- Feel free to add more information about your environment here -->\r\n\r\n**Description**\r\n<!-- A clear and concise description of what the bug is. -->\r\nWe noticed pip will cache the http response for future installation. However if the cached http response includes corruped data (network issue for example), installing the same package will result in pip cache error as follow: \r\n\r\n```\r\n(venv2) H:\\>pip install pyside\r\nDEPRECATION: Python 2.7 reached the end of its life on January 1st, 2020. Please upgrade your Python as Python 2.7 is no longer maintained. pip 21.0 will drop support for Python 2.7 in January 2021. More details about Python 2 support in pip can be found at https://pip.pypa.io/en/latest/development/release-process/#python-2-support pip 21.0 will remove support for this functionality.\r\nCollecting pyside\r\n  Using cached PySide-1.2.4-cp27-none-win32.whl (41.0 MB)\r\nERROR: THESE PACKAGES DO NOT MATCH THE HASHES FROM THE REQUIREMENTS FILE. If you have updated the package versions, please update the hashes. Otherwise, examine the package contents carefully; someone may have tampered with them.\r\n    pyside from https://files.pythonhosted.org/packages/39/78/2b5fcd3b4ff4fc891f1c3a8bee09616d59fa6d644b0dc6252d46d8fbb423/PySide-1.2.4-cp27-none-win32.whl#sha256=104c0f3aee597e92c43b60f31205cbbd57a4307fea0fae4bbaeeb58b61878908:\r\n        Expected sha256 104c0f3aee597e92c43b60f31205cbbd57a4307fea0fae4bbaeeb58b61878908\r\n             Got        9c9bdae0c8b07e8e834b3bd9f35ab93f3ddbae8365047b1596553eb70e996427\r\n```\r\n\r\n\r\nThe symption of this issue has already been reported in https://github.com/pypa/warehouse/issues/8330. \r\n\r\n**Expected behavior**\r\n<!-- A clear and concise description of what you expected to happen. -->\r\nIf the error is caused by the data corruption in http response cache then pip should invalidate the cache and try to re-download for best attempt. \r\n\r\nCurrently `pip cache purge` will not clear http response cache. The only solution to this case is to remove http directory from the file system forcing pip to rebuild http cache. \r\n\r\n**How to Reproduce**\r\n<!-- Describe the steps to reproduce this bug. -->\r\n\r\n1. Create a Python 2 virtual environment\r\n2. Download the example corruped file https://mega.nz/file/WsthyLTS#AWD7NmS-w9B62Q3Y8Lb4SvCalqCb1d83a5FniKPmFqY\r\n3. Overwrite http folder in C:\\Users\\<account name>\\AppData\\Local\\pip\\cache\\http\r\n4. Uninstall pyside and install pyside by `pip install pyside`\r\n\r\n\r\n**Output**\r\n\r\n```\r\n(venv2) H:\\>pip install pyside\r\nDEPRECATION: Python 2.7 reached the end of its life on January 1st, 2020. Please upgrade your Python as Python 2.7 is no longer maintained. pip 21.0 will drop support for Python 2.7 in January 2021. More details about Python 2 support in pip can be found at https://pip.pypa.io/en/latest/development/release-process/#python-2-support pip 21.0 will remove support for this functionality.\r\nCollecting pyside\r\n  Using cached PySide-1.2.4-cp27-none-win32.whl (41.0 MB)\r\nERROR: THESE PACKAGES DO NOT MATCH THE HASHES FROM THE REQUIREMENTS FILE. If you have updated the package versions, please update the hashes. Otherwise, examine the package contents carefully; someone may have tampered with them.\r\n    pyside from https://files.pythonhosted.org/packages/39/78/2b5fcd3b4ff4fc891f1c3a8bee09616d59fa6d644b0dc6252d46d8fbb423/PySide-1.2.4-cp27-none-win32.whl#sha256=104c0f3aee597e92c43b60f31205cbbd57a4307fea0fae4bbaeeb58b61878908:\r\n        Expected sha256 104c0f3aee597e92c43b60f31205cbbd57a4307fea0fae4bbaeeb58b61878908\r\n             Got        9c9bdae0c8b07e8e834b3bd9f35ab93f3ddbae8365047b1596553eb70e996427\r\n```\r\n\n", "before_files": [{"content": "from __future__ import absolute_import\n\nimport logging\nimport os\nimport textwrap\n\nimport pip._internal.utils.filesystem as filesystem\nfrom pip._internal.cli.base_command import Command\nfrom pip._internal.cli.status_codes import ERROR, SUCCESS\nfrom pip._internal.exceptions import CommandError, PipError\nfrom pip._internal.utils.typing import MYPY_CHECK_RUNNING\n\nif MYPY_CHECK_RUNNING:\n    from optparse import Values\n    from typing import Any, List\n\n\nlogger = logging.getLogger(__name__)\n\n\nclass CacheCommand(Command):\n    \"\"\"\n    Inspect and manage pip's wheel cache.\n\n    Subcommands:\n\n    - dir: Show the cache directory.\n    - info: Show information about the cache.\n    - list: List filenames of packages stored in the cache.\n    - remove: Remove one or more package from the cache.\n    - purge: Remove all items from the cache.\n\n    ``<pattern>`` can be a glob expression or a package name.\n    \"\"\"\n\n    ignore_require_venv = True\n    usage = \"\"\"\n        %prog dir\n        %prog info\n        %prog list [<pattern>] [--format=[human, abspath]]\n        %prog remove <pattern>\n        %prog purge\n    \"\"\"\n\n    def add_options(self):\n        # type: () -> None\n\n        self.cmd_opts.add_option(\n            '--format',\n            action='store',\n            dest='list_format',\n            default=\"human\",\n            choices=('human', 'abspath'),\n            help=\"Select the output format among: human (default) or abspath\"\n        )\n\n        self.parser.insert_option_group(0, self.cmd_opts)\n\n    def run(self, options, args):\n        # type: (Values, List[Any]) -> int\n        handlers = {\n            \"dir\": self.get_cache_dir,\n            \"info\": self.get_cache_info,\n            \"list\": self.list_cache_items,\n            \"remove\": self.remove_cache_items,\n            \"purge\": self.purge_cache,\n        }\n\n        if not options.cache_dir:\n            logger.error(\"pip cache commands can not \"\n                         \"function since cache is disabled.\")\n            return ERROR\n\n        # Determine action\n        if not args or args[0] not in handlers:\n            logger.error(\n                \"Need an action (%s) to perform.\",\n                \", \".join(sorted(handlers)),\n            )\n            return ERROR\n\n        action = args[0]\n\n        # Error handling happens here, not in the action-handlers.\n        try:\n            handlers[action](options, args[1:])\n        except PipError as e:\n            logger.error(e.args[0])\n            return ERROR\n\n        return SUCCESS\n\n    def get_cache_dir(self, options, args):\n        # type: (Values, List[Any]) -> None\n        if args:\n            raise CommandError('Too many arguments')\n\n        logger.info(options.cache_dir)\n\n    def get_cache_info(self, options, args):\n        # type: (Values, List[Any]) -> None\n        if args:\n            raise CommandError('Too many arguments')\n\n        num_packages = len(self._find_wheels(options, '*'))\n\n        cache_location = self._wheels_cache_dir(options)\n        cache_size = filesystem.format_directory_size(cache_location)\n\n        message = textwrap.dedent(\"\"\"\n            Location: {location}\n            Size: {size}\n            Number of wheels: {package_count}\n        \"\"\").format(\n            location=cache_location,\n            package_count=num_packages,\n            size=cache_size,\n        ).strip()\n\n        logger.info(message)\n\n    def list_cache_items(self, options, args):\n        # type: (Values, List[Any]) -> None\n        if len(args) > 1:\n            raise CommandError('Too many arguments')\n\n        if args:\n            pattern = args[0]\n        else:\n            pattern = '*'\n\n        files = self._find_wheels(options, pattern)\n        if options.list_format == 'human':\n            self.format_for_human(files)\n        else:\n            self.format_for_abspath(files)\n\n    def format_for_human(self, files):\n        # type: (List[str]) -> None\n        if not files:\n            logger.info('Nothing cached.')\n            return\n\n        results = []\n        for filename in files:\n            wheel = os.path.basename(filename)\n            size = filesystem.format_file_size(filename)\n            results.append(' - {} ({})'.format(wheel, size))\n        logger.info('Cache contents:\\n')\n        logger.info('\\n'.join(sorted(results)))\n\n    def format_for_abspath(self, files):\n        # type: (List[str]) -> None\n        if not files:\n            return\n\n        results = []\n        for filename in files:\n            results.append(filename)\n\n        logger.info('\\n'.join(sorted(results)))\n\n    def remove_cache_items(self, options, args):\n        # type: (Values, List[Any]) -> None\n        if len(args) > 1:\n            raise CommandError('Too many arguments')\n\n        if not args:\n            raise CommandError('Please provide a pattern')\n\n        files = self._find_wheels(options, args[0])\n        if not files:\n            raise CommandError('No matching packages')\n\n        for filename in files:\n            os.unlink(filename)\n            logger.debug('Removed %s', filename)\n        logger.info('Files removed: %s', len(files))\n\n    def purge_cache(self, options, args):\n        # type: (Values, List[Any]) -> None\n        if args:\n            raise CommandError('Too many arguments')\n\n        return self.remove_cache_items(options, ['*'])\n\n    def _wheels_cache_dir(self, options):\n        # type: (Values) -> str\n        return os.path.join(options.cache_dir, 'wheels')\n\n    def _find_wheels(self, options, pattern):\n        # type: (Values, str) -> List[str]\n        wheel_dir = self._wheels_cache_dir(options)\n\n        # The wheel filename format, as specified in PEP 427, is:\n        #     {distribution}-{version}(-{build})?-{python}-{abi}-{platform}.whl\n        #\n        # Additionally, non-alphanumeric values in the distribution are\n        # normalized to underscores (_), meaning hyphens can never occur\n        # before `-{version}`.\n        #\n        # Given that information:\n        # - If the pattern we're given contains a hyphen (-), the user is\n        #   providing at least the version. Thus, we can just append `*.whl`\n        #   to match the rest of it.\n        # - If the pattern we're given doesn't contain a hyphen (-), the\n        #   user is only providing the name. Thus, we append `-*.whl` to\n        #   match the hyphen before the version, followed by anything else.\n        #\n        # PEP 427: https://www.python.org/dev/peps/pep-0427/\n        pattern = pattern + (\"*.whl\" if \"-\" in pattern else \"-*.whl\")\n\n        return filesystem.find_files(wheel_dir, pattern)\n", "path": "src/pip/_internal/commands/cache.py"}], "after_files": [{"content": "from __future__ import absolute_import\n\nimport logging\nimport os\nimport textwrap\n\nimport pip._internal.utils.filesystem as filesystem\nfrom pip._internal.cli.base_command import Command\nfrom pip._internal.cli.status_codes import ERROR, SUCCESS\nfrom pip._internal.exceptions import CommandError, PipError\nfrom pip._internal.utils.typing import MYPY_CHECK_RUNNING\n\nif MYPY_CHECK_RUNNING:\n    from optparse import Values\n    from typing import Any, List\n\n\nlogger = logging.getLogger(__name__)\n\n\nclass CacheCommand(Command):\n    \"\"\"\n    Inspect and manage pip's wheel cache.\n\n    Subcommands:\n\n    - dir: Show the cache directory.\n    - info: Show information about the cache.\n    - list: List filenames of packages stored in the cache.\n    - remove: Remove one or more package from the cache.\n    - purge: Remove all items from the cache.\n\n    ``<pattern>`` can be a glob expression or a package name.\n    \"\"\"\n\n    ignore_require_venv = True\n    usage = \"\"\"\n        %prog dir\n        %prog info\n        %prog list [<pattern>] [--format=[human, abspath]]\n        %prog remove <pattern>\n        %prog purge\n    \"\"\"\n\n    def add_options(self):\n        # type: () -> None\n\n        self.cmd_opts.add_option(\n            '--format',\n            action='store',\n            dest='list_format',\n            default=\"human\",\n            choices=('human', 'abspath'),\n            help=\"Select the output format among: human (default) or abspath\"\n        )\n\n        self.parser.insert_option_group(0, self.cmd_opts)\n\n    def run(self, options, args):\n        # type: (Values, List[Any]) -> int\n        handlers = {\n            \"dir\": self.get_cache_dir,\n            \"info\": self.get_cache_info,\n            \"list\": self.list_cache_items,\n            \"remove\": self.remove_cache_items,\n            \"purge\": self.purge_cache,\n        }\n\n        if not options.cache_dir:\n            logger.error(\"pip cache commands can not \"\n                         \"function since cache is disabled.\")\n            return ERROR\n\n        # Determine action\n        if not args or args[0] not in handlers:\n            logger.error(\n                \"Need an action (%s) to perform.\",\n                \", \".join(sorted(handlers)),\n            )\n            return ERROR\n\n        action = args[0]\n\n        # Error handling happens here, not in the action-handlers.\n        try:\n            handlers[action](options, args[1:])\n        except PipError as e:\n            logger.error(e.args[0])\n            return ERROR\n\n        return SUCCESS\n\n    def get_cache_dir(self, options, args):\n        # type: (Values, List[Any]) -> None\n        if args:\n            raise CommandError('Too many arguments')\n\n        logger.info(options.cache_dir)\n\n    def get_cache_info(self, options, args):\n        # type: (Values, List[Any]) -> None\n        if args:\n            raise CommandError('Too many arguments')\n\n        num_http_files = len(self._find_http_files(options))\n        num_packages = len(self._find_wheels(options, '*'))\n\n        http_cache_location = self._cache_dir(options, 'http')\n        wheels_cache_location = self._cache_dir(options, 'wheels')\n        http_cache_size = filesystem.format_directory_size(http_cache_location)\n        wheels_cache_size = filesystem.format_directory_size(\n            wheels_cache_location\n        )\n\n        message = textwrap.dedent(\"\"\"\n            Package index page cache location: {http_cache_location}\n            Package index page cache size: {http_cache_size}\n            Number of HTTP files: {num_http_files}\n            Wheels location: {wheels_cache_location}\n            Wheels size: {wheels_cache_size}\n            Number of wheels: {package_count}\n        \"\"\").format(\n            http_cache_location=http_cache_location,\n            http_cache_size=http_cache_size,\n            num_http_files=num_http_files,\n            wheels_cache_location=wheels_cache_location,\n            package_count=num_packages,\n            wheels_cache_size=wheels_cache_size,\n        ).strip()\n\n        logger.info(message)\n\n    def list_cache_items(self, options, args):\n        # type: (Values, List[Any]) -> None\n        if len(args) > 1:\n            raise CommandError('Too many arguments')\n\n        if args:\n            pattern = args[0]\n        else:\n            pattern = '*'\n\n        files = self._find_wheels(options, pattern)\n        if options.list_format == 'human':\n            self.format_for_human(files)\n        else:\n            self.format_for_abspath(files)\n\n    def format_for_human(self, files):\n        # type: (List[str]) -> None\n        if not files:\n            logger.info('Nothing cached.')\n            return\n\n        results = []\n        for filename in files:\n            wheel = os.path.basename(filename)\n            size = filesystem.format_file_size(filename)\n            results.append(' - {} ({})'.format(wheel, size))\n        logger.info('Cache contents:\\n')\n        logger.info('\\n'.join(sorted(results)))\n\n    def format_for_abspath(self, files):\n        # type: (List[str]) -> None\n        if not files:\n            return\n\n        results = []\n        for filename in files:\n            results.append(filename)\n\n        logger.info('\\n'.join(sorted(results)))\n\n    def remove_cache_items(self, options, args):\n        # type: (Values, List[Any]) -> None\n        if len(args) > 1:\n            raise CommandError('Too many arguments')\n\n        if not args:\n            raise CommandError('Please provide a pattern')\n\n        files = self._find_wheels(options, args[0])\n\n        # Only fetch http files if no specific pattern given\n        if args[0] == '*':\n            files += self._find_http_files(options)\n\n        if not files:\n            raise CommandError('No matching packages')\n\n        for filename in files:\n            os.unlink(filename)\n            logger.debug('Removed %s', filename)\n        logger.info('Files removed: %s', len(files))\n\n    def purge_cache(self, options, args):\n        # type: (Values, List[Any]) -> None\n        if args:\n            raise CommandError('Too many arguments')\n\n        return self.remove_cache_items(options, ['*'])\n\n    def _cache_dir(self, options, subdir):\n        # type: (Values, str) -> str\n        return os.path.join(options.cache_dir, subdir)\n\n    def _find_http_files(self, options):\n        # type: (Values) -> List[str]\n        http_dir = self._cache_dir(options, 'http')\n        return filesystem.find_files(http_dir, '*')\n\n    def _find_wheels(self, options, pattern):\n        # type: (Values, str) -> List[str]\n        wheel_dir = self._cache_dir(options, 'wheels')\n\n        # The wheel filename format, as specified in PEP 427, is:\n        #     {distribution}-{version}(-{build})?-{python}-{abi}-{platform}.whl\n        #\n        # Additionally, non-alphanumeric values in the distribution are\n        # normalized to underscores (_), meaning hyphens can never occur\n        # before `-{version}`.\n        #\n        # Given that information:\n        # - If the pattern we're given contains a hyphen (-), the user is\n        #   providing at least the version. Thus, we can just append `*.whl`\n        #   to match the rest of it.\n        # - If the pattern we're given doesn't contain a hyphen (-), the\n        #   user is only providing the name. Thus, we append `-*.whl` to\n        #   match the hyphen before the version, followed by anything else.\n        #\n        # PEP 427: https://www.python.org/dev/peps/pep-0427/\n        pattern = pattern + (\"*.whl\" if \"-\" in pattern else \"-*.whl\")\n\n        return filesystem.find_files(wheel_dir, pattern)\n", "path": "src/pip/_internal/commands/cache.py"}]}