Script 'mail_helper' called by obssrc Hello community, here is the log from the commit of package python-resolvelib for openSUSE:Factory checked in at 2022-12-04 16:17:06 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/python-resolvelib (Old) and /work/SRC/openSUSE:Factory/.python-resolvelib.new.1835 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "python-resolvelib" Sun Dec 4 16:17:06 2022 rev:7 rq: version:0.8.1 Changes: -------- --- /work/SRC/openSUSE:Factory/python-resolvelib/python-resolvelib.changes 2022-12-04 14:59:15.736584108 +0100 +++ /work/SRC/openSUSE:Factory/.python-resolvelib.new.1835/python-resolvelib.changes 2022-12-04 16:17:07.375487179 +0100 @@ -2,12 +1,0 @@ -Sat Dec 3 21:52:31 UTC 2022 - Yogalakshmi Arunachalam <yarunacha...@suse.com> - -- Update to v0.9.0 - Features - * A new reporter hook rejecting_candidate is added, replacing backtracking. The hook is called every time the resolver - rejects a conflicting candidate before trying out the next one in line. #101 - Bug Fixes - * Some valid states that were previously rejected are now accepted. This affects states where multiple candidates for the - same dependency conflict with each other. The information argument passed to AbstractProvider.get_preference may now contain - empty iterators. This has always been allowed by the method definition but it was previously not possible in practice. #91 - -------------------------------------------------------------------- Old: ---- resolvelib-0.9.0.tar.gz New: ---- resolvelib-0.8.1.tar.gz ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ python-resolvelib.spec ++++++ --- /var/tmp/diff_new_pack.pOxwJI/_old 2022-12-04 16:17:08.047491046 +0100 +++ /var/tmp/diff_new_pack.pOxwJI/_new 2022-12-04 16:17:08.051491069 +0100 @@ -18,7 +18,7 @@ %{?!python_module:%define python_module() python-%{**} python3-%{**}} Name: python-resolvelib -Version: 0.9.0 +Version: 0.8.1 Release: 0 Summary: Module to resolve abstract dependencies into concrete ones License: ISC ++++++ resolvelib-0.9.0.tar.gz -> resolvelib-0.8.1.tar.gz ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/resolvelib-0.9.0/CHANGELOG.rst new/resolvelib-0.8.1/CHANGELOG.rst --- old/resolvelib-0.9.0/CHANGELOG.rst 2022-11-16 21:11:34.000000000 +0100 +++ new/resolvelib-0.8.1/CHANGELOG.rst 2021-10-11 23:05:57.000000000 +0200 @@ -1,25 +1,3 @@ -0.9.0 (2022-11-17) -================== - -Features --------- - -- A new reporter hook ``rejecting_candidate`` is added, replacing ``backtracking``. - The hook is called every time the resolver rejects a conflicting candidate before - trying out the next one in line. `#101 <https://github.com/sarugaku/resolvelib/issues/101>`_ - - -Bug Fixes ---------- - -- Some valid states that were previously rejected are now accepted. This affects - states where multiple candidates for the same dependency conflict with each - other. The ``information`` argument passed to - ``AbstractProvider.get_preference`` may now contain empty iterators. This has - always been allowed by the method definition but it was previously not possible - in practice. `#91 <https://github.com/sarugaku/resolvelib/issues/91>`_ - - 0.8.1 (2021-10-12) ================== diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/resolvelib-0.9.0/README.rst new/resolvelib-0.8.1/README.rst --- old/resolvelib-0.9.0/README.rst 2022-11-16 21:11:34.000000000 +0100 +++ new/resolvelib-0.8.1/README.rst 2021-10-11 23:05:57.000000000 +0200 @@ -56,8 +56,8 @@ ------- A string, usually in a number form, describing a snapshot of a Package. This -number should increase when a Package posts a new snapshot, -i.e a higher number means a more up-to-date snapshot. +number should increase when a Package post a new snapshot, i.e. a higher number +means a more up-to-date snapshot. Specifier --------- diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/resolvelib-0.9.0/noxfile.py new/resolvelib-0.8.1/noxfile.py --- old/resolvelib-0.9.0/noxfile.py 2022-11-16 21:11:34.000000000 +0100 +++ new/resolvelib-0.8.1/noxfile.py 2021-10-11 23:05:57.000000000 +0200 @@ -82,7 +82,7 @@ if options.version: _write_package_version(options.version) - session.run("towncrier", "build", "--version", options.version) + session.run("towncrier", "--version", options.version) session.run( "git", "commit", diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/resolvelib-0.9.0/setup.cfg new/resolvelib-0.8.1/setup.cfg --- old/resolvelib-0.9.0/setup.cfg 2022-11-16 21:11:34.000000000 +0100 +++ new/resolvelib-0.8.1/setup.cfg 2021-10-11 23:05:57.000000000 +0200 @@ -6,7 +6,6 @@ author = Tzu-ping Chung author_email = uranu...@gmail.com long_description = file: README.rst -long_description_content_type = text/x-rst license = ISC License keywords = dependency diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/resolvelib-0.9.0/src/resolvelib/__init__.py new/resolvelib-0.8.1/src/resolvelib/__init__.py --- old/resolvelib-0.9.0/src/resolvelib/__init__.py 2022-11-16 21:11:34.000000000 +0100 +++ new/resolvelib-0.8.1/src/resolvelib/__init__.py 2021-10-11 23:05:57.000000000 +0200 @@ -11,7 +11,7 @@ "ResolutionTooDeep", ] -__version__ = "0.9.0" +__version__ = "0.8.1" from .providers import AbstractProvider, AbstractResolver diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/resolvelib-0.9.0/src/resolvelib/compat/collections_abc.pyi new/resolvelib-0.8.1/src/resolvelib/compat/collections_abc.pyi --- old/resolvelib-0.9.0/src/resolvelib/compat/collections_abc.pyi 2022-11-16 21:11:34.000000000 +0100 +++ new/resolvelib-0.8.1/src/resolvelib/compat/collections_abc.pyi 1970-01-01 01:00:00.000000000 +0100 @@ -1 +0,0 @@ -from collections.abc import Mapping, Sequence diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/resolvelib-0.9.0/src/resolvelib/providers.py new/resolvelib-0.8.1/src/resolvelib/providers.py --- old/resolvelib-0.9.0/src/resolvelib/providers.py 2022-11-16 21:11:34.000000000 +0100 +++ new/resolvelib-0.8.1/src/resolvelib/providers.py 2021-10-11 23:05:57.000000000 +0200 @@ -1,5 +1,5 @@ class AbstractProvider(object): - """Delegate class to provide the required interface for the resolver.""" + """Delegate class to provide requirement interface for the resolver.""" def identify(self, requirement_or_candidate): """Given a requirement, return an identifier for it. @@ -24,9 +24,9 @@ this group of arguments is. :param identifier: An identifier as returned by ``identify()``. This - identifies the dependency matches which should be returned. + 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 is a candidate. + 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. @@ -39,10 +39,10 @@ * ``requirement`` specifies a requirement contributing to the current list of candidates. - * ``parent`` specifies the candidate that provides (depended on) the + * ``parent`` specifies the candidate that provides (dependend on) the requirement, or ``None`` to indicate a root requirement. - The preference could depend on various issues, including (not + The preference could depend on a various of issues, including (not necessarily in this order): * Is this package pinned in the current resolution result? @@ -61,7 +61,7 @@ raise NotImplementedError def find_matches(self, identifier, requirements, incompatibilities): - """Find all possible candidates that satisfy the given constraints. + """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. @@ -92,7 +92,7 @@ def is_satisfied_by(self, requirement, candidate): """Whether the given requirement can be satisfied by a candidate. - The candidate is guaranteed to have been generated from the + The candidate is guarenteed to have been generated from the requirement. A boolean should be returned to indicate whether ``candidate`` is a diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/resolvelib-0.9.0/src/resolvelib/providers.pyi new/resolvelib-0.8.1/src/resolvelib/providers.pyi --- old/resolvelib-0.9.0/src/resolvelib/providers.pyi 2022-11-16 21:11:34.000000000 +0100 +++ new/resolvelib-0.8.1/src/resolvelib/providers.pyi 2021-10-11 23:05:57.000000000 +0200 @@ -1,11 +1,12 @@ from typing import ( Any, + Collection, Generic, Iterable, Iterator, Mapping, + Optional, Protocol, - Sequence, Union, ) @@ -24,7 +25,6 @@ resolutions: Mapping[KT, CT], candidates: Mapping[KT, Iterator[CT]], information: Mapping[KT, Iterator[RequirementInformation[RT, CT]]], - backtrack_causes: Sequence[RequirementInformation[RT, CT]], ) -> Preference: ... def find_matches( self, diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/resolvelib-0.9.0/src/resolvelib/reporters.py new/resolvelib-0.8.1/src/resolvelib/reporters.py --- old/resolvelib-0.9.0/src/resolvelib/reporters.py 2022-11-16 21:11:34.000000000 +0100 +++ new/resolvelib-0.8.1/src/resolvelib/reporters.py 2021-10-11 23:05:57.000000000 +0200 @@ -36,7 +36,7 @@ :param causes: The information on the collision that caused the backtracking. """ - def rejecting_candidate(self, criterion, candidate): + def backtracking(self, candidate): """Called when rejecting a candidate during backtracking.""" def pinning(self, candidate): diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/resolvelib-0.9.0/src/resolvelib/reporters.pyi new/resolvelib-0.8.1/src/resolvelib/reporters.pyi --- old/resolvelib-0.9.0/src/resolvelib/reporters.pyi 2022-11-16 21:11:34.000000000 +0100 +++ new/resolvelib-0.8.1/src/resolvelib/reporters.pyi 2021-10-11 23:05:57.000000000 +0200 @@ -6,6 +6,6 @@ def ending_round(self, index: int, state: Any) -> Any: ... def ending(self, state: Any) -> Any: ... def adding_requirement(self, requirement: Any, parent: Any) -> Any: ... - def rejecting_candidate(self, criterion: Any, candidate: Any) -> Any: ... + def backtracking(self, candidate: Any) -> Any: ... def resolving_conflicts(self, causes: Any) -> Any: ... def pinning(self, candidate: Any) -> Any: ... diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/resolvelib-0.9.0/src/resolvelib/resolvers.py new/resolvelib-0.8.1/src/resolvelib/resolvers.py --- old/resolvelib-0.9.0/src/resolvelib/resolvers.py 2022-11-16 21:11:34.000000000 +0100 +++ new/resolvelib-0.8.1/src/resolvelib/resolvers.py 2021-10-11 23:05:57.000000000 +0200 @@ -173,31 +173,6 @@ raise RequirementsConflicted(criterion) criteria[identifier] = criterion - def _remove_information_from_criteria(self, criteria, parents): - """Remove information from parents of criteria. - - Concretely, removes all values from each criterion's ``information`` - field that have one of ``parents`` as provider of the requirement. - - :param criteria: The criteria to update. - :param parents: Identifiers for which to remove information from all criteria. - """ - if not parents: - return - for key, criterion in criteria.items(): - criteria[key] = Criterion( - criterion.candidates, - [ - information - for information in criterion.information - if ( - information[1] is None - or self._p.identify(information[1]) not in parents - ) - ], - criterion.incompatibilities, - ) - def _get_preference(self, name): return self._p.get_preference( identifier=name, @@ -237,7 +212,6 @@ try: criteria = self._get_updated_criteria(candidate) except RequirementsConflicted as e: - self._r.rejecting_candidate(e.criterion, candidate) causes.append(e.criterion) continue @@ -307,6 +281,8 @@ # Also mark the newly known incompatibility. incompatibilities_from_broken.append((name, [candidate])) + self._r.backtracking(candidate=candidate) + # Create a new state from the last known-to-work one, and apply # the previously gathered incompatibility information. def _patch_criteria(): @@ -392,11 +368,6 @@ self._r.ending(state=self.state) return self.state - # keep track of satisfied names to calculate diff after pinning - satisfied_names = set(self.state.criteria.keys()) - set( - unsatisfied_names - ) - # Choose the most preferred unpinned criterion to try. name = min(unsatisfied_names, key=self._get_preference) failure_causes = self._attempt_to_pin_criterion(name) @@ -413,17 +384,6 @@ if not success: raise ResolutionImpossible(self.state.backtrack_causes) else: - # discard as information sources any invalidated names - # (unsatisfied names that were previously satisfied) - newly_unsatisfied_names = { - key - for key, criterion in self.state.criteria.items() - if key in satisfied_names - and not self._is_current_pin_satisfying(key, criterion) - } - self._remove_information_from_criteria( - self.state.criteria, newly_unsatisfied_names - ) # Pinning was successful. Push a new state to do another pin. self._push_new_state() diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/resolvelib-0.9.0/src/resolvelib/resolvers.pyi new/resolvelib-0.8.1/src/resolvelib/resolvers.pyi --- old/resolvelib-0.9.0/src/resolvelib/resolvers.pyi 2022-11-16 21:11:34.000000000 +0100 +++ new/resolvelib-0.8.1/src/resolvelib/resolvers.pyi 2021-10-11 23:05:57.000000000 +0200 @@ -55,18 +55,6 @@ class ResolutionTooDeep(ResolutionError): round_count: int -# This should be a NamedTuple, but Python 3.6 has a bug that prevents it. -# https://stackoverflow.com/a/50531189/1376863 -class State(tuple, Generic[RT, CT, KT]): - mapping: Mapping[KT, CT] - criteria: Mapping[KT, Criterion[RT, CT, KT]] - backtrack_causes: Collection[RequirementInformation[RT, CT]] - -class Resolution(Generic[RT, CT, KT]): - def resolve( - self, requirements: Iterable[RT], max_rounds: int - ) -> State[RT, CT, KT]: ... - class Result(Generic[RT, CT, KT]): mapping: Mapping[KT, CT] graph: DirectedGraph[Optional[KT]] diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/resolvelib-0.9.0/src/resolvelib/structs.py new/resolvelib-0.8.1/src/resolvelib/structs.py --- old/resolvelib-0.9.0/src/resolvelib/structs.py 2022-11-16 21:11:34.000000000 +0100 +++ new/resolvelib-0.8.1/src/resolvelib/structs.py 2021-10-11 23:05:57.000000000 +0200 @@ -117,14 +117,13 @@ def __init__(self, factory): self._factory = factory - self._iterable = None def __repr__(self): - return "{}({})".format(type(self).__name__, list(self)) + return "{}({})".format(type(self).__name__, list(self._factory())) def __bool__(self): try: - next(iter(self)) + next(self._factory()) except StopIteration: return False return True @@ -132,11 +131,7 @@ __nonzero__ = __bool__ # XXX: Python 2. def __iter__(self): - iterable = ( - self._factory() if self._iterable is None else self._iterable - ) - self._iterable, current = itertools.tee(iterable) - return current + return self._factory() class _SequenceIterableView(object): diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/resolvelib-0.9.0/src/resolvelib/structs.pyi new/resolvelib-0.8.1/src/resolvelib/structs.pyi --- old/resolvelib-0.9.0/src/resolvelib/structs.pyi 2022-11-16 21:11:34.000000000 +0100 +++ new/resolvelib-0.8.1/src/resolvelib/structs.pyi 2021-10-11 23:05:57.000000000 +0200 @@ -16,7 +16,7 @@ CT = TypeVar("CT") # Candidate. _T = TypeVar("_T") -Matches = Union[Iterable[CT], Callable[[], Iterable[CT]]] +Matches = Union[Iterable[CT], Callable[[], Iterator[CT]]] class IteratorMapping(Mapping[KT, _T], metaclass=ABCMeta): pass diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/resolvelib-0.9.0/tests/conftest.py new/resolvelib-0.8.1/tests/conftest.py --- old/resolvelib-0.9.0/tests/conftest.py 2022-11-16 21:11:34.000000000 +0100 +++ new/resolvelib-0.8.1/tests/conftest.py 2021-10-11 23:05:57.000000000 +0200 @@ -9,9 +9,10 @@ def __init__(self): self._indent = 0 - def rejecting_candidate(self, criterion, candidate): + def backtracking(self, candidate): self._indent -= 1 - print(" " * self._indent, "Reject ", candidate, sep="") + assert self._indent >= 0 + print(" " * self._indent, "Back ", candidate, sep="") def pinning(self, candidate): print(" " * self._indent, "Pin ", candidate, sep="") diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/resolvelib-0.9.0/tests/functional/python/inputs/index/same-package.json new/resolvelib-0.8.1/tests/functional/python/inputs/index/same-package.json --- old/resolvelib-0.9.0/tests/functional/python/inputs/index/same-package.json 2022-11-16 21:11:34.000000000 +0100 +++ new/resolvelib-0.8.1/tests/functional/python/inputs/index/same-package.json 2021-10-11 23:05:57.000000000 +0200 @@ -2,37 +2,37 @@ "package-a": { "0.1.0": { "dependencies": [ - "package-x==0.1.0; extra == 'x'", - "package-y==0.1.0; extra == 'y'", - "package-z==0.1.0; extra == 'z'" + "package-x=='0.1.0'; extra == 'x'", + "package-y=='0.1.0'; extra == 'y'", + "package-z=='0.1.0'; extra == 'z'" ] }, "1.0.0": { "dependencies": [ - "package-x==1.0.0; extra == 'x'", - "package-y==1.0.0; extra == 'y'", - "package-z==1.0.0; extra == 'z'" + "package-x=='1.0.0'; extra == 'x'", + "package-y=='1.0.0'; extra == 'y'", + "package-z=='1.0.0'; extra == 'z'" ] }, "1.1.0": { "dependencies": [ - "package-x==1.1.0; extra == 'x'", - "package-y==1.1.0; extra == 'y'", - "package-z==1.1.0; extra == 'z'" + "package-x=='1.1.0'; extra == 'x'", + "package-y=='1.1.0'; extra == 'y'", + "package-z=='1.1.0'; extra == 'z'" ] }, "1.2.0": { "dependencies": [ - "package-x==1.2.0; extra == 'x'", - "package-y==1.2.0; extra == 'y'", - "package-z==1.2.0; extra == 'z'" + "package-x=='1.2.0'; extra == 'x'", + "package-y=='1.2.0'; extra == 'y'", + "package-z=='1.2.0'; extra == 'z'" ] }, "1.3.0": { "dependencies": [ - "package-x==1.3.0; extra == 'x'", - "package-y==1.3.0; extra == 'y'", - "package-z==1.3.0; extra == 'z'" + "package-x=='1.3.0'; extra == 'x'", + "package-y=='1.3.0'; extra == 'y'", + "package-z=='1.3.0'; extra == 'z'" ] } }, diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/resolvelib-0.9.0/tests/functional/python/test_resolvers_python.py new/resolvelib-0.8.1/tests/functional/python/test_resolvers_python.py --- old/resolvelib-0.9.0/tests/functional/python/test_resolvers_python.py 2022-11-16 21:11:34.000000000 +0100 +++ new/resolvelib-0.8.1/tests/functional/python/test_resolvers_python.py 2021-10-11 23:05:57.000000000 +0200 @@ -129,6 +129,7 @@ XFAIL_CASES = { "pyrex-1.9.8.json": "Too many rounds (>500)", + "same-package-extras.json": "State not cleaned up correctly", } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/resolvelib-0.9.0/tests/test_resolvers.py new/resolvelib-0.8.1/tests/test_resolvers.py --- old/resolvelib-0.9.0/tests/test_resolvers.py 2022-11-16 21:11:34.000000000 +0100 +++ new/resolvelib-0.8.1/tests/test_resolvers.py 2021-10-11 23:05:57.000000000 +0200 @@ -1,18 +1,4 @@ -from typing import ( - Any, - Iterable, - Iterator, - List, - Mapping, - Sequence, - Set, - Tuple, - Union, -) - import pytest -from packaging.requirements import Requirement -from packaging.version import Version from resolvelib import ( AbstractProvider, @@ -21,12 +7,6 @@ ResolutionImpossible, Resolver, ) -from resolvelib.resolvers import ( - Criterion, - RequirementInformation, - RequirementsConflicted, - Resolution, -) def test_candidate_inconsistent_error(): @@ -163,109 +143,3 @@ backtracking_causes = run_resolver([("a", {1, 2}), ("b", {1})]) exception_causes = run_resolver([("a", {2}), ("b", {1})]) assert exception_causes == backtracking_causes - - -def test_pin_conflict_with_self(monkeypatch, reporter): - # type: (Any, BaseReporter) -> None - """ - Verify correct behavior of attempting to pin a candidate version that conflicts - with a previously pinned (now invalidated) version for that same candidate (#91). - """ - Candidate = Tuple[ - str, Version, Sequence[str] - ] # name, version, requirements - all_candidates = { - "parent": [("parent", Version("1"), ["child<2"])], - "child": [ - ("child", Version("2"), ["grandchild>=2"]), - ("child", Version("1"), ["grandchild<2"]), - ("child", Version("0.1"), ["grandchild"]), - ], - "grandchild": [ - ("grandchild", Version("2"), []), - ("grandchild", Version("1"), []), - ], - } # type: Mapping[str, Sequence[Candidate]] - - class Provider(AbstractProvider): # AbstractProvider[str, Candidate, str] - def identify(self, requirement_or_candidate): - # type: (Union[str, Candidate]) -> str - result = ( - Requirement(requirement_or_candidate).name - if isinstance(requirement_or_candidate, str) - else requirement_or_candidate[0] - ) - assert result in all_candidates, "unknown requirement_or_candidate" - return result - - def get_preference(self, identifier, *args, **kwargs): - # type: (str, *object, **object) -> str - # prefer child over parent (alphabetically) - return identifier - - def get_dependencies(self, candidate): - # type: (Candidate) -> Sequence[str] - return candidate[2] - - def find_matches( - self, - identifier, # type: str - requirements, # type: Mapping[str, Iterator[str]] - incompatibilities, # type: Mapping[str, Iterator[Candidate]] - ): - # type: (...) -> Iterator[Candidate] - return ( - candidate - for candidate in all_candidates[identifier] - if all( - self.is_satisfied_by(req, candidate) - for req in requirements[identifier] - ) - if candidate not in incompatibilities[identifier] - ) - - def is_satisfied_by(self, requirement, candidate): - # type: (str, Candidate) -> bool - return candidate[1] in Requirement(requirement).specifier - - # patch Resolution._get_updated_criteria to collect rejected states - rejected_criteria = [] # type: List[Criterion] - get_updated_criteria_orig = ( - Resolution._get_updated_criteria # type: ignore[attr-defined] - ) - - def get_updated_criteria_patch(self, candidate): - try: - return get_updated_criteria_orig(self, candidate) - except RequirementsConflicted as e: - rejected_criteria.append(e.criterion) - raise - - monkeypatch.setattr( - Resolution, "_get_updated_criteria", get_updated_criteria_patch - ) - - resolver = Resolver( - Provider(), reporter - ) # type: Resolver[str, Candidate, str] - result = resolver.resolve(["child", "parent"]) - - def get_child_versions(information): - # type: (Iterable[RequirementInformation[str, Candidate]]) -> Set[str] - return { - str(inf.parent[1]) - for inf in information - if inf.parent is not None and inf.parent[0] == "child" - } - - # verify that none of the rejected criteria are based on more than one candidate for - # child - assert not any( - len(get_child_versions(criterion.information)) > 1 - for criterion in rejected_criteria - ) - - assert set(result.mapping) == {"parent", "child", "grandchild"} - assert result.mapping["parent"][1] == Version("1") - assert result.mapping["child"][1] == Version("1") - assert result.mapping["grandchild"][1] == Version("1")