| class AbstractProvider(object): | |
| """Delegate class to provide requirement interface for the resolver.""" | |
| def identify(self, requirement_or_candidate): | |
| """Given a requirement, return an identifier for it. | |
| This is used to identify a requirement, e.g. whether two requirements | |
| should have their specifier parts merged. | |
| """ | |
| raise NotImplementedError | |
| def get_preference( | |
| self, | |
| identifier, | |
| resolutions, | |
| candidates, | |
| information, | |
| backtrack_causes, | |
| ): | |
| """Produce a sort key for given requirement based on preference. | |
| 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 dependency matches of which should be returned. | |
| :param resolutions: Mapping of candidates currently pinned by the | |
| resolver. Each key is an identifier, and the value 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 were | |
| 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 (dependend on) the | |
| requirement, or ``None`` to indicate a root requirement. | |
| The preference could depend on a various of 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, requirements, incompatibilities): | |
| """Find all possible candidates that satisfy given constraints. | |
| :param identifier: An identifier as returned by ``identify()``. This | |
| identifies the dependency matches of which should be returned. | |
| :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 incompatibilities 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, candidate): | |
| """Whether the given requirement can be satisfied by a candidate. | |
| The candidate is guarenteed 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): | |
| """Get dependencies of a candidate. | |
| This should return a collection of requirements that `candidate` | |
| specifies as its dependencies. | |
| """ | |
| raise NotImplementedError | |
| class AbstractResolver(object): | |
| """The thing that performs the actual resolution work.""" | |
| base_exception = Exception | |
| def __init__(self, provider, reporter): | |
| self.provider = provider | |
| self.reporter = reporter | |
| def resolve(self, requirements, **kwargs): | |
| """Take a collection of constraints, spit out the resolution result. | |
| This returns a representation of the final resolution state, with one | |
| guarenteed attribute ``mapping`` that contains resolved candidates as | |
| values. The keys are their respective identifiers. | |
| :param requirements: A collection of constraints. | |
| :param kwargs: Additional keyword arguments that subclasses may accept. | |
| :raises: ``self.base_exception`` or its subclass. | |
| """ | |
| raise NotImplementedError | |