| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196 |
- from __future__ import annotations
- from typing import (
- TYPE_CHECKING,
- Generic,
- Iterable,
- Iterator,
- Mapping,
- Sequence,
- )
- from .structs import CT, KT, RT, Matches, RequirementInformation
- if TYPE_CHECKING:
- from typing import Any, Protocol
- class Preference(Protocol):
- def __lt__(self, __other: Any) -> bool: ...
- class AbstractProvider(Generic[RT, CT, KT]):
- """Delegate class to provide the required interface for the resolver."""
- def identify(self, requirement_or_candidate: RT | CT) -> KT:
- """Given a requirement or candidate, return an identifier for it.
- This is used to identify, e.g. whether two requirements
- should have their specifier parts merged or a candidate matches a
- requirement via ``find_matches()``.
- """
- raise NotImplementedError
- def get_preference(
- self,
- identifier: KT,
- resolutions: Mapping[KT, CT],
- candidates: Mapping[KT, Iterator[CT]],
- information: Mapping[KT, Iterator[RequirementInformation[RT, CT]]],
- backtrack_causes: Sequence[RequirementInformation[RT, CT]],
- ) -> Preference:
- """Produce a sort key for given requirement based on preference.
- As this is a sort key it will be called O(n) times per backtrack
- step, where n is the number of `identifier`s, if you have a check
- which is expensive in some sense. E.g. It needs to make O(n) checks
- per call or takes significant wall clock time, consider using
- `narrow_requirement_selection` to filter the `identifier`s, which
- is applied before this sort key is called.
- The preference is defined as "I think this requirement should be
- resolved first". The lower the return value is, the more preferred
- this group of arguments is.
- :param identifier: An identifier as returned by ``identify()``. This
- identifies the requirement being considered.
- :param resolutions: Mapping of candidates currently pinned by the
- resolver. Each key is an identifier, and the value is a candidate.
- The candidate may conflict with requirements from ``information``.
- :param candidates: Mapping of each dependency's possible candidates.
- Each value is an iterator of candidates.
- :param information: Mapping of requirement information of each package.
- Each value is an iterator of *requirement information*.
- :param backtrack_causes: Sequence of *requirement information* that are
- the requirements that caused the resolver to most recently
- backtrack.
- A *requirement information* instance is a named tuple with two members:
- * ``requirement`` specifies a requirement contributing to the current
- list of candidates.
- * ``parent`` specifies the candidate that provides (depended on) the
- requirement, or ``None`` to indicate a root requirement.
- The preference could depend on various issues, including (not
- necessarily in this order):
- * Is this package pinned in the current resolution result?
- * How relaxed is the requirement? Stricter ones should probably be
- worked on first? (I don't know, actually.)
- * How many possibilities are there to satisfy this requirement? Those
- with few left should likely be worked on first, I guess?
- * Are there any known conflicts for this requirement? We should
- probably work on those with the most known conflicts.
- A sortable value should be returned (this will be used as the ``key``
- parameter of the built-in sorting function). The smaller the value is,
- the more preferred this requirement is (i.e. the sorting function
- is called with ``reverse=False``).
- """
- raise NotImplementedError
- def find_matches(
- self,
- identifier: KT,
- requirements: Mapping[KT, Iterator[RT]],
- incompatibilities: Mapping[KT, Iterator[CT]],
- ) -> Matches[CT]:
- """Find all possible candidates that satisfy the given constraints.
- :param identifier: An identifier as returned by ``identify()``. All
- candidates returned by this method should produce the same
- identifier.
- :param requirements: A mapping of requirements that all returned
- candidates must satisfy. Each key is an identifier, and the value
- an iterator of requirements for that dependency.
- :param incompatibilities: A mapping of known incompatibile candidates of
- each dependency. Each key is an identifier, and the value an
- iterator of incompatibilities known to the resolver. All
- incompatibilities *must* be excluded from the return value.
- This should try to get candidates based on the requirements' types.
- For VCS, local, and archive requirements, the one-and-only match is
- returned, and for a "named" requirement, the index(es) should be
- consulted to find concrete candidates for this requirement.
- The return value should produce candidates ordered by preference; the
- most preferred candidate should come first. The return type may be one
- of the following:
- * A callable that returns an iterator that yields candidates.
- * An collection of candidates.
- * An iterable of candidates. This will be consumed immediately into a
- list of candidates.
- """
- raise NotImplementedError
- def is_satisfied_by(self, requirement: RT, candidate: CT) -> bool:
- """Whether the given requirement can be satisfied by a candidate.
- The candidate is guaranteed to have been generated from the
- requirement.
- A boolean should be returned to indicate whether ``candidate`` is a
- viable solution to the requirement.
- """
- raise NotImplementedError
- def get_dependencies(self, candidate: CT) -> Iterable[RT]:
- """Get dependencies of a candidate.
- This should return a collection of requirements that `candidate`
- specifies as its dependencies.
- """
- raise NotImplementedError
- def narrow_requirement_selection(
- self,
- identifiers: Iterable[KT],
- resolutions: Mapping[KT, CT],
- candidates: Mapping[KT, Iterator[CT]],
- information: Mapping[KT, Iterator[RequirementInformation[RT, CT]]],
- backtrack_causes: Sequence[RequirementInformation[RT, CT]],
- ) -> Iterable[KT]:
- """
- An optional method to narrow the selection of requirements being
- considered during resolution. This method is called O(1) time per
- backtrack step.
- :param identifiers: An iterable of `identifiers` as returned by
- ``identify()``. These identify all requirements currently being
- considered.
- :param resolutions: A mapping of candidates currently pinned by the
- resolver. Each key is an identifier, and the value is a candidate
- that may conflict with requirements from ``information``.
- :param candidates: A mapping of each dependency's possible candidates.
- Each value is an iterator of candidates.
- :param information: A mapping of requirement information for each package.
- Each value is an iterator of *requirement information*.
- :param backtrack_causes: A sequence of *requirement information* that are
- the requirements causing the resolver to most recently
- backtrack.
- A *requirement information* instance is a named tuple with two members:
- * ``requirement`` specifies a requirement contributing to the current
- list of candidates.
- * ``parent`` specifies the candidate that provides (is depended on for)
- the requirement, or ``None`` to indicate a root requirement.
- Must return a non-empty subset of `identifiers`, with the default
- implementation being to return `identifiers` unchanged. Those `identifiers`
- will then be passed to the sort key `get_preference` to pick the most
- prefered requirement to attempt to pin, unless `narrow_requirement_selection`
- returns only 1 requirement, in which case that will be used without
- calling the sort key `get_preference`.
- This method is designed to be used by the provider to optimize the
- dependency resolution, e.g. if a check cost is O(m) and it can be done
- against all identifiers at once then filtering the requirement selection
- here will cost O(m) but making it part of the sort key in `get_preference`
- will cost O(m*n), where n is the number of `identifiers`.
- Returns:
- Iterable[KT]: A non-empty subset of `identifiers`.
- """
- return identifiers
|