Skip to content

Commit

Permalink
Make resolvelib.resolvers a sub-package
Browse files Browse the repository at this point in the history
This makes the `Resolver` object live in a diffferent module than the
`AbstractResolver`, clarifying their separation and more cleanly
accomodating additional resolver implementations.
  • Loading branch information
pradyunsg committed Dec 9, 2023
1 parent c1bc75e commit f6a8b32
Show file tree
Hide file tree
Showing 6 changed files with 61 additions and 57 deletions.
4 changes: 2 additions & 2 deletions src/resolvelib/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,8 @@

from .providers import AbstractProvider
from .reporters import BaseReporter
from .resolvers import (
AbstractResolver,
from .resolvers.abstract import AbstractResolver
from .resolvers.criterion import (
InconsistentCandidate,
RequirementsConflicted,
ResolutionError,
Expand Down
Empty file.
49 changes: 49 additions & 0 deletions src/resolvelib/resolvers/abstract.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
from __future__ import annotations

import collections
from typing import TYPE_CHECKING, Any, Generic, Iterable, Mapping, NamedTuple

from resolvelib.providers import AbstractProvider
from resolvelib.reporters import BaseReporter

from ..structs import CT, KT, RT, Criterion, DirectedGraph

if TYPE_CHECKING:

class Result(NamedTuple, Generic[RT, CT, KT]):
mapping: Mapping[KT, CT]
graph: DirectedGraph[KT | None]
criteria: Mapping[KT, Criterion[RT, CT]]

else:
Result = collections.namedtuple("Result", ["mapping", "graph", "criteria"])


class AbstractResolver(Generic[RT, CT, KT]):
"""The thing that performs the actual resolution work."""

base_exception = Exception

def __init__(
self,
provider: AbstractProvider[RT, CT, KT],
reporter: BaseReporter[RT, CT, KT],
) -> None:
self.provider = provider
self.reporter = reporter

def resolve(
self, requirements: Iterable[RT], **kwargs: Any
) -> Result[RT, CT, KT]:
"""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
Original file line number Diff line number Diff line change
Expand Up @@ -3,19 +3,11 @@
import collections
import itertools
import operator
from typing import (
TYPE_CHECKING,
Any,
Collection,
Generic,
Iterable,
Mapping,
NamedTuple,
)
from typing import TYPE_CHECKING, Collection, Generic, Iterable, Mapping

from .providers import AbstractProvider
from .reporters import BaseReporter
from .structs import (
from ..providers import AbstractProvider
from ..reporters import BaseReporter
from ..structs import (
CT,
KT,
RT,
Expand All @@ -27,17 +19,10 @@
State,
build_iter_view,
)
from .abstract import AbstractResolver, Result

if TYPE_CHECKING:
from .providers import Preference

class Result(NamedTuple, Generic[RT, CT, KT]):
mapping: Mapping[KT, CT]
graph: DirectedGraph[KT | None]
criteria: Mapping[KT, Criterion[RT, CT]]

else:
Result = collections.namedtuple("Result", ["mapping", "graph", "criteria"])
from ..providers import Preference


class ResolverException(Exception):
Expand Down Expand Up @@ -525,36 +510,6 @@ def _build_result(state: State[RT, CT, KT]) -> Result[RT, CT, KT]:
)


class AbstractResolver(Generic[RT, CT, KT]):
"""The thing that performs the actual resolution work."""

base_exception = Exception

def __init__(
self,
provider: AbstractProvider[RT, CT, KT],
reporter: BaseReporter[RT, CT, KT],
) -> None:
self.provider = provider
self.reporter = reporter

def resolve(
self, requirements: Iterable[RT], **kwargs: Any
) -> Result[RT, CT, KT]:
"""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


class Resolver(AbstractResolver[RT, CT, KT]):
"""The thing that performs the actual resolution work."""

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@

import pytest

from resolvelib import Resolver
from resolvelib.providers import AbstractProvider
from resolvelib.resolvers import Resolver

Requirement = collections.namedtuple("Requirement", "container constraint")
Candidate = collections.namedtuple("Candidate", "container version")
Expand Down
6 changes: 3 additions & 3 deletions tests/test_resolvers.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,12 +14,12 @@
ResolutionImpossible,
Resolver,
)
from resolvelib.resolvers import Resolution
from resolvelib.resolvers.criterion import Resolution

if TYPE_CHECKING:
from typing import Iterable, Mapping

from resolvelib.resolvers import (
from resolvelib.resolvers.criterion import (
Criterion,
RequirementInformation,
RequirementsConflicted,
Expand Down Expand Up @@ -261,7 +261,7 @@ def get_updated_criteria_patch(self, candidate):
result = resolver.resolve(["child", "parent"])

def get_child_versions(
information: Iterable[RequirementInformation[str, Candidate]]
information: Iterable[RequirementInformation[str, Candidate]],
) -> set[str]:
return {
str(inf.parent[1])
Expand Down

0 comments on commit f6a8b32

Please sign in to comment.