|
1 |
| -from typing import TYPE_CHECKING, List, Optional |
| 1 | +from typing import ( |
| 2 | + TYPE_CHECKING, |
| 3 | + Dict, |
| 4 | + Iterable, |
| 5 | + Iterator, |
| 6 | + List, |
| 7 | + Mapping, |
| 8 | + Optional, |
| 9 | + Sequence, |
| 10 | +) |
| 11 | +from unittest.mock import Mock |
2 | 12 |
|
| 13 | +import pytest |
3 | 14 | from pip._vendor.resolvelib.resolvers import RequirementInformation
|
4 | 15 |
|
5 | 16 | from pip._internal.models.candidate import InstallationCandidate
|
6 | 17 | from pip._internal.models.link import Link
|
7 | 18 | from pip._internal.req.constructors import install_req_from_req_string
|
| 19 | +from pip._internal.resolution.resolvelib.base import Candidate, Constraint, Requirement |
| 20 | +from pip._internal.resolution.resolvelib.candidates import ( |
| 21 | + REQUIRES_PYTHON_IDENTIFIER, |
| 22 | + RequiresPythonCandidate, |
| 23 | +) |
8 | 24 | from pip._internal.resolution.resolvelib.factory import Factory
|
9 | 25 | from pip._internal.resolution.resolvelib.provider import PipProvider
|
10 | 26 | from pip._internal.resolution.resolvelib.requirements import SpecifierRequirement
|
11 | 27 |
|
12 | 28 | if TYPE_CHECKING:
|
13 |
| - from pip._internal.resolution.resolvelib.provider import PreferenceInformation |
| 29 | + from pip._vendor.resolvelib.providers import Preference |
| 30 | + |
| 31 | + PreferenceInformation = RequirementInformation[Requirement, Candidate] |
14 | 32 |
|
15 | 33 |
|
16 | 34 | def build_requirement_information(
|
17 | 35 | name: str, parent: Optional[InstallationCandidate]
|
18 |
| -) -> List["PreferenceInformation"]: |
| 36 | +) -> "List[PreferenceInformation]": |
19 | 37 | install_requirement = install_req_from_req_string(name)
|
20 |
| - # RequirementInformation is typed as a tuple, but it is a namedtupled. |
21 |
| - # https://github.com/sarugaku/resolvelib/blob/7bc025aa2a4e979597c438ad7b17d2e8a08a364e/src/resolvelib/resolvers.pyi#L20-L22 |
22 |
| - requirement_information: PreferenceInformation = RequirementInformation( |
23 |
| - requirement=SpecifierRequirement(install_requirement), # type: ignore[call-arg] |
24 |
| - parent=parent, |
25 |
| - ) |
26 |
| - return [requirement_information] |
| 38 | + return [RequirementInformation(SpecifierRequirement(install_requirement), parent)] # type: ignore |
27 | 39 |
|
28 | 40 |
|
29 | 41 | def test_provider_known_depths(factory: Factory) -> None:
|
@@ -76,3 +88,86 @@ def test_provider_known_depths(factory: Factory) -> None:
|
76 | 88 | transitive_requirement_name: 2.0,
|
77 | 89 | root_requirement_name: 1.0,
|
78 | 90 | }
|
| 91 | + |
| 92 | + |
| 93 | +def create_mock_factory() -> Factory: |
| 94 | + # Mock the required components for the Factory initialization |
| 95 | + finder = Mock() |
| 96 | + preparer = Mock() |
| 97 | + make_install_req = Mock() |
| 98 | + wheel_cache = Mock() |
| 99 | + use_user_site = False |
| 100 | + force_reinstall = False |
| 101 | + ignore_installed = False |
| 102 | + ignore_requires_python = False |
| 103 | + |
| 104 | + # Create a Factory instance with mock components |
| 105 | + return Factory( |
| 106 | + finder=finder, |
| 107 | + preparer=preparer, |
| 108 | + make_install_req=make_install_req, |
| 109 | + wheel_cache=wheel_cache, |
| 110 | + use_user_site=use_user_site, |
| 111 | + force_reinstall=force_reinstall, |
| 112 | + ignore_installed=ignore_installed, |
| 113 | + ignore_requires_python=ignore_requires_python, |
| 114 | + ) |
| 115 | + |
| 116 | + |
| 117 | +@pytest.mark.parametrize( |
| 118 | + "identifier, resolutions, candidates, information, backtrack_causes, expected", |
| 119 | + [ |
| 120 | + ( |
| 121 | + REQUIRES_PYTHON_IDENTIFIER, |
| 122 | + {}, |
| 123 | + {REQUIRES_PYTHON_IDENTIFIER: iter([RequiresPythonCandidate((3, 7))])}, |
| 124 | + {REQUIRES_PYTHON_IDENTIFIER: build_requirement_information("python", None)}, |
| 125 | + [], |
| 126 | + ( |
| 127 | + False, |
| 128 | + False, |
| 129 | + True, |
| 130 | + True, |
| 131 | + 1.0, |
| 132 | + float("inf"), |
| 133 | + True, |
| 134 | + REQUIRES_PYTHON_IDENTIFIER, |
| 135 | + ), |
| 136 | + ), |
| 137 | + ], |
| 138 | +) |
| 139 | +def test_get_preference( |
| 140 | + identifier: str, |
| 141 | + resolutions: Mapping[str, Candidate], |
| 142 | + candidates: Mapping[str, Iterator[Candidate]], |
| 143 | + information: Mapping[str, Iterable["PreferenceInformation"]], |
| 144 | + backtrack_causes: Sequence["PreferenceInformation"], |
| 145 | + expected: "Preference", |
| 146 | +) -> None: |
| 147 | + # Create the factory with mock components |
| 148 | + factory = create_mock_factory() |
| 149 | + constraints: Dict[str, Constraint] = {} |
| 150 | + user_requested = {"requested-package": 0} |
| 151 | + ignore_dependencies = False |
| 152 | + upgrade_strategy = "to-satisfy-only" |
| 153 | + |
| 154 | + # Initialize PipProvider |
| 155 | + provider = PipProvider( |
| 156 | + factory=factory, |
| 157 | + constraints=constraints, |
| 158 | + ignore_dependencies=ignore_dependencies, |
| 159 | + upgrade_strategy=upgrade_strategy, |
| 160 | + user_requested=user_requested, |
| 161 | + ) |
| 162 | + |
| 163 | + # Get the preference for the test case |
| 164 | + preference = provider.get_preference( |
| 165 | + identifier, |
| 166 | + resolutions, |
| 167 | + candidates, |
| 168 | + information, |
| 169 | + backtrack_causes, |
| 170 | + ) |
| 171 | + |
| 172 | + # Assert the calculated preference matches the expected preference |
| 173 | + assert preference == expected, f"Expected {expected}, got {preference}" |
0 commit comments