diff --git a/src/pip/_internal/req/req_install.py b/src/pip/_internal/req/req_install.py index 1d3ee5edc68..7538c9546ca 100644 --- a/src/pip/_internal/req/req_install.py +++ b/src/pip/_internal/req/req_install.py @@ -864,3 +864,35 @@ def install( raise self.install_succeeded = success + + +def check_invalid_constraint_type(req): + # type: (InstallRequirement) -> str + + # Check for unsupported forms + problem = "" + if not req.name: + problem = "Unnamed requirements are not allowed as constraints" + elif req.link: + problem = "Links are not allowed as constraints" + elif req.extras: + problem = "Constraints cannot have extras" + + if problem: + deprecated( + reason=( + "Constraints are only allowed to take the form of a package " + "name and a version specifier. Other forms were originally " + "permitted as an accident of the implementation, but were " + "undocumented. The new implementation of the resolver no " + "longer supports these forms." + ), + replacement=( + "replacing the constraint with a requirement." + ), + # No plan yet for when the new resolver becomes default + gone_in=None, + issue=8210 + ) + + return problem diff --git a/src/pip/_internal/resolution/legacy/resolver.py b/src/pip/_internal/resolution/legacy/resolver.py index 7fdff1bc4f3..51a1d0b5dcb 100644 --- a/src/pip/_internal/resolution/legacy/resolver.py +++ b/src/pip/_internal/resolution/legacy/resolver.py @@ -28,6 +28,7 @@ HashErrors, UnsupportedPythonVersion, ) +from pip._internal.req.req_install import check_invalid_constraint_type from pip._internal.req.req_set import RequirementSet from pip._internal.resolution.base import BaseResolver from pip._internal.utils.compatibility_tags import get_supported @@ -167,6 +168,8 @@ def resolve(self, root_reqs, check_supported_wheels): check_supported_wheels=check_supported_wheels ) for req in root_reqs: + if req.constraint: + check_invalid_constraint_type(req) requirement_set.add_requirement(req) # Actually prepare the files, and collect any exceptions. Most hash diff --git a/src/pip/_internal/resolution/resolvelib/resolver.py b/src/pip/_internal/resolution/resolvelib/resolver.py index 35941d19e98..841057135a7 100644 --- a/src/pip/_internal/resolution/resolvelib/resolver.py +++ b/src/pip/_internal/resolution/resolvelib/resolver.py @@ -7,10 +7,10 @@ from pip._vendor.resolvelib import Resolver as RLResolver from pip._internal.exceptions import InstallationError +from pip._internal.req.req_install import check_invalid_constraint_type from pip._internal.req.req_set import RequirementSet from pip._internal.resolution.base import BaseResolver from pip._internal.resolution.resolvelib.provider import PipProvider -from pip._internal.utils.deprecation import deprecated from pip._internal.utils.typing import MYPY_CHECK_RUNNING from .factory import Factory @@ -32,37 +32,6 @@ logger = logging.getLogger(__name__) -def reject_invalid_constraint_types(req): - # type: (InstallRequirement) -> None - - # Check for unsupported forms - problem = "" - if not req.name: - problem = "Unnamed requirements are not allowed as constraints" - elif req.link: - problem = "Links are not allowed as constraints" - elif req.extras: - problem = "Constraints cannot have extras" - - if problem: - deprecated( - reason=( - "Constraints are only allowed to take the form of a package " - "name and a version specifier. Other forms were originally " - "permitted as an accident of the implementation, but were " - "undocumented. The new implementation of the resolver no " - "longer supports these forms." - ), - replacement=( - "replacing the constraint with a requirement." - ), - # No plan yet for when the new resolver becomes default - gone_in=None, - issue=8210 - ) - raise InstallationError(problem) - - class Resolver(BaseResolver): _allowed_strategies = {"eager", "only-if-needed", "to-satisfy-only"} @@ -108,7 +77,9 @@ def resolve(self, root_reqs, check_supported_wheels): for req in root_reqs: if req.constraint: # Ensure we only accept valid constraints - reject_invalid_constraint_types(req) + problem = check_invalid_constraint_type(req) + if problem: + raise InstallationError(problem) name = canonicalize_name(req.name) if name in constraints: diff --git a/tests/functional/test_install_reqs.py b/tests/functional/test_install_reqs.py index 577feb0eabf..ae90a041b54 100644 --- a/tests/functional/test_install_reqs.py +++ b/tests/functional/test_install_reqs.py @@ -344,6 +344,7 @@ def test_constraints_constrain_to_local_editable( result = script.pip( 'install', '--no-index', '-f', data.find_links, '-c', script.scratch_path / 'constraints.txt', 'singlemodule', + allow_stderr_warning=True, expect_error=use_new_resolver ) if use_new_resolver: @@ -360,6 +361,7 @@ def test_constraints_constrain_to_local(script, data, use_new_resolver): result = script.pip( 'install', '--no-index', '-f', data.find_links, '-c', script.scratch_path / 'constraints.txt', 'singlemodule', + allow_stderr_warning=True, expect_error=use_new_resolver ) if use_new_resolver: @@ -375,6 +377,7 @@ def test_constrained_to_url_install_same_url(script, data, use_new_resolver): result = script.pip( 'install', '--no-index', '-f', data.find_links, '-c', script.scratch_path / 'constraints.txt', to_install, + allow_stderr_warning=True, expect_error=use_new_resolver ) if use_new_resolver: @@ -425,6 +428,7 @@ def test_install_with_extras_from_constraints(script, data, use_new_resolver): ) result = script.pip_install_local( '-c', script.scratch_path / 'constraints.txt', 'LocalExtras', + allow_stderr_warning=True, expect_error=use_new_resolver ) if use_new_resolver: @@ -456,6 +460,7 @@ def test_install_with_extras_joined(script, data, use_new_resolver): ) result = script.pip_install_local( '-c', script.scratch_path / 'constraints.txt', 'LocalExtras[baz]', + allow_stderr_warning=True, expect_error=use_new_resolver ) if use_new_resolver: @@ -472,6 +477,7 @@ def test_install_with_extras_editable_joined(script, data, use_new_resolver): ) result = script.pip_install_local( '-c', script.scratch_path / 'constraints.txt', 'LocalExtras[baz]', + allow_stderr_warning=True, expect_error=use_new_resolver ) if use_new_resolver: @@ -510,6 +516,7 @@ def test_install_distribution_union_with_constraints( "{to_install}[bar]".format(**locals())) result = script.pip_install_local( '-c', script.scratch_path / 'constraints.txt', to_install + '[baz]', + allow_stderr_warning=True, expect_error=use_new_resolver ) if use_new_resolver: