Skip to content

Commit b441f48

Browse files
committed
Refactor root requirement collection into factory
1 parent a53af79 commit b441f48

File tree

2 files changed

+50
-42
lines changed

2 files changed

+50
-42
lines changed

src/pip/_internal/resolution/resolvelib/factory.py

Lines changed: 43 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
Iterator,
1010
List,
1111
Mapping,
12+
NamedTuple,
1213
Optional,
1314
Sequence,
1415
Set,
@@ -38,7 +39,10 @@
3839
from pip._internal.models.wheel import Wheel
3940
from pip._internal.operations.prepare import RequirementPreparer
4041
from pip._internal.req.constructors import install_req_from_link_and_ireq
41-
from pip._internal.req.req_install import InstallRequirement
42+
from pip._internal.req.req_install import (
43+
InstallRequirement,
44+
check_invalid_constraint_type,
45+
)
4246
from pip._internal.resolution.base import InstallRequirementProvider
4347
from pip._internal.utils.compatibility_tags import get_supported
4448
from pip._internal.utils.hashes import Hashes
@@ -81,6 +85,12 @@ class ConflictCause(Protocol):
8185
Cache = Dict[Link, C]
8286

8387

88+
class CollectedRootRequirements(NamedTuple):
89+
requirements: List[Requirement]
90+
constraints: Dict[str, Constraint]
91+
user_requested: Dict[str, int]
92+
93+
8494
class Factory:
8595
def __init__(
8696
self,
@@ -414,7 +424,7 @@ def find_candidates(
414424
and all(req.is_satisfied_by(c) for req in requirements[identifier])
415425
)
416426

417-
def make_requirement_from_install_req(self, ireq, requested_extras):
427+
def _make_requirement_from_install_req(self, ireq, requested_extras):
418428
# type: (InstallRequirement, Iterable[str]) -> Optional[Requirement]
419429
if not ireq.match_markers(requested_extras):
420430
logger.info(
@@ -445,6 +455,36 @@ def make_requirement_from_install_req(self, ireq, requested_extras):
445455
return UnsatisfiableRequirement(canonicalize_name(ireq.name))
446456
return self.make_requirement_from_candidate(cand)
447457

458+
def collect_root_requirements(self, root_ireqs):
459+
# type: (List[InstallRequirement]) -> CollectedRootRequirements
460+
collected = CollectedRootRequirements([], {}, {})
461+
for i, ireq in enumerate(root_ireqs):
462+
if ireq.constraint:
463+
# Ensure we only accept valid constraints
464+
problem = check_invalid_constraint_type(ireq)
465+
if problem:
466+
raise InstallationError(problem)
467+
if not ireq.match_markers():
468+
continue
469+
assert ireq.name, "Constraint must be named"
470+
name = canonicalize_name(ireq.name)
471+
if name in collected.constraints:
472+
collected.constraints[name] &= ireq
473+
else:
474+
collected.constraints[name] = Constraint.from_ireq(ireq)
475+
else:
476+
if ireq.user_supplied and ireq.name:
477+
canonical_name = canonicalize_name(ireq.name)
478+
if canonical_name not in collected.user_requested:
479+
collected.user_requested[canonical_name] = i
480+
req = self._make_requirement_from_install_req(
481+
ireq,
482+
requested_extras=(),
483+
)
484+
if req is not None:
485+
collected.requirements.append(req)
486+
return collected
487+
448488
def make_requirement_from_candidate(self, candidate):
449489
# type: (Candidate) -> ExplicitRequirement
450490
return ExplicitRequirement(candidate)
@@ -457,7 +497,7 @@ def make_requirement_from_spec(
457497
):
458498
# type: (...) -> Optional[Requirement]
459499
ireq = self._make_install_req_from_spec(specifier, comes_from)
460-
return self.make_requirement_from_install_req(ireq, requested_extras)
500+
return self._make_requirement_from_install_req(ireq, requested_extras)
461501

462502
def make_requires_python_requirement(self, specifier):
463503
# type: (Optional[SpecifierSet]) -> Optional[Requirement]

src/pip/_internal/resolution/resolvelib/resolver.py

Lines changed: 7 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -10,13 +10,9 @@
1010
from pip._vendor.resolvelib.structs import DirectedGraph
1111

1212
from pip._internal.cache import WheelCache
13-
from pip._internal.exceptions import InstallationError
1413
from pip._internal.index.package_finder import PackageFinder
1514
from pip._internal.operations.prepare import RequirementPreparer
16-
from pip._internal.req.req_install import (
17-
InstallRequirement,
18-
check_invalid_constraint_type,
19-
)
15+
from pip._internal.req.req_install import InstallRequirement
2016
from pip._internal.req.req_set import RequirementSet
2117
from pip._internal.resolution.base import BaseResolver, InstallRequirementProvider
2218
from pip._internal.resolution.resolvelib.provider import PipProvider
@@ -28,7 +24,7 @@
2824
from pip._internal.utils.filetypes import is_archive_file
2925
from pip._internal.utils.misc import dist_is_editable
3026

31-
from .base import Candidate, Constraint, Requirement
27+
from .base import Candidate, Requirement
3228
from .factory import Factory
3329

3430
if TYPE_CHECKING:
@@ -77,41 +73,13 @@ def __init__(
7773

7874
def resolve(self, root_reqs, check_supported_wheels):
7975
# type: (List[InstallRequirement], bool) -> RequirementSet
80-
81-
constraints = {} # type: Dict[str, Constraint]
82-
user_requested = {} # type: Dict[str, int]
83-
requirements = []
84-
for i, req in enumerate(root_reqs):
85-
if req.constraint:
86-
# Ensure we only accept valid constraints
87-
problem = check_invalid_constraint_type(req)
88-
if problem:
89-
raise InstallationError(problem)
90-
if not req.match_markers():
91-
continue
92-
assert req.name, "Constraint must be named"
93-
name = canonicalize_name(req.name)
94-
if name in constraints:
95-
constraints[name] &= req
96-
else:
97-
constraints[name] = Constraint.from_ireq(req)
98-
else:
99-
if req.user_supplied and req.name:
100-
canonical_name = canonicalize_name(req.name)
101-
if canonical_name not in user_requested:
102-
user_requested[canonical_name] = i
103-
r = self.factory.make_requirement_from_install_req(
104-
req, requested_extras=()
105-
)
106-
if r is not None:
107-
requirements.append(r)
108-
76+
collected = self.factory.collect_root_requirements(root_reqs)
10977
provider = PipProvider(
11078
factory=self.factory,
111-
constraints=constraints,
79+
constraints=collected.constraints,
11280
ignore_dependencies=self.ignore_dependencies,
11381
upgrade_strategy=self.upgrade_strategy,
114-
user_requested=user_requested,
82+
user_requested=collected.user_requested,
11583
)
11684
if "PIP_RESOLVER_DEBUG" in os.environ:
11785
reporter = PipDebuggingReporter() # type: BaseReporter
@@ -125,13 +93,13 @@ def resolve(self, root_reqs, check_supported_wheels):
12593
try:
12694
try_to_avoid_resolution_too_deep = 2000000
12795
result = self._result = resolver.resolve(
128-
requirements, max_rounds=try_to_avoid_resolution_too_deep
96+
collected.requirements, max_rounds=try_to_avoid_resolution_too_deep
12997
)
13098

13199
except ResolutionImpossible as e:
132100
error = self.factory.get_installation_error(
133101
cast("ResolutionImpossible[Requirement, Candidate]", e),
134-
constraints,
102+
collected.constraints,
135103
)
136104
raise error from e
137105

0 commit comments

Comments
 (0)