pex 2.54.2__py2.py3-none-any.whl → 2.69.0__py2.py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of pex might be problematic. Click here for more details.
- pex/auth.py +1 -1
- pex/bin/pex.py +15 -2
- pex/build_backend/configuration.py +5 -5
- pex/build_backend/wrap.py +27 -23
- pex/build_system/pep_517.py +4 -1
- pex/cache/dirs.py +17 -12
- pex/cli/commands/lock.py +302 -165
- pex/cli/commands/pip/core.py +4 -12
- pex/cli/commands/pip/wheel.py +1 -1
- pex/cli/commands/run.py +13 -20
- pex/cli/commands/venv.py +85 -16
- pex/cli/pex.py +11 -4
- pex/common.py +57 -7
- pex/compatibility.py +1 -1
- pex/dependency_configuration.py +87 -15
- pex/dist_metadata.py +143 -25
- pex/docs/html/_pagefind/fragment/en_4250138.pf_fragment +0 -0
- pex/docs/html/_pagefind/fragment/en_7125dad.pf_fragment +0 -0
- pex/docs/html/_pagefind/fragment/en_785d562.pf_fragment +0 -0
- pex/docs/html/_pagefind/fragment/en_8e94bb8.pf_fragment +0 -0
- pex/docs/html/_pagefind/fragment/en_a0396bb.pf_fragment +0 -0
- pex/docs/html/_pagefind/fragment/en_a8a3588.pf_fragment +0 -0
- pex/docs/html/_pagefind/fragment/en_c07d988.pf_fragment +0 -0
- pex/docs/html/_pagefind/fragment/en_d718411.pf_fragment +0 -0
- pex/docs/html/_pagefind/index/en_a2e3c5e.pf_index +0 -0
- pex/docs/html/_pagefind/pagefind-entry.json +1 -1
- pex/docs/html/_pagefind/pagefind.en_4ce1afa9e3.pf_meta +0 -0
- pex/docs/html/_static/documentation_options.js +1 -1
- pex/docs/html/_static/pygments.css +164 -146
- pex/docs/html/_static/styles/furo.css +1 -1
- pex/docs/html/_static/styles/furo.css.map +1 -1
- pex/docs/html/api/vars.html +25 -34
- pex/docs/html/buildingpex.html +25 -34
- pex/docs/html/genindex.html +24 -33
- pex/docs/html/index.html +25 -34
- pex/docs/html/recipes.html +25 -34
- pex/docs/html/scie.html +25 -34
- pex/docs/html/search.html +24 -33
- pex/docs/html/whatispex.html +25 -34
- pex/entry_points_txt.py +98 -0
- pex/environment.py +54 -33
- pex/finders.py +1 -1
- pex/hashing.py +71 -9
- pex/installed_wheel.py +141 -0
- pex/interpreter.py +41 -38
- pex/interpreter_constraints.py +25 -25
- pex/interpreter_implementation.py +40 -0
- pex/jobs.py +13 -6
- pex/pep_376.py +68 -384
- pex/pep_425.py +11 -2
- pex/pep_427.py +937 -205
- pex/pep_508.py +4 -5
- pex/pex_builder.py +5 -8
- pex/pex_info.py +14 -9
- pex/pip/dependencies/__init__.py +85 -13
- pex/pip/dependencies/requires.py +38 -3
- pex/pip/foreign_platform/__init__.py +4 -3
- pex/pip/installation.py +2 -2
- pex/pip/local_project.py +6 -14
- pex/pip/package_repositories/__init__.py +78 -0
- pex/pip/package_repositories/link_collector.py +96 -0
- pex/pip/tool.py +139 -33
- pex/pip/vcs.py +109 -43
- pex/pip/version.py +8 -1
- pex/requirements.py +121 -16
- pex/resolve/config.py +5 -1
- pex/resolve/configured_resolve.py +32 -10
- pex/resolve/configured_resolver.py +10 -39
- pex/resolve/downloads.py +4 -3
- pex/resolve/lock_downloader.py +16 -23
- pex/resolve/lock_resolver.py +41 -51
- pex/resolve/locked_resolve.py +89 -32
- pex/resolve/locker.py +145 -101
- pex/resolve/locker_patches.py +123 -197
- pex/resolve/lockfile/create.py +232 -87
- pex/resolve/lockfile/download_manager.py +5 -1
- pex/resolve/lockfile/json_codec.py +103 -28
- pex/resolve/lockfile/model.py +13 -35
- pex/resolve/lockfile/pep_751.py +117 -98
- pex/resolve/lockfile/requires_dist.py +17 -262
- pex/resolve/lockfile/subset.py +11 -0
- pex/resolve/lockfile/targets.py +445 -0
- pex/resolve/lockfile/updater.py +22 -10
- pex/resolve/package_repository.py +406 -0
- pex/resolve/pex_repository_resolver.py +1 -1
- pex/resolve/pre_resolved_resolver.py +19 -16
- pex/resolve/project.py +233 -47
- pex/resolve/requirement_configuration.py +28 -10
- pex/resolve/resolver_configuration.py +18 -32
- pex/resolve/resolver_options.py +234 -28
- pex/resolve/resolvers.py +3 -12
- pex/resolve/target_options.py +18 -2
- pex/resolve/target_system.py +908 -0
- pex/resolve/venv_resolver.py +670 -0
- pex/resolver.py +673 -209
- pex/scie/__init__.py +40 -1
- pex/scie/model.py +2 -0
- pex/scie/science.py +25 -3
- pex/sdist.py +219 -0
- pex/sh_boot.py +24 -21
- pex/sysconfig.py +5 -3
- pex/targets.py +31 -10
- pex/third_party/__init__.py +1 -1
- pex/tools/commands/repository.py +48 -25
- pex/vendor/__init__.py +4 -9
- pex/vendor/__main__.py +65 -41
- pex/vendor/_vendored/ansicolors/.layout.json +1 -1
- pex/vendor/_vendored/ansicolors/ansicolors-1.1.8.dist-info/RECORD +11 -0
- pex/vendor/_vendored/ansicolors/ansicolors-1.1.8.pex-info/original-whl-info.json +1 -0
- pex/vendor/_vendored/appdirs/.layout.json +1 -1
- pex/vendor/_vendored/appdirs/appdirs-1.4.4.dist-info/RECORD +7 -0
- pex/vendor/_vendored/appdirs/appdirs-1.4.4.pex-info/original-whl-info.json +1 -0
- pex/vendor/_vendored/attrs/.layout.json +1 -1
- pex/vendor/_vendored/attrs/attrs-21.5.0.dev0.dist-info/RECORD +37 -0
- pex/vendor/_vendored/attrs/attrs-21.5.0.dev0.pex-info/original-whl-info.json +1 -0
- pex/vendor/_vendored/packaging_20_9/.layout.json +1 -1
- pex/vendor/_vendored/packaging_20_9/packaging-20.9.dist-info/RECORD +20 -0
- pex/vendor/_vendored/packaging_20_9/packaging-20.9.pex-info/original-whl-info.json +1 -0
- pex/vendor/_vendored/packaging_20_9/pyparsing-2.4.7.dist-info/RECORD +7 -0
- pex/vendor/_vendored/packaging_20_9/pyparsing-2.4.7.pex-info/original-whl-info.json +1 -0
- pex/vendor/_vendored/packaging_21_3/.layout.json +1 -1
- pex/vendor/_vendored/packaging_21_3/packaging-21.3.dist-info/RECORD +20 -0
- pex/vendor/_vendored/packaging_21_3/packaging-21.3.pex-info/original-whl-info.json +1 -0
- pex/vendor/_vendored/packaging_21_3/pyparsing-3.0.7.dist-info/RECORD +18 -0
- pex/vendor/_vendored/packaging_21_3/pyparsing-3.0.7.pex-info/original-whl-info.json +1 -0
- pex/vendor/_vendored/packaging_24_0/.layout.json +1 -1
- pex/vendor/_vendored/packaging_24_0/packaging-24.0.dist-info/RECORD +22 -0
- pex/vendor/_vendored/packaging_24_0/packaging-24.0.pex-info/original-whl-info.json +1 -0
- pex/vendor/_vendored/packaging_25_0/.layout.json +1 -1
- pex/vendor/_vendored/packaging_25_0/packaging-25.0.dist-info/RECORD +24 -0
- pex/vendor/_vendored/packaging_25_0/packaging-25.0.pex-info/original-whl-info.json +1 -0
- pex/vendor/_vendored/pip/.layout.json +1 -1
- pex/vendor/_vendored/pip/pip/_vendor/certifi/cacert.pem +63 -1
- pex/vendor/_vendored/pip/pip-20.3.4.dist-info/RECORD +388 -0
- pex/vendor/_vendored/pip/pip-20.3.4.pex-info/original-whl-info.json +1 -0
- pex/vendor/_vendored/setuptools/.layout.json +1 -1
- pex/vendor/_vendored/setuptools/setuptools-44.0.0+3acb925dd708430aeaf197ea53ac8a752f7c1863.dist-info/RECORD +107 -0
- pex/vendor/_vendored/setuptools/setuptools-44.0.0+3acb925dd708430aeaf197ea53ac8a752f7c1863.pex-info/original-whl-info.json +1 -0
- pex/vendor/_vendored/toml/.layout.json +1 -1
- pex/vendor/_vendored/toml/toml-0.10.2.dist-info/RECORD +11 -0
- pex/vendor/_vendored/toml/toml-0.10.2.pex-info/original-whl-info.json +1 -0
- pex/vendor/_vendored/tomli/.layout.json +1 -1
- pex/vendor/_vendored/tomli/tomli-2.0.1.dist-info/RECORD +10 -0
- pex/vendor/_vendored/tomli/tomli-2.0.1.pex-info/original-whl-info.json +1 -0
- pex/venv/installer.py +46 -19
- pex/venv/venv_pex.py +6 -3
- pex/version.py +1 -1
- pex/wheel.py +188 -40
- pex/whl.py +67 -0
- pex/windows/__init__.py +14 -11
- {pex-2.54.2.dist-info → pex-2.69.0.dist-info}/METADATA +6 -5
- {pex-2.54.2.dist-info → pex-2.69.0.dist-info}/RECORD +157 -133
- {pex-2.54.2.dist-info → pex-2.69.0.dist-info}/entry_points.txt +1 -0
- {pex-2.54.2.dist-info → pex-2.69.0.dist-info}/pylock/pylock.toml +1 -1
- pex/docs/html/_pagefind/fragment/en_42c9d8c.pf_fragment +0 -0
- pex/docs/html/_pagefind/fragment/en_45dd5a2.pf_fragment +0 -0
- pex/docs/html/_pagefind/fragment/en_4ca74d2.pf_fragment +0 -0
- pex/docs/html/_pagefind/fragment/en_77273d5.pf_fragment +0 -0
- pex/docs/html/_pagefind/fragment/en_87a59c5.pf_fragment +0 -0
- pex/docs/html/_pagefind/fragment/en_8dc89b5.pf_fragment +0 -0
- pex/docs/html/_pagefind/fragment/en_9d1319b.pf_fragment +0 -0
- pex/docs/html/_pagefind/fragment/en_e55df9d.pf_fragment +0 -0
- pex/docs/html/_pagefind/index/en_1e98c6f.pf_index +0 -0
- pex/docs/html/_pagefind/pagefind.en_d1c488ecae.pf_meta +0 -0
- pex/vendor/_vendored/ansicolors/ansicolors-1.1.8.dist-info/INSTALLER +0 -1
- pex/vendor/_vendored/appdirs/appdirs-1.4.4.dist-info/INSTALLER +0 -1
- pex/vendor/_vendored/attrs/attrs-21.5.0.dev0.dist-info/INSTALLER +0 -1
- pex/vendor/_vendored/packaging_20_9/packaging-20.9.dist-info/INSTALLER +0 -1
- pex/vendor/_vendored/packaging_20_9/pyparsing-2.4.7.dist-info/INSTALLER +0 -1
- pex/vendor/_vendored/packaging_21_3/packaging-21.3.dist-info/INSTALLER +0 -1
- pex/vendor/_vendored/packaging_21_3/pyparsing-3.0.7.dist-info/INSTALLER +0 -1
- pex/vendor/_vendored/packaging_24_0/packaging-24.0.dist-info/INSTALLER +0 -1
- pex/vendor/_vendored/packaging_25_0/packaging-25.0.dist-info/INSTALLER +0 -1
- pex/vendor/_vendored/pip/pip-20.3.4.dist-info/INSTALLER +0 -1
- pex/vendor/_vendored/setuptools/setuptools-44.0.0+3acb925dd708430aeaf197ea53ac8a752f7c1863.dist-info/INSTALLER +0 -1
- pex/vendor/_vendored/toml/toml-0.10.2.dist-info/INSTALLER +0 -1
- pex/vendor/_vendored/tomli/tomli-2.0.1.dist-info/INSTALLER +0 -1
- {pex-2.54.2.dist-info → pex-2.69.0.dist-info}/WHEEL +0 -0
- {pex-2.54.2.dist-info → pex-2.69.0.dist-info}/licenses/LICENSE +0 -0
- {pex-2.54.2.dist-info → pex-2.69.0.dist-info}/top_level.txt +0 -0
pex/pep_508.py
CHANGED
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
|
|
4
4
|
from __future__ import absolute_import
|
|
5
5
|
|
|
6
|
+
from pex.interpreter_implementation import InterpreterImplementation
|
|
6
7
|
from pex.platforms import Platform
|
|
7
8
|
from pex.third_party.packaging import markers
|
|
8
9
|
from pex.typing import TYPE_CHECKING
|
|
@@ -117,11 +118,9 @@ class MarkerEnvironment(object):
|
|
|
117
118
|
sys_platform = "win32"
|
|
118
119
|
|
|
119
120
|
platform_python_implementation = None
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
elif platform.impl == "pp":
|
|
124
|
-
platform_python_implementation = "PyPy"
|
|
121
|
+
for implementation in InterpreterImplementation.values():
|
|
122
|
+
if implementation.abbr == platform.impl:
|
|
123
|
+
platform_python_implementation = implementation.value
|
|
125
124
|
|
|
126
125
|
python_version = ".".join(map(str, platform.version_info[:2]))
|
|
127
126
|
|
pex/pex_builder.py
CHANGED
|
@@ -33,11 +33,11 @@ from pex.enum import Enum
|
|
|
33
33
|
from pex.executables import chmod_plus_x, create_sh_python_redirector_shebang
|
|
34
34
|
from pex.finders import get_entry_point_from_console_script, get_script_from_distributions
|
|
35
35
|
from pex.fs import safe_rename, safe_symlink
|
|
36
|
+
from pex.installed_wheel import InstalledWheel
|
|
36
37
|
from pex.interpreter import PythonInterpreter
|
|
37
38
|
from pex.layout import Layout
|
|
38
39
|
from pex.orderedset import OrderedSet
|
|
39
40
|
from pex.os import WINDOWS
|
|
40
|
-
from pex.pep_376 import InstalledWheel
|
|
41
41
|
from pex.pex import PEX
|
|
42
42
|
from pex.pex_info import PexInfo
|
|
43
43
|
from pex.sh_boot import create_sh_boot_script
|
|
@@ -470,10 +470,7 @@ class PEXBuilder(object):
|
|
|
470
470
|
def _prepare_code(self):
|
|
471
471
|
chroot_path = self._chroot.path()
|
|
472
472
|
self._pex_info.code_hash = CacheHelper.pex_code_hash(
|
|
473
|
-
chroot_path,
|
|
474
|
-
exclude_dirs=tuple(
|
|
475
|
-
os.path.join(chroot_path, d) for d in (layout.BOOTSTRAP_DIR, layout.DEPS_DIR)
|
|
476
|
-
),
|
|
473
|
+
chroot_path, exclude_dirs=(layout.BOOTSTRAP_DIR, layout.DEPS_DIR)
|
|
477
474
|
)
|
|
478
475
|
self._pex_info.pex_hash = hashlib.sha1(self._pex_info.dump().encode("utf-8")).hexdigest()
|
|
479
476
|
self._chroot.write(self._pex_info.dump().encode("utf-8"), PexInfo.PATH, label="manifest")
|
|
@@ -790,9 +787,9 @@ class PEXBuilder(object):
|
|
|
790
787
|
self._chroot.zip(
|
|
791
788
|
os.path.join(atomic_zip_dir.work_dir, location),
|
|
792
789
|
deterministic=deterministic,
|
|
793
|
-
exclude_file=
|
|
794
|
-
|
|
795
|
-
|
|
790
|
+
exclude_file=(
|
|
791
|
+
is_pyc_temporary_file if bytecode_compile else is_pyc_file
|
|
792
|
+
),
|
|
796
793
|
strip_prefix=os.path.join(pex_info.internal_cache, location),
|
|
797
794
|
labels=(location,),
|
|
798
795
|
compress=compress,
|
pex/pex_info.py
CHANGED
|
@@ -25,11 +25,11 @@ if TYPE_CHECKING:
|
|
|
25
25
|
from typing import Collection # type: ignore[attr-defined]
|
|
26
26
|
from typing import Any, Dict, Iterable, Mapping, Optional, Text, Tuple, Union
|
|
27
27
|
|
|
28
|
-
from pex.cache.dirs import VenvDir
|
|
29
|
-
from pex.dist_metadata import Requirement
|
|
30
|
-
|
|
31
28
|
# N.B.: These are expensive imports and PexInfo is used during PEX bootstrapping which we want
|
|
32
29
|
# to be as fast as possible.
|
|
30
|
+
from pex.cache.dirs import VenvDir
|
|
31
|
+
from pex.dependency_configuration import Override
|
|
32
|
+
from pex.dist_metadata import Requirement
|
|
33
33
|
from pex.interpreter import PythonInterpreter
|
|
34
34
|
from pex.interpreter_constraints import InterpreterConstraints
|
|
35
35
|
|
|
@@ -491,9 +491,9 @@ class PexInfo(object):
|
|
|
491
491
|
# type: () -> Iterable[str]
|
|
492
492
|
return self._excluded
|
|
493
493
|
|
|
494
|
-
def add_override(self,
|
|
495
|
-
# type: (
|
|
496
|
-
self._overridden.add(str(
|
|
494
|
+
def add_override(self, override):
|
|
495
|
+
# type: (Override) -> None
|
|
496
|
+
self._overridden.add(str(override))
|
|
497
497
|
|
|
498
498
|
@property
|
|
499
499
|
def overridden(self):
|
|
@@ -604,9 +604,14 @@ class PexInfo(object):
|
|
|
604
604
|
data["distributions"] = self._distributions.copy()
|
|
605
605
|
return data
|
|
606
606
|
|
|
607
|
-
def dump(self,
|
|
608
|
-
# type: (
|
|
609
|
-
return json.dumps(
|
|
607
|
+
def dump(self, indent=None):
|
|
608
|
+
# type: (Optional[int]) -> str
|
|
609
|
+
return json.dumps(
|
|
610
|
+
self.as_json_dict(),
|
|
611
|
+
sort_keys=True,
|
|
612
|
+
indent=indent,
|
|
613
|
+
separators=None if indent else (",", ":"),
|
|
614
|
+
)
|
|
610
615
|
|
|
611
616
|
def copy(self):
|
|
612
617
|
# type: () -> PexInfo
|
pex/pip/dependencies/__init__.py
CHANGED
|
@@ -8,30 +8,82 @@ import os
|
|
|
8
8
|
|
|
9
9
|
from pex.common import safe_mkdtemp
|
|
10
10
|
from pex.dependency_configuration import DependencyConfiguration
|
|
11
|
+
from pex.exceptions import reportable_unexpected_error_msg
|
|
12
|
+
from pex.interpreter_implementation import InterpreterImplementation
|
|
13
|
+
from pex.pep_508 import MarkerEnvironment
|
|
11
14
|
from pex.pip.download_observer import DownloadObserver, Patch, PatchSet
|
|
12
|
-
from pex.
|
|
15
|
+
from pex.resolve.target_system import TargetSystem, UniversalTarget
|
|
16
|
+
from pex.third_party.packaging.specifiers import SpecifierSet
|
|
17
|
+
from pex.typing import TYPE_CHECKING, cast
|
|
13
18
|
|
|
14
19
|
if TYPE_CHECKING:
|
|
15
|
-
from typing import Mapping, Optional
|
|
20
|
+
from typing import Mapping, Optional, Union
|
|
16
21
|
|
|
22
|
+
import attr # vendor:skip
|
|
23
|
+
else:
|
|
24
|
+
from pex.third_party import attr
|
|
17
25
|
|
|
26
|
+
|
|
27
|
+
@attr.s(frozen=True)
|
|
18
28
|
class PatchContext(object):
|
|
19
29
|
_PEX_DEP_CONFIG_FILE_ENV_VAR_NAME = "_PEX_DEP_CONFIG_FILE"
|
|
20
30
|
|
|
21
31
|
@classmethod
|
|
22
|
-
def
|
|
23
|
-
# type: () ->
|
|
32
|
+
def load(cls):
|
|
33
|
+
# type: () -> PatchContext
|
|
24
34
|
|
|
25
35
|
dep_config_file = os.environ.pop(cls._PEX_DEP_CONFIG_FILE_ENV_VAR_NAME)
|
|
26
36
|
with open(dep_config_file) as fp:
|
|
27
37
|
data = json.load(fp)
|
|
28
|
-
|
|
29
|
-
|
|
38
|
+
|
|
39
|
+
universal_target = None # type: Optional[UniversalTarget]
|
|
40
|
+
universal_target_data = data["universal_target"]
|
|
41
|
+
if universal_target_data:
|
|
42
|
+
implementation = universal_target_data["implementation"]
|
|
43
|
+
universal_target = UniversalTarget(
|
|
44
|
+
implementation=(
|
|
45
|
+
InterpreterImplementation.for_value(implementation) if implementation else None
|
|
46
|
+
),
|
|
47
|
+
requires_python=tuple(
|
|
48
|
+
SpecifierSet(requires_python)
|
|
49
|
+
for requires_python in universal_target_data["requires_python"]
|
|
50
|
+
),
|
|
51
|
+
systems=tuple(
|
|
52
|
+
TargetSystem.for_value(system) for system in universal_target_data["systems"]
|
|
53
|
+
),
|
|
54
|
+
)
|
|
55
|
+
|
|
56
|
+
marker_environment = None # type: Optional[MarkerEnvironment]
|
|
57
|
+
marker_environment_data = data["marker_environment"]
|
|
58
|
+
if marker_environment_data:
|
|
59
|
+
marker_environment = MarkerEnvironment(**marker_environment_data)
|
|
60
|
+
|
|
61
|
+
if not (bool(universal_target) ^ bool(marker_environment)):
|
|
62
|
+
raise AssertionError(
|
|
63
|
+
reportable_unexpected_error_msg(
|
|
64
|
+
"Expected exactly one of lock_configuration or marker_environment to be "
|
|
65
|
+
"defined, found data: {data}",
|
|
66
|
+
data=data,
|
|
67
|
+
)
|
|
68
|
+
)
|
|
69
|
+
|
|
70
|
+
return cls(
|
|
71
|
+
dependency_configuration=DependencyConfiguration.create(
|
|
72
|
+
excluded=data["excluded"], overridden=data["overridden"]
|
|
73
|
+
),
|
|
74
|
+
target=cast(
|
|
75
|
+
"Union[UniversalTarget, MarkerEnvironment]",
|
|
76
|
+
universal_target or marker_environment,
|
|
77
|
+
),
|
|
30
78
|
)
|
|
31
79
|
|
|
32
80
|
@classmethod
|
|
33
|
-
def
|
|
34
|
-
|
|
81
|
+
def dump(
|
|
82
|
+
cls,
|
|
83
|
+
dependency_configuration, # type: DependencyConfiguration
|
|
84
|
+
target, # type: Union[UniversalTarget, MarkerEnvironment]
|
|
85
|
+
):
|
|
86
|
+
# type: (...) -> Mapping[str, str]
|
|
35
87
|
|
|
36
88
|
dep_config_file = os.path.join(safe_mkdtemp(), "dep_config.json")
|
|
37
89
|
with open(dep_config_file, "w") as fp:
|
|
@@ -41,14 +93,36 @@ class PatchContext(object):
|
|
|
41
93
|
"overridden": [
|
|
42
94
|
str(override) for override in dependency_configuration.all_overrides()
|
|
43
95
|
],
|
|
96
|
+
"universal_target": (
|
|
97
|
+
{
|
|
98
|
+
"implementation": (
|
|
99
|
+
str(target.implementation) if target.implementation else None
|
|
100
|
+
),
|
|
101
|
+
"requires_python": [
|
|
102
|
+
str(specifier_set) for specifier_set in target.requires_python
|
|
103
|
+
],
|
|
104
|
+
"systems": [str(system) for system in target.systems],
|
|
105
|
+
}
|
|
106
|
+
if isinstance(target, UniversalTarget)
|
|
107
|
+
else None
|
|
108
|
+
),
|
|
109
|
+
"marker_environment": (
|
|
110
|
+
target.as_dict() if isinstance(target, MarkerEnvironment) else None
|
|
111
|
+
),
|
|
44
112
|
},
|
|
45
113
|
fp,
|
|
46
114
|
)
|
|
47
115
|
return {cls._PEX_DEP_CONFIG_FILE_ENV_VAR_NAME: dep_config_file}
|
|
48
116
|
|
|
117
|
+
dependency_configuration = attr.ib() # type: DependencyConfiguration
|
|
118
|
+
target = attr.ib() # type: Union[UniversalTarget, MarkerEnvironment]
|
|
119
|
+
|
|
49
120
|
|
|
50
|
-
def patch(
|
|
51
|
-
# type:
|
|
121
|
+
def patch(
|
|
122
|
+
dependency_configuration, # type: DependencyConfiguration
|
|
123
|
+
target, # type: Union[UniversalTarget, MarkerEnvironment]
|
|
124
|
+
):
|
|
125
|
+
# type: (...) -> Optional[DownloadObserver]
|
|
52
126
|
|
|
53
127
|
if not dependency_configuration:
|
|
54
128
|
return None
|
|
@@ -57,9 +131,7 @@ def patch(dependency_configuration):
|
|
|
57
131
|
analyzer=None,
|
|
58
132
|
patch_set=PatchSet.create(
|
|
59
133
|
Patch.from_code_resource(
|
|
60
|
-
__name__,
|
|
61
|
-
"requires.py",
|
|
62
|
-
**PatchContext.dump_dependency_configuration(dependency_configuration)
|
|
134
|
+
__name__, "requires.py", **PatchContext.dump(dependency_configuration, target)
|
|
63
135
|
)
|
|
64
136
|
),
|
|
65
137
|
)
|
pex/pip/dependencies/requires.py
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
# Copyright 2024 Pex project contributors.
|
|
2
2
|
# Licensed under the Apache License, Version 2.0 (see LICENSE).
|
|
3
3
|
|
|
4
|
-
from __future__ import absolute_import
|
|
4
|
+
from __future__ import absolute_import
|
|
5
5
|
|
|
6
6
|
import logging
|
|
7
7
|
import sys
|
|
@@ -14,9 +14,34 @@ def patch():
|
|
|
14
14
|
|
|
15
15
|
from pex.common import pluralize
|
|
16
16
|
from pex.dist_metadata import Requirement as PexRequirement
|
|
17
|
+
from pex.pep_508 import MarkerEnvironment
|
|
17
18
|
from pex.pip.dependencies import PatchContext
|
|
19
|
+
from pex.resolve.target_system import UniversalTarget
|
|
20
|
+
from pex.typing import TYPE_CHECKING
|
|
18
21
|
|
|
19
|
-
|
|
22
|
+
if TYPE_CHECKING:
|
|
23
|
+
from typing import Dict, Optional, Sequence
|
|
24
|
+
|
|
25
|
+
patch_context = PatchContext.load()
|
|
26
|
+
dependency_configuration = patch_context.dependency_configuration
|
|
27
|
+
target = patch_context.target
|
|
28
|
+
|
|
29
|
+
marker_environment = None # type: Optional[Dict[str, str]]
|
|
30
|
+
if isinstance(target, MarkerEnvironment):
|
|
31
|
+
marker_environment = target.as_dict()
|
|
32
|
+
|
|
33
|
+
def are_exhaustive(
|
|
34
|
+
universal_target, # type: UniversalTarget
|
|
35
|
+
overrides, # type: Sequence[Requirement]
|
|
36
|
+
):
|
|
37
|
+
# type: (...) -> bool
|
|
38
|
+
|
|
39
|
+
markers = [override.marker for override in overrides if override.marker]
|
|
40
|
+
if len(markers) < len(overrides):
|
|
41
|
+
# We have at least one override without a marker; i.e.: the override always applies.
|
|
42
|
+
return True
|
|
43
|
+
|
|
44
|
+
return universal_target.are_exhaustive(markers=markers)
|
|
20
45
|
|
|
21
46
|
def create_requires(orig_requires):
|
|
22
47
|
def requires(self, *args, **kwargs):
|
|
@@ -37,7 +62,17 @@ def patch():
|
|
|
37
62
|
)
|
|
38
63
|
)
|
|
39
64
|
continue
|
|
40
|
-
|
|
65
|
+
|
|
66
|
+
overrides = list(dependency_configuration.overrides_for(requirement))
|
|
67
|
+
if marker_environment:
|
|
68
|
+
overrides = [
|
|
69
|
+
override
|
|
70
|
+
for override in overrides
|
|
71
|
+
if not override.marker or override.marker.evaluate(marker_environment)
|
|
72
|
+
]
|
|
73
|
+
elif overrides and not are_exhaustive(patch_context.target, overrides):
|
|
74
|
+
overrides.append(req)
|
|
75
|
+
|
|
41
76
|
if overrides:
|
|
42
77
|
logger.debug(
|
|
43
78
|
"[{type}: patched {orig_requires}] Overrode {dep} from {dist} with "
|
|
@@ -12,6 +12,7 @@ from pex.pep_425 import CompatibilityTags
|
|
|
12
12
|
from pex.pip.download_observer import DownloadObserver, Patch, PatchSet
|
|
13
13
|
from pex.platforms import PlatformSpec
|
|
14
14
|
from pex.targets import AbbreviatedPlatform, CompletePlatform, Target
|
|
15
|
+
from pex.third_party.packaging.specifiers import SpecifierSet
|
|
15
16
|
from pex.tracer import TRACER
|
|
16
17
|
from pex.typing import TYPE_CHECKING
|
|
17
18
|
|
|
@@ -156,7 +157,7 @@ def patch(target):
|
|
|
156
157
|
"environment markers defined and an abbreviated platform should always have at least the"
|
|
157
158
|
"`python_version` environment marker defined. Given: {target}".format(target=target)
|
|
158
159
|
)
|
|
159
|
-
requires_python = (
|
|
160
|
+
requires_python = SpecifierSet(
|
|
160
161
|
"=={full_version}".format(full_version=target.marker_environment.python_full_version)
|
|
161
162
|
if target.marker_environment.python_full_version
|
|
162
163
|
else "=={version}.*".format(version=target.marker_environment.python_version)
|
|
@@ -179,7 +180,7 @@ def patch_tags(
|
|
|
179
180
|
|
|
180
181
|
|
|
181
182
|
def patch_requires_python(
|
|
182
|
-
requires_python, # type: Iterable[
|
|
183
|
+
requires_python, # type: Iterable[SpecifierSet]
|
|
183
184
|
patches_dir=None, # type: Optional[str]
|
|
184
185
|
):
|
|
185
186
|
# type: (...) -> Patch
|
|
@@ -193,7 +194,7 @@ def patch_requires_python(
|
|
|
193
194
|
"""
|
|
194
195
|
with TRACER.timed(
|
|
195
196
|
"Calculating compatible python versions for {requires_python}".format(
|
|
196
|
-
requires_python=requires_python
|
|
197
|
+
requires_python=" or ".join(map(str, requires_python))
|
|
197
198
|
)
|
|
198
199
|
):
|
|
199
200
|
python_full_versions = list(iter_compatible_versions(requires_python))
|
pex/pip/installation.py
CHANGED
|
@@ -221,7 +221,7 @@ def _install_wheel(wheel_path):
|
|
|
221
221
|
with atomic_directory(installed_wheel_dir) as atomic_dir:
|
|
222
222
|
if not atomic_dir.is_finalized():
|
|
223
223
|
installed_wheel = pep_427.install_wheel_chroot(
|
|
224
|
-
|
|
224
|
+
wheel=wheel_path, destination=atomic_dir.work_dir
|
|
225
225
|
)
|
|
226
226
|
runtime_key_dir = InstalledWheelDir.create(
|
|
227
227
|
wheel_name=wheel_name,
|
|
@@ -384,7 +384,7 @@ class PipInstallation(object):
|
|
|
384
384
|
"{pip_version} requires Python {requires_python}.".format(
|
|
385
385
|
pip_requirement=self.version.requirement,
|
|
386
386
|
pip_version=self.version.value,
|
|
387
|
-
python_impl=self.interpreter.identity.
|
|
387
|
+
python_impl=self.interpreter.identity.implementation,
|
|
388
388
|
python_version=self.interpreter.identity.version_str,
|
|
389
389
|
python_binary=self.interpreter.binary,
|
|
390
390
|
requires_python=self.version.requires_python,
|
pex/pip/local_project.py
CHANGED
|
@@ -4,9 +4,8 @@
|
|
|
4
4
|
from __future__ import absolute_import
|
|
5
5
|
|
|
6
6
|
import os.path
|
|
7
|
-
import tarfile
|
|
8
7
|
|
|
9
|
-
from pex import hashing
|
|
8
|
+
from pex import hashing, sdist
|
|
10
9
|
from pex.build_system import pep_517
|
|
11
10
|
from pex.common import temporary_dir
|
|
12
11
|
from pex.pip.version import PipVersionValue
|
|
@@ -33,25 +32,18 @@ def digest_local_project(
|
|
|
33
32
|
# type: (...) -> Union[str, Error]
|
|
34
33
|
with TRACER.timed("Fingerprinting local project at {directory}".format(directory=directory)):
|
|
35
34
|
with temporary_dir() as td:
|
|
36
|
-
|
|
35
|
+
sdist_path_or_error = pep_517.build_sdist(
|
|
37
36
|
project_directory=directory,
|
|
38
37
|
dist_dir=os.path.join(td, "dists"),
|
|
39
38
|
pip_version=pip_version,
|
|
40
39
|
target=target,
|
|
41
40
|
resolver=resolver,
|
|
42
41
|
)
|
|
43
|
-
if isinstance(
|
|
44
|
-
return
|
|
45
|
-
|
|
42
|
+
if isinstance(sdist_path_or_error, Error):
|
|
43
|
+
return sdist_path_or_error
|
|
44
|
+
sdist_path = sdist_path_or_error
|
|
46
45
|
|
|
47
46
|
extract_dir = dest_dir or os.path.join(td, "extracted")
|
|
48
|
-
|
|
49
|
-
tf.extractall(extract_dir)
|
|
50
|
-
listing = os.listdir(extract_dir)
|
|
51
|
-
assert len(listing) == 1, (
|
|
52
|
-
"Expected sdist generated for {directory} to contain one top-level directory, "
|
|
53
|
-
"found:\n{listing}".format(directory=directory, listing="\n".join(listing))
|
|
54
|
-
)
|
|
55
|
-
project_dir = os.path.join(extract_dir, listing[0])
|
|
47
|
+
project_dir = sdist.extract_tarball(sdist_path, dest_dir=extract_dir)
|
|
56
48
|
hashing.dir_hash(directory=project_dir, digest=digest)
|
|
57
49
|
return os.path.join(extract_dir, project_dir)
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
# Copyright 2025 Pex project contributors.
|
|
2
|
+
# Licensed under the Apache License, Version 2.0 (see LICENSE).
|
|
3
|
+
|
|
4
|
+
from __future__ import absolute_import
|
|
5
|
+
|
|
6
|
+
import json
|
|
7
|
+
import os
|
|
8
|
+
|
|
9
|
+
from pex.common import safe_mkdtemp
|
|
10
|
+
from pex.pep_508 import MarkerEnvironment
|
|
11
|
+
from pex.pip.download_observer import DownloadObserver, Patch, PatchSet
|
|
12
|
+
from pex.pip.version import PipVersion, PipVersionValue
|
|
13
|
+
from pex.resolve.package_repository import PackageRepositories, ReposConfiguration
|
|
14
|
+
from pex.resolve.target_system import MarkerEnv, UniversalTarget
|
|
15
|
+
from pex.typing import TYPE_CHECKING
|
|
16
|
+
|
|
17
|
+
if TYPE_CHECKING:
|
|
18
|
+
from typing import Dict, Mapping, Optional, Union
|
|
19
|
+
|
|
20
|
+
import attr # vendor:skip
|
|
21
|
+
else:
|
|
22
|
+
from pex.third_party import attr
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
@attr.s(frozen=True)
|
|
26
|
+
class PatchContext(object):
|
|
27
|
+
_PEX_REPOS_CONFIG_FILE_ENV_VAR_NAME = "_PEX_REPOS_CONFIG_FILE"
|
|
28
|
+
|
|
29
|
+
@classmethod
|
|
30
|
+
def load(cls):
|
|
31
|
+
# type: () -> PatchContext
|
|
32
|
+
|
|
33
|
+
dep_config_file = os.environ.pop(cls._PEX_REPOS_CONFIG_FILE_ENV_VAR_NAME)
|
|
34
|
+
with open(dep_config_file) as fp:
|
|
35
|
+
data = json.load(fp)
|
|
36
|
+
return cls(
|
|
37
|
+
pip_version=PipVersion.for_value(data["pip_version"]),
|
|
38
|
+
package_repositories=PackageRepositories.from_dict(data["package_repositories"]),
|
|
39
|
+
)
|
|
40
|
+
|
|
41
|
+
def dump(self):
|
|
42
|
+
# type: () -> Mapping[str, str]
|
|
43
|
+
|
|
44
|
+
repos_config_file = os.path.join(safe_mkdtemp(), "repos_config.json")
|
|
45
|
+
with open(repos_config_file, "w") as fp:
|
|
46
|
+
json.dump(
|
|
47
|
+
{
|
|
48
|
+
"pip_version": str(self.pip_version),
|
|
49
|
+
"package_repositories": self.package_repositories.as_dict(),
|
|
50
|
+
},
|
|
51
|
+
fp,
|
|
52
|
+
)
|
|
53
|
+
return {self._PEX_REPOS_CONFIG_FILE_ENV_VAR_NAME: repos_config_file}
|
|
54
|
+
|
|
55
|
+
pip_version = attr.ib() # type: PipVersionValue
|
|
56
|
+
package_repositories = attr.ib() # type: PackageRepositories
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
def patch(
|
|
60
|
+
repos_configuration, # type: ReposConfiguration
|
|
61
|
+
pip_version, # type: PipVersionValue
|
|
62
|
+
target, # type: Union[UniversalTarget, MarkerEnvironment]
|
|
63
|
+
):
|
|
64
|
+
# type: (...) -> Optional[DownloadObserver]
|
|
65
|
+
|
|
66
|
+
target_env = (
|
|
67
|
+
target.marker_env() if isinstance(target, UniversalTarget) else target.as_dict()
|
|
68
|
+
) # type: Union[MarkerEnv, Dict[str, str]]
|
|
69
|
+
package_repositories = repos_configuration.scoped(target_env)
|
|
70
|
+
if not package_repositories.has_scoped_repositories:
|
|
71
|
+
return None
|
|
72
|
+
|
|
73
|
+
patches = [
|
|
74
|
+
Patch.from_code_resource(
|
|
75
|
+
__name__, "link_collector.py", **PatchContext(pip_version, package_repositories).dump()
|
|
76
|
+
)
|
|
77
|
+
]
|
|
78
|
+
return DownloadObserver(analyzer=None, patch_set=PatchSet(patches=tuple(patches)))
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
# Copyright 2025 Pex project contributors.
|
|
2
|
+
# Licensed under the Apache License, Version 2.0 (see LICENSE).
|
|
3
|
+
|
|
4
|
+
from __future__ import absolute_import
|
|
5
|
+
|
|
6
|
+
import logging
|
|
7
|
+
|
|
8
|
+
from pex.pip.version import PipVersion
|
|
9
|
+
|
|
10
|
+
logger = logging.getLogger(__name__)
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
def patch():
|
|
14
|
+
# type: () -> None
|
|
15
|
+
|
|
16
|
+
from contextlib import contextmanager
|
|
17
|
+
|
|
18
|
+
from pip._internal.index.collector import LinkCollector
|
|
19
|
+
from pip._internal.models.search_scope import SearchScope
|
|
20
|
+
|
|
21
|
+
from pex.common import pluralize
|
|
22
|
+
from pex.pep_503 import ProjectName
|
|
23
|
+
from pex.pip.package_repositories import PatchContext
|
|
24
|
+
from pex.typing import TYPE_CHECKING
|
|
25
|
+
|
|
26
|
+
if TYPE_CHECKING:
|
|
27
|
+
from typing import Any, Iterator
|
|
28
|
+
|
|
29
|
+
patch_context = PatchContext.load()
|
|
30
|
+
|
|
31
|
+
@contextmanager
|
|
32
|
+
def scoped_repositories(link_collector, project_name):
|
|
33
|
+
# type: (...) -> Iterator[None]
|
|
34
|
+
|
|
35
|
+
project = ProjectName(project_name)
|
|
36
|
+
find_links = patch_context.package_repositories.in_scope_find_links(project)
|
|
37
|
+
if find_links:
|
|
38
|
+
logger.debug(
|
|
39
|
+
"pex: scoped {project_name} to {find_links_repos} {locations}".format(
|
|
40
|
+
project_name=project_name,
|
|
41
|
+
find_links_repos=pluralize(find_links, "find links repo"),
|
|
42
|
+
locations=" and ".join(find_links),
|
|
43
|
+
)
|
|
44
|
+
)
|
|
45
|
+
index_urls = patch_context.package_repositories.in_scope_indexes(project)
|
|
46
|
+
if index_urls:
|
|
47
|
+
logger.debug(
|
|
48
|
+
"pex: scoped {project_name} to {indexes} {locations}".format(
|
|
49
|
+
project_name=project_name,
|
|
50
|
+
indexes=pluralize(index_urls, "index"),
|
|
51
|
+
locations=" and ".join(index_urls),
|
|
52
|
+
)
|
|
53
|
+
)
|
|
54
|
+
if not find_links and not index_urls:
|
|
55
|
+
find_links = list(patch_context.package_repositories.global_find_links)
|
|
56
|
+
index_urls = list(patch_context.package_repositories.global_indexes)
|
|
57
|
+
|
|
58
|
+
kwargs = {}
|
|
59
|
+
if patch_context.pip_version >= PipVersion.v22_3:
|
|
60
|
+
kwargs["no_index"] = link_collector.search_scope.no_index
|
|
61
|
+
|
|
62
|
+
orig_search_scope = link_collector.search_scope
|
|
63
|
+
link_collector.search_scope = SearchScope.create(
|
|
64
|
+
find_links=find_links, index_urls=index_urls, **kwargs
|
|
65
|
+
)
|
|
66
|
+
try:
|
|
67
|
+
yield
|
|
68
|
+
finally:
|
|
69
|
+
link_collector.search_scope = orig_search_scope
|
|
70
|
+
|
|
71
|
+
if patch_context.pip_version is PipVersion.VENDORED:
|
|
72
|
+
orig_collect_links = LinkCollector.collect_links
|
|
73
|
+
|
|
74
|
+
def collect_links(
|
|
75
|
+
self, # type: LinkCollector
|
|
76
|
+
project_name, # type: str
|
|
77
|
+
):
|
|
78
|
+
# type: (...) -> Any
|
|
79
|
+
with scoped_repositories(self, project_name):
|
|
80
|
+
return orig_collect_links(self, project_name)
|
|
81
|
+
|
|
82
|
+
LinkCollector.collect_links = collect_links
|
|
83
|
+
else:
|
|
84
|
+
orig_collect_sources = LinkCollector.collect_sources
|
|
85
|
+
|
|
86
|
+
def collect_sources(
|
|
87
|
+
self, # type: LinkCollector
|
|
88
|
+
project_name, # type: str
|
|
89
|
+
*args, # type: Any
|
|
90
|
+
**kwargs # type: Any
|
|
91
|
+
):
|
|
92
|
+
# type: (...) -> Any
|
|
93
|
+
with scoped_repositories(self, project_name):
|
|
94
|
+
return orig_collect_sources(self, project_name, *args, **kwargs)
|
|
95
|
+
|
|
96
|
+
LinkCollector.collect_sources = collect_sources
|