Skip to content

Commit 8b20443

Browse files
authored
Merge pull request #7704 from chrahunt/refactor/simpler-resolver-interface
Reduce usage of RequirementSet in commands
2 parents 3c684b5 + e7998a3 commit 8b20443

File tree

8 files changed

+64
-64
lines changed

8 files changed

+64
-64
lines changed

src/pip/_internal/cli/req_command.py

+12-9
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
install_req_from_req_string,
2626
)
2727
from pip._internal.req.req_file import parse_requirements
28+
from pip._internal.req.req_set import RequirementSet
2829
from pip._internal.self_outdated_check import (
2930
make_link_collector,
3031
pip_self_version_check,
@@ -38,7 +39,7 @@
3839

3940
from pip._internal.cache import WheelCache
4041
from pip._internal.models.target_python import TargetPython
41-
from pip._internal.req.req_set import RequirementSet
42+
from pip._internal.req.req_install import InstallRequirement
4243
from pip._internal.req.req_tracker import RequirementTracker
4344
from pip._internal.utils.temp_dir import (
4445
TempDirectory,
@@ -269,19 +270,22 @@ def make_resolver(
269270
py_version_info=py_version_info,
270271
)
271272

272-
def populate_requirement_set(
273+
def get_requirements(
273274
self,
274-
requirement_set, # type: RequirementSet
275275
args, # type: List[str]
276276
options, # type: Values
277277
finder, # type: PackageFinder
278278
session, # type: PipSession
279279
wheel_cache, # type: Optional[WheelCache]
280+
check_supported_wheels=True, # type: bool
280281
):
281-
# type: (...) -> None
282+
# type: (...) -> List[InstallRequirement]
282283
"""
283-
Marshal cmd line args into a requirement set.
284+
Parse command-line arguments into the corresponding requirements.
284285
"""
286+
requirement_set = RequirementSet(
287+
check_supported_wheels=check_supported_wheels
288+
)
285289
for filename in options.constraints:
286290
for req_to_add in parse_requirements(
287291
filename,
@@ -320,10 +324,7 @@ def populate_requirement_set(
320324
requirement_set.add_requirement(req_to_add)
321325

322326
# If any requirement has hash options, enable hash checking.
323-
requirements = (
324-
requirement_set.unnamed_requirements +
325-
list(requirement_set.requirements.values())
326-
)
327+
requirements = requirement_set.all_requirements
327328
if any(req.has_hash_options for req in requirements):
328329
options.require_hashes = True
329330

@@ -339,6 +340,8 @@ def populate_requirement_set(
339340
'You must give at least one requirement to %(name)s '
340341
'(see "pip help %(name)s")' % opts)
341342

343+
return requirements
344+
342345
@staticmethod
343346
def trace_basic_info(finder):
344347
# type: (PackageFinder) -> None

src/pip/_internal/commands/download.py

+4-6
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@
99
from pip._internal.cli import cmdoptions
1010
from pip._internal.cli.cmdoptions import make_target_python
1111
from pip._internal.cli.req_command import RequirementCommand, with_cleanup
12-
from pip._internal.req import RequirementSet
1312
from pip._internal.req.req_tracker import get_requirement_tracker
1413
from pip._internal.utils.misc import ensure_dir, normalize_path, write_output
1514
from pip._internal.utils.temp_dir import TempDirectory
@@ -102,10 +101,7 @@ def run(self, options, args):
102101
with get_requirement_tracker() as req_tracker, TempDirectory(
103102
options.build_dir, delete=build_delete, kind="download"
104103
) as directory:
105-
106-
requirement_set = RequirementSet()
107-
self.populate_requirement_set(
108-
requirement_set,
104+
reqs = self.get_requirements(
109105
args,
110106
options,
111107
finder,
@@ -132,7 +128,9 @@ def run(self, options, args):
132128

133129
self.trace_basic_info(finder)
134130

135-
resolver.resolve(requirement_set)
131+
requirement_set = resolver.resolve(
132+
reqs, check_supported_wheels=True
133+
)
136134

137135
downloaded = ' '.join([
138136
req.name for req in requirement_set.successfully_downloaded

src/pip/_internal/commands/install.py

+10-17
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@
3030
)
3131
from pip._internal.locations import distutils_scheme
3232
from pip._internal.operations.check import check_install_conflicts
33-
from pip._internal.req import RequirementSet, install_given_reqs
33+
from pip._internal.req import install_given_reqs
3434
from pip._internal.req.req_tracker import get_requirement_tracker
3535
from pip._internal.utils.deprecation import deprecated
3636
from pip._internal.utils.distutils_args import parse_distutils_args
@@ -291,18 +291,14 @@ def run(self, options, args):
291291
with get_requirement_tracker() as req_tracker, TempDirectory(
292292
options.build_dir, delete=build_delete, kind="install"
293293
) as directory:
294-
requirement_set = RequirementSet(
295-
check_supported_wheels=not options.target_dir,
296-
)
297-
298294
try:
299-
self.populate_requirement_set(
300-
requirement_set, args, options, finder, session,
301-
wheel_cache
295+
reqs = self.get_requirements(
296+
args, options, finder, session,
297+
wheel_cache, check_supported_wheels=not options.target_dir,
302298
)
303299

304300
warn_deprecated_install_options(
305-
requirement_set, options.install_options
301+
reqs, options.install_options
306302
)
307303

308304
preparer = self.make_requirement_preparer(
@@ -328,7 +324,9 @@ def run(self, options, args):
328324

329325
self.trace_basic_info(finder)
330326

331-
resolver.resolve(requirement_set)
327+
requirement_set = resolver.resolve(
328+
reqs, check_supported_wheels=not options.target_dir
329+
)
332330

333331
try:
334332
pip_req = requirement_set.get_requirement("pip")
@@ -605,20 +603,15 @@ def decide_user_install(
605603
return True
606604

607605

608-
def warn_deprecated_install_options(requirement_set, options):
609-
# type: (RequirementSet, Optional[List[str]]) -> None
606+
def warn_deprecated_install_options(requirements, options):
607+
# type: (List[InstallRequirement], Optional[List[str]]) -> None
610608
"""If any location-changing --install-option arguments were passed for
611609
requirements or on the command-line, then show a deprecation warning.
612610
"""
613611
def format_options(option_names):
614612
# type: (Iterable[str]) -> List[str]
615613
return ["--{}".format(name.replace("_", "-")) for name in option_names]
616614

617-
requirements = (
618-
requirement_set.unnamed_requirements +
619-
list(requirement_set.requirements.values())
620-
)
621-
622615
offenders = []
623616

624617
for requirement in requirements:

src/pip/_internal/commands/wheel.py

+5-7
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,6 @@
1313
from pip._internal.cli import cmdoptions
1414
from pip._internal.cli.req_command import RequirementCommand, with_cleanup
1515
from pip._internal.exceptions import CommandError, PreviousBuildDirError
16-
from pip._internal.req import RequirementSet
1716
from pip._internal.req.req_tracker import get_requirement_tracker
1817
from pip._internal.utils.misc import ensure_dir, normalize_path
1918
from pip._internal.utils.temp_dir import TempDirectory
@@ -128,12 +127,9 @@ def run(self, options, args):
128127
with get_requirement_tracker() as req_tracker, TempDirectory(
129128
options.build_dir, delete=build_delete, kind="wheel"
130129
) as directory:
131-
132-
requirement_set = RequirementSet()
133-
134130
try:
135-
self.populate_requirement_set(
136-
requirement_set, args, options, finder, session,
131+
reqs = self.get_requirements(
132+
args, options, finder, session,
137133
wheel_cache
138134
)
139135

@@ -158,7 +154,9 @@ def run(self, options, args):
158154

159155
self.trace_basic_info(finder)
160156

161-
resolver.resolve(requirement_set)
157+
requirement_set = resolver.resolve(
158+
reqs, check_supported_wheels=True
159+
)
162160

163161
reqs_to_build = [
164162
r for r in requirement_set.requirements.values()

src/pip/_internal/legacy_resolve.py

+9-8
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
HashErrors,
2929
UnsupportedPythonVersion,
3030
)
31+
from pip._internal.req.req_set import RequirementSet
3132
from pip._internal.utils.logging import indent_log
3233
from pip._internal.utils.misc import dist_in_usersite, normalize_version_info
3334
from pip._internal.utils.packaging import (
@@ -44,7 +45,6 @@
4445
from pip._internal.index.package_finder import PackageFinder
4546
from pip._internal.operations.prepare import RequirementPreparer
4647
from pip._internal.req.req_install import InstallRequirement
47-
from pip._internal.req.req_set import RequirementSet
4848

4949
InstallRequirementProvider = Callable[
5050
[str, InstallRequirement], InstallRequirement
@@ -147,8 +147,8 @@ def __init__(
147147
self._discovered_dependencies = \
148148
defaultdict(list) # type: DiscoveredDependencies
149149

150-
def resolve(self, requirement_set):
151-
# type: (RequirementSet) -> None
150+
def resolve(self, root_reqs, check_supported_wheels):
151+
# type: (List[InstallRequirement], bool) -> RequirementSet
152152
"""Resolve what operations need to be done
153153
154154
As a side-effect of this method, the packages (and their dependencies)
@@ -159,12 +159,11 @@ def resolve(self, requirement_set):
159159
possible to move the preparation to become a step separated from
160160
dependency resolution.
161161
"""
162-
# If any top-level requirement has a hash specified, enter
163-
# hash-checking mode, which requires hashes from all.
164-
root_reqs = (
165-
requirement_set.unnamed_requirements +
166-
list(requirement_set.requirements.values())
162+
requirement_set = RequirementSet(
163+
check_supported_wheels=check_supported_wheels
167164
)
165+
for req in root_reqs:
166+
requirement_set.add_requirement(req)
168167

169168
# Actually prepare the files, and collect any exceptions. Most hash
170169
# exceptions cannot be checked ahead of time, because
@@ -182,6 +181,8 @@ def resolve(self, requirement_set):
182181
if hash_errors:
183182
raise hash_errors
184183

184+
return requirement_set
185+
185186
def _is_upgrade_allowed(self, req):
186187
# type: (InstallRequirement) -> bool
187188
if self.upgrade_strategy == "to-satisfy-only":

src/pip/_internal/req/req_set.py

+5
Original file line numberDiff line numberDiff line change
@@ -196,3 +196,8 @@ def get_requirement(self, name):
196196
return self.requirements[project_name]
197197

198198
raise KeyError("No project with the name %r" % name)
199+
200+
@property
201+
def all_requirements(self):
202+
# type: () -> List[InstallRequirement]
203+
return self.unnamed_requirements + list(self.requirements.values())

tests/unit/test_command_install.py

+4-7
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@
1010
warn_deprecated_install_options,
1111
)
1212
from pip._internal.req.req_install import InstallRequirement
13-
from pip._internal.req.req_set import RequirementSet
1413

1514

1615
class TestDecideUserInstall:
@@ -47,8 +46,7 @@ def test_most_cases(
4746

4847
def test_deprecation_notice_for_pip_install_options(recwarn):
4948
install_options = ["--prefix=/hello"]
50-
req_set = RequirementSet()
51-
warn_deprecated_install_options(req_set, install_options)
49+
warn_deprecated_install_options([], install_options)
5250

5351
assert len(recwarn) == 1
5452
message = recwarn[0].message.args[0]
@@ -57,21 +55,20 @@ def test_deprecation_notice_for_pip_install_options(recwarn):
5755

5856
def test_deprecation_notice_for_requirement_options(recwarn):
5957
install_options = []
60-
req_set = RequirementSet()
6158

6259
bad_named_req_options = {"install_options": ["--home=/wow"]}
6360
bad_named_req = InstallRequirement(
6461
Requirement("hello"), "requirements.txt", options=bad_named_req_options
6562
)
66-
req_set.add_named_requirement(bad_named_req)
6763

6864
bad_unnamed_req_options = {"install_options": ["--install-lib=/lib"]}
6965
bad_unnamed_req = InstallRequirement(
7066
None, "requirements2.txt", options=bad_unnamed_req_options
7167
)
72-
req_set.add_unnamed_requirement(bad_unnamed_req)
7368

74-
warn_deprecated_install_options(req_set, install_options)
69+
warn_deprecated_install_options(
70+
[bad_named_req, bad_unnamed_req], install_options
71+
)
7572

7673
assert len(recwarn) == 1
7774
message = recwarn[0].message.args[0]

tests/unit/test_req.py

+15-10
Original file line numberDiff line numberDiff line change
@@ -112,7 +112,8 @@ def test_no_reuse_existing_build_dir(self, data):
112112
r"pip can't proceed with [\s\S]*%s[\s\S]*%s" %
113113
(req, build_dir.replace('\\', '\\\\')),
114114
resolver.resolve,
115-
reqset,
115+
reqset.all_requirements,
116+
True,
116117
)
117118

118119
# TODO: Update test when Python 2.7 is dropped.
@@ -129,7 +130,7 @@ def test_environment_marker_extras(self, data):
129130
reqset.add_requirement(req)
130131
finder = make_test_finder(find_links=[data.find_links])
131132
with self._basic_resolver(finder) as resolver:
132-
resolver.resolve(reqset)
133+
reqset = resolver.resolve(reqset.all_requirements, True)
133134
# This is hacky but does test both case in py2 and py3
134135
if sys.version_info[:2] == (2, 7):
135136
assert reqset.has_requirement('simple')
@@ -155,21 +156,21 @@ def test_missing_hash_with_require_hashes(self, data):
155156
r' simple==1.0 --hash=sha256:393043e672415891885c9a2a0929b1'
156157
r'af95fb866d6ca016b42d2e6ce53619b653$',
157158
resolver.resolve,
158-
reqset
159+
reqset.all_requirements,
160+
True,
159161
)
160162

161163
def test_missing_hash_with_require_hashes_in_reqs_file(self, data, tmpdir):
162164
"""--require-hashes in a requirements file should make its way to the
163165
RequirementSet.
164166
"""
165-
req_set = RequirementSet()
166167
finder = make_test_finder(find_links=[data.find_links])
167168
session = finder._link_collector.session
168169
command = create_command('install')
169170
with requirements_file('--require-hashes', tmpdir) as reqs_file:
170171
options, args = command.parse_args(['-r', reqs_file])
171-
command.populate_requirement_set(
172-
req_set, args, options, finder, session, wheel_cache=None,
172+
command.get_requirements(
173+
args, options, finder, session, wheel_cache=None,
173174
)
174175
assert options.require_hashes
175176

@@ -209,7 +210,8 @@ def test_unsupported_hashes(self, data):
209210
r" file://.*{sep}data{sep}packages{sep}FSPkg "
210211
r"\(from -r file \(line 2\)\)".format(sep=sep),
211212
resolver.resolve,
212-
reqset,
213+
reqset.all_requirements,
214+
True,
213215
)
214216

215217
def test_unpinned_hash_checking(self, data):
@@ -237,7 +239,8 @@ def test_unpinned_hash_checking(self, data):
237239
r' simple .* \(from -r file \(line 1\)\)\n'
238240
r' simple2>1.0 .* \(from -r file \(line 2\)\)',
239241
resolver.resolve,
240-
reqset,
242+
reqset.all_requirements,
243+
True,
241244
)
242245

243246
def test_hash_mismatch(self, data):
@@ -258,7 +261,8 @@ def test_hash_mismatch(self, data):
258261
r' Got 393043e672415891885c9a2a0929b1af95fb'
259262
r'866d6ca016b42d2e6ce53619b653$',
260263
resolver.resolve,
261-
reqset,
264+
reqset.all_requirements,
265+
True,
262266
)
263267

264268
def test_unhashed_deps_on_require_hashes(self, data):
@@ -280,7 +284,8 @@ def test_unhashed_deps_on_require_hashes(self, data):
280284
r'versions pinned.*\n'
281285
r' TopoRequires from .*$',
282286
resolver.resolve,
283-
reqset,
287+
reqset.all_requirements,
288+
True,
284289
)
285290

286291
def test_hashed_deps_on_require_hashes(self):

0 commit comments

Comments
 (0)