diff --git a/news/8085.feature b/news/8085.feature new file mode 100644 index 00000000000..e1d56dd2aab --- /dev/null +++ b/news/8085.feature @@ -0,0 +1,5 @@ +Add a ``--prefer-minimum-versions`` command line flag to tell pip to +use older versions instead of newer versions for all +dependencies. This is useful for running test suites using the "lower +bounds" of requirements to ensure that they are accurate. The flag is +only available when the new resolver is enabled. diff --git a/src/pip/_internal/cli/cmdoptions.py b/src/pip/_internal/cli/cmdoptions.py index ff9acfd4644..5ba79b1ce1c 100644 --- a/src/pip/_internal/cli/cmdoptions.py +++ b/src/pip/_internal/cli/cmdoptions.py @@ -930,6 +930,17 @@ def check_list_path_option(options): ) # type: Callable[..., Option] +prefer_minimum_versions = partial( + Option, + '--prefer-minimum-versions', + dest='prefer_minimum_versions', + action='store_true', + default=False, + help=SUPPRESS_HELP, # TODO: Enable this when the resolver actually works. + # help='Use the lowest version that matches a requirement.', +) # type: Callable[..., Option] + + ########## # groups # ########## diff --git a/src/pip/_internal/cli/req_command.py b/src/pip/_internal/cli/req_command.py index 104b033281f..c722ae6e3e6 100644 --- a/src/pip/_internal/cli/req_command.py +++ b/src/pip/_internal/cli/req_command.py @@ -200,6 +200,7 @@ def __init__(self, *args, **kw): super(RequirementCommand, self).__init__(*args, **kw) self.cmd_opts.add_option(cmdoptions.no_clean()) + self.cmd_opts.add_option(cmdoptions.prefer_minimum_versions()) @staticmethod def make_requirement_preparer( @@ -274,6 +275,7 @@ def make_resolver( force_reinstall=force_reinstall, upgrade_strategy=upgrade_strategy, py_version_info=py_version_info, + prefer_minimum_versions=options.prefer_minimum_versions, ) import pip._internal.resolution.legacy.resolver return pip._internal.resolution.legacy.resolver.Resolver( diff --git a/src/pip/_internal/resolution/resolvelib/provider.py b/src/pip/_internal/resolution/resolvelib/provider.py index 5c3d210a31a..0579f361d90 100644 --- a/src/pip/_internal/resolution/resolvelib/provider.py +++ b/src/pip/_internal/resolution/resolvelib/provider.py @@ -16,10 +16,12 @@ def __init__( self, factory, # type: Factory ignore_dependencies, # type: bool + prefer_minimum_versions=False, # type: bool ): # type: (...) -> None self._factory = factory self._ignore_dependencies = ignore_dependencies + self._prefer_minimum_versions = prefer_minimum_versions def get_install_requirement(self, c): # type: (Candidate) -> Optional[InstallRequirement] @@ -36,12 +38,14 @@ def get_preference( information # type: Sequence[Tuple[Requirement, Candidate]] ): # type: (...) -> Any - # Use the "usual" value for now return len(candidates) def find_matches(self, requirement): # type: (Requirement) -> Sequence[Candidate] - return requirement.find_matches() + results = requirement.find_matches() + if self._prefer_minimum_versions: + results = list(reversed(results)) + return results def is_satisfied_by(self, requirement, candidate): # type: (Requirement, Candidate) -> bool diff --git a/src/pip/_internal/resolution/resolvelib/resolver.py b/src/pip/_internal/resolution/resolvelib/resolver.py index cba5a496508..9033e405334 100644 --- a/src/pip/_internal/resolution/resolvelib/resolver.py +++ b/src/pip/_internal/resolution/resolvelib/resolver.py @@ -43,6 +43,7 @@ def __init__( force_reinstall, # type: bool upgrade_strategy, # type: str py_version_info=None, # type: Optional[Tuple[int, ...]] + prefer_minimum_versions=False, # type: bool ): super(Resolver, self).__init__() self.factory = Factory( @@ -55,6 +56,7 @@ def __init__( py_version_info=py_version_info, ) self.ignore_dependencies = ignore_dependencies + self.prefer_minimum_versions = prefer_minimum_versions self._result = None # type: Optional[Result] def resolve(self, root_reqs, check_supported_wheels): @@ -67,6 +69,7 @@ def resolve(self, root_reqs, check_supported_wheels): provider = PipProvider( factory=self.factory, ignore_dependencies=self.ignore_dependencies, + prefer_minimum_versions=self.prefer_minimum_versions, ) reporter = BaseReporter() resolver = RLResolver(provider, reporter)