Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions news/10621.feature.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Optimize performance of conflict cause resolution while the dependency resolver backtracks.
34 changes: 26 additions & 8 deletions src/pip/_internal/resolution/resolvelib/provider.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@
Iterator,
Mapping,
Sequence,
Set,
Tuple,
TypeVar,
Union,
)
Expand Down Expand Up @@ -100,6 +102,7 @@ def __init__(
self._upgrade_strategy = upgrade_strategy
self._user_requested = user_requested
self._known_depths: Dict[str, float] = collections.defaultdict(lambda: math.inf)
self._backtrack_cause_name_collections: Dict[Tuple[int, ...], Set[str]] = {}

def identify(self, requirement_or_candidate: Union[Requirement, Candidate]) -> str:
return requirement_or_candidate.name
Expand Down Expand Up @@ -236,13 +239,28 @@ def get_dependencies(self, candidate: Candidate) -> Sequence[Requirement]:
with_requires = not self._ignore_dependencies
return [r for r in candidate.iter_dependencies(with_requires) if r is not None]

@staticmethod
def is_backtrack_cause(
identifier: str, backtrack_causes: Sequence["PreferenceInformation"]
self, identifier: str, backtrack_causes: Sequence["PreferenceInformation"]
) -> bool:
for backtrack_cause in backtrack_causes:
if identifier == backtrack_cause.requirement.name:
return True
if backtrack_cause.parent and identifier == backtrack_cause.parent.name:
return True
return False
return identifier in self._get_causes_set(backtrack_causes)

def _get_causes_set(
self,
backtrack_causes: Sequence["PreferenceInformation"],
) -> Set[str]:
backtrack_causes_collection_key = tuple(id(c) for c in backtrack_causes)
cached_names = self._backtrack_cause_name_collections.get(
backtrack_causes_collection_key
)
if cached_names is None:
self._backtrack_cause_name_collections.clear()
cached_names = set()
for backtrack_cause in backtrack_causes:
cached_names.add(backtrack_cause.requirement.name)
parent = backtrack_cause.parent
if parent:
cached_names.add(parent.name)
self._backtrack_cause_name_collections[
backtrack_causes_collection_key
] = cached_names
return cached_names