Skip to content

Commit cdc5422

Browse files
authored
Merge pull request #9019 from pradyunsg/flip-the-switch-on-new-resolver
2 parents 9a62dd8 + 64ff484 commit cdc5422

31 files changed

+210
-195
lines changed

.travis.yml

-20
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@ addons:
1010
stages:
1111
- primary
1212
- secondary
13-
- experimental
1413

1514
jobs:
1615
include:
@@ -32,25 +31,6 @@ jobs:
3231
- env: GROUP=2
3332
python: pypy2.7-7.1.1
3433

35-
# Test experimental stuff that are not part of the standard pip usage.
36-
# Helpful for developers working on them to see how they're doing.
37-
- stage: experimental
38-
env:
39-
- GROUP=1
40-
- NEW_RESOLVER=1
41-
- env:
42-
- GROUP=2
43-
- NEW_RESOLVER=1
44-
- env:
45-
- GROUP=3
46-
- NEW_RESOLVER=1
47-
48-
fast_finish: true
49-
allow_failures:
50-
- env:
51-
- GROUP=3
52-
- NEW_RESOLVER=1
53-
5434
before_install: tools/travis/setup.sh
5535
install: travis_retry tools/travis/install.sh
5636
script: tools/travis/run.sh

news/9019.feature.rst

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Switch to the new dependency resolver by default.

setup.cfg

-1
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,6 @@ markers =
6161
mercurial: VCS: Mercurial
6262
git: VCS: git
6363
yaml: yaml based tests
64-
fails_on_new_resolver: Does not yet work on the new resolver
6564

6665
[coverage:run]
6766
branch = True

src/pip/_internal/cli/cmdoptions.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -905,7 +905,7 @@ def check_list_path_option(options):
905905
metavar='feature',
906906
action='append',
907907
default=[],
908-
choices=[],
908+
choices=['legacy-resolver'],
909909
help=(
910910
'Enable deprecated functionality, that will be removed in the future.'
911911
),

src/pip/_internal/cli/req_command.py

+39-4
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@
99
import os
1010
from functools import partial
1111

12+
from pip._vendor.six import PY2
13+
1214
from pip._internal.cli import cmdoptions
1315
from pip._internal.cli.base_command import Command
1416
from pip._internal.cli.command_context import CommandContextMixIn
@@ -195,7 +197,33 @@ def __init__(self, *args, **kw):
195197
self.cmd_opts.add_option(cmdoptions.no_clean())
196198

197199
@staticmethod
200+
def determine_resolver_variant(options):
201+
# type: (Values) -> str
202+
"""Determines which resolver should be used, based on the given options."""
203+
# We didn't want to change things for Python 2, since it's nearly done with
204+
# and we're using performance improvements that only work on Python 3.
205+
if PY2:
206+
if '2020-resolver' in options.features_enabled:
207+
return "2020-resolver"
208+
else:
209+
return "legacy"
210+
211+
# Warn about the options that are gonna be removed.
212+
if '2020-resolver' in options.features_enabled:
213+
logger.warning(
214+
"--use-feature=2020-resolver no longer has any effect, "
215+
"since it is now the default dependency resolver in pip. "
216+
"This will become an error in pip 21.0."
217+
)
218+
219+
if "legacy-resolver" in options.deprecated_features_enabled:
220+
return "legacy"
221+
222+
return "2020-resolver"
223+
224+
@classmethod
198225
def make_requirement_preparer(
226+
cls,
199227
temp_build_dir, # type: TempDirectory
200228
options, # type: Values
201229
req_tracker, # type: RequirementTracker
@@ -211,7 +239,8 @@ def make_requirement_preparer(
211239
temp_build_dir_path = temp_build_dir.path
212240
assert temp_build_dir_path is not None
213241

214-
if '2020-resolver' in options.features_enabled:
242+
resolver_variant = cls.determine_resolver_variant(options)
243+
if resolver_variant == "2020-resolver":
215244
lazy_wheel = 'fast-deps' in options.features_enabled
216245
if lazy_wheel:
217246
logger.warning(
@@ -223,6 +252,10 @@ def make_requirement_preparer(
223252
)
224253
else:
225254
lazy_wheel = False
255+
if 'fast-deps' in options.features_enabled:
256+
logger.warning(
257+
'fast-deps has no effect when used with the legacy resolver.'
258+
)
226259

227260
return RequirementPreparer(
228261
build_dir=temp_build_dir_path,
@@ -238,8 +271,9 @@ def make_requirement_preparer(
238271
lazy_wheel=lazy_wheel,
239272
)
240273

241-
@staticmethod
274+
@classmethod
242275
def make_resolver(
276+
cls,
243277
preparer, # type: RequirementPreparer
244278
finder, # type: PackageFinder
245279
options, # type: Values
@@ -250,7 +284,7 @@ def make_resolver(
250284
force_reinstall=False, # type: bool
251285
upgrade_strategy="to-satisfy-only", # type: str
252286
use_pep517=None, # type: Optional[bool]
253-
py_version_info=None # type: Optional[Tuple[int, ...]]
287+
py_version_info=None, # type: Optional[Tuple[int, ...]]
254288
):
255289
# type: (...) -> BaseResolver
256290
"""
@@ -261,10 +295,11 @@ def make_resolver(
261295
isolated=options.isolated_mode,
262296
use_pep517=use_pep517,
263297
)
298+
resolver_variant = cls.determine_resolver_variant(options)
264299
# The long import name and duplicated invocation is needed to convince
265300
# Mypy into correctly typechecking. Otherwise it would complain the
266301
# "Resolver" class being redefined.
267-
if '2020-resolver' in options.features_enabled:
302+
if resolver_variant == "2020-resolver":
268303
import pip._internal.resolution.resolvelib.resolver
269304

270305
return pip._internal.resolution.resolvelib.resolver.Resolver(

src/pip/_internal/commands/install.py

+4-4
Original file line numberDiff line numberDiff line change
@@ -427,7 +427,7 @@ def run(self, options, args):
427427
if conflicts is not None:
428428
self._warn_about_conflicts(
429429
conflicts,
430-
new_resolver='2020-resolver' in options.features_enabled,
430+
resolver_variant=self.determine_resolver_variant(options),
431431
)
432432

433433
installed_desc = ' '.join(items)
@@ -520,14 +520,14 @@ def _determine_conflicts(self, to_install):
520520
)
521521
return None
522522

523-
def _warn_about_conflicts(self, conflict_details, new_resolver):
524-
# type: (ConflictDetails, bool) -> None
523+
def _warn_about_conflicts(self, conflict_details, resolver_variant):
524+
# type: (ConflictDetails, str) -> None
525525
package_set, (missing, conflicting) = conflict_details
526526
if not missing and not conflicting:
527527
return
528528

529529
parts = [] # type: List[str]
530-
if not new_resolver:
530+
if resolver_variant == "legacy":
531531
parts.append(
532532
"After October 2020 you may experience errors when installing "
533533
"or updating packages. This is because pip will change the "

tests/conftest.py

+28-24
Original file line numberDiff line numberDiff line change
@@ -39,16 +39,11 @@ def pytest_addoption(parser):
3939
help="keep temporary test directories",
4040
)
4141
parser.addoption(
42-
"--new-resolver",
43-
action="store_true",
44-
default=False,
45-
help="use new resolver in tests",
46-
)
47-
parser.addoption(
48-
"--new-resolver-runtests",
49-
action="store_true",
50-
default=False,
51-
help="run the skipped tests for the new resolver",
42+
"--resolver",
43+
action="store",
44+
default="2020-resolver",
45+
choices=["2020-resolver", "legacy"],
46+
help="use given resolver in tests",
5247
)
5348
parser.addoption(
5449
"--use-venv",
@@ -68,12 +63,6 @@ def pytest_collection_modifyitems(config, items):
6863
if item.get_closest_marker('network') is not None:
6964
item.add_marker(pytest.mark.flaky(reruns=3, reruns_delay=2))
7065

71-
if (item.get_closest_marker('fails_on_new_resolver') and
72-
config.getoption("--new-resolver") and
73-
not config.getoption("--new-resolver-runtests")):
74-
item.add_marker(pytest.mark.skip(
75-
'This test does not work with the new resolver'))
76-
7766
if six.PY3:
7867
if (item.get_closest_marker('incompatible_with_test_venv') and
7968
config.getoption("--use-venv")):
@@ -103,17 +92,32 @@ def pytest_collection_modifyitems(config, items):
10392

10493

10594
@pytest.fixture(scope="session", autouse=True)
106-
def use_new_resolver(request):
107-
"""Set environment variable to make pip default to the new resolver.
95+
def resolver_variant(request):
96+
"""Set environment variable to make pip default to the correct resolver.
10897
"""
109-
new_resolver = request.config.getoption("--new-resolver")
98+
resolver = request.config.getoption("--resolver")
99+
100+
# Handle the environment variables for this test.
110101
features = set(os.environ.get("PIP_USE_FEATURE", "").split())
111-
if new_resolver:
112-
features.add("2020-resolver")
102+
deprecated_features = set(os.environ.get("PIP_USE_DEPRECATED", "").split())
103+
104+
if six.PY3:
105+
if resolver == "legacy":
106+
deprecated_features.add("legacy-resolver")
107+
else:
108+
deprecated_features.discard("legacy-resolver")
113109
else:
114-
features.discard("2020-resolver")
115-
with patch.dict(os.environ, {"PIP_USE_FEATURE": " ".join(features)}):
116-
yield new_resolver
110+
if resolver == "2020-resolver":
111+
features.add("2020-resolver")
112+
else:
113+
features.discard("2020-resolver")
114+
115+
env = {
116+
"PIP_USE_FEATURE": " ".join(features),
117+
"PIP_USE_DEPRECATED": " ".join(deprecated_features),
118+
}
119+
with patch.dict(os.environ, env):
120+
yield resolver
117121

118122

119123
@pytest.fixture(scope='session')

tests/functional/test_install.py

+14-13
Original file line numberDiff line numberDiff line change
@@ -407,7 +407,7 @@ def test_vcs_url_urlquote_normalization(script, tmpdir):
407407
)
408408

409409

410-
@pytest.mark.parametrize("resolver", ["", "--use-feature=2020-resolver"])
410+
@pytest.mark.parametrize("resolver", ["", "--use-deprecated=legacy-resolver"])
411411
def test_basic_install_from_local_directory(
412412
script, data, resolver, with_wheel
413413
):
@@ -538,7 +538,7 @@ def assert_re_match(pattern, text):
538538

539539

540540
@pytest.mark.network
541-
@pytest.mark.fails_on_new_resolver
541+
@pytest.mark.skip("Fails on new resolver")
542542
def test_hashed_install_failure_later_flag(script, tmpdir):
543543
with requirements_file(
544544
"blessings==1.0\n"
@@ -941,7 +941,7 @@ def test_install_nonlocal_compatible_wheel(script, data):
941941
def test_install_nonlocal_compatible_wheel_path(
942942
script,
943943
data,
944-
use_new_resolver
944+
resolver_variant,
945945
):
946946
target_dir = script.scratch_path / 'target'
947947

@@ -952,9 +952,9 @@ def test_install_nonlocal_compatible_wheel_path(
952952
'--no-index',
953953
'--only-binary=:all:',
954954
Path(data.packages) / 'simplewheel-2.0-py3-fakeabi-fakeplat.whl',
955-
expect_error=use_new_resolver
955+
expect_error=(resolver_variant == "2020-resolver"),
956956
)
957-
if use_new_resolver:
957+
if resolver_variant == "2020-resolver":
958958
assert result.returncode == ERROR
959959
else:
960960
assert result.returncode == SUCCESS
@@ -1456,7 +1456,7 @@ def test_install_no_binary_disables_cached_wheels(script, data, with_wheel):
14561456
assert "Running setup.py install for upper" in str(res), str(res)
14571457

14581458

1459-
def test_install_editable_with_wrong_egg_name(script, use_new_resolver):
1459+
def test_install_editable_with_wrong_egg_name(script, resolver_variant):
14601460
script.scratch_path.joinpath("pkga").mkdir()
14611461
pkga_path = script.scratch_path / 'pkga'
14621462
pkga_path.joinpath("setup.py").write_text(textwrap.dedent("""
@@ -1467,12 +1467,12 @@ def test_install_editable_with_wrong_egg_name(script, use_new_resolver):
14671467
result = script.pip(
14681468
'install', '--editable',
14691469
'file://{pkga_path}#egg=pkgb'.format(**locals()),
1470-
expect_error=use_new_resolver,
1470+
expect_error=(resolver_variant == "2020-resolver"),
14711471
)
14721472
assert ("Generating metadata for package pkgb produced metadata "
14731473
"for project name pkga. Fix your #egg=pkgb "
14741474
"fragments.") in result.stderr
1475-
if use_new_resolver:
1475+
if resolver_variant == "2020-resolver":
14761476
assert "has different name in metadata" in result.stderr, str(result)
14771477
else:
14781478
assert "Successfully installed pkga" in str(result), str(result)
@@ -1505,7 +1505,7 @@ def test_double_install(script):
15051505
assert msg not in result.stderr
15061506

15071507

1508-
def test_double_install_fail(script, use_new_resolver):
1508+
def test_double_install_fail(script, resolver_variant):
15091509
"""
15101510
Test double install failing with two different version requirements
15111511
"""
@@ -1514,9 +1514,9 @@ def test_double_install_fail(script, use_new_resolver):
15141514
'pip==7.*',
15151515
'pip==7.1.2',
15161516
# The new resolver is perfectly capable of handling this
1517-
expect_error=(not use_new_resolver)
1517+
expect_error=(resolver_variant == "legacy"),
15181518
)
1519-
if not use_new_resolver:
1519+
if resolver_variant == "legacy":
15201520
msg = ("Double requirement given: pip==7.1.2 (already in pip==7.*, "
15211521
"name='pip')")
15221522
assert msg in result.stderr
@@ -1770,11 +1770,11 @@ def test_user_config_accepted(script):
17701770
)
17711771
@pytest.mark.parametrize("use_module", [True, False])
17721772
def test_install_pip_does_not_modify_pip_when_satisfied(
1773-
script, install_args, expected_message, use_module, use_new_resolver):
1773+
script, install_args, expected_message, use_module, resolver_variant):
17741774
"""
17751775
Test it doesn't upgrade the pip if it already satisfies the requirement.
17761776
"""
1777-
variation = "satisfied" if use_new_resolver else "up-to-date"
1777+
variation = "satisfied" if resolver_variant else "up-to-date"
17781778
expected_message = expected_message.format(variation)
17791779
result = script.pip_install_local(
17801780
'pip', *install_args, use_module=use_module
@@ -1837,6 +1837,7 @@ def test_install_yanked_file_and_print_warning(script, data):
18371837
assert 'Successfully installed simple-3.0\n' in result.stdout, str(result)
18381838

18391839

1840+
@skip_if_python2
18401841
@pytest.mark.parametrize("install_args", [
18411842
(),
18421843
("--trusted-host", "localhost"),

tests/functional/test_install_config.py

+3
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55

66
import pytest
77

8+
from tests.lib import skip_if_python2
89
from tests.lib.server import (
910
authorization_response,
1011
file_response,
@@ -129,6 +130,7 @@ def test_command_line_appends_correctly(script, data):
129130
), 'stdout: {}'.format(result.stdout)
130131

131132

133+
@skip_if_python2
132134
def test_config_file_override_stack(
133135
script, virtualenv, mock_server, shared_data
134136
):
@@ -247,6 +249,7 @@ def test_prompt_for_authentication(script, data, cert_factory):
247249
result.stdout, str(result)
248250

249251

252+
@skip_if_python2
250253
def test_do_not_prompt_for_authentication(script, data, cert_factory):
251254
"""Test behaviour if --no-input option is given while installing
252255
from a index url requiring authentication

0 commit comments

Comments
 (0)