diff --git a/.github/CONTRIBUTING.md b/.github/CONTRIBUTING.md
index fbccffdfd..4da3a9515 100644
--- a/.github/CONTRIBUTING.md
+++ b/.github/CONTRIBUTING.md
@@ -7,9 +7,6 @@ As a reminder, all contributors are expected to follow our [Code of Conduct][coc
 
 [coc]: https://www.pypa.io/en/latest/code-of-conduct/
 
-## Development Documentation
-
-Our [development documentation](https://pip.pypa.io/en/latest/development/) contains details on how to get started with contributing to pip, and details of our development processes.
 
 ## Bot Commands
 
diff --git a/docs/html/reference/pip_install.rst b/docs/html/reference/pip_install.rst
index f0a5e075c..cc38f0bd7 100644
--- a/docs/html/reference/pip_install.rst
+++ b/docs/html/reference/pip_install.rst
@@ -153,7 +153,6 @@ The following options are supported:
   *  :ref:`--no-binary <install_--no-binary>`
   *  :ref:`--only-binary <install_--only-binary>`
   *  :ref:`--require-hashes <--require-hashes>`
-  *  :ref:`--trusted-host <--trusted-host>`
 
 For example, to specify :ref:`--no-index <--no-index>` and two
 :ref:`--find-links <--find-links>` locations:
diff --git a/news/3799.feature b/news/3799.feature
deleted file mode 100644
index e15c2a1da..000000000
--- a/news/3799.feature
+++ /dev/null
@@ -1,1 +0,0 @@
-Fully support using ``--trusted-host`` inside requirements files.
diff --git a/news/6527.bugfix b/news/6527.bugfix
new file mode 100644
index 000000000..92d29d9ff
--- /dev/null
+++ b/news/6527.bugfix
@@ -0,0 +1,2 @@
+Add the line number and file location to the error message when reading an
+invalid requirements file in certain situations.
diff --git a/news/6579.trivial b/news/6579.trivial
deleted file mode 100644
index 497dfaefd..000000000
--- a/news/6579.trivial
+++ /dev/null
@@ -1,1 +0,0 @@
-Link with developer documentation added in .github/CONTRIBUTING.md
\ No newline at end of file
diff --git a/src/pip/_internal/cli/cmdoptions.py b/src/pip/_internal/cli/cmdoptions.py
index 4b766b918..dc00b9a1b 100644
--- a/src/pip/_internal/cli/cmdoptions.py
+++ b/src/pip/_internal/cli/cmdoptions.py
@@ -822,24 +822,6 @@ require_hashes = partial(
 )  # type: Callable[..., Option]
 
 
-list_path = partial(
-    Option,
-    '--path',
-    dest='path',
-    action='append',
-    help='Restrict to the specified installation path for listing '
-         'packages (can be used multiple times).'
-)  # type: Callable[..., Option]
-
-
-def check_list_path_option(options):
-    # type: (Values) -> None
-    if options.path and (options.user or options.local):
-        raise CommandError(
-            "Cannot combine '--path' with '--user' or '--local'"
-        )
-
-
 ##########
 # groups #
 ##########
diff --git a/src/pip/_internal/commands/freeze.py b/src/pip/_internal/commands/freeze.py
index 9fc5b0469..47bd443a4 100644
--- a/src/pip/_internal/commands/freeze.py
+++ b/src/pip/_internal/commands/freeze.py
@@ -3,8 +3,8 @@ from __future__ import absolute_import
 import sys
 
 from pip._internal.cache import WheelCache
-from pip._internal.cli import cmdoptions
 from pip._internal.cli.base_command import Command
+from pip._internal.exceptions import CommandError
 from pip._internal.models.format_control import FormatControl
 from pip._internal.operations.freeze import freeze
 from pip._internal.utils.compat import stdlib_pkgs
@@ -57,7 +57,12 @@ class FreezeCommand(Command):
             action='store_true',
             default=False,
             help='Only output packages installed in user-site.')
-        self.cmd_opts.add_option(cmdoptions.list_path())
+        self.cmd_opts.add_option(
+            '--path',
+            dest='path',
+            action='append',
+            help='Restrict to the specified installation path for listing '
+                 'packages (can be used multiple times).')
         self.cmd_opts.add_option(
             '--all',
             dest='freeze_all',
@@ -79,7 +84,10 @@ class FreezeCommand(Command):
         if not options.freeze_all:
             skip.update(DEV_PKGS)
 
-        cmdoptions.check_list_path_option(options)
+        if options.path and (options.user or options.local):
+            raise CommandError(
+                "Cannot combine '--path' with '--user' or '--local'"
+            )
 
         freeze_kwargs = dict(
             requirement=options.requirements,
diff --git a/src/pip/_internal/commands/list.py b/src/pip/_internal/commands/list.py
index add31c0bf..2fbc31687 100644
--- a/src/pip/_internal/commands/list.py
+++ b/src/pip/_internal/commands/list.py
@@ -62,7 +62,12 @@ class ListCommand(Command):
             action='store_true',
             default=False,
             help='Only output packages installed in user-site.')
-        cmd_opts.add_option(cmdoptions.list_path())
+        self.cmd_opts.add_option(
+            '--path',
+            dest='path',
+            action='append',
+            help='Restrict to the specified installation path for listing '
+                 'packages (can be used multiple times).')
         cmd_opts.add_option(
             '--pre',
             action='store_true',
@@ -126,7 +131,10 @@ class ListCommand(Command):
             raise CommandError(
                 "Options --outdated and --uptodate cannot be combined.")
 
-        cmdoptions.check_list_path_option(options)
+        if options.path and (options.user or options.local):
+            raise CommandError(
+                "Cannot combine '--path' with '--user' or '--local'"
+            )
 
         packages = get_installed_distributions(
             local_only=options.local,
diff --git a/src/pip/_internal/distributions/__init__.py b/src/pip/_internal/distributions/__init__.py
deleted file mode 100644
index 92ea47336..000000000
--- a/src/pip/_internal/distributions/__init__.py
+++ /dev/null
@@ -1,23 +0,0 @@
-from pip._internal.distributions.source import SourceDistribution
-from pip._internal.distributions.wheel import WheelDistribution
-
-from pip._internal.utils.typing import MYPY_CHECK_RUNNING
-
-if MYPY_CHECK_RUNNING:
-    from pip._internal.distributions.base import AbstractDistribution
-    from pip._internal.req.req_install import InstallRequirement
-
-
-def make_abstract_dist(install_req):
-    # type: (InstallRequirement) -> AbstractDistribution
-    """Returns a Distribution for the given InstallRequirement
-    """
-    # If it's not an editable, is a wheel, it's a WheelDistribution
-    if install_req.editable:
-        return SourceDistribution(install_req)
-
-    if install_req.link and install_req.is_wheel:
-        return WheelDistribution(install_req)
-
-    # Otherwise, a SourceDistribution
-    return SourceDistribution(install_req)
diff --git a/src/pip/_internal/distributions/base.py b/src/pip/_internal/distributions/base.py
deleted file mode 100644
index 710b98911..000000000
--- a/src/pip/_internal/distributions/base.py
+++ /dev/null
@@ -1,35 +0,0 @@
-import abc
-
-from pip._vendor.six import add_metaclass
-
-
-@add_metaclass(abc.ABCMeta)
-class AbstractDistribution(object):
-    """A base class for handling installable artifacts.
-
-    The requirements for anything installable are as follows:
-
-     - we must be able to determine the requirement name
-       (or we can't correctly handle the non-upgrade case).
-
-     - for packages with setup requirements, we must also be able
-       to determine their requirements without installing additional
-       packages (for the same reason as run-time dependencies)
-
-     - we must be able to create a Distribution object exposing the
-       above metadata.
-    """
-
-    def __init__(self, req):
-        super(AbstractDistribution, self).__init__()
-        self.req = req
-
-    # TODO:  Give this a better name.
-    @abc.abstractmethod
-    def dist(self):
-        raise NotImplementedError()
-
-    # TODO:  Give this a better name.
-    @abc.abstractmethod
-    def prep_for_dist(self, finder, build_isolation):
-        raise NotImplementedError()
diff --git a/src/pip/_internal/distributions/installed.py b/src/pip/_internal/distributions/installed.py
deleted file mode 100644
index c4dfaa565..000000000
--- a/src/pip/_internal/distributions/installed.py
+++ /dev/null
@@ -1,15 +0,0 @@
-from pip._internal.distributions.base import AbstractDistribution
-
-
-class InstalledDistribution(AbstractDistribution):
-    """Represents an installed package.
-
-    This does not need any preparation as the required information has already
-    been computed.
-    """
-
-    def dist(self):
-        return self.req.satisfied_by
-
-    def prep_for_dist(self, finder, build_isolation):
-        pass
diff --git a/src/pip/_internal/distributions/source.py b/src/pip/_internal/distributions/source.py
deleted file mode 100644
index 4bec64a29..000000000
--- a/src/pip/_internal/distributions/source.py
+++ /dev/null
@@ -1,80 +0,0 @@
-import logging
-
-from pip._internal.build_env import BuildEnvironment
-from pip._internal.distributions.base import AbstractDistribution
-from pip._internal.exceptions import InstallationError
-
-logger = logging.getLogger(__name__)
-
-
-class SourceDistribution(AbstractDistribution):
-    """Represents a source distribution.
-
-    The preparation step for these needs metadata for the packages to be
-    generated, either using PEP 517 or using the legacy `setup.py egg_info`.
-
-    NOTE from @pradyunsg (14 June 2019)
-    I expect SourceDistribution class will need to be split into
-    `legacy_source` (setup.py based) and `source` (PEP 517 based) when we start
-    bringing logic for preparation out of InstallRequirement into this class.
-    """
-
-    def dist(self):
-        return self.req.get_dist()
-
-    def prep_for_dist(self, finder, build_isolation):
-        # Prepare for building. We need to:
-        #   1. Load pyproject.toml (if it exists)
-        #   2. Set up the build environment
-
-        self.req.load_pyproject_toml()
-        should_isolate = self.req.use_pep517 and build_isolation
-
-        def _raise_conflicts(conflicting_with, conflicting_reqs):
-            raise InstallationError(
-                "Some build dependencies for %s conflict with %s: %s." % (
-                    self.req, conflicting_with, ', '.join(
-                        '%s is incompatible with %s' % (installed, wanted)
-                        for installed, wanted in sorted(conflicting))))
-
-        if should_isolate:
-            # Isolate in a BuildEnvironment and install the build-time
-            # requirements.
-            self.req.build_env = BuildEnvironment()
-            self.req.build_env.install_requirements(
-                finder, self.req.pyproject_requires, 'overlay',
-                "Installing build dependencies"
-            )
-            conflicting, missing = self.req.build_env.check_requirements(
-                self.req.requirements_to_check
-            )
-            if conflicting:
-                _raise_conflicts("PEP 517/518 supported requirements",
-                                 conflicting)
-            if missing:
-                logger.warning(
-                    "Missing build requirements in pyproject.toml for %s.",
-                    self.req,
-                )
-                logger.warning(
-                    "The project does not specify a build backend, and "
-                    "pip cannot fall back to setuptools without %s.",
-                    " and ".join(map(repr, sorted(missing)))
-                )
-            # Install any extra build dependencies that the backend requests.
-            # This must be done in a second pass, as the pyproject.toml
-            # dependencies must be installed before we can call the backend.
-            with self.req.build_env:
-                # We need to have the env active when calling the hook.
-                self.req.spin_message = "Getting requirements to build wheel"
-                reqs = self.req.pep517_backend.get_requires_for_build_wheel()
-            conflicting, missing = self.req.build_env.check_requirements(reqs)
-            if conflicting:
-                _raise_conflicts("the backend dependencies", conflicting)
-            self.req.build_env.install_requirements(
-                finder, missing, 'normal',
-                "Installing backend dependencies"
-            )
-
-        self.req.prepare_metadata()
-        self.req.assert_source_matches_version()
diff --git a/src/pip/_internal/distributions/wheel.py b/src/pip/_internal/distributions/wheel.py
deleted file mode 100644
index 90883bc4d..000000000
--- a/src/pip/_internal/distributions/wheel.py
+++ /dev/null
@@ -1,17 +0,0 @@
-from pip._vendor import pkg_resources
-
-from pip._internal.distributions.base import AbstractDistribution
-
-
-class WheelDistribution(AbstractDistribution):
-    """Represents a wheel distribution.
-
-    This does not need any preparation as wheels can be directly unpacked.
-    """
-
-    def dist(self):
-        return list(pkg_resources.find_distributions(
-                    self.req.source_dir))[0]
-
-    def prep_for_dist(self, finder, build_isolation):
-        pass
diff --git a/src/pip/_internal/download.py b/src/pip/_internal/download.py
index 0aa692b15..6a54f8940 100644
--- a/src/pip/_internal/download.py
+++ b/src/pip/_internal/download.py
@@ -588,8 +588,6 @@ class PipSession(requests.Session):
         # well as any https:// host that we've marked as ignoring TLS errors
         # for.
         insecure_adapter = InsecureHTTPAdapter(max_retries=retries)
-        # Save this for later use in add_insecure_host().
-        self._insecure_adapter = insecure_adapter
 
         self.mount("https://", secure_adapter)
         self.mount("http://", insecure_adapter)
@@ -600,11 +598,7 @@ class PipSession(requests.Session):
         # We want to use a non-validating adapter for any requests which are
         # deemed insecure.
         for host in insecure_hosts:
-            self.add_insecure_host(host)
-
-    def add_insecure_host(self, host):
-        # type: (str) -> None
-        self.mount('https://{}/'.format(host), self._insecure_adapter)
+            self.mount("https://{}/".format(host), insecure_adapter)
 
     def request(self, method, url, *args, **kwargs):
         # Allow setting a default timeout on a session
diff --git a/src/pip/_internal/index.py b/src/pip/_internal/index.py
index 1c8f1ecb1..c2a2415a2 100644
--- a/src/pip/_internal/index.py
+++ b/src/pip/_internal/index.py
@@ -608,8 +608,8 @@ class PackageFinder(object):
         # type: (...) -> PackageFinder
         """Create a PackageFinder.
 
-        :param trusted_hosts: Domains not to emit warnings for when not using
-            HTTPS.
+        :param trusted_hosts: Domains that we won't emit warnings for when
+            not using HTTPS.
         :param session: The Session to use to make requests.
         :param format_control: A FormatControl object or None. Used to control
             the selection of source packages / binary packages when consulting
@@ -676,23 +676,12 @@ class PackageFinder(object):
         # type: () -> None
         self.candidate_evaluator.allow_all_prereleases = True
 
-    def add_trusted_host(self, host, source=None):
-        # type: (str, Optional[str]) -> None
-        """
-        :param source: An optional source string, for logging where the host
-            string came from.
-        """
-        # It is okay to add a previously added host because PipSession stores
-        # the resulting prefixes in a dict.
-        msg = 'adding trusted host: {!r}'.format(host)
-        if source is not None:
-            msg += ' (from {})'.format(source)
-        logger.info(msg)
-        self.session.add_insecure_host(host)
-        if host in self.trusted_hosts:
-            return
-
-        self.trusted_hosts.append(host)
+    def extend_trusted_hosts(self, hosts):
+        # type: (List[str]) -> None
+        for host in hosts:
+            if host in self.trusted_hosts:
+                continue
+            self.trusted_hosts.append(host)
 
     def iter_secure_origins(self):
         # type: () -> Iterator[SecureOrigin]
diff --git a/src/pip/_internal/legacy_resolve.py b/src/pip/_internal/legacy_resolve.py
index 08347b53e..1cc8531d1 100644
--- a/src/pip/_internal/legacy_resolve.py
+++ b/src/pip/_internal/legacy_resolve.py
@@ -34,14 +34,14 @@ from pip._internal.utils.typing import MYPY_CHECK_RUNNING
 if MYPY_CHECK_RUNNING:
     from typing import DefaultDict, List, Optional, Set, Tuple
     from pip._vendor import pkg_resources
-
-    from pip._internal.cache import WheelCache
-    from pip._internal.distributions import AbstractDistribution
     from pip._internal.download import PipSession
-    from pip._internal.index import PackageFinder
-    from pip._internal.operations.prepare import RequirementPreparer
     from pip._internal.req.req_install import InstallRequirement
+    from pip._internal.index import PackageFinder
     from pip._internal.req.req_set import RequirementSet
+    from pip._internal.operations.prepare import (
+        DistAbstraction, RequirementPreparer
+    )
+    from pip._internal.cache import WheelCache
 
 logger = logging.getLogger(__name__)
 
@@ -277,7 +277,7 @@ class Resolver(object):
         return None
 
     def _get_abstract_dist_for(self, req):
-        # type: (InstallRequirement) -> AbstractDistribution
+        # type: (InstallRequirement) -> DistAbstraction
         """Takes a InstallRequirement and returns a single AbstractDist \
         representing a prepared variant of the same.
         """
diff --git a/src/pip/_internal/operations/check.py b/src/pip/_internal/operations/check.py
index f8653c894..920df5d48 100644
--- a/src/pip/_internal/operations/check.py
+++ b/src/pip/_internal/operations/check.py
@@ -7,7 +7,7 @@ from collections import namedtuple
 from pip._vendor.packaging.utils import canonicalize_name
 from pip._vendor.pkg_resources import RequirementParseError
 
-from pip._internal.distributions import make_abstract_dist
+from pip._internal.operations.prepare import make_abstract_dist
 from pip._internal.utils.misc import get_installed_distributions
 from pip._internal.utils.typing import MYPY_CHECK_RUNNING
 
diff --git a/src/pip/_internal/operations/prepare.py b/src/pip/_internal/operations/prepare.py
index 3a4a70699..077a985ae 100644
--- a/src/pip/_internal/operations/prepare.py
+++ b/src/pip/_internal/operations/prepare.py
@@ -4,10 +4,9 @@
 import logging
 import os
 
-from pip._vendor import requests
+from pip._vendor import pkg_resources, requests
 
-from pip._internal.distributions import make_abstract_dist
-from pip._internal.distributions.installed import InstalledDistribution
+from pip._internal.build_env import BuildEnvironment
 from pip._internal.download import (
     is_dir_url, is_file_url, is_vcs_url, unpack_url, url_to_path,
 )
@@ -22,17 +21,168 @@ from pip._internal.utils.misc import display_path, normalize_path
 from pip._internal.utils.typing import MYPY_CHECK_RUNNING
 
 if MYPY_CHECK_RUNNING:
-    from typing import Optional
-
-    from pip._internal.distributions import AbstractDistribution
-    from pip._internal.download import PipSession
-    from pip._internal.index import PackageFinder
+    from typing import Any, Optional
     from pip._internal.req.req_install import InstallRequirement
+    from pip._internal.index import PackageFinder
+    from pip._internal.download import PipSession
     from pip._internal.req.req_tracker import RequirementTracker
 
 logger = logging.getLogger(__name__)
 
 
+def make_abstract_dist(req):
+    # type: (InstallRequirement) -> DistAbstraction
+    """Factory to make an abstract dist object.
+
+    Preconditions: Either an editable req with a source_dir, or satisfied_by or
+    a wheel link, or a non-editable req with a source_dir.
+
+    :return: A concrete DistAbstraction.
+    """
+    if req.editable:
+        return IsSDist(req)
+    elif req.link and req.link.is_wheel:
+        return IsWheel(req)
+    else:
+        return IsSDist(req)
+
+
+class DistAbstraction(object):
+    """Abstracts out the wheel vs non-wheel Resolver.resolve() logic.
+
+    The requirements for anything installable are as follows:
+     - we must be able to determine the requirement name
+       (or we can't correctly handle the non-upgrade case).
+     - we must be able to generate a list of run-time dependencies
+       without installing any additional packages (or we would
+       have to either burn time by doing temporary isolated installs
+       or alternatively violate pips 'don't start installing unless
+       all requirements are available' rule - neither of which are
+       desirable).
+     - for packages with setup requirements, we must also be able
+       to determine their requirements without installing additional
+       packages (for the same reason as run-time dependencies)
+     - we must be able to create a Distribution object exposing the
+       above metadata.
+    """
+
+    def __init__(self, req):
+        # type: (InstallRequirement) -> None
+        self.req = req  # type: InstallRequirement
+
+    def dist(self):
+        # type: () -> Any
+        """Return a setuptools Dist object."""
+        raise NotImplementedError
+
+    def prep_for_dist(self, finder, build_isolation):
+        # type: (PackageFinder, bool) -> Any
+        """Ensure that we can get a Dist for this requirement."""
+        raise NotImplementedError
+
+
+class IsWheel(DistAbstraction):
+
+    def dist(self):
+        # type: () -> pkg_resources.Distribution
+        return list(pkg_resources.find_distributions(
+            self.req.source_dir))[0]
+
+    def prep_for_dist(self, finder, build_isolation):
+        # type: (PackageFinder, bool) -> Any
+        # FIXME:https://github.com/pypa/pip/issues/1112
+        pass
+
+
+class IsSDist(DistAbstraction):
+
+    def dist(self):
+        return self.req.get_dist()
+
+    def _raise_conflicts(self, conflicting_with, conflicting_reqs):
+        conflict_messages = [
+            '%s is incompatible with %s' % (installed, wanted)
+            for installed, wanted in sorted(conflicting_reqs)
+        ]
+        raise InstallationError(
+            "Some build dependencies for %s conflict with %s: %s." % (
+                self.req, conflicting_with, ', '.join(conflict_messages))
+        )
+
+    def install_backend_dependencies(self, finder):
+        # type: (PackageFinder) -> None
+        """
+        Install any extra build dependencies that the backend requests.
+
+        :param finder: a PackageFinder object.
+        """
+        req = self.req
+        with req.build_env:
+            # We need to have the env active when calling the hook.
+            req.spin_message = "Getting requirements to build wheel"
+            reqs = req.pep517_backend.get_requires_for_build_wheel()
+        conflicting, missing = req.build_env.check_requirements(reqs)
+        if conflicting:
+            self._raise_conflicts("the backend dependencies", conflicting)
+        req.build_env.install_requirements(
+            finder, missing, 'normal',
+            "Installing backend dependencies"
+        )
+
+    def prep_for_dist(self, finder, build_isolation):
+        # type: (PackageFinder, bool) -> None
+        # Prepare for building. We need to:
+        #   1. Load pyproject.toml (if it exists)
+        #   2. Set up the build environment
+
+        self.req.load_pyproject_toml()
+        should_isolate = self.req.use_pep517 and build_isolation
+
+        if should_isolate:
+            # Isolate in a BuildEnvironment and install the build-time
+            # requirements.
+            self.req.build_env = BuildEnvironment()
+            self.req.build_env.install_requirements(
+                finder, self.req.pyproject_requires, 'overlay',
+                "Installing build dependencies"
+            )
+            conflicting, missing = self.req.build_env.check_requirements(
+                self.req.requirements_to_check
+            )
+            if conflicting:
+                self._raise_conflicts("PEP 517/518 supported requirements",
+                                      conflicting)
+            if missing:
+                logger.warning(
+                    "Missing build requirements in pyproject.toml for %s.",
+                    self.req,
+                )
+                logger.warning(
+                    "The project does not specify a build backend, and "
+                    "pip cannot fall back to setuptools without %s.",
+                    " and ".join(map(repr, sorted(missing)))
+                )
+
+            # Install any extra build dependencies that the backend requests.
+            # This must be done in a second pass, as the pyproject.toml
+            # dependencies must be installed before we can call the backend.
+            self.install_backend_dependencies(finder=finder)
+
+        self.req.prepare_metadata()
+        self.req.assert_source_matches_version()
+
+
+class Installed(DistAbstraction):
+
+    def dist(self):
+        # type: () -> pkg_resources.Distribution
+        return self.req.satisfied_by
+
+    def prep_for_dist(self, finder, build_isolation):
+        # type: (PackageFinder, bool) -> Any
+        pass
+
+
 class RequirementPreparer(object):
     """Prepares a Requirement
     """
@@ -98,7 +248,7 @@ class RequirementPreparer(object):
         upgrade_allowed,  # type: bool
         require_hashes  # type: bool
     ):
-        # type: (...) -> AbstractDistribution
+        # type: (...) -> DistAbstraction
         """Prepare a requirement that would be obtained from req.link
         """
         # TODO: Breakup into smaller functions
@@ -223,7 +373,7 @@ class RequirementPreparer(object):
         use_user_site,  # type: bool
         finder  # type: PackageFinder
     ):
-        # type: (...) -> AbstractDistribution
+        # type: (...) -> DistAbstraction
         """Prepare an editable requirement
         """
         assert req.editable, "cannot prepare a non-editable req as editable"
@@ -250,13 +400,8 @@ class RequirementPreparer(object):
 
         return abstract_dist
 
-    def prepare_installed_requirement(
-        self,
-        req,  # type: InstallRequirement
-        require_hashes,  # type: bool
-        skip_reason  # type: str
-    ):
-        # type: (...) -> AbstractDistribution
+    def prepare_installed_requirement(self, req, require_hashes, skip_reason):
+        # type: (InstallRequirement, bool, Optional[str]) -> DistAbstraction
         """Prepare an already-installed requirement
         """
         assert req.satisfied_by, "req should have been satisfied but isn't"
@@ -276,6 +421,6 @@ class RequirementPreparer(object):
                     'completely repeatable environment, install into an '
                     'empty virtualenv.'
                 )
-            abstract_dist = InstalledDistribution(req)
+            abstract_dist = Installed(req)
 
         return abstract_dist
diff --git a/src/pip/_internal/req/constructors.py b/src/pip/_internal/req/constructors.py
index 99df626b7..d0b0c7153 100644
--- a/src/pip/_internal/req/constructors.py
+++ b/src/pip/_internal/req/constructors.py
@@ -205,11 +205,15 @@ def install_req_from_line(
     isolated=False,  # type: bool
     options=None,  # type: Optional[Dict[str, Any]]
     wheel_cache=None,  # type: Optional[WheelCache]
-    constraint=False  # type: bool
+    constraint=False,  # type: bool
+    line_source=None,  # type: Optional[str]
 ):
     # type: (...) -> InstallRequirement
     """Creates an InstallRequirement from a name, which might be a
     requirement, directory containing 'setup.py', filename, or URL.
+
+    :param line_source: An optional string describing where the line is from,
+        for logging purposes in case of an error.
     """
     if is_url(name):
         marker_sep = '; '
@@ -289,10 +293,17 @@ def install_req_from_line(
                   not any(op in req_as_string for op in operators)):
                 add_msg = "= is not a valid operator. Did you mean == ?"
             else:
-                add_msg = ""
-            raise InstallationError(
-                "Invalid requirement: '%s'\n%s" % (req_as_string, add_msg)
+                add_msg = ''
+            if line_source is None:
+                source = ''
+            else:
+                source = ' (from {})'.format(line_source)
+            msg = (
+                'Invalid requirement: {!r}{}'.format(req_as_string, source)
             )
+            if add_msg:
+                msg += '\nHint: {}'.format(add_msg)
+            raise InstallationError(msg)
     else:
         req = None
 
diff --git a/src/pip/_internal/req/req_file.py b/src/pip/_internal/req/req_file.py
index ee62171da..41fdd362f 100644
--- a/src/pip/_internal/req/req_file.py
+++ b/src/pip/_internal/req/req_file.py
@@ -138,7 +138,7 @@ def process_line(
     session=None,  # type: Optional[PipSession]
     wheel_cache=None,  # type: Optional[WheelCache]
     use_pep517=None,  # type: Optional[bool]
-    constraint=False  # type: bool
+    constraint=False,  # type: bool
 ):
     # type: (...) -> Iterator[InstallRequirement]
     """Process a single requirements line; This can result in creating/yielding
@@ -187,10 +187,16 @@ def process_line(
         for dest in SUPPORTED_OPTIONS_REQ_DEST:
             if dest in opts.__dict__ and opts.__dict__[dest]:
                 req_options[dest] = opts.__dict__[dest]
+        line_source = 'line {} of {}'.format(line_number, filename)
         yield install_req_from_line(
-            args_str, line_comes_from, constraint=constraint,
+            args_str,
+            comes_from=line_comes_from,
             use_pep517=use_pep517,
-            isolated=isolated, options=req_options, wheel_cache=wheel_cache
+            isolated=isolated,
+            options=req_options,
+            wheel_cache=wheel_cache,
+            constraint=constraint,
+            line_source=line_source,
         )
 
     # yield an editable requirement
@@ -250,9 +256,8 @@ def process_line(
             finder.find_links.append(value)
         if opts.pre:
             finder.set_allow_all_prereleases()
-        for host in opts.trusted_hosts or []:
-            source = 'line {} of {}'.format(line_number, filename)
-            finder.add_trusted_host(host, source=source)
+        if opts.trusted_hosts:
+            finder.extend_trusted_hosts(opts.trusted_hosts)
 
 
 def break_args_options(line):

Improve error message for invalid requirements files
A `pip3 install` command is failing with esoteric error message. I am running as the root user on Ubuntu.

* pip version: pip 9.0.1 from /usr/lib/python3/dist-packages (python 3.6)
* Python version: Python 3.6.7
* OS: Ubuntu


I have this:

```Dockerfile
WORKDIR /apps/datavana/moodwire/mwapi
RUN mkdir -p /pth/to/downloaded/files
RUN mkdir -p /interos/temp
ARG commit

ADD https://bitbucket.org/interos/datavana/raw/"$commit"/moodwire/mwapi/requirements.txt  '/interos/temp/requirements.txt'
ADD https://bitbucket.org/interos/datavana/raw/"$commit"/moodwire/mwapi/constraints.txt '/interos/temp/constraints.txt'

# the ADD commands succeed

RUN pip3 install --cache-dir="/pth/to/downloaded/files" -r /interos/temp/requirements.txt -c /interos/temp/constraints.txt
```

I get this error:

```
Step 28/92 : RUN pip3 install --cache-dir="/pth/to/downloaded/files" -r /interos/temp/requirements.txt -c /interos/temp/constraints.txt
 ---> Running in ac48ca1a7f93
Invalid requirement: '<html>'
Traceback (most recent call last):
  File "/usr/share/python-wheels/packaging-17.1-py2.py3-none-any.whl/packaging/requirements.py", line 93, in __init__
    req = REQUIREMENT.parseString(requirement_string)
  File "/usr/share/python-wheels/pyparsing-2.2.0-py2.py3-none-any.whl/pyparsing.py", line 1632, in parseString
    raise exc
  File "/usr/share/python-wheels/pyparsing-2.2.0-py2.py3-none-any.whl/pyparsing.py", line 1622, in parseString
    loc, tokens = self._parse( instring, 0 )
  File "/usr/share/python-wheels/pyparsing-2.2.0-py2.py3-none-any.whl/pyparsing.py", line 1379, in _parseNoCache
    loc,tokens = self.parseImpl( instring, preloc, doActions )
  File "/usr/share/python-wheels/pyparsing-2.2.0-py2.py3-none-any.whl/pyparsing.py", line 3395, in parseImpl
    loc, exprtokens = e._parse( instring, loc, doActions )
  File "/usr/share/python-wheels/pyparsing-2.2.0-py2.py3-none-any.whl/pyparsing.py", line 1379, in _parseNoCache
    loc,tokens = self.parseImpl( instring, preloc, doActions )
  File "/usr/share/python-wheels/pyparsing-2.2.0-py2.py3-none-any.whl/pyparsing.py", line 3717, in parseImpl
    return self.expr._parse( instring, loc, doActions, callPreParse=False )
  File "/usr/share/python-wheels/pyparsing-2.2.0-py2.py3-none-any.whl/pyparsing.py", line 1379, in _parseNoCache
    loc,tokens = self.parseImpl( instring, preloc, doActions )
  File "/usr/share/python-wheels/pyparsing-2.2.0-py2.py3-none-any.whl/pyparsing.py", line 3378, in parseImpl
    loc, resultlist = self.exprs[0]._parse( instring, loc, doActions, callPreParse=False )
  File "/usr/share/python-wheels/pyparsing-2.2.0-py2.py3-none-any.whl/pyparsing.py", line 1383, in _parseNoCache
    loc,tokens = self.parseImpl( instring, preloc, doActions )
  File "/usr/share/python-wheels/pyparsing-2.2.0-py2.py3-none-any.whl/pyparsing.py", line 2689, in parseImpl
    raise ParseException(instring, loc, self.errmsg, self)
pyparsing.ParseException: Expected W:(abcd...) (at char 0), (line:1, col:1)

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "/usr/lib/python3/dist-packages/pip/req/req_install.py", line 82, in __init__
    req = Requirement(req)
  File "/usr/share/python-wheels/packaging-17.1-py2.py3-none-any.whl/packaging/requirements.py", line 97, in __init__
    requirement_string[e.loc:e.loc + 8]))
pip._vendor.packaging.requirements.InvalidRequirement: Invalid requirement, parse error at "'<html>'"

The command '/bin/sh -c pip3 install --cache-dir="/pth/to/downloaded/files" -r /interos/temp/requirements.txt -c /interos/temp/constraints.txt' returned a non-zero code: 1

```

the error message is pretty bad - no matter what's going on.
diff --git a/tests/functional/test_install_vcs_svn.py b/tests/functional/test_install_vcs_svn.py
new file mode 100644
index 000000000..3034b0625
--- /dev/null
+++ b/tests/functional/test_install_vcs_svn.py
@@ -0,0 +1,66 @@
+from unittest import TestCase
+
+from mock import patch
+
+from pip._internal.vcs.subversion import Subversion
+from pip._internal.vcs.versioncontrol import RevOptions
+
+
+class TestSubversionArgs(TestCase):
+    def setUp(self):
+        patcher = patch('pip._internal.vcs.versioncontrol.call_subprocess')
+        self.addCleanup(patcher.stop)
+        self.call_subprocess_mock = patcher.start()
+
+        # Test Data.
+        self.url = 'svn+http://username:password@svn.example.com/'
+        # use_interactive is set to False to test that remote call options are
+        # properly added.
+        self.svn = Subversion(use_interactive=False)
+        self.rev_options = RevOptions(Subversion)
+        self.dest = '/tmp/test'
+
+    def assert_call_args(self, args):
+        assert self.call_subprocess_mock.call_args[0][0] == args
+
+    def test_obtain(self):
+        self.svn.obtain(self.dest, self.url)
+        self.assert_call_args(
+            ['svn', 'checkout', '-q', '--non-interactive', '--username',
+             'username', '--password', 'password',
+             'http://svn.example.com/', '/tmp/test'])
+
+    def test_export(self):
+        self.svn.export(self.dest, self.url)
+        self.assert_call_args(
+            ['svn', 'export', '--non-interactive', '--username', 'username',
+             '--password', 'password', 'http://svn.example.com/',
+             '/tmp/test'])
+
+    def test_fetch_new(self):
+        self.svn.fetch_new(self.dest, self.url, self.rev_options)
+        self.assert_call_args(
+            ['svn', 'checkout', '-q', '--non-interactive',
+             'svn+http://username:password@svn.example.com/',
+             '/tmp/test'])
+
+    def test_fetch_new_revision(self):
+        rev_options = RevOptions(Subversion, '123')
+        self.svn.fetch_new(self.dest, self.url, rev_options)
+        self.assert_call_args(
+            ['svn', 'checkout', '-q', '--non-interactive',
+             '-r', '123',
+             'svn+http://username:password@svn.example.com/',
+             '/tmp/test'])
+
+    def test_switch(self):
+        self.svn.switch(self.dest, self.url, self.rev_options)
+        self.assert_call_args(
+            ['svn', 'switch', '--non-interactive',
+             'svn+http://username:password@svn.example.com/',
+             '/tmp/test'])
+
+    def test_update(self):
+        self.svn.update(self.dest, self.url, self.rev_options)
+        self.assert_call_args(
+            ['svn', 'update', '--non-interactive', '/tmp/test'])
diff --git a/tests/unit/test_index.py b/tests/unit/test_index.py
index 4ffc6475e..c7dc1715a 100644
--- a/tests/unit/test_index.py
+++ b/tests/unit/test_index.py
@@ -163,60 +163,15 @@ class TestPackageFinder:
         assert actual_target_python is target_python
         assert actual_target_python.py_version_info == (3, 7, 3)
 
-    def test_add_trusted_host(self):
-        # Leave a gap to test how the ordering is affected.
-        trusted_hosts = ['host1', 'host3']
-        session = PipSession(insecure_hosts=trusted_hosts)
-        finder = make_test_finder(
-            session=session,
-            trusted_hosts=trusted_hosts,
-        )
-        insecure_adapter = session._insecure_adapter
-        prefix2 = 'https://host2/'
-        prefix3 = 'https://host3/'
-
-        # Confirm some initial conditions as a baseline.
-        assert finder.trusted_hosts == ['host1', 'host3']
-        assert session.adapters[prefix3] is insecure_adapter
-        assert prefix2 not in session.adapters
-
-        # Test adding a new host.
-        finder.add_trusted_host('host2')
-        assert finder.trusted_hosts == ['host1', 'host3', 'host2']
-        # Check that prefix3 is still present.
-        assert session.adapters[prefix3] is insecure_adapter
-        assert session.adapters[prefix2] is insecure_adapter
-
-        # Test that adding the same host doesn't create a duplicate.
-        finder.add_trusted_host('host3')
-        assert finder.trusted_hosts == ['host1', 'host3', 'host2'], (
-            'actual: {}'.format(finder.trusted_hosts)
-        )
+    def test_extend_trusted_hosts(self):
+        trusted_hosts = ['host1', 'host2']
+        finder = make_test_finder(trusted_hosts=trusted_hosts)
 
-    def test_add_trusted_host__logging(self, caplog):
-        """
-        Test logging when add_trusted_host() is called.
-        """
-        trusted_hosts = ['host1']
-        session = PipSession(insecure_hosts=trusted_hosts)
-        finder = make_test_finder(
-            session=session,
-            trusted_hosts=trusted_hosts,
+        # Check that extend_trusted_hosts() prevents duplicates.
+        finder.extend_trusted_hosts(['host2', 'host3', 'host2'])
+        assert finder.trusted_hosts == ['host1', 'host2', 'host3'], (
+            'actual: {}'.format(finder.trusted_hosts)
         )
-        with caplog.at_level(logging.INFO):
-            # Test adding an existing host.
-            finder.add_trusted_host('host1', source='somewhere')
-            finder.add_trusted_host('host2')
-            # Test calling add_trusted_host() on the same host twice.
-            finder.add_trusted_host('host2')
-
-        actual = [(r.levelname, r.message) for r in caplog.records]
-        expected = [
-            ('INFO', "adding trusted host: 'host1' (from somewhere)"),
-            ('INFO', "adding trusted host: 'host2'"),
-            ('INFO', "adding trusted host: 'host2'"),
-        ]
-        assert actual == expected
 
     def test_iter_secure_origins(self):
         trusted_hosts = ['host1', 'host2']
diff --git a/tests/unit/test_req.py b/tests/unit/test_req.py
index 3f8c38ce5..a7f830475 100644
--- a/tests/unit/test_req.py
+++ b/tests/unit/test_req.py
@@ -530,7 +530,7 @@ class TestInstallRequirement(object):
         with pytest.raises(InstallationError) as e:
             install_req_from_line(test_name)
         err_msg = e.value.args[0]
-        assert ("Invalid requirement: '%s'\n" % test_name) == err_msg
+        assert "Invalid requirement: '{}'".format(test_name) == err_msg
 
     def test_requirement_file(self):
         req_file_path = os.path.join(self.tempdir, 'test.txt')
diff --git a/tests/unit/test_req_file.py b/tests/unit/test_req_file.py
index 972d84684..2cd3e6a47 100644
--- a/tests/unit/test_req_file.py
+++ b/tests/unit/test_req_file.py
@@ -1,4 +1,3 @@
-import logging
 import os
 import subprocess
 import textwrap
@@ -191,6 +190,26 @@ class TestProcessLine(object):
         with pytest.raises(InstallationError):
             list(process_line("req1 req2", "file", 1))
 
+    def test_error_message(self):
+        """
+        Test the error message if a parsing error occurs (all of path,
+        line number, and hint).
+        """
+        iterator = process_line(
+            'my-package=1.0',
+            filename='path/requirements.txt',
+            line_number=3
+        )
+        with pytest.raises(InstallationError) as exc:
+            list(iterator)
+
+        expected = (
+            "Invalid requirement: 'my-package=1.0' "
+            '(from line 3 of path/requirements.txt)\n'
+            'Hint: = is not a valid operator. Did you mean == ?'
+        )
+        assert str(exc.value) == expected
+
     def test_yield_line_requirement(self):
         line = 'SomeProject'
         filename = 'filename'
@@ -315,21 +334,9 @@ class TestProcessLine(object):
         list(process_line("--extra-index-url=url", "file", 1, finder=finder))
         assert finder.index_urls == ['url']
 
-    def test_set_finder_trusted_host(self, caplog, finder):
-        with caplog.at_level(logging.INFO):
-            list(process_line(
-                "--trusted-host=host", "file.txt", 1, finder=finder,
-            ))
-        assert finder.trusted_hosts == ['host']
-        session = finder.session
-        assert session.adapters['https://host/'] is session._insecure_adapter
-
-        # Test the log message.
-        actual = [(r.levelname, r.message) for r in caplog.records]
-        expected = [
-            ('INFO', "adding trusted host: 'host' (from line 1 of file.txt)"),
-        ]
-        assert actual == expected
+    def test_set_finder_trusted_host(self, finder):
+        list(process_line("--trusted-host=url", "file", 1, finder=finder))
+        assert finder.trusted_hosts == ['url']
 
     def test_noop_always_unzip(self, finder):
         # noop, but confirm it can be set
diff --git a/tests/unit/test_vcs.py b/tests/unit/test_vcs.py
index 36e80326e..95bce95ec 100644
--- a/tests/unit/test_vcs.py
+++ b/tests/unit/test_vcs.py
@@ -1,5 +1,4 @@
 import os
-from unittest import TestCase
 
 import pytest
 from mock import patch
@@ -495,63 +494,3 @@ def test_subversion__get_remote_call_options(
     svn = Subversion(use_interactive=use_interactive)
     svn._vcs_version = vcs_version
     assert svn.get_remote_call_options() == expected_options
-
-
-class TestSubversionArgs(TestCase):
-    def setUp(self):
-        patcher = patch('pip._internal.vcs.versioncontrol.call_subprocess')
-        self.addCleanup(patcher.stop)
-        self.call_subprocess_mock = patcher.start()
-
-        # Test Data.
-        self.url = 'svn+http://username:password@svn.example.com/'
-        # use_interactive is set to False to test that remote call options are
-        # properly added.
-        self.svn = Subversion(use_interactive=False)
-        self.rev_options = RevOptions(Subversion)
-        self.dest = '/tmp/test'
-
-    def assert_call_args(self, args):
-        assert self.call_subprocess_mock.call_args[0][0] == args
-
-    def test_obtain(self):
-        self.svn.obtain(self.dest, self.url)
-        self.assert_call_args(
-            ['svn', 'checkout', '-q', '--non-interactive', '--username',
-             'username', '--password', 'password',
-             'http://svn.example.com/', '/tmp/test'])
-
-    def test_export(self):
-        self.svn.export(self.dest, self.url)
-        self.assert_call_args(
-            ['svn', 'export', '--non-interactive', '--username', 'username',
-             '--password', 'password', 'http://svn.example.com/',
-             '/tmp/test'])
-
-    def test_fetch_new(self):
-        self.svn.fetch_new(self.dest, self.url, self.rev_options)
-        self.assert_call_args(
-            ['svn', 'checkout', '-q', '--non-interactive',
-             'svn+http://username:password@svn.example.com/',
-             '/tmp/test'])
-
-    def test_fetch_new_revision(self):
-        rev_options = RevOptions(Subversion, '123')
-        self.svn.fetch_new(self.dest, self.url, rev_options)
-        self.assert_call_args(
-            ['svn', 'checkout', '-q', '--non-interactive',
-             '-r', '123',
-             'svn+http://username:password@svn.example.com/',
-             '/tmp/test'])
-
-    def test_switch(self):
-        self.svn.switch(self.dest, self.url, self.rev_options)
-        self.assert_call_args(
-            ['svn', 'switch', '--non-interactive',
-             'svn+http://username:password@svn.example.com/',
-             '/tmp/test'])
-
-    def test_update(self):
-        self.svn.update(self.dest, self.url, self.rev_options)
-        self.assert_call_args(
-            ['svn', 'update', '--non-interactive', '/tmp/test'])

pip install -e .
parse_log_pytest
pytest
pytest pytest-cov pytest-rerunfailures pytest-timeout pytest-xdist freezegun mock pretend pyyaml setuptools>=39.2.0 scripttest virtualenv wheel
3.9
pytest --no-header -rA --tb=line --color=no -p no:cacheprovider -W ignore::DeprecationWarning
coverage==7.8.0
distlib==0.3.9
exceptiongroup==1.2.0
execnet==2.1.1
filelock==3.18.0
freezegun==1.5.1
iniconfig==1.1.1
mock==5.2.0
packaging==24.2
platformdirs==4.3.7
pluggy==1.5.0
pretend==1.0.9
pytest==8.3.4
pytest-cov==6.0.0
pytest-rerunfailures==15.0
pytest-timeout==2.3.1
pytest-xdist==3.6.1
python-dateutil==2.9.0.post0
PyYAML==6.0.2
scripttest==2.0
six==1.17.0
tomli==2.0.1
virtualenv==20.29.3

name: pip
channels:
  - defaults
  - https://repo.anaconda.com/pkgs/main
  - https://repo.anaconda.com/pkgs/r
  - conda-forge
dependencies:
  - _libgcc_mutex=0.1=main
  - _openmp_mutex=5.1=1_gnu
  - ca-certificates=2025.2.25=h06a4308_0
  - exceptiongroup=1.2.0=py39h06a4308_0
  - iniconfig=1.1.1=pyhd3eb1b0_0
  - ld_impl_linux-64=2.40=h12ee557_0
  - libffi=3.4.4=h6a678d5_1
  - libgcc-ng=11.2.0=h1234567_1
  - libgomp=11.2.0=h1234567_1
  - libstdcxx-ng=11.2.0=h1234567_1
  - ncurses=6.4=h6a678d5_0
  - openssl=3.0.16=h5eee18b_0
  - packaging=24.2=py39h06a4308_0
  - pluggy=1.5.0=py39h06a4308_0
  - pytest=8.3.4=py39h06a4308_0
  - python=3.9.21=he870216_1
  - readline=8.2=h5eee18b_0
  - setuptools=75.8.0=py39h06a4308_0
  - sqlite=3.45.3=h5eee18b_0
  - tk=8.6.14=h39e8969_0
  - tomli=2.0.1=py39h06a4308_0
  - tzdata=2025a=h04d1e81_0
  - wheel=0.45.1=py39h06a4308_0
  - xz=5.6.4=h5eee18b_1
  - zlib=1.2.13=h5eee18b_1
  - pip:
      - coverage==7.8.0
      - distlib==0.3.9
      - execnet==2.1.1
      - filelock==3.18.0
      - freezegun==1.5.1
      - mock==5.2.0
      - pip==19.1.1
      - platformdirs==4.3.7
      - pretend==1.0.9
      - pytest-cov==6.0.0
      - pytest-rerunfailures==15.0
      - pytest-timeout==2.3.1
      - pytest-xdist==3.6.1
      - python-dateutil==2.9.0.post0
      - pyyaml==6.0.2
      - scripttest==2.0
      - six==1.17.0
      - virtualenv==20.29.3
prefix: /opt/conda/envs/pip

tests/unit/test_index.py::TestPackageFinder::test_extend_trusted_hosts tests/unit/test_req.py::TestInstallRequirement::test_unidentifiable_name tests/unit/test_req_file.py::TestProcessLine::test_error_message
tests/unit/test_req.py::TestRequirementSet::test_no_reuse_existing_build_dir tests/unit/test_req.py::TestRequirementSet::test_environment_marker_extras tests/unit/test_req.py::TestRequirementSet::test_missing_hash_checking tests/unit/test_req.py::TestRequirementSet::test_missing_hash_with_require_hashes tests/unit/test_req.py::TestRequirementSet::test_unsupported_hashes tests/unit/test_req.py::TestRequirementSet::test_unpinned_hash_checking tests/unit/test_req.py::TestRequirementSet::test_hash_mismatch tests/unit/test_req.py::TestRequirementSet::test_unhashed_deps_on_require_hashes tests/unit/test_req.py::TestInstallRequirement::test_requirement_file
tests/functional/test_install_vcs_svn.py::TestSubversionArgs::test_export tests/functional/test_install_vcs_svn.py::TestSubversionArgs::test_fetch_new tests/functional/test_install_vcs_svn.py::TestSubversionArgs::test_fetch_new_revision tests/functional/test_install_vcs_svn.py::TestSubversionArgs::test_obtain tests/functional/test_install_vcs_svn.py::TestSubversionArgs::test_switch tests/functional/test_install_vcs_svn.py::TestSubversionArgs::test_update tests/unit/test_index.py::test_check_link_requires_python[== tests/unit/test_index.py::test_check_link_requires_python[invalid-True] tests/unit/test_index.py::test_check_link_requires_python__incompatible_python[None-expected0] tests/unit/test_index.py::test_check_link_requires_python__incompatible_python[True-expected1] tests/unit/test_index.py::test_check_link_requires_python__invalid_requires tests/unit/test_index.py::TestCandidateEvaluator::test_init__target_python tests/unit/test_index.py::TestCandidateEvaluator::test_init__target_python_none tests/unit/test_index.py::TestCandidateEvaluator::test_evaluate_link[py_version_info0-None-expected0] tests/unit/test_index.py::TestCandidateEvaluator::test_evaluate_link[py_version_info1-None-expected1] tests/unit/test_index.py::TestCandidateEvaluator::test_evaluate_link[py_version_info2-True-expected2] tests/unit/test_index.py::TestCandidateEvaluator::test_evaluate_link__incompatible_wheel tests/unit/test_index.py::TestPackageFinder::test_create__target_python tests/unit/test_index.py::TestPackageFinder::test_iter_secure_origins tests/unit/test_index.py::TestPackageFinder::test_iter_secure_origins__none_trusted_hosts tests/unit/test_index.py::test_sort_locations_file_expand_dir tests/unit/test_index.py::test_sort_locations_file_not_find_link tests/unit/test_index.py::test_sort_locations_non_existing_path tests/unit/test_index.py::TestLink::test_splitext tests/unit/test_index.py::TestLink::test_filename[http://yo/wheel.whl-wheel.whl] tests/unit/test_index.py::TestLink::test_filename[http://yo/wheel-wheel] tests/unit/test_index.py::TestLink::test_filename[http://yo/myproject-1.0%2Bfoobar.0-py2.py3-none-any.whl-myproject-1.0+foobar.0-py2.py3-none-any.whl] tests/unit/test_index.py::TestLink::test_no_ext tests/unit/test_index.py::TestLink::test_ext tests/unit/test_index.py::TestLink::test_ext_fragment tests/unit/test_index.py::TestLink::test_ext_query tests/unit/test_index.py::TestLink::test_is_wheel tests/unit/test_index.py::TestLink::test_is_wheel_false tests/unit/test_index.py::TestLink::test_fragments tests/unit/test_index.py::test_determine_base_url[<html></html>-https://example.com/-https://example.com/] tests/unit/test_index.py::test_determine_base_url[<html><head><base tests/unit/test_index.py::test_determine_base_url[<html><head><base><base tests/unit/test_index.py::test_secure_origin[http://pypi.org/something-trusted0-True] tests/unit/test_index.py::test_secure_origin[https://pypi.org/something-trusted1-False] tests/unit/test_index.py::test_secure_origin[git+http://pypi.org/something-trusted2-True] tests/unit/test_index.py::test_secure_origin[git+https://pypi.org/something-trusted3-False] tests/unit/test_index.py::test_secure_origin[git+ssh://git@pypi.org/something-trusted4-False] tests/unit/test_index.py::test_secure_origin[http://localhost-trusted5-False] tests/unit/test_index.py::test_secure_origin[http://127.0.0.1-trusted6-False] tests/unit/test_index.py::test_secure_origin[http://example.com/something/-trusted7-True] tests/unit/test_index.py::test_secure_origin[http://example.com/something/-trusted8-False] tests/unit/test_index.py::test_secure_origin[http://eXample.com/something/-trusted9-False] tests/unit/test_index.py::test_get_formatted_locations_basic_auth tests/unit/test_index.py::test_find_name_version_sep[pip-18.0-pip-3] tests/unit/test_index.py::test_find_name_version_sep[zope-interface-4.5.0-zope-interface-14] tests/unit/test_index.py::test_find_name_version_sep[Jinja2-2.10-jinja2-6] tests/unit/test_index.py::test_find_name_version_sep[zope.interface-4.5.0-zope-interface-14] tests/unit/test_index.py::test_find_name_version_sep[zope_interface-4.5.0-zope-interface-14] tests/unit/test_index.py::test_find_name_version_sep[foo-2-2-foo-3] tests/unit/test_index.py::test_find_name_version_sep[foo-2-2-foo-2-5] tests/unit/test_index.py::test_find_name_version_sep[foo--bar-1.0-foo-bar-8] tests/unit/test_index.py::test_find_name_version_sep[foo-_bar-1.0-foo-bar-8] tests/unit/test_index.py::test_find_name_version_sep[zope.interface--4.5.0-zope-interface-14] tests/unit/test_index.py::test_find_name_version_sep[zope.interface---zope-interface-14] tests/unit/test_index.py::test_find_name_version_sep[zope.interface--zope-interface-14] tests/unit/test_index.py::test_find_name_version_sep_failure[zope.interface4.5.0-zope-interface] tests/unit/test_index.py::test_find_name_version_sep_failure[zope.interface.4.5.0-zope-interface] tests/unit/test_index.py::test_find_name_version_sep_failure[zope.interface.-4.5.0-zope-interface] tests/unit/test_index.py::test_find_name_version_sep_failure[zope.interface-zope-interface] tests/unit/test_index.py::test_egg_info_matches[pip-18.0-pip-18.0] tests/unit/test_index.py::test_egg_info_matches[zope-interface-4.5.0-zope-interface-4.5.0] tests/unit/test_index.py::test_egg_info_matches[Jinja2-2.10-jinja2-2.10] tests/unit/test_index.py::test_egg_info_matches[zope.interface-4.5.0-zope-interface-4.5.0] tests/unit/test_index.py::test_egg_info_matches[zope_interface-4.5.0-zope-interface-4.5.0] tests/unit/test_index.py::test_egg_info_matches[foo-2-2-foo-2-2_0] tests/unit/test_index.py::test_egg_info_matches[foo-2-2-foo-2-2_1] tests/unit/test_index.py::test_egg_info_matches[zope.interface--4.5.0-zope-interface--4.5.0] tests/unit/test_index.py::test_egg_info_matches[zope.interface---zope-interface--] tests/unit/test_index.py::test_egg_info_matches[foo--bar-1.0-foo-bar-1.0] tests/unit/test_index.py::test_egg_info_matches[foo-_bar-1.0-foo-bar-1.0] tests/unit/test_index.py::test_egg_info_matches[the-package-name-8.19-does-not-match-None] tests/unit/test_index.py::test_egg_info_matches[zope.interface.-4.5.0-zope.interface-None] tests/unit/test_index.py::test_egg_info_matches[zope.interface--zope-interface-None] tests/unit/test_index.py::test_egg_info_matches[zope.interface4.5.0-zope-interface-None] tests/unit/test_index.py::test_egg_info_matches[zope.interface.4.5.0-zope-interface-None] tests/unit/test_index.py::test_egg_info_matches[zope.interface.-4.5.0-zope-interface-None] tests/unit/test_index.py::test_egg_info_matches[zope.interface-zope-interface-None] tests/unit/test_index.py::test_request_http_error tests/unit/test_index.py::test_request_retries tests/unit/test_index.py::test_clean_link[https://localhost.localdomain:8181/path/with tests/unit/test_index.py::test_clean_link[https://localhost.localdomain:8181/path/with%20quoted%20space/-https://localhost.localdomain:8181/path/with%20quoted%20space/] tests/unit/test_index.py::test_clean_link[https://127.0.0.1:8181/path/with tests/unit/test_index.py::test_clean_link[https://[fd00:0:0:236::100]:8181/path/with tests/unit/test_index.py::test_clean_link[https://localhost.localdomain:8181/path/with/query?request=test-https://localhost.localdomain:8181/path/with/query?request=test] tests/unit/test_index.py::test_clean_link[https://localhost.localdomain:8181/path:/with:/colon-https://localhost.localdomain:8181/path%3A/with%3A/colon] tests/unit/test_index.py::test_clean_link[https://localhost.localdomain/T:/path/-https://localhost.localdomain/T%3A/path/] tests/unit/test_index.py::test_clean_link[git+ssh://example.com/path tests/unit/test_index.py::test_clean_link_non_windows[file:///T:/path/with tests/unit/test_req.py::TestRequirementSet::test_missing_hash_with_require_hashes_in_reqs_file tests/unit/test_req.py::TestRequirementSet::test_hashed_deps_on_require_hashes tests/unit/test_req.py::TestInstallRequirement::test_url_with_query tests/unit/test_req.py::TestInstallRequirement::test_unsupported_wheel_link_requirement_raises tests/unit/test_req.py::TestInstallRequirement::test_unsupported_wheel_local_file_requirement_raises tests/unit/test_req.py::TestInstallRequirement::test_installed_version_not_installed tests/unit/test_req.py::TestInstallRequirement::test_str tests/unit/test_req.py::TestInstallRequirement::test_repr tests/unit/test_req.py::TestInstallRequirement::test_invalid_wheel_requirement_raises tests/unit/test_req.py::TestInstallRequirement::test_wheel_requirement_sets_req_attribute tests/unit/test_req.py::TestInstallRequirement::test_url_preserved_line_req tests/unit/test_req.py::TestInstallRequirement::test_url_preserved_editable_req tests/unit/test_req.py::TestInstallRequirement::test_get_dist[/path/to/foo.egg-info] tests/unit/test_req.py::TestInstallRequirement::test_get_dist[/path/to/foo.egg-info/] tests/unit/test_req.py::TestInstallRequirement::test_markers tests/unit/test_req.py::TestInstallRequirement::test_markers_semicolon tests/unit/test_req.py::TestInstallRequirement::test_markers_url tests/unit/test_req.py::TestInstallRequirement::test_markers_match_from_line tests/unit/test_req.py::TestInstallRequirement::test_markers_match tests/unit/test_req.py::TestInstallRequirement::test_extras_for_line_path_requirement tests/unit/test_req.py::TestInstallRequirement::test_extras_for_line_url_requirement tests/unit/test_req.py::TestInstallRequirement::test_extras_for_editable_path_requirement tests/unit/test_req.py::TestInstallRequirement::test_extras_for_editable_url_requirement tests/unit/test_req.py::TestInstallRequirement::test_unexisting_path tests/unit/test_req.py::TestInstallRequirement::test_single_equal_sign tests/unit/test_req.py::test_parse_editable_local tests/unit/test_req.py::test_parse_editable_explicit_vcs tests/unit/test_req.py::test_parse_editable_vcs_extras tests/unit/test_req.py::test_parse_editable_local_extras tests/unit/test_req.py::test_exclusive_environment_markers tests/unit/test_req.py::test_mismatched_versions tests/unit/test_req_file.py::TestPreprocess::test_comments_and_joins_case1 tests/unit/test_req_file.py::TestPreprocess::test_comments_and_joins_case2 tests/unit/test_req_file.py::TestPreprocess::test_comments_and_joins_case3 tests/unit/test_req_file.py::TestPreprocess::test_skip_regex_after_joining_case1 tests/unit/test_req_file.py::TestPreprocess::test_skip_regex_after_joining_case2 tests/unit/test_req_file.py::TestIgnoreComments::test_ignore_line tests/unit/test_req_file.py::TestIgnoreComments::test_ignore_comment tests/unit/test_req_file.py::TestIgnoreComments::test_strip_comment tests/unit/test_req_file.py::TestJoinLines::test_join_lines tests/unit/test_req_file.py::TestJoinLines::test_last_line_with_escape tests/unit/test_req_file.py::TestSkipRegex::test_skip_regex_pattern_match tests/unit/test_req_file.py::TestSkipRegex::test_skip_regex_pattern_not_match tests/unit/test_req_file.py::TestSkipRegex::test_skip_regex_no_options tests/unit/test_req_file.py::TestSkipRegex::test_skip_regex_no_skip_option tests/unit/test_req_file.py::TestProcessLine::test_parser_error tests/unit/test_req_file.py::TestProcessLine::test_parser_offending_line tests/unit/test_req_file.py::TestProcessLine::test_parser_non_offending_line tests/unit/test_req_file.py::TestProcessLine::test_only_one_req_per_line tests/unit/test_req_file.py::TestProcessLine::test_yield_line_requirement tests/unit/test_req_file.py::TestProcessLine::test_yield_line_constraint tests/unit/test_req_file.py::TestProcessLine::test_yield_line_requirement_with_spaces_in_specifier tests/unit/test_req_file.py::TestProcessLine::test_yield_editable_requirement tests/unit/test_req_file.py::TestProcessLine::test_yield_editable_constraint tests/unit/test_req_file.py::TestProcessLine::test_nested_requirements_file tests/unit/test_req_file.py::TestProcessLine::test_nested_constraints_file tests/unit/test_req_file.py::TestProcessLine::test_options_on_a_requirement_line tests/unit/test_req_file.py::TestProcessLine::test_hash_options tests/unit/test_req_file.py::TestProcessLine::test_set_isolated tests/unit/test_req_file.py::TestProcessLine::test_set_finder_no_index tests/unit/test_req_file.py::TestProcessLine::test_set_finder_index_url tests/unit/test_req_file.py::TestProcessLine::test_set_finder_find_links tests/unit/test_req_file.py::TestProcessLine::test_set_finder_extra_index_urls tests/unit/test_req_file.py::TestProcessLine::test_set_finder_trusted_host tests/unit/test_req_file.py::TestProcessLine::test_noop_always_unzip tests/unit/test_req_file.py::TestProcessLine::test_set_finder_allow_all_prereleases tests/unit/test_req_file.py::TestProcessLine::test_relative_local_find_links tests/unit/test_req_file.py::TestProcessLine::test_relative_http_nested_req_files tests/unit/test_req_file.py::TestProcessLine::test_relative_local_nested_req_files tests/unit/test_req_file.py::TestProcessLine::test_absolute_local_nested_req_files tests/unit/test_req_file.py::TestProcessLine::test_absolute_http_nested_req_file_in_local tests/unit/test_req_file.py::TestBreakOptionsArgs::test_no_args tests/unit/test_req_file.py::TestBreakOptionsArgs::test_no_options tests/unit/test_req_file.py::TestBreakOptionsArgs::test_args_short_options tests/unit/test_req_file.py::TestBreakOptionsArgs::test_args_long_options tests/unit/test_req_file.py::TestOptionVariants::test_variant1 tests/unit/test_req_file.py::TestOptionVariants::test_variant2 tests/unit/test_req_file.py::TestOptionVariants::test_variant3 tests/unit/test_req_file.py::TestOptionVariants::test_variant4 tests/unit/test_req_file.py::TestOptionVariants::test_variant5 tests/unit/test_req_file.py::TestParseRequirements::test_remote_reqs_parse tests/unit/test_req_file.py::TestParseRequirements::test_multiple_appending_options tests/unit/test_req_file.py::TestParseRequirements::test_skip_regex tests/unit/test_req_file.py::TestParseRequirements::test_expand_existing_env_variables tests/unit/test_req_file.py::TestParseRequirements::test_expand_missing_env_variables tests/unit/test_req_file.py::TestParseRequirements::test_join_lines tests/unit/test_req_file.py::TestParseRequirements::test_req_file_parse_no_only_binary tests/unit/test_req_file.py::TestParseRequirements::test_req_file_parse_comment_start_of_line tests/unit/test_req_file.py::TestParseRequirements::test_req_file_parse_comment_end_of_line_with_url tests/unit/test_req_file.py::TestParseRequirements::test_req_file_parse_egginfo_end_of_line_with_url tests/unit/test_req_file.py::TestParseRequirements::test_req_file_no_finder tests/unit/test_req_file.py::TestParseRequirements::test_install_requirements_with_options tests/unit/test_vcs.py::test_make_vcs_requirement_url[args0-git+https://example.com/pkg@dev#egg=myproj] tests/unit/test_vcs.py::test_make_vcs_requirement_url[args1-git+https://example.com/pkg@dev#egg=myproj&subdirectory=sub/dir] tests/unit/test_vcs.py::test_make_vcs_requirement_url[args2-git+https://example.com/pkg@dev#egg=myproj] tests/unit/test_vcs.py::test_make_vcs_requirement_url[args3-git+https://example.com/pkg@dev#egg=zope_interface] tests/unit/test_vcs.py::test_rev_options_repr tests/unit/test_vcs.py::test_rev_options_to_args[Bazaar-expected10-expected20-kwargs0] tests/unit/test_vcs.py::test_rev_options_to_args[Git-expected11-expected21-kwargs1] tests/unit/test_vcs.py::test_rev_options_to_args[Mercurial-expected12-expected22-kwargs2] tests/unit/test_vcs.py::test_rev_options_to_args[Subversion-expected13-expected23-kwargs3] tests/unit/test_vcs.py::test_rev_options_to_args[Git-expected14-expected24-kwargs4] tests/unit/test_vcs.py::test_rev_options_to_display tests/unit/test_vcs.py::test_rev_options_make_new tests/unit/test_vcs.py::test_looks_like_hash tests/unit/test_vcs.py::test_should_add_vcs_url_prefix[Git-git://example.com/MyProject-False] tests/unit/test_vcs.py::test_should_add_vcs_url_prefix[Git-http://example.com/MyProject-True] tests/unit/test_vcs.py::test_should_add_vcs_url_prefix[Subversion-svn://example.com/MyProject-True] tests/unit/test_vcs.py::test_git_get_src_requirements tests/unit/test_vcs.py::test_git_resolve_revision_rev_exists tests/unit/test_vcs.py::test_git_resolve_revision_rev_not_found tests/unit/test_vcs.py::test_git_resolve_revision_not_found_warning tests/unit/test_vcs.py::test_git_is_commit_id_equal[5547fa909e83df8bd743d3978d6667497983a4b7-True] tests/unit/test_vcs.py::test_git_is_commit_id_equal[5547fa909-False] tests/unit/test_vcs.py::test_git_is_commit_id_equal[5678-False] tests/unit/test_vcs.py::test_git_is_commit_id_equal[abc123-False] tests/unit/test_vcs.py::test_git_is_commit_id_equal[foo-False] tests/unit/test_vcs.py::test_git_is_commit_id_equal[None-False] tests/unit/test_vcs.py::test_git__get_netloc_and_auth[args0-expected0] tests/unit/test_vcs.py::test_git__get_netloc_and_auth[args1-expected1] tests/unit/test_vcs.py::test_subversion__get_netloc_and_auth[args0-expected0] tests/unit/test_vcs.py::test_subversion__get_netloc_and_auth[args1-expected1] tests/unit/test_vcs.py::test_subversion__get_netloc_and_auth[args2-expected2] tests/unit/test_vcs.py::test_subversion__get_netloc_and_auth[args3-expected3] tests/unit/test_vcs.py::test_subversion__get_netloc_and_auth[args4-expected4] tests/unit/test_vcs.py::test_git__get_url_rev__idempotent tests/unit/test_vcs.py::test_version_control__get_url_rev_and_auth[svn+https://svn.example.com/MyProject-expected0] tests/unit/test_vcs.py::test_version_control__get_url_rev_and_auth[svn+https://svn.example.com/My+Project-expected1] tests/unit/test_vcs.py::test_version_control__get_url_rev_and_auth__missing_plus[https://svn.example.com/MyProject] tests/unit/test_vcs.py::test_version_control__get_url_rev_and_auth__missing_plus[https://svn.example.com/My+Project] tests/unit/test_vcs.py::test_bazaar__get_url_rev_and_auth[bzr+http://bzr.myproject.org/MyProject/trunk/#egg=MyProject-http://bzr.myproject.org/MyProject/trunk/] tests/unit/test_vcs.py::test_bazaar__get_url_rev_and_auth[bzr+https://bzr.myproject.org/MyProject/trunk/#egg=MyProject-https://bzr.myproject.org/MyProject/trunk/] tests/unit/test_vcs.py::test_bazaar__get_url_rev_and_auth[bzr+ftp://bzr.myproject.org/MyProject/trunk/#egg=MyProject-ftp://bzr.myproject.org/MyProject/trunk/] tests/unit/test_vcs.py::test_bazaar__get_url_rev_and_auth[bzr+sftp://bzr.myproject.org/MyProject/trunk/#egg=MyProject-sftp://bzr.myproject.org/MyProject/trunk/] tests/unit/test_vcs.py::test_bazaar__get_url_rev_and_auth[bzr+lp:MyLaunchpadProject#egg=MyLaunchpadProject-lp:MyLaunchpadProject] tests/unit/test_vcs.py::test_bazaar__get_url_rev_and_auth[bzr+ssh://bzr.myproject.org/MyProject/trunk/#egg=MyProject-bzr+ssh://bzr.myproject.org/MyProject/trunk/] tests/unit/test_vcs.py::test_subversion__get_url_rev_and_auth[svn+https://svn.example.com/MyProject#egg=MyProject-expected0] tests/unit/test_vcs.py::test_subversion__get_url_rev_and_auth[svn+https://user:pass@svn.example.com/MyProject#egg=MyProject-expected1] tests/unit/test_vcs.py::test_subversion__get_url_rev_and_auth[svn+ssh://svn.example.com/MyProject#egg=MyProject-expected2] tests/unit/test_vcs.py::test_subversion__get_url_rev_and_auth[svn+ssh://user@svn.example.com/MyProject#egg=MyProject-expected3] tests/unit/test_vcs.py::test_git__make_rev_args[None-None-expected0] tests/unit/test_vcs.py::test_git__make_rev_args[user-None-expected1] tests/unit/test_vcs.py::test_git__make_rev_args[user-pass-expected2] tests/unit/test_vcs.py::test_subversion__make_rev_args[None-None-expected0] tests/unit/test_vcs.py::test_subversion__make_rev_args[user-None-expected1] tests/unit/test_vcs.py::test_subversion__make_rev_args[user-pass-expected2] tests/unit/test_vcs.py::test_subversion__get_url_rev_options tests/unit/test_vcs.py::test_get_git_version tests/unit/test_vcs.py::test_subversion__init_use_interactive[None-False-False] tests/unit/test_vcs.py::test_subversion__init_use_interactive[None-True-True] tests/unit/test_vcs.py::test_subversion__init_use_interactive[False-False-False] tests/unit/test_vcs.py::test_subversion__init_use_interactive[False-True-False] tests/unit/test_vcs.py::test_subversion__init_use_interactive[True-False-True] tests/unit/test_vcs.py::test_subversion__init_use_interactive[True-True-True] tests/unit/test_vcs.py::test_subversion__call_vcs_version tests/unit/test_vcs.py::test_subversion__call_vcs_version_patched[svn, tests/unit/test_vcs.py::test_subversion__call_vcs_version_patched[svn tests/unit/test_vcs.py::test_subversion__call_vcs_version_patched[-expected_version8] tests/unit/test_vcs.py::test_subversion__call_vcs_version_svn_not_installed tests/unit/test_vcs.py::test_subversion__get_vcs_version_cached[version0] tests/unit/test_vcs.py::test_subversion__get_vcs_version_cached[version1] tests/unit/test_vcs.py::test_subversion__get_vcs_version_cached[version2] tests/unit/test_vcs.py::test_subversion__get_vcs_version_cached[version3] tests/unit/test_vcs.py::test_subversion__get_vcs_version_call_vcs[vcs_version0] tests/unit/test_vcs.py::test_subversion__get_vcs_version_call_vcs[vcs_version1] tests/unit/test_vcs.py::test_subversion__get_vcs_version_call_vcs[vcs_version2] tests/unit/test_vcs.py::test_subversion__get_remote_call_options[False-vcs_version0-expected_options0] tests/unit/test_vcs.py::test_subversion__get_remote_call_options[False-vcs_version1-expected_options1] tests/unit/test_vcs.py::test_subversion__get_remote_call_options[False-vcs_version2-expected_options2] tests/unit/test_vcs.py::test_subversion__get_remote_call_options[True-vcs_version3-expected_options3] tests/unit/test_vcs.py::test_subversion__get_remote_call_options[True-vcs_version4-expected_options4] tests/unit/test_vcs.py::test_subversion__get_remote_call_options[True-vcs_version5-expected_options5]
news/6579.trivial docs/html/reference/pip_install.rst src/pip/_internal/distributions/__init__.py src/pip/_internal/req/req_file.py src/pip/_internal/download.py src/pip/_internal/commands/list.py news/3799.feature src/pip/_internal/legacy_resolve.py src/pip/_internal/commands/freeze.py src/pip/_internal/operations/check.py src/pip/_internal/index.py src/pip/_internal/req/constructors.py .github/CONTRIBUTING.md src/pip/_internal/distributions/base.py news/6527.bugfix src/pip/_internal/distributions/source.py src/pip/_internal/cli/cmdoptions.py src/pip/_internal/operations/prepare.py src/pip/_internal/distributions/installed.py src/pip/_internal/distributions/wheel.py
news/6579.trivial docs/html/reference/pip_install.rst src/pip/_internal/distributions/__init__.py src/pip/_internal/req/req_file.py src/pip/_internal/download.py src/pip/_internal/commands/list.py news/3799.feature src/pip/_internal/legacy_resolve.py src/pip/_internal/commands/freeze.py src/pip/_internal/operations/check.py src/pip/_internal/index.py src/pip/_internal/req/constructors.py .github/CONTRIBUTING.md src/pip/_internal/distributions/base.py news/6527.bugfix src/pip/_internal/distributions/source.py src/pip/_internal/cli/cmdoptions.py src/pip/_internal/operations/prepare.py src/pip/_internal/distributions/installed.py src/pip/_internal/distributions/wheel.py