Repository: pypa/pip

Issue:
New Resolver: inconsistent output when using cached wheels
#8066 added logic to make pip's new resolver perform lookups in the wheel cache. The way it's populating the requirement is, however, breaking the presentation logic in RequirementPreparer. This issue is present on 20.2 as well as master.

```
Processing /Users/pradyunsg/Library/Caches/pip/wheels/da/f1/6f/450a8e3042772f552f5316cfbd51552bb13995077e4502ba2f/rackspace_novaclient-2.1-py3-none-any.whl
Processing /Users/pradyunsg/Library/Caches/pip/wheels/45/42/fc/37502e2e6b8c5e745d2ec318c6d1ee9328ead3d704b5584797/ip_associations_python_novaclient_ext-0.2-py3-none-any.whl
Processing /Users/pradyunsg/Library/Caches/pip/wheels/b8/0c/c5/f4087714c89b18994a27c42c01bd9a8ce3bfcccf5d72ff978e/rackspace_auth_openstack-1.3-py3-none-any.whl
Processing /Users/pradyunsg/Library/Caches/pip/wheels/bc/eb/b2/2d27f5c5d3d8caecebbf87ccb272f60ee278d968c1c3a10c85/os_diskconfig_python_novaclient_ext-0.1.3-py3-none-any.whl
Processing /Users/pradyunsg/Library/Caches/pip/wheels/25/01/b7/d60cc1e3f2b4f9e5b359ce1b7fe03f65084020bfb0d4edcca2/os_networksv2_python_novaclient_ext-0.26-py3-none-any.whl
Processing /Users/pradyunsg/Library/Caches/pip/wheels/64/ce/0e/e407508c11ef0d63567a51a86302b44de81b78f602d7e8dc82/rax_scheduled_images_python_novaclient_ext-0.3.1-py3-none-any.whl
Processing /Users/pradyunsg/Library/Caches/pip/wheels/1d/b7/c2/8988a8a46e720cced366730c323604d1dba6644886f9a666aa/rax_default_network_flags_python_novaclient_ext-0.4.0-py3-none-any.whl
Processing /Users/pradyunsg/Library/Caches/pip/wheels/89/7c/51/371c863bd836d32c94f518678e612386ea757e4b195a080c78/os_virtual_interfacesv2_python_novaclient_ext-0.20-py3-none-any.whl
Collecting python-novaclient
  Using cached python_novaclient-17.2.1-py3-none-any.whl (319 kB)
Processing /Users/pradyunsg/Library/Caches/pip/wheels/48/6d/77/9517cb933af254f51a446f1a5ec9c2be3e45f17384940bce68/prettytable-0.7.2-py3-none-any.whl
Collecting iso8601>=0.1.11
  Using cached iso8601-0.1.12-py3-none-any.whl (12 kB)
Collecting stevedore>=2.0.1
  Using cached stevedore-3.2.1-py3-none-any.whl (42 kB)
Collecting oslo.i18n>=3.15.3
  Using cached oslo.i18n-5.0.0-py3-none-any.whl (46 kB)
Collecting six>=1.10.0
  Using cached six-1.15.0-py2.py3-none-any.whl (10 kB)
Collecting oslo.serialization!=2.19.1,>=2.18.0
  Using cached oslo.serialization-4.0.0-py3-none-any.whl (25 kB)
Collecting msgpack>=0.5.2
  Using cached msgpack-1.0.0-cp38-cp38-macosx_10_13_x86_64.whl (78 kB)
Collecting simplejson>=3.5.1
  Using cached simplejson-3.17.2-cp38-cp38-macosx_10_14_x86_64.whl (74 kB)
Collecting keystoneauth1>=3.5.0
  Using cached keystoneauth1-4.2.1-py3-none-any.whl (308 kB)
```

Notice the initial wheel files that are from the cache, printed in full. That should not happen.

_Originally posted by @pradyunsg in https://github.com/pypa/pip/pull/8066#issuecomment-690192278_



Discussion:

Resolving patch:
diff --git a/src/pip/_internal/operations/prepare.py b/src/pip/_internal/operations/prepare.py
--- a/src/pip/_internal/operations/prepare.py
+++ b/src/pip/_internal/operations/prepare.py
@@ -357,6 +357,9 @@ def __init__(
         # Memoized downloaded files, as mapping of url: (path, mime type)
         self._downloaded = {}  # type: Dict[str, Tuple[str, str]]
 
+        # Previous "header" printed for a link-based InstallRequirement
+        self._previous_requirement_header = ("", "")
+
     @property
     def _download_should_save(self):
         # type: () -> bool
@@ -373,12 +376,21 @@ def _download_should_save(self):
 
     def _log_preparing_link(self, req):
         # type: (InstallRequirement) -> None
-        """Log the way the link prepared."""
-        if req.link.is_file:
-            path = req.link.file_path
-            logger.info('Processing %s', display_path(path))
+        """Provide context for the requirement being prepared."""
+        if req.link.is_file and not req.original_link_is_in_wheel_cache:
+            message = "Processing %s"
+            information = str(display_path(req.link.file_path))
         else:
-            logger.info('Collecting %s', req.req or req)
+            message = "Collecting %s"
+            information = str(req.req or req)
+
+        if (message, information) != self._previous_requirement_header:
+            self._previous_requirement_header = (message, information)
+            logger.info(message, information)
+
+        if req.original_link_is_in_wheel_cache:
+            with indent_log():
+                logger.info("Using cached %s", req.link.filename)
 
     def _get_download_dir(self, link):
         # type: (Link) -> Optional[str]


Test patch: