Skip to content

Commit

Permalink
Prepare for Pip 23.2 release.
Browse files Browse the repository at this point in the history
A recent Pip commit has broken
`pip --use-deprecated legacy-resolver download ...` which is our
backwards-compatible default use case. Whether or not Pip decides to
fix, the legacy resolver will be yanked at some point and it seems
reasonable to just require any Pex user on Python 3.12 and thus Pip 23.2
to only use the Pip 2020 resolver.

See: pypa/pip#12138
  • Loading branch information
jsirois committed Jul 11, 2023
1 parent 85502a7 commit 145a1ef
Show file tree
Hide file tree
Showing 19 changed files with 79 additions and 39 deletions.
15 changes: 10 additions & 5 deletions pex/build_system/testing.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
from pex.pip.installation import get_pip
from pex.pip.version import PipVersion
from pex.resolve.configured_resolver import ConfiguredResolver
from pex.resolve.resolver_configuration import PipConfiguration
from pex.resolve.resolver_configuration import PipConfiguration, ResolverVersion
from pex.result import Error
from pex.targets import LocalInterpreter
from pex.typing import TYPE_CHECKING
Expand All @@ -38,14 +38,19 @@ def assert_expected_dist(dist):
sdist_dir = os.path.join(str(tmpdir), "sdist_dir")

# This test utility is used by all versions of Python Pex supports; so we need to use a Pip
# which is guaranteed to work with the current Python version.
# setup which is guaranteed to work with the current Python version.
pip_version = PipVersion.DEFAULT
resolver_version = ResolverVersion.default(pip_version)

target = LocalInterpreter.create()
resolver = ConfiguredResolver(
PipConfiguration(version=pip_version, resolver_version=resolver_version)
)
location = build_sdist(
project_dir,
sdist_dir,
LocalInterpreter.create(),
ConfiguredResolver(PipConfiguration(version=pip_version)),
target,
resolver,
pip_version=pip_version,
)
assert not isinstance(location, Error), location
Expand All @@ -56,7 +61,7 @@ def assert_expected_dist(dist):

# Verify the sdist is valid such that we can build a wheel from it.
wheel_dir = os.path.join(str(tmpdir), "wheel_dir")
get_pip(resolver=ConfiguredResolver(pip_configuration=PipConfiguration())).spawn_build_wheels(
get_pip(resolver=resolver).spawn_build_wheels(
distributions=[sdist.location], wheel_dir=wheel_dir
).wait()
wheels = glob.glob(os.path.join(wheel_dir, "*.whl"))
Expand Down
4 changes: 2 additions & 2 deletions pex/pip/tool.py
Original file line number Diff line number Diff line change
Expand Up @@ -141,7 +141,7 @@ def create(
password_entries=(), # type: Iterable[PasswordEntry]
):
# type: (...) -> PackageIndexConfiguration
resolver_version = resolver_version or ResolverVersion.PIP_LEGACY
resolver_version = resolver_version or ResolverVersion.default(pip_version)
network_configuration = network_configuration or NetworkConfiguration()

# We must pass `--client-cert` via PIP_CLIENT_CERT to work around
Expand Down Expand Up @@ -241,7 +241,7 @@ def _calculate_resolver_version(package_index_configuration=None):
return (
package_index_configuration.resolver_version
if package_index_configuration
else ResolverVersion.PIP_LEGACY
else ResolverVersion.default()
)

@classmethod
Expand Down
4 changes: 2 additions & 2 deletions pex/pip/version.py
Original file line number Diff line number Diff line change
Expand Up @@ -202,8 +202,8 @@ def values(cls):
)

v23_2 = PipVersionValue(
version="23.2.dev0+8a1eea4a",
requirement="pip @ git+https://github.com/pypa/pip@8a1eea4aaedb1fb1c6b4c652cd0c43502f05ff37",
version="23.2.dev0+ea727e4d",
requirement="pip @ git+https://github.com/pypa/pip@ea727e4d6ab598f34f97c50a22350febc1214a97",
setuptools_version="67.8.0",
wheel_version="0.40.0",
requires_python=">=3.7",
Expand Down
6 changes: 3 additions & 3 deletions pex/platforms.py
Original file line number Diff line number Diff line change
Expand Up @@ -240,9 +240,9 @@ def parse_tags(output):
job = SpawnedJob.stdout(
# TODO(John Sirois): Plumb pip_version and the user-configured resolver:
# https://github.com/pantsbuild/pex/issues/1894
job=get_pip(
resolver=ConfiguredResolver(pip_configuration=PipConfiguration())
).spawn_debug(platform=self, manylinux=manylinux),
job=get_pip(resolver=ConfiguredResolver.default()).spawn_debug(
platform=self, manylinux=manylinux
),
result_func=parse_tags,
)
return job.await_result()
Expand Down
11 changes: 8 additions & 3 deletions pex/resolve/configured_resolver.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,10 @@
from __future__ import absolute_import

from pex import resolver
from pex.pip.version import PipVersionValue
from pex.pip.version import PipVersion, PipVersionValue
from pex.resolve import lock_resolver
from pex.resolve.lockfile.model import Lockfile
from pex.resolve.resolver_configuration import PipConfiguration, ReposConfiguration
from pex.resolve.resolver_configuration import PipConfiguration, ReposConfiguration, ResolverVersion
from pex.resolve.resolvers import Installed, Resolver
from pex.result import try_
from pex.targets import Targets
Expand All @@ -29,7 +29,12 @@ class ConfiguredResolver(Resolver):
@classmethod
def default(cls):
# type: () -> ConfiguredResolver
return cls(PipConfiguration())
pip_version = PipVersion.DEFAULT
return cls(
PipConfiguration(
version=pip_version, resolver_version=ResolverVersion.default(pip_version)
)
)

pip_configuration = attr.ib() # type: PipConfiguration

Expand Down
7 changes: 4 additions & 3 deletions pex/resolve/lockfile/model.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,6 @@ def create(
style, # type: LockStyle.Value
requires_python, # type: Iterable[str]
target_systems, # type: Iterable[TargetSystem.Value]
resolver_version, # type: ResolverVersion.Value
requirements, # type: Iterable[Union[Requirement, ParsedRequirement]]
constraints, # type: Iterable[Requirement]
allow_prereleases, # type: bool
Expand All @@ -47,6 +46,7 @@ def create(
locked_resolves, # type: Iterable[LockedResolve]
source=None, # type: Optional[str]
pip_version=None, # type: Optional[PipVersionValue]
resolver_version=None, # type: Optional[ResolverVersion.Value]
):
# type: (...) -> Lockfile

Expand Down Expand Up @@ -88,13 +88,14 @@ def extract_requirement(req):

resolve_requirements = OrderedSet(extract_requirement(req) for req in requirements)

pip_ver = pip_version or PipVersion.DEFAULT
return cls(
pex_version=pex_version,
style=style,
requires_python=SortedTuple(requires_python),
target_systems=SortedTuple(target_systems),
pip_version=pip_version or PipVersion.DEFAULT,
resolver_version=resolver_version,
pip_version=pip_ver,
resolver_version=resolver_version or ResolverVersion.default(pip_ver),
requirements=SortedTuple(resolve_requirements, key=str),
constraints=SortedTuple(constraints, key=str),
allow_prereleases=allow_prereleases,
Expand Down
24 changes: 22 additions & 2 deletions pex/resolve/resolver_configuration.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,12 @@
from __future__ import absolute_import

import itertools
import os

from pex.auth import PasswordEntry
from pex.enum import Enum
from pex.jobs import DEFAULT_MAX_JOBS
from pex.network_configuration import NetworkConfiguration
from pex.pep_440 import Version
from pex.pip.version import PipVersion, PipVersionValue
from pex.typing import TYPE_CHECKING

Expand All @@ -31,6 +31,26 @@ class ResolverVersion(Enum["ResolverVersion.Value"]):
class Value(Enum.Value):
pass

@staticmethod
def _supports_legacy_resolver(pip_version=None):
# type: (Optional[PipVersionValue]) -> bool
pip_ver = pip_version or PipVersion.DEFAULT
return pip_ver.version < Version("23.2")

@classmethod
def applies(
cls,
resolver_version, # type: ResolverVersion.Value
pip_version=None,
):
# type: (...) -> bool
return resolver_version is cls.PIP_2020 or cls._supports_legacy_resolver(pip_version)

@classmethod
def default(cls, pip_version=None):
# type: (Optional[PipVersionValue]) -> ResolverVersion.Value
return cls.PIP_LEGACY if cls._supports_legacy_resolver(pip_version) else cls.PIP_2020

PIP_LEGACY = Value("pip-legacy-resolver")
PIP_2020 = Value("pip-2020-resolver")

Expand Down Expand Up @@ -63,7 +83,6 @@ def create(

@attr.s(frozen=True)
class PipConfiguration(object):
resolver_version = attr.ib(default=ResolverVersion.PIP_LEGACY) # type: ResolverVersion.Value
repos_configuration = attr.ib(default=ReposConfiguration()) # type: ReposConfiguration
network_configuration = attr.ib(default=NetworkConfiguration()) # type: NetworkConfiguration
allow_prereleases = attr.ib(default=False) # type: bool
Expand All @@ -76,6 +95,7 @@ class PipConfiguration(object):
max_jobs = attr.ib(default=DEFAULT_MAX_JOBS) # type: int
preserve_log = attr.ib(default=False) # type: bool
version = attr.ib(default=None) # type: Optional[PipVersionValue]
resolver_version = attr.ib(default=None) # type: Optional[ResolverVersion.Value]
allow_version_fallback = attr.ib(default=True) # type: bool


Expand Down
4 changes: 2 additions & 2 deletions pex/resolve/resolver_options.py
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ def register(
parser.add_argument(
"--resolver-version",
dest="resolver_version",
default=default_resolver_configuration.resolver_version,
default=ResolverVersion.default(),
choices=ResolverVersion.values(),
type=ResolverVersion.for_value,
help=(
Expand Down Expand Up @@ -446,7 +446,6 @@ def create_pip_configuration(options):
pip_version = PipVersion.for_value(options.pip_version)

return PipConfiguration(
resolver_version=options.resolver_version,
repos_configuration=repos_configuration,
network_configuration=create_network_configuration(options),
allow_prereleases=options.allow_prereleases,
Expand All @@ -459,6 +458,7 @@ def create_pip_configuration(options):
max_jobs=get_max_jobs_value(options),
preserve_log=options.preserve_pip_download_log,
version=pip_version,
resolver_version=options.resolver_version,
allow_version_fallback=options.allow_pip_version_fallback,
)

Expand Down
4 changes: 1 addition & 3 deletions tests/build_system/test_pep_518.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,7 @@
from pex.common import touch
from pex.environment import PEXEnvironment
from pex.pep_503 import ProjectName
from pex.pip.version import PipVersion
from pex.resolve.configured_resolver import ConfiguredResolver
from pex.resolve.resolver_configuration import PipConfiguration
from pex.result import Error
from pex.targets import LocalInterpreter
from pex.typing import TYPE_CHECKING
Expand All @@ -26,7 +24,7 @@ def load_build_system(project_directory):
# type: (...) -> Union[Optional[BuildSystem], Error]
return pep_518.load_build_system(
LocalInterpreter.create(),
ConfiguredResolver(PipConfiguration(version=PipVersion.DEFAULT)),
ConfiguredResolver.default(),
project_directory,
)

Expand Down
11 changes: 10 additions & 1 deletion tests/integration/cli/commands/test_issue_1801.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,12 @@
import os.path
import re

import pytest
from colors import green

from pex.cli.testing import run_pex3
from pex.resolve.lockfile import json_codec
from pex.resolve.resolver_configuration import ResolverVersion
from pex.testing import run_pex_command


Expand Down Expand Up @@ -58,6 +60,13 @@ def test_preserve_pip_download_log():
assert expected_hash == artifact.fingerprint.hash


@pytest.mark.skipif(
ResolverVersion.default() is ResolverVersion.PIP_2020,
reason=(
"The PIP_2020 resolver triggers download analysis in normal resolves but this test is "
"concerned with the case when there is no analysis to be performed."
),
)
def test_preserve_pip_download_log_none():
# type: () -> None

Expand All @@ -76,4 +85,4 @@ def test_preserve_pip_download_log_none():
assert (
"pex: The `pip download` log is not being utilized, to see more `pip download` details, "
"re-run with more Pex verbosity (more `-v`s).\n"
) in result.error
) in result.error, result.error
1 change: 0 additions & 1 deletion tests/integration/cli/commands/test_issue_2050.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@
from pex.dist_metadata import Requirement
from pex.pep_440 import Version
from pex.pep_503 import ProjectName
from pex.pip.version import PipVersion
from pex.resolve.configured_resolver import ConfiguredResolver
from pex.resolve.locked_resolve import LockedRequirement
from pex.resolve.lockfile import json_codec
Expand Down
1 change: 1 addition & 0 deletions tests/integration/cli/commands/test_lock.py
Original file line number Diff line number Diff line change
Expand Up @@ -1821,6 +1821,7 @@ def test_excludes_pep517_build_requirements_issue_1565(tmpdir):
resolver_version, EXPECTED_LOCKFILES.get(resolver_version), id=resolver_version.value
)
for resolver_version in ResolverVersion.values()
if ResolverVersion.applies(resolver_version)
],
)
def test_universal_lock(
Expand Down
1 change: 1 addition & 0 deletions tests/integration/resolve/test_issue_1918.py
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@ def has_ssh_access():
[
pytest.param(resolver_version, id=resolver_version.value)
for resolver_version in ResolverVersion.values()
if ResolverVersion.applies(resolver_version)
],
)
def test_redacted_requirement_handling(
Expand Down
2 changes: 1 addition & 1 deletion tests/integration/test_downloads.py
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ def file_artifact(
@pytest.fixture
def downloader():
# type: () -> ArtifactDownloader
return ArtifactDownloader(ConfiguredResolver(PipConfiguration()))
return ArtifactDownloader(ConfiguredResolver.default())


def test_issue_1849_download_foreign_artifact(
Expand Down
1 change: 1 addition & 0 deletions tests/integration/test_integration.py
Original file line number Diff line number Diff line change
Expand Up @@ -1666,6 +1666,7 @@ def test_constraint_file_from_url(tmpdir):
# requirements URL contains `requests[security]>=2.20.1` which uses an extra; so we use
# older Pip here.
"--pip-version=20.3.4-patched",
"--resolver-version=pip-legacy-resolver",
"-o",
pex_file,
],
Expand Down
8 changes: 4 additions & 4 deletions tests/test_environment.py
Original file line number Diff line number Diff line change
Expand Up @@ -141,7 +141,7 @@ def add_requirements(builder):
for installed_dist in resolver.resolve(
targets=Targets(interpreters=(builder.interpreter,)),
requirements=requirements,
resolver=ConfiguredResolver(pip_configuration=PipConfiguration()),
resolver=ConfiguredResolver.default(),
).installed_distributions:
builder.add_distribution(installed_dist.distribution)
for direct_req in installed_dist.direct_requirements:
Expand Down Expand Up @@ -274,7 +274,7 @@ def bad_interpreter():
for installed_dist in resolver.resolve(
targets=Targets(interpreters=(pb.interpreter,)),
requirements=["psutil==5.4.3"],
resolver=ConfiguredResolver(pip_configuration=PipConfiguration()),
resolver=ConfiguredResolver.default(),
).installed_distributions:
pb.add_dist_location(installed_dist.distribution.location)
pb.build(pex_file)
Expand Down Expand Up @@ -342,7 +342,7 @@ def test_activate_extras_issue_615():
for installed_dist in resolver.resolve(
targets=Targets(interpreters=(pb.interpreter,)),
requirements=["pex[requests]==1.6.3"],
resolver=ConfiguredResolver(pip_configuration=PipConfiguration()),
resolver=ConfiguredResolver.default(),
).installed_distributions:
for direct_req in installed_dist.direct_requirements:
pb.add_requirement(direct_req)
Expand All @@ -369,7 +369,7 @@ def assert_namespace_packages_warning(distribution, version, expected_warning):
pb = PEXBuilder()
for installed_dist in resolver.resolve(
requirements=[requirement],
resolver=ConfiguredResolver(pip_configuration=PipConfiguration()),
resolver=ConfiguredResolver.default(),
).installed_distributions:
pb.add_dist_location(installed_dist.distribution.location)
pb.freeze()
Expand Down
6 changes: 3 additions & 3 deletions tests/test_pex.py
Original file line number Diff line number Diff line change
Expand Up @@ -839,7 +839,7 @@ def test_pex_run_custom_setuptools_useable(
# type: (...) -> None
result = resolver.resolve(
requirements=[setuptools_requirement],
resolver=ConfiguredResolver(pip_configuration=PipConfiguration()),
resolver=ConfiguredResolver.default(),
)
dists = [installed_dist.distribution for installed_dist in result.installed_distributions]
with temporary_dir() as temp_dir:
Expand All @@ -864,7 +864,7 @@ def test_pex_run_conflicting_custom_setuptools_useable(

result = resolver.resolve(
requirements=[setuptools_requirement],
resolver=ConfiguredResolver(pip_configuration=PipConfiguration()),
resolver=ConfiguredResolver.default(),
)
dists = [installed_dist.distribution for installed_dist in result.installed_distributions]
with temporary_dir() as temp_dir:
Expand All @@ -891,7 +891,7 @@ def test_pex_run_custom_pex_useable():
old_pex_version = "0.7.0"
result = resolver.resolve(
requirements=["pex=={}".format(old_pex_version), "setuptools==40.6.3"],
resolver=ConfiguredResolver(pip_configuration=PipConfiguration()),
resolver=ConfiguredResolver.default(),
)
dists = [installed_dist.distribution for installed_dist in result.installed_distributions]
with temporary_dir() as temp_dir:
Expand Down
Loading

0 comments on commit 145a1ef

Please sign in to comment.