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/resolve/project.py
CHANGED
|
@@ -3,35 +3,44 @@
|
|
|
3
3
|
|
|
4
4
|
from __future__ import absolute_import
|
|
5
5
|
|
|
6
|
+
import hashlib
|
|
6
7
|
import os.path
|
|
7
8
|
from argparse import Namespace, _ActionsContainer
|
|
8
9
|
|
|
9
|
-
from pex import requirements, toml
|
|
10
|
+
from pex import requirements, sdist, toml
|
|
10
11
|
from pex.build_system import pep_517
|
|
11
|
-
from pex.common import pluralize
|
|
12
|
+
from pex.common import pluralize, safe_mkdtemp
|
|
12
13
|
from pex.compatibility import string
|
|
13
14
|
from pex.dependency_configuration import DependencyConfiguration
|
|
14
|
-
from pex.dist_metadata import DistMetadata, Requirement, RequirementParseError
|
|
15
|
+
from pex.dist_metadata import DistMetadata, Requirement, RequirementParseError, is_wheel
|
|
15
16
|
from pex.fingerprinted_distribution import FingerprintedDistribution
|
|
16
17
|
from pex.interpreter import PythonInterpreter
|
|
17
|
-
from pex.jobs import
|
|
18
|
+
from pex.jobs import Job, Retain, SpawnedJob, execute_parallel
|
|
18
19
|
from pex.orderedset import OrderedSet
|
|
19
20
|
from pex.pep_427 import InstallableType
|
|
20
21
|
from pex.pep_503 import ProjectName
|
|
22
|
+
from pex.pip.tool import PackageIndexConfiguration
|
|
21
23
|
from pex.pip.version import PipVersionValue
|
|
22
|
-
from pex.requirements import LocalProjectRequirement, ParseError
|
|
24
|
+
from pex.requirements import LocalProjectRequirement, ParseError, URLRequirement
|
|
23
25
|
from pex.resolve.configured_resolve import resolve
|
|
26
|
+
from pex.resolve.configured_resolver import ConfiguredResolver
|
|
24
27
|
from pex.resolve.requirement_configuration import RequirementConfiguration
|
|
25
28
|
from pex.resolve.resolver_configuration import PipConfiguration
|
|
26
|
-
from pex.resolve.resolvers import Resolver
|
|
29
|
+
from pex.resolve.resolvers import Resolver
|
|
30
|
+
from pex.resolver import BuildAndInstallRequest, BuildRequest, InstallRequest
|
|
31
|
+
from pex.result import Error, ResultError
|
|
27
32
|
from pex.sorted_tuple import SortedTuple
|
|
28
33
|
from pex.targets import LocalInterpreter, Target, Targets
|
|
34
|
+
from pex.tracer import TRACER
|
|
29
35
|
from pex.typing import TYPE_CHECKING
|
|
36
|
+
from pex.util import CacheHelper
|
|
30
37
|
|
|
31
38
|
if TYPE_CHECKING:
|
|
32
|
-
from typing import Any, Iterable, Iterator, List, Mapping, Optional, Set, Tuple, Union
|
|
39
|
+
from typing import Any, Dict, Iterable, Iterator, List, Mapping, Optional, Set, Tuple, Union
|
|
33
40
|
|
|
34
41
|
import attr # vendor:skip
|
|
42
|
+
|
|
43
|
+
from pex.requirements import ParsedRequirement
|
|
35
44
|
else:
|
|
36
45
|
from pex.third_party import attr
|
|
37
46
|
|
|
@@ -69,10 +78,14 @@ class BuiltProject(object):
|
|
|
69
78
|
|
|
70
79
|
|
|
71
80
|
@attr.s(frozen=True)
|
|
72
|
-
class
|
|
73
|
-
path = attr.ib() # type: str
|
|
81
|
+
class ProjectDirectory(object):
|
|
74
82
|
requirement = attr.ib() # type: LocalProjectRequirement
|
|
75
83
|
|
|
84
|
+
@property
|
|
85
|
+
def path(self):
|
|
86
|
+
# type: () -> str
|
|
87
|
+
return self.requirement.path
|
|
88
|
+
|
|
76
89
|
@property
|
|
77
90
|
def requirement_str(self):
|
|
78
91
|
# type: () -> str
|
|
@@ -80,9 +93,30 @@ class Project(object):
|
|
|
80
93
|
return str(self.requirement.line.processed_text)
|
|
81
94
|
|
|
82
95
|
|
|
96
|
+
@attr.s(frozen=True)
|
|
97
|
+
class ProjectArchive(object):
|
|
98
|
+
requirement = attr.ib() # type: URLRequirement
|
|
99
|
+
|
|
100
|
+
@property
|
|
101
|
+
def path(self):
|
|
102
|
+
# type: () -> str
|
|
103
|
+
return self.requirement.url.path
|
|
104
|
+
|
|
105
|
+
@property
|
|
106
|
+
def is_wheel(self):
|
|
107
|
+
# type: () -> bool
|
|
108
|
+
return is_wheel(self.path)
|
|
109
|
+
|
|
110
|
+
@property
|
|
111
|
+
def subdirectory(self):
|
|
112
|
+
# type: () -> Optional[str]
|
|
113
|
+
return self.requirement.subdirectory
|
|
114
|
+
|
|
115
|
+
|
|
83
116
|
@attr.s(frozen=True)
|
|
84
117
|
class Projects(object):
|
|
85
|
-
|
|
118
|
+
project_directories = attr.ib(default=()) # type: Tuple[ProjectDirectory, ...]
|
|
119
|
+
project_archives = attr.ib(default=()) # type: Tuple[ProjectArchive, ...]
|
|
86
120
|
|
|
87
121
|
def build(
|
|
88
122
|
self,
|
|
@@ -95,24 +129,93 @@ class Projects(object):
|
|
|
95
129
|
):
|
|
96
130
|
# type: (...) -> Iterator[BuiltProject]
|
|
97
131
|
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
132
|
+
if self.project_directories:
|
|
133
|
+
resolve_result = resolve(
|
|
134
|
+
targets=targets,
|
|
135
|
+
requirement_configuration=RequirementConfiguration(
|
|
136
|
+
requirements=[project.requirement_str for project in self.project_directories]
|
|
137
|
+
),
|
|
138
|
+
resolver_configuration=attr.evolve(pip_configuration, transitive=False),
|
|
139
|
+
compile_pyc=compile_pyc,
|
|
140
|
+
ignore_errors=ignore_errors,
|
|
141
|
+
result_type=result_type,
|
|
142
|
+
dependency_configuration=dependency_config,
|
|
143
|
+
)
|
|
144
|
+
for resolved_distribution in resolve_result.distributions:
|
|
145
|
+
yield BuiltProject(
|
|
146
|
+
target=resolved_distribution.target,
|
|
147
|
+
fingerprinted_distribution=resolved_distribution.fingerprinted_distribution,
|
|
148
|
+
satisfied_direct_requirements=resolved_distribution.direct_requirements,
|
|
149
|
+
)
|
|
150
|
+
|
|
151
|
+
if self.project_archives:
|
|
152
|
+
build_requests = [] # type: List[BuildRequest]
|
|
153
|
+
install_requests = [] # type: List[InstallRequest]
|
|
154
|
+
direct_requirements = [] # type: List[ParsedRequirement]
|
|
155
|
+
for project_archive in self.project_archives:
|
|
156
|
+
fingerprint = CacheHelper.hash(project_archive.path, hasher=hashlib.sha256)
|
|
157
|
+
direct_requirements.append(project_archive.requirement)
|
|
158
|
+
for target in targets.unique_targets():
|
|
159
|
+
if project_archive.is_wheel:
|
|
160
|
+
install_requests.append(
|
|
161
|
+
InstallRequest(
|
|
162
|
+
download_target=target,
|
|
163
|
+
wheel_path=project_archive.path,
|
|
164
|
+
fingerprint=fingerprint,
|
|
165
|
+
)
|
|
166
|
+
)
|
|
167
|
+
else:
|
|
168
|
+
build_requests.append(
|
|
169
|
+
BuildRequest(
|
|
170
|
+
download_target=target,
|
|
171
|
+
source_path=project_archive.path,
|
|
172
|
+
fingerprint=fingerprint,
|
|
173
|
+
subdirectory=project_archive.subdirectory,
|
|
174
|
+
)
|
|
175
|
+
)
|
|
176
|
+
|
|
177
|
+
build_and_install_request = BuildAndInstallRequest(
|
|
178
|
+
build_requests=build_requests,
|
|
179
|
+
install_requests=install_requests,
|
|
180
|
+
direct_requirements=direct_requirements,
|
|
181
|
+
package_index_configuration=PackageIndexConfiguration.create(
|
|
182
|
+
pip_version=pip_configuration.version,
|
|
183
|
+
resolver_version=pip_configuration.resolver_version,
|
|
184
|
+
repos_configuration=pip_configuration.repos_configuration,
|
|
185
|
+
network_configuration=pip_configuration.network_configuration,
|
|
186
|
+
use_pip_config=pip_configuration.use_pip_config,
|
|
187
|
+
extra_pip_requirements=pip_configuration.extra_requirements,
|
|
188
|
+
keyring_provider=pip_configuration.keyring_provider,
|
|
189
|
+
),
|
|
190
|
+
compile=compile_pyc,
|
|
191
|
+
build_configuration=pip_configuration.build_configuration,
|
|
192
|
+
pip_version=pip_configuration.version,
|
|
193
|
+
resolver=ConfiguredResolver(pip_configuration=pip_configuration),
|
|
194
|
+
dependency_configuration=dependency_config,
|
|
114
195
|
)
|
|
115
196
|
|
|
197
|
+
# This checks the resolve, but we're not doing a full resolve here - we're installing
|
|
198
|
+
# projects to gather their requirements and _then_ perform a resolve of those
|
|
199
|
+
# requirements.
|
|
200
|
+
ignore_errors = True
|
|
201
|
+
|
|
202
|
+
if result_type is InstallableType.INSTALLED_WHEEL_CHROOT:
|
|
203
|
+
resolved_distributions = build_and_install_request.install_distributions(
|
|
204
|
+
max_parallel_jobs=pip_configuration.max_jobs, ignore_errors=ignore_errors
|
|
205
|
+
)
|
|
206
|
+
else:
|
|
207
|
+
resolved_distributions = build_and_install_request.build_distributions(
|
|
208
|
+
max_parallel_jobs=pip_configuration.max_jobs,
|
|
209
|
+
ignore_errors=ignore_errors,
|
|
210
|
+
)
|
|
211
|
+
|
|
212
|
+
for resolved_distribution in resolved_distributions:
|
|
213
|
+
yield BuiltProject(
|
|
214
|
+
target=resolved_distribution.target,
|
|
215
|
+
fingerprinted_distribution=resolved_distribution.fingerprinted_distribution,
|
|
216
|
+
satisfied_direct_requirements=resolved_distribution.direct_requirements,
|
|
217
|
+
)
|
|
218
|
+
|
|
116
219
|
def collect_requirements(
|
|
117
220
|
self,
|
|
118
221
|
resolver, # type: Resolver
|
|
@@ -123,33 +226,105 @@ class Projects(object):
|
|
|
123
226
|
# type: (...) -> Iterator[Requirement]
|
|
124
227
|
|
|
125
228
|
target = LocalInterpreter.create(interpreter)
|
|
229
|
+
seen = set() # type: Set[Requirement]
|
|
230
|
+
|
|
231
|
+
source_projects = list(
|
|
232
|
+
self.project_directories
|
|
233
|
+
) # type: List[Union[ProjectDirectory, ProjectArchive]]
|
|
234
|
+
for project_archive in self.project_archives:
|
|
235
|
+
if project_archive.is_wheel:
|
|
236
|
+
for req in DistMetadata.load(project_archive.path).requires_dists:
|
|
237
|
+
if req not in seen:
|
|
238
|
+
seen.add(req)
|
|
239
|
+
yield req
|
|
240
|
+
else:
|
|
241
|
+
source_projects.append(project_archive)
|
|
242
|
+
|
|
243
|
+
wheels_to_build = [] # type: List[str]
|
|
244
|
+
prepare_metadata_errors = {} # type: Dict[str, str]
|
|
245
|
+
|
|
246
|
+
def spawn_prepare_metadata_func(project):
|
|
247
|
+
# type: (Union[ProjectDirectory, ProjectArchive]) -> SpawnedJob[DistMetadata]
|
|
248
|
+
|
|
249
|
+
if isinstance(project, ProjectDirectory):
|
|
250
|
+
project_dir = project.path
|
|
251
|
+
else:
|
|
252
|
+
project_dir = sdist.extract_tarball(
|
|
253
|
+
tarball_path=project.path, dest_dir=safe_mkdtemp()
|
|
254
|
+
)
|
|
126
255
|
|
|
127
|
-
def spawn_func(project):
|
|
128
|
-
# type: (Project) -> SpawnedJob[DistMetadata]
|
|
129
256
|
return pep_517.spawn_prepare_metadata(
|
|
130
|
-
|
|
257
|
+
project_directory=project_dir,
|
|
258
|
+
target=target,
|
|
259
|
+
resolver=resolver,
|
|
260
|
+
pip_version=pip_version,
|
|
131
261
|
)
|
|
132
262
|
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
self.projects,
|
|
263
|
+
for project_directory, dist_metadata_result in zip(
|
|
264
|
+
source_projects,
|
|
136
265
|
execute_parallel(
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
266
|
+
source_projects,
|
|
267
|
+
# MyPy just can't figure out the next two args types; they're OK.
|
|
268
|
+
spawn_func=spawn_prepare_metadata_func, # type: ignore[arg-type]
|
|
269
|
+
error_handler=Retain["Union[ProjectDirectory, ProjectArchive]"](), # type: ignore[arg-type]
|
|
140
270
|
max_jobs=max_jobs,
|
|
141
271
|
),
|
|
142
272
|
):
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
273
|
+
if isinstance(dist_metadata_result, DistMetadata):
|
|
274
|
+
for req in _iter_requirements(
|
|
275
|
+
target=target,
|
|
276
|
+
dist_metadata=dist_metadata_result,
|
|
277
|
+
extras=project_directory.requirement.extras,
|
|
278
|
+
):
|
|
279
|
+
if req not in seen:
|
|
280
|
+
seen.add(req)
|
|
281
|
+
yield req
|
|
282
|
+
else:
|
|
283
|
+
_item, error = dist_metadata_result
|
|
284
|
+
if isinstance(error, Job.Error) and pep_517.is_hook_unavailable_error(error):
|
|
285
|
+
TRACER.log(
|
|
286
|
+
"Failed to prepare metadata for {project}, trying to build a wheel "
|
|
287
|
+
"instead: {err}".format(
|
|
288
|
+
project=project_directory.path, err=dist_metadata_result
|
|
289
|
+
),
|
|
290
|
+
V=3,
|
|
291
|
+
)
|
|
292
|
+
wheels_to_build.append(project_directory.path)
|
|
293
|
+
else:
|
|
294
|
+
prepare_metadata_errors[project_directory.path] = str(error)
|
|
295
|
+
|
|
296
|
+
if wheels_to_build:
|
|
297
|
+
resolve_result = resolver.resolve_requirements(
|
|
298
|
+
requirements=wheels_to_build,
|
|
299
|
+
targets=Targets.from_target(target),
|
|
300
|
+
pip_version=pip_version,
|
|
301
|
+
)
|
|
302
|
+
for resolved_distribution in resolve_result.distributions:
|
|
303
|
+
for req in resolved_distribution.distribution.requires():
|
|
304
|
+
if req not in seen:
|
|
305
|
+
seen.add(req)
|
|
306
|
+
yield req
|
|
307
|
+
|
|
308
|
+
if prepare_metadata_errors:
|
|
309
|
+
raise ResultError(
|
|
310
|
+
Error(
|
|
311
|
+
"Encountered {count} {errors} collecting project requirements:\n"
|
|
312
|
+
"{error_items}".format(
|
|
313
|
+
count=len(prepare_metadata_errors),
|
|
314
|
+
errors=pluralize(prepare_metadata_errors, "error"),
|
|
315
|
+
error_items="\n".join(
|
|
316
|
+
"{index}. {path}: {error}".format(index=index, path=path, error=error)
|
|
317
|
+
for index, (path, error) in enumerate(
|
|
318
|
+
prepare_metadata_errors.items(), start=1
|
|
319
|
+
)
|
|
320
|
+
),
|
|
321
|
+
)
|
|
322
|
+
)
|
|
323
|
+
)
|
|
149
324
|
|
|
150
325
|
def __len__(self):
|
|
151
326
|
# type: () -> int
|
|
152
|
-
return len(self.
|
|
327
|
+
return len(self.project_directories) + len(self.project_archives)
|
|
153
328
|
|
|
154
329
|
|
|
155
330
|
@attr.s(frozen=True)
|
|
@@ -330,7 +505,8 @@ def register_options(
|
|
|
330
505
|
def get_projects(options):
|
|
331
506
|
# type: (Namespace) -> Projects
|
|
332
507
|
|
|
333
|
-
|
|
508
|
+
project_directories = [] # type: List[ProjectDirectory]
|
|
509
|
+
project_archives = [] # type: List[ProjectArchive]
|
|
334
510
|
errors = [] # type: List[str]
|
|
335
511
|
for project in getattr(options, "projects", ()):
|
|
336
512
|
try:
|
|
@@ -342,18 +518,26 @@ def get_projects(options):
|
|
|
342
518
|
)
|
|
343
519
|
)
|
|
344
520
|
else:
|
|
345
|
-
if isinstance(parsed, LocalProjectRequirement):
|
|
521
|
+
if isinstance(parsed, (LocalProjectRequirement, URLRequirement)):
|
|
346
522
|
if parsed.marker:
|
|
347
523
|
errors.append(
|
|
348
524
|
"The --project {project} has a marker, which is not supported. "
|
|
349
525
|
"Remove marker: ;{marker}".format(project=project, marker=parsed.marker)
|
|
350
526
|
)
|
|
527
|
+
elif isinstance(parsed, LocalProjectRequirement):
|
|
528
|
+
project_directories.append(ProjectDirectory(requirement=parsed))
|
|
529
|
+
elif parsed.url.scheme != "file":
|
|
530
|
+
errors.append(
|
|
531
|
+
"The --project {project} URL must be a local file: URL.".format(
|
|
532
|
+
project=project
|
|
533
|
+
)
|
|
534
|
+
)
|
|
351
535
|
else:
|
|
352
|
-
|
|
536
|
+
project_archives.append(ProjectArchive(requirement=parsed))
|
|
353
537
|
else:
|
|
354
538
|
errors.append(
|
|
355
539
|
"The --project {project} does not appear to point to a directory containing a "
|
|
356
|
-
"Python project.".format(project=project)
|
|
540
|
+
"Python project or a project archive (sdist or whl).".format(project=project)
|
|
357
541
|
)
|
|
358
542
|
|
|
359
543
|
if errors:
|
|
@@ -368,7 +552,9 @@ def get_projects(options):
|
|
|
368
552
|
)
|
|
369
553
|
)
|
|
370
554
|
|
|
371
|
-
return Projects(
|
|
555
|
+
return Projects(
|
|
556
|
+
project_directories=tuple(project_directories), project_archives=tuple(project_archives)
|
|
557
|
+
)
|
|
372
558
|
|
|
373
559
|
|
|
374
560
|
def get_group_requirements(options):
|
|
@@ -5,11 +5,19 @@ from __future__ import absolute_import
|
|
|
5
5
|
|
|
6
6
|
from pex.fetcher import URLFetcher
|
|
7
7
|
from pex.network_configuration import NetworkConfiguration
|
|
8
|
-
from pex.requirements import
|
|
8
|
+
from pex.requirements import (
|
|
9
|
+
Constraint,
|
|
10
|
+
LocalProjectRequirement,
|
|
11
|
+
PyPIRequirement,
|
|
12
|
+
URLRequirement,
|
|
13
|
+
VCSRequirement,
|
|
14
|
+
parse_requirement_file,
|
|
15
|
+
parse_requirement_strings,
|
|
16
|
+
)
|
|
9
17
|
from pex.typing import TYPE_CHECKING
|
|
10
18
|
|
|
11
19
|
if TYPE_CHECKING:
|
|
12
|
-
from typing import Iterable, List, Optional
|
|
20
|
+
from typing import Iterable, List, Optional, Tuple
|
|
13
21
|
|
|
14
22
|
import attr # vendor:skip
|
|
15
23
|
|
|
@@ -18,14 +26,21 @@ else:
|
|
|
18
26
|
from pex.third_party import attr
|
|
19
27
|
|
|
20
28
|
|
|
29
|
+
def _as_str_tuple(items):
|
|
30
|
+
# type: (Optional[Iterable[str]]) -> Tuple[str, ...]
|
|
31
|
+
if not items:
|
|
32
|
+
return ()
|
|
33
|
+
return items if isinstance(items, tuple) else tuple(items)
|
|
34
|
+
|
|
35
|
+
|
|
21
36
|
@attr.s(frozen=True)
|
|
22
37
|
class RequirementConfiguration(object):
|
|
23
|
-
requirements = attr.ib(default=
|
|
24
|
-
requirement_files = attr.ib(default=
|
|
25
|
-
constraint_files = attr.ib(default=
|
|
38
|
+
requirements = attr.ib(default=(), converter=_as_str_tuple) # type: Tuple[str, ...]
|
|
39
|
+
requirement_files = attr.ib(default=(), converter=_as_str_tuple) # type: Tuple[str, ...]
|
|
40
|
+
constraint_files = attr.ib(default=(), converter=_as_str_tuple) # type: Tuple[str, ...]
|
|
26
41
|
|
|
27
42
|
def parse_requirements(self, network_configuration=None):
|
|
28
|
-
# type: (Optional[NetworkConfiguration]) ->
|
|
43
|
+
# type: (Optional[NetworkConfiguration]) -> Tuple[ParsedRequirement, ...]
|
|
29
44
|
parsed_requirements = [] # type: List[ParsedRequirement]
|
|
30
45
|
if self.requirements:
|
|
31
46
|
parsed_requirements.extend(parse_requirement_strings(self.requirements))
|
|
@@ -37,12 +52,15 @@ class RequirementConfiguration(object):
|
|
|
37
52
|
for requirement_or_constraint in parse_requirement_file(
|
|
38
53
|
requirement_file, is_constraints=False, fetcher=fetcher
|
|
39
54
|
)
|
|
40
|
-
if
|
|
55
|
+
if isinstance(
|
|
56
|
+
requirement_or_constraint,
|
|
57
|
+
(PyPIRequirement, URLRequirement, VCSRequirement, LocalProjectRequirement),
|
|
58
|
+
)
|
|
41
59
|
)
|
|
42
|
-
return parsed_requirements
|
|
60
|
+
return tuple(parsed_requirements)
|
|
43
61
|
|
|
44
62
|
def parse_constraints(self, network_configuration=None):
|
|
45
|
-
# type: (Optional[NetworkConfiguration]) ->
|
|
63
|
+
# type: (Optional[NetworkConfiguration]) -> Tuple[Constraint, ...]
|
|
46
64
|
parsed_constraints = [] # type: List[Constraint]
|
|
47
65
|
if self.constraint_files:
|
|
48
66
|
fetcher = URLFetcher(network_configuration=network_configuration)
|
|
@@ -54,7 +72,7 @@ class RequirementConfiguration(object):
|
|
|
54
72
|
)
|
|
55
73
|
if isinstance(requirement_or_constraint, Constraint)
|
|
56
74
|
)
|
|
57
|
-
return parsed_constraints
|
|
75
|
+
return tuple(parsed_constraints)
|
|
58
76
|
|
|
59
77
|
@property
|
|
60
78
|
def has_requirements(self):
|
|
@@ -3,17 +3,16 @@
|
|
|
3
3
|
|
|
4
4
|
from __future__ import absolute_import
|
|
5
5
|
|
|
6
|
-
import itertools
|
|
7
|
-
|
|
8
6
|
from pex import pex_warnings
|
|
9
|
-
from pex.auth import PasswordEntry
|
|
10
7
|
from pex.enum import Enum
|
|
11
8
|
from pex.jobs import DEFAULT_MAX_JOBS
|
|
12
9
|
from pex.network_configuration import NetworkConfiguration
|
|
13
10
|
from pex.pep_440 import Version
|
|
14
11
|
from pex.pep_503 import ProjectName
|
|
15
12
|
from pex.pip.version import PipVersion, PipVersionValue
|
|
13
|
+
from pex.resolve.package_repository import ReposConfiguration
|
|
16
14
|
from pex.typing import TYPE_CHECKING
|
|
15
|
+
from pex.venv.virtualenv import Virtualenv
|
|
17
16
|
|
|
18
17
|
if TYPE_CHECKING:
|
|
19
18
|
from typing import Callable, FrozenSet, Iterable, Optional, Tuple, Union
|
|
@@ -26,9 +25,6 @@ else:
|
|
|
26
25
|
from pex.third_party import attr
|
|
27
26
|
|
|
28
27
|
|
|
29
|
-
PYPI = "https://pypi.org/simple"
|
|
30
|
-
|
|
31
|
-
|
|
32
28
|
class ResolverVersion(Enum["ResolverVersion.Value"]):
|
|
33
29
|
class Value(Enum.Value):
|
|
34
30
|
pass
|
|
@@ -60,32 +56,6 @@ class ResolverVersion(Enum["ResolverVersion.Value"]):
|
|
|
60
56
|
ResolverVersion.seal()
|
|
61
57
|
|
|
62
58
|
|
|
63
|
-
@attr.s(frozen=True)
|
|
64
|
-
class ReposConfiguration(object):
|
|
65
|
-
@classmethod
|
|
66
|
-
def create(
|
|
67
|
-
cls,
|
|
68
|
-
indexes=(), # type: Iterable[str]
|
|
69
|
-
find_links=(), # type: Iterable[str]
|
|
70
|
-
):
|
|
71
|
-
# type: (...) -> ReposConfiguration
|
|
72
|
-
password_entries = []
|
|
73
|
-
for url in itertools.chain(indexes, find_links):
|
|
74
|
-
password_entry = PasswordEntry.maybe_extract_from_url(url)
|
|
75
|
-
if password_entry:
|
|
76
|
-
password_entries.append(password_entry)
|
|
77
|
-
|
|
78
|
-
return cls(
|
|
79
|
-
indexes=tuple(indexes),
|
|
80
|
-
find_links=tuple(find_links),
|
|
81
|
-
password_entries=tuple(password_entries),
|
|
82
|
-
)
|
|
83
|
-
|
|
84
|
-
indexes = attr.ib(default=(PYPI,)) # type: Tuple[str, ...]
|
|
85
|
-
find_links = attr.ib(default=()) # type: Tuple[str, ...]
|
|
86
|
-
password_entries = attr.ib(default=()) # type: Tuple[PasswordEntry, ...]
|
|
87
|
-
|
|
88
|
-
|
|
89
59
|
@attr.s(frozen=True)
|
|
90
60
|
class BuildConfiguration(object):
|
|
91
61
|
class Error(ValueError):
|
|
@@ -277,3 +247,19 @@ class PreResolvedConfiguration(object):
|
|
|
277
247
|
def network_configuration(self):
|
|
278
248
|
# type: () -> NetworkConfiguration
|
|
279
249
|
return self.pip_configuration.network_configuration
|
|
250
|
+
|
|
251
|
+
|
|
252
|
+
@attr.s(frozen=True)
|
|
253
|
+
class VenvRepositoryConfiguration(object):
|
|
254
|
+
venvs = attr.ib() # type: Tuple[Virtualenv, ...]
|
|
255
|
+
pip_configuration = attr.ib() # type: PipConfiguration
|
|
256
|
+
|
|
257
|
+
@property
|
|
258
|
+
def repos_configuration(self):
|
|
259
|
+
# type: () -> ReposConfiguration
|
|
260
|
+
return self.pip_configuration.repos_configuration
|
|
261
|
+
|
|
262
|
+
@property
|
|
263
|
+
def network_configuration(self):
|
|
264
|
+
# type: () -> NetworkConfiguration
|
|
265
|
+
return self.pip_configuration.network_configuration
|