pex 2.59.4__py2.py3-none-any.whl → 2.60.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/build_backend/wrap.py +25 -4
- pex/cache/dirs.py +14 -4
- pex/cli/commands/lock.py +8 -5
- pex/common.py +57 -7
- pex/compatibility.py +1 -1
- pex/dist_metadata.py +48 -6
- pex/docs/html/_pagefind/fragment/en_39c0488.pf_fragment +0 -0
- pex/docs/html/_pagefind/fragment/en_3eeaaf4.pf_fragment +0 -0
- pex/docs/html/_pagefind/fragment/en_a1dde36.pf_fragment +0 -0
- pex/docs/html/_pagefind/fragment/en_a755644.pf_fragment +0 -0
- pex/docs/html/_pagefind/fragment/en_b16e3bd.pf_fragment +0 -0
- pex/docs/html/_pagefind/fragment/{en_e323b0a.pf_fragment → en_c5d35a7.pf_fragment} +0 -0
- pex/docs/html/_pagefind/fragment/en_ec62bd2.pf_fragment +0 -0
- pex/docs/html/_pagefind/fragment/en_f32628f.pf_fragment +0 -0
- pex/docs/html/_pagefind/index/{en_9894162.pf_index → en_b211695.pf_index} +0 -0
- pex/docs/html/_pagefind/pagefind-entry.json +1 -1
- pex/docs/html/_pagefind/pagefind.en_e8a49380e5.pf_meta +0 -0
- pex/docs/html/_static/documentation_options.js +1 -1
- pex/docs/html/api/vars.html +5 -5
- pex/docs/html/buildingpex.html +5 -5
- pex/docs/html/genindex.html +5 -5
- pex/docs/html/index.html +5 -5
- pex/docs/html/recipes.html +5 -5
- pex/docs/html/scie.html +5 -5
- pex/docs/html/search.html +5 -5
- pex/docs/html/whatispex.html +5 -5
- pex/entry_points_txt.py +98 -0
- pex/environment.py +13 -10
- pex/finders.py +1 -1
- pex/installed_wheel.py +127 -0
- pex/interpreter.py +17 -5
- pex/interpreter_constraints.py +4 -4
- pex/pep_376.py +37 -385
- pex/pep_427.py +736 -248
- pex/pex_builder.py +4 -4
- pex/pex_info.py +8 -3
- pex/resolve/venv_resolver.py +98 -23
- pex/resolver.py +10 -3
- pex/sysconfig.py +5 -3
- pex/third_party/__init__.py +1 -1
- pex/tools/commands/repository.py +47 -24
- pex/vendor/__init__.py +4 -9
- pex/vendor/__main__.py +62 -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 +9 -5
- pex/version.py +1 -1
- pex/wheel.py +79 -15
- pex/whl.py +67 -0
- pex/windows/__init__.py +14 -11
- {pex-2.59.4.dist-info → pex-2.60.0.dist-info}/METADATA +4 -4
- {pex-2.59.4.dist-info → pex-2.60.0.dist-info}/RECORD +93 -77
- pex/docs/html/_pagefind/fragment/en_144b803.pf_fragment +0 -0
- pex/docs/html/_pagefind/fragment/en_1df1379.pf_fragment +0 -0
- pex/docs/html/_pagefind/fragment/en_2c6c6cb.pf_fragment +0 -0
- pex/docs/html/_pagefind/fragment/en_a916b1c.pf_fragment +0 -0
- pex/docs/html/_pagefind/fragment/en_b33e5d4.pf_fragment +0 -0
- pex/docs/html/_pagefind/fragment/en_c1c571a.pf_fragment +0 -0
- pex/docs/html/_pagefind/fragment/en_fda06e7.pf_fragment +0 -0
- pex/docs/html/_pagefind/pagefind.en_84c8322e7a.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.59.4.dist-info → pex-2.60.0.dist-info}/WHEEL +0 -0
- {pex-2.59.4.dist-info → pex-2.60.0.dist-info}/entry_points.txt +0 -0
- {pex-2.59.4.dist-info → pex-2.60.0.dist-info}/licenses/LICENSE +0 -0
- {pex-2.59.4.dist-info → pex-2.60.0.dist-info}/pylock/pylock.toml +0 -0
- {pex-2.59.4.dist-info → pex-2.60.0.dist-info}/top_level.txt +0 -0
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
|
|
@@ -790,9 +790,9 @@ class PEXBuilder(object):
|
|
|
790
790
|
self._chroot.zip(
|
|
791
791
|
os.path.join(atomic_zip_dir.work_dir, location),
|
|
792
792
|
deterministic=deterministic,
|
|
793
|
-
exclude_file=
|
|
794
|
-
|
|
795
|
-
|
|
793
|
+
exclude_file=(
|
|
794
|
+
is_pyc_temporary_file if bytecode_compile else is_pyc_file
|
|
795
|
+
),
|
|
796
796
|
strip_prefix=os.path.join(pex_info.internal_cache, location),
|
|
797
797
|
labels=(location,),
|
|
798
798
|
compress=compress,
|
pex/pex_info.py
CHANGED
|
@@ -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/resolve/venv_resolver.py
CHANGED
|
@@ -5,6 +5,7 @@ from __future__ import absolute_import
|
|
|
5
5
|
|
|
6
6
|
import functools
|
|
7
7
|
import hashlib
|
|
8
|
+
import io
|
|
8
9
|
import itertools
|
|
9
10
|
import os
|
|
10
11
|
from collections import defaultdict, deque
|
|
@@ -13,6 +14,7 @@ from pex import pex_warnings
|
|
|
13
14
|
from pex.atomic_directory import atomic_directory
|
|
14
15
|
from pex.cache.dirs import CacheDir, InstalledWheelDir
|
|
15
16
|
from pex.common import safe_relative_symlink
|
|
17
|
+
from pex.compatibility import PY2, commonpath
|
|
16
18
|
from pex.dependency_configuration import DependencyConfiguration
|
|
17
19
|
from pex.dist_metadata import (
|
|
18
20
|
Constraint,
|
|
@@ -24,9 +26,11 @@ from pex.dist_metadata import (
|
|
|
24
26
|
)
|
|
25
27
|
from pex.exceptions import production_assert, reportable_unexpected_error_msg
|
|
26
28
|
from pex.fingerprinted_distribution import FingerprintedDistribution
|
|
29
|
+
from pex.installed_wheel import InstalledWheel
|
|
30
|
+
from pex.interpreter import PythonInterpreter
|
|
27
31
|
from pex.jobs import DEFAULT_MAX_JOBS, iter_map_parallel
|
|
28
32
|
from pex.orderedset import OrderedSet
|
|
29
|
-
from pex.pep_376 import
|
|
33
|
+
from pex.pep_376 import Record
|
|
30
34
|
from pex.pep_427 import InstallableType, InstallableWheel, InstallPaths, install_wheel_chroot
|
|
31
35
|
from pex.pep_503 import ProjectName
|
|
32
36
|
from pex.pip.version import PipVersion
|
|
@@ -36,10 +40,12 @@ from pex.resolve.requirement_configuration import RequirementConfiguration
|
|
|
36
40
|
from pex.resolve.resolver_configuration import PipConfiguration
|
|
37
41
|
from pex.resolve.resolvers import ResolvedDistribution, Resolver, ResolveResult
|
|
38
42
|
from pex.result import Error
|
|
43
|
+
from pex.sysconfig import script_name
|
|
39
44
|
from pex.targets import LocalInterpreter, Target, Targets
|
|
40
45
|
from pex.typing import TYPE_CHECKING
|
|
41
46
|
from pex.venv.virtualenv import Virtualenv
|
|
42
47
|
from pex.wheel import Wheel
|
|
48
|
+
from pex.whl import repacked_whl
|
|
43
49
|
|
|
44
50
|
if TYPE_CHECKING:
|
|
45
51
|
from typing import DefaultDict, Deque, FrozenSet, Iterable, Iterator, List, Mapping, Set, Union
|
|
@@ -49,17 +55,71 @@ else:
|
|
|
49
55
|
import pex.third_party.attr as attr
|
|
50
56
|
|
|
51
57
|
|
|
58
|
+
def _normalize_record(
|
|
59
|
+
distribution, # type: Distribution
|
|
60
|
+
install_paths, # type: InstallPaths
|
|
61
|
+
record_data, # type: bytes
|
|
62
|
+
):
|
|
63
|
+
# type: (...) -> bytes
|
|
64
|
+
|
|
65
|
+
entry_map = distribution.get_entry_map()
|
|
66
|
+
entry_point_scripts = {
|
|
67
|
+
script_name(entry_point)
|
|
68
|
+
for key in ("console_scripts", "gui_scripts")
|
|
69
|
+
for entry_point in entry_map.get(key, {})
|
|
70
|
+
}
|
|
71
|
+
if not entry_point_scripts:
|
|
72
|
+
return record_data
|
|
73
|
+
|
|
74
|
+
scripts_dir = os.path.realpath(install_paths.scripts)
|
|
75
|
+
record_lines = record_data.decode("utf-8").splitlines(True) # N.B. no kw in 2.7: keepends=True
|
|
76
|
+
eol = os.sep
|
|
77
|
+
if record_lines:
|
|
78
|
+
eol = "\r\n" if record_lines[0].endswith("\r\n") else "\n"
|
|
79
|
+
|
|
80
|
+
installed_files = [
|
|
81
|
+
installed_file
|
|
82
|
+
for installed_file in Record.read(lines=iter(record_lines))
|
|
83
|
+
if (
|
|
84
|
+
(os.path.basename(installed_file.path) not in entry_point_scripts)
|
|
85
|
+
or (
|
|
86
|
+
scripts_dir
|
|
87
|
+
!= commonpath(
|
|
88
|
+
(
|
|
89
|
+
scripts_dir,
|
|
90
|
+
os.path.realpath(os.path.join(distribution.location, installed_file.path)),
|
|
91
|
+
)
|
|
92
|
+
)
|
|
93
|
+
)
|
|
94
|
+
)
|
|
95
|
+
]
|
|
96
|
+
|
|
97
|
+
if PY2:
|
|
98
|
+
record_fp = io.BytesIO()
|
|
99
|
+
Record.write_fp(fp=record_fp, installed_files=installed_files, eol=eol)
|
|
100
|
+
return record_fp.getvalue()
|
|
101
|
+
else:
|
|
102
|
+
record_fp = io.StringIO()
|
|
103
|
+
Record.write_fp(fp=record_fp, installed_files=installed_files, eol=eol)
|
|
104
|
+
return record_fp.getvalue().encode("utf-8")
|
|
105
|
+
|
|
106
|
+
|
|
52
107
|
def _install_distribution(
|
|
53
|
-
|
|
108
|
+
interpreter, # type: PythonInterpreter
|
|
109
|
+
result_type, # type: InstallableType.Value
|
|
110
|
+
use_system_time, # type: bool
|
|
54
111
|
distribution, # type: Distribution
|
|
55
112
|
):
|
|
56
|
-
# type: (...) ->
|
|
113
|
+
# type: (...) -> FingerprintedDistribution
|
|
57
114
|
|
|
58
115
|
production_assert(distribution.type is DistributionType.INSTALLED)
|
|
59
116
|
production_assert(distribution.metadata.files.metadata.type is MetadataType.DIST_INFO)
|
|
60
117
|
|
|
61
|
-
|
|
62
|
-
|
|
118
|
+
venv_install_paths = InstallPaths.interpreter(
|
|
119
|
+
interpreter, project_name=distribution.metadata.project_name
|
|
120
|
+
)
|
|
121
|
+
wheel = InstallableWheel.from_whl(
|
|
122
|
+
whl=Wheel.from_distribution(distribution), install_paths=venv_install_paths
|
|
63
123
|
)
|
|
64
124
|
record_data = wheel.metadata_files.read("RECORD")
|
|
65
125
|
if not record_data:
|
|
@@ -74,7 +134,14 @@ def _install_distribution(
|
|
|
74
134
|
)
|
|
75
135
|
|
|
76
136
|
installed_wheel_dir = InstalledWheelDir.create(
|
|
77
|
-
wheel_name=wheel.wheel_file_name,
|
|
137
|
+
wheel_name=wheel.wheel_file_name,
|
|
138
|
+
install_hash=hashlib.sha256(
|
|
139
|
+
_normalize_record(
|
|
140
|
+
distribution=Distribution(location=wheel.location, metadata=wheel.dist_metadata()),
|
|
141
|
+
install_paths=venv_install_paths,
|
|
142
|
+
record_data=record_data,
|
|
143
|
+
)
|
|
144
|
+
).hexdigest(),
|
|
78
145
|
)
|
|
79
146
|
with atomic_directory(target_dir=installed_wheel_dir) as atomic_dir:
|
|
80
147
|
if not atomic_dir.is_finalized():
|
|
@@ -94,28 +161,37 @@ def _install_distribution(
|
|
|
94
161
|
installed_wheel_dir,
|
|
95
162
|
os.path.join(symlink_atomic_dir.work_dir, wheel.wheel_file_name),
|
|
96
163
|
)
|
|
97
|
-
|
|
164
|
+
|
|
165
|
+
installed_wheel = InstalledWheel.load(installed_wheel_dir)
|
|
166
|
+
if not installed_wheel.fingerprint:
|
|
167
|
+
raise AssertionError(reportable_unexpected_error_msg())
|
|
168
|
+
|
|
169
|
+
if result_type is InstallableType.INSTALLED_WHEEL_CHROOT:
|
|
170
|
+
return FingerprintedDistribution(
|
|
171
|
+
distribution=Distribution.load(installed_wheel.prefix_dir),
|
|
172
|
+
fingerprint=installed_wheel.fingerprint,
|
|
173
|
+
)
|
|
174
|
+
return repacked_whl(
|
|
175
|
+
installed_wheel, fingerprint=installed_wheel.fingerprint, use_system_time=use_system_time
|
|
176
|
+
)
|
|
98
177
|
|
|
99
178
|
|
|
100
179
|
def _install_venv_distributions(
|
|
101
180
|
venv, # type: Virtualenv
|
|
102
181
|
distributions, # type: Iterable[Distribution]
|
|
103
182
|
max_install_jobs=DEFAULT_MAX_JOBS, # type: int
|
|
183
|
+
result_type=InstallableType.INSTALLED_WHEEL_CHROOT, # type: InstallableType.Value
|
|
184
|
+
use_system_time=False, # type: bool
|
|
104
185
|
):
|
|
105
186
|
# type: (...) -> Iterator[FingerprintedDistribution]
|
|
106
187
|
|
|
107
|
-
|
|
108
|
-
for installed_wheel in iter_map_parallel(
|
|
188
|
+
return iter_map_parallel(
|
|
109
189
|
inputs=distributions,
|
|
110
|
-
function=functools.partial(
|
|
190
|
+
function=functools.partial(
|
|
191
|
+
_install_distribution, venv.interpreter, result_type, use_system_time
|
|
192
|
+
),
|
|
111
193
|
max_jobs=max_install_jobs,
|
|
112
|
-
)
|
|
113
|
-
if not installed_wheel.fingerprint:
|
|
114
|
-
raise AssertionError(reportable_unexpected_error_msg())
|
|
115
|
-
yield FingerprintedDistribution(
|
|
116
|
-
distribution=Distribution.load(installed_wheel.prefix_dir),
|
|
117
|
-
fingerprint=installed_wheel.fingerprint,
|
|
118
|
-
)
|
|
194
|
+
)
|
|
119
195
|
|
|
120
196
|
|
|
121
197
|
@attr.s(frozen=True)
|
|
@@ -186,6 +262,7 @@ def _resolve_distributions(
|
|
|
186
262
|
allow_prereleases=False, # type: bool
|
|
187
263
|
compile=False, # type: bool
|
|
188
264
|
ignore_errors=False, # type: bool
|
|
265
|
+
result_type=InstallableType.INSTALLED_WHEEL_CHROOT, # type: InstallableType.Value
|
|
189
266
|
):
|
|
190
267
|
# type: (...) -> Iterator[Union[Distribution, FingerprintedDistribution, Error]]
|
|
191
268
|
|
|
@@ -261,6 +338,7 @@ def _resolve_distributions(
|
|
|
261
338
|
transitive=False,
|
|
262
339
|
compile=compile,
|
|
263
340
|
ignore_errors=ignore_errors,
|
|
341
|
+
result_type=result_type,
|
|
264
342
|
)
|
|
265
343
|
for dist in result.distributions:
|
|
266
344
|
to_resolve.extend(
|
|
@@ -300,12 +378,6 @@ def resolve_from_venv(
|
|
|
300
378
|
):
|
|
301
379
|
# type: (...) -> Union[ResolveResult, Error]
|
|
302
380
|
|
|
303
|
-
if result_type is InstallableType.WHEEL_FILE:
|
|
304
|
-
return Error(
|
|
305
|
-
"Cannot resolve .whl files from virtual environment at {venv_dir}; its distributions "
|
|
306
|
-
"are all installed.".format(venv_dir=venv.venv_dir)
|
|
307
|
-
)
|
|
308
|
-
|
|
309
381
|
target = LocalInterpreter.create(venv.interpreter)
|
|
310
382
|
if not targets.is_empty:
|
|
311
383
|
return Error(
|
|
@@ -392,6 +464,7 @@ def resolve_from_venv(
|
|
|
392
464
|
allow_prereleases=pip_configuration.allow_prereleases,
|
|
393
465
|
compile=compile,
|
|
394
466
|
ignore_errors=ignore_errors,
|
|
467
|
+
result_type=result_type,
|
|
395
468
|
):
|
|
396
469
|
if isinstance(distribution_or_error, Error):
|
|
397
470
|
return distribution_or_error
|
|
@@ -437,6 +510,8 @@ def resolve_from_venv(
|
|
|
437
510
|
venv=venv,
|
|
438
511
|
distributions=venv_distributions,
|
|
439
512
|
max_install_jobs=pip_configuration.max_jobs,
|
|
513
|
+
result_type=result_type,
|
|
514
|
+
use_system_time=True,
|
|
440
515
|
)
|
|
441
516
|
),
|
|
442
517
|
fingerprinted_distributions,
|
pex/resolver.py
CHANGED
|
@@ -37,10 +37,10 @@ from pex.dist_metadata import (
|
|
|
37
37
|
)
|
|
38
38
|
from pex.exceptions import production_assert
|
|
39
39
|
from pex.fingerprinted_distribution import FingerprintedDistribution
|
|
40
|
+
from pex.installed_wheel import InstalledWheel
|
|
40
41
|
from pex.jobs import Raise, SpawnedJob, execute_parallel, iter_map_parallel
|
|
41
42
|
from pex.network_configuration import NetworkConfiguration
|
|
42
43
|
from pex.orderedset import OrderedSet
|
|
43
|
-
from pex.pep_376 import InstalledWheel
|
|
44
44
|
from pex.pep_425 import CompatibilityTags
|
|
45
45
|
from pex.pep_427 import InstallableType, WheelError, install_wheel_chroot
|
|
46
46
|
from pex.pep_503 import ProjectName
|
|
@@ -622,7 +622,7 @@ class BuildResult(object):
|
|
|
622
622
|
target=self.request.target.render_description(),
|
|
623
623
|
)
|
|
624
624
|
)
|
|
625
|
-
return InstallRequest.create(self.request.target, wheel_path)
|
|
625
|
+
return InstallRequest.create(self.request.target, wheel_path, was_built_locally=True)
|
|
626
626
|
|
|
627
627
|
|
|
628
628
|
@attr.s(frozen=True)
|
|
@@ -632,6 +632,7 @@ class InstallRequest(object):
|
|
|
632
632
|
cls,
|
|
633
633
|
target, # type: Union[DownloadTarget, Target]
|
|
634
634
|
wheel_path, # type: str
|
|
635
|
+
was_built_locally=False, # type: bool
|
|
635
636
|
):
|
|
636
637
|
# type: (...) -> InstallRequest
|
|
637
638
|
fingerprint = fingerprint_path(wheel_path)
|
|
@@ -639,11 +640,13 @@ class InstallRequest(object):
|
|
|
639
640
|
download_target=_as_download_target(target),
|
|
640
641
|
wheel_path=wheel_path,
|
|
641
642
|
fingerprint=fingerprint,
|
|
643
|
+
was_built_locally=was_built_locally,
|
|
642
644
|
)
|
|
643
645
|
|
|
644
646
|
download_target = attr.ib(converter=_as_download_target) # type: DownloadTarget
|
|
645
647
|
wheel_path = attr.ib() # type: str
|
|
646
648
|
fingerprint = attr.ib() # type: str
|
|
649
|
+
was_built_locally = attr.ib(default=False) # type: bool
|
|
647
650
|
|
|
648
651
|
@property
|
|
649
652
|
def target(self):
|
|
@@ -987,7 +990,11 @@ def _perform_install(
|
|
|
987
990
|
):
|
|
988
991
|
# type: (...) -> InstallResult
|
|
989
992
|
install_result = install_request.result(installed_wheels_dir)
|
|
990
|
-
install_wheel_chroot(
|
|
993
|
+
install_wheel_chroot(
|
|
994
|
+
wheel=install_request.wheel_path,
|
|
995
|
+
destination=install_result.build_chroot,
|
|
996
|
+
normalize_file_stat=install_request.was_built_locally,
|
|
997
|
+
)
|
|
991
998
|
return install_result
|
|
992
999
|
|
|
993
1000
|
|
pex/sysconfig.py
CHANGED
|
@@ -82,7 +82,7 @@ class _PlatformValue(Enum.Value):
|
|
|
82
82
|
self.arch = arch
|
|
83
83
|
|
|
84
84
|
@property
|
|
85
|
-
def
|
|
85
|
+
def exe_extension(self):
|
|
86
86
|
# type: () -> str
|
|
87
87
|
return ".exe" if self.os is Os.WINDOWS else ""
|
|
88
88
|
|
|
@@ -93,12 +93,14 @@ class _PlatformValue(Enum.Value):
|
|
|
93
93
|
|
|
94
94
|
def binary_name(self, binary_name):
|
|
95
95
|
# type: (_Text) -> _Text
|
|
96
|
-
return "{binary_name}{extension}".format(
|
|
96
|
+
return "{binary_name}{extension}".format(
|
|
97
|
+
binary_name=binary_name, extension=self.exe_extension
|
|
98
|
+
)
|
|
97
99
|
|
|
98
100
|
def qualified_binary_name(self, binary_name):
|
|
99
101
|
# type: (_Text) -> _Text
|
|
100
102
|
return "{binary_name}-{platform}{extension}".format(
|
|
101
|
-
binary_name=binary_name, platform=self, extension=self.
|
|
103
|
+
binary_name=binary_name, platform=self, extension=self.exe_extension
|
|
102
104
|
)
|
|
103
105
|
|
|
104
106
|
def qualified_file_name(self, file_name):
|
pex/third_party/__init__.py
CHANGED
|
@@ -639,7 +639,7 @@ def expose_installed_wheels(
|
|
|
639
639
|
|
|
640
640
|
from pex.atomic_directory import atomic_directory
|
|
641
641
|
from pex.cache.dirs import InstalledWheelDir
|
|
642
|
-
from pex.
|
|
642
|
+
from pex.installed_wheel import InstalledWheel
|
|
643
643
|
|
|
644
644
|
for path in expose(dists, interpreter=interpreter):
|
|
645
645
|
# TODO(John Sirois): Maybe consolidate with pex.resolver.BuildAndInstallRequest.
|
pex/tools/commands/repository.py
CHANGED
|
@@ -18,12 +18,14 @@ from pex import dist_metadata
|
|
|
18
18
|
from pex.atomic_directory import atomic_directory
|
|
19
19
|
from pex.cache.dirs import CacheDir
|
|
20
20
|
from pex.commands.command import JsonMixin, OutputMixin
|
|
21
|
-
from pex.common import
|
|
21
|
+
from pex.common import pluralize, safe_mkdir, safe_mkdtemp, safe_open
|
|
22
22
|
from pex.compatibility import Queue
|
|
23
23
|
from pex.dist_metadata import Distribution
|
|
24
24
|
from pex.environment import PEXEnvironment
|
|
25
|
+
from pex.installed_wheel import InstalledWheel
|
|
25
26
|
from pex.interpreter import PythonInterpreter
|
|
26
|
-
from pex.jobs import Job,
|
|
27
|
+
from pex.jobs import Job, iter_map_parallel
|
|
28
|
+
from pex.pep_427 import WheelInstallError, repack
|
|
27
29
|
from pex.pex import PEX
|
|
28
30
|
from pex.result import Error, Ok, Result
|
|
29
31
|
from pex.tools.command import PEXCommand
|
|
@@ -31,7 +33,7 @@ from pex.typing import TYPE_CHECKING, cast
|
|
|
31
33
|
from pex.venv.virtualenv import InstallationChoice, Virtualenv
|
|
32
34
|
|
|
33
35
|
if TYPE_CHECKING:
|
|
34
|
-
from typing import IO, Any, Callable, Iterable, Iterator, List,
|
|
36
|
+
from typing import IO, Any, Callable, Iterable, Iterator, List, Tuple
|
|
35
37
|
|
|
36
38
|
import attr # vendor:skip
|
|
37
39
|
|
|
@@ -121,6 +123,29 @@ class FindLinksRepo(object):
|
|
|
121
123
|
self._server_process.kill()
|
|
122
124
|
|
|
123
125
|
|
|
126
|
+
def _extract_wheel(
|
|
127
|
+
distribution, # type: Distribution
|
|
128
|
+
dest_dir, # type: str
|
|
129
|
+
use_system_time=False, # type: bool
|
|
130
|
+
):
|
|
131
|
+
# type: (...) -> Tuple[Distribution, Result]
|
|
132
|
+
|
|
133
|
+
try:
|
|
134
|
+
whl = repack(
|
|
135
|
+
installed_wheel=InstalledWheel.load(distribution.location),
|
|
136
|
+
dest_dir=dest_dir,
|
|
137
|
+
use_system_time=use_system_time,
|
|
138
|
+
)
|
|
139
|
+
except (InstalledWheel.LoadError, WheelInstallError) as e:
|
|
140
|
+
result = Error(str(e)) # type: Result
|
|
141
|
+
else:
|
|
142
|
+
result = Ok(
|
|
143
|
+
"{distribution}: Repacked wheel as {whl}".format(distribution=distribution, whl=whl)
|
|
144
|
+
)
|
|
145
|
+
|
|
146
|
+
return distribution, result
|
|
147
|
+
|
|
148
|
+
|
|
124
149
|
class Repository(JsonMixin, OutputMixin, PEXCommand):
|
|
125
150
|
"""Interact with the Python distribution repository contained in a PEX file."""
|
|
126
151
|
|
|
@@ -270,36 +295,23 @@ class Repository(JsonMixin, OutputMixin, PEXCommand):
|
|
|
270
295
|
if self.options.sources:
|
|
271
296
|
self._extract_sdist(pex, dest_dir)
|
|
272
297
|
|
|
273
|
-
def spawn_extract(distribution):
|
|
274
|
-
# type: (Distribution) -> SpawnedJob[Text]
|
|
275
|
-
env = os.environ.copy()
|
|
276
|
-
if not self.options.use_system_time:
|
|
277
|
-
env.update(REPRODUCIBLE_BUILDS_ENV)
|
|
278
|
-
job = spawn_python_job_with_setuptools_and_wheel(
|
|
279
|
-
args=["-m", "wheel", "pack", "--dest-dir", dest_dir, distribution.location],
|
|
280
|
-
interpreter=pex.interpreter,
|
|
281
|
-
stdout=subprocess.PIPE,
|
|
282
|
-
env=env,
|
|
283
|
-
)
|
|
284
|
-
return SpawnedJob.stdout(
|
|
285
|
-
job, result_func=lambda out: "{}: {}".format(distribution, out.decode())
|
|
286
|
-
)
|
|
287
|
-
|
|
288
298
|
with self._distributions_output(pex) as (distributions, output):
|
|
289
299
|
errors = [] # type: List[Distribution]
|
|
290
|
-
for result in
|
|
291
|
-
distributions,
|
|
300
|
+
for distribution, result in iter_map_parallel(
|
|
301
|
+
distributions,
|
|
302
|
+
functools.partial(
|
|
303
|
+
_extract_wheel, dest_dir=dest_dir, use_system_time=self.options.use_system_time
|
|
304
|
+
),
|
|
292
305
|
):
|
|
293
|
-
if isinstance(result,
|
|
294
|
-
distribution, error = result
|
|
306
|
+
if isinstance(result, Error):
|
|
295
307
|
errors.append(distribution)
|
|
296
308
|
output.write(
|
|
297
309
|
"Failed to build a wheel for {distribution}: {error}\n".format(
|
|
298
|
-
distribution=distribution, error=
|
|
310
|
+
distribution=distribution, error=result
|
|
299
311
|
)
|
|
300
312
|
)
|
|
301
313
|
else:
|
|
302
|
-
output.write(result)
|
|
314
|
+
output.write(str(result))
|
|
303
315
|
if errors:
|
|
304
316
|
return Error(
|
|
305
317
|
"Failed to build wheels for {count} {distributions}.".format(
|
|
@@ -435,6 +447,17 @@ class Repository(JsonMixin, OutputMixin, PEXCommand):
|
|
|
435
447
|
with open(os.path.join(chroot, "setup.py"), "w") as fp:
|
|
436
448
|
fp.write("import setuptools; setuptools.setup()")
|
|
437
449
|
|
|
450
|
+
with open(os.path.join(chroot, "pyproject.toml"), "w") as fp:
|
|
451
|
+
fp.write(
|
|
452
|
+
dedent(
|
|
453
|
+
"""\
|
|
454
|
+
[build-system]
|
|
455
|
+
requires = ["setuptools"]
|
|
456
|
+
backend = "setuptools.build_meta"
|
|
457
|
+
"""
|
|
458
|
+
)
|
|
459
|
+
)
|
|
460
|
+
|
|
438
461
|
spawn_python_job_with_setuptools_and_wheel(
|
|
439
462
|
args=["setup.py", "sdist", "--dist-dir", dest_dir],
|
|
440
463
|
interpreter=pex.interpreter,
|
pex/vendor/__init__.py
CHANGED
|
@@ -201,9 +201,11 @@ class VendorSpec(
|
|
|
201
201
|
# Automated update of Pip's vendored certifi's cacert.pem to that from certifi 2025.7.14.
|
|
202
202
|
# 12.) https://github.com/pex-tool/pip/commit/21a4058f77f9864151510b725419206a2e5645ae
|
|
203
203
|
# Automated update of Pip's vendored certifi's cacert.pem to that from certifi 2025.8.3.
|
|
204
|
+
# 13.) https://github.com/pex-tool/pip/commit/cef23bb7153ec49037d963e84fcad0f08880fbc5
|
|
205
|
+
# Automated update of Pip's vendored certifi's cacert.pem to that from certifi 2025.10.5.
|
|
204
206
|
PIP_SPEC = VendorSpec.git(
|
|
205
207
|
repo="https://github.com/pex-tool/pip",
|
|
206
|
-
commit="
|
|
208
|
+
commit="cef23bb7153ec49037d963e84fcad0f08880fbc5",
|
|
207
209
|
project_name="pip",
|
|
208
210
|
rewrite=False,
|
|
209
211
|
)
|
|
@@ -316,7 +318,6 @@ def vendor_runtime(
|
|
|
316
318
|
dest_basedir, # type: str
|
|
317
319
|
label, # type: str
|
|
318
320
|
root_module_names, # type: Iterable[str]
|
|
319
|
-
include_dist_info=(), # type: Iterable[str]
|
|
320
321
|
):
|
|
321
322
|
# type: (...) -> Set[str]
|
|
322
323
|
"""Includes portions of vendored distributions in a chroot.
|
|
@@ -329,7 +330,6 @@ def vendor_runtime(
|
|
|
329
330
|
:param dest_basedir: The prefix to store the vendored code under in the ``chroot``.
|
|
330
331
|
:param label: The chroot label for the vendored code fileset.
|
|
331
332
|
:param root_module_names: The names of the root vendored modules to include in the chroot.
|
|
332
|
-
:param include_dist_info: Include the .dist-info dirs associated with these root module names.
|
|
333
333
|
:returns: The set of absolute paths of the source files that were vendored.
|
|
334
334
|
:raise: :class:`ValueError` if any of the given ``root_module_names`` could not be found amongst
|
|
335
335
|
the vendored code and added to the chroot.
|
|
@@ -368,12 +368,7 @@ def vendor_runtime(
|
|
|
368
368
|
vendor_module_names[name] = True
|
|
369
369
|
TRACER.log("Vendoring {} from {} @ {}".format(name, spec, spec.target_dir), V=3)
|
|
370
370
|
|
|
371
|
-
dirs[:] = packages
|
|
372
|
-
d
|
|
373
|
-
for project in include_dist_info
|
|
374
|
-
for d in dirs
|
|
375
|
-
if d.startswith(project) and d.endswith(".dist-info")
|
|
376
|
-
]
|
|
371
|
+
dirs[:] = packages
|
|
377
372
|
files[:] = modules
|
|
378
373
|
|
|
379
374
|
# We copy over sources and data only; no pyc files.
|