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
|
@@ -0,0 +1,908 @@
|
|
|
1
|
+
# Copyright 2021 Pex project contributors.
|
|
2
|
+
# Licensed under the Apache License, Version 2.0 (see LICENSE).
|
|
3
|
+
|
|
4
|
+
from __future__ import absolute_import
|
|
5
|
+
|
|
6
|
+
import operator
|
|
7
|
+
import sys
|
|
8
|
+
|
|
9
|
+
from pex import pex_warnings
|
|
10
|
+
from pex.common import pluralize
|
|
11
|
+
from pex.compatibility import string
|
|
12
|
+
from pex.enum import Enum
|
|
13
|
+
from pex.exceptions import production_assert, reportable_unexpected_error_msg
|
|
14
|
+
from pex.interpreter_constraints import InterpreterConstraint, iter_compatible_versions
|
|
15
|
+
from pex.interpreter_implementation import InterpreterImplementation
|
|
16
|
+
from pex.orderedset import OrderedSet
|
|
17
|
+
from pex.os import LINUX, MAC, WINDOWS
|
|
18
|
+
from pex.pep_503 import ProjectName
|
|
19
|
+
from pex.sorted_tuple import SortedTuple
|
|
20
|
+
from pex.third_party.packaging.markers import Marker, Variable
|
|
21
|
+
from pex.third_party.packaging.specifiers import Specifier, SpecifierSet
|
|
22
|
+
from pex.typing import TYPE_CHECKING, Generic, cast
|
|
23
|
+
|
|
24
|
+
if TYPE_CHECKING:
|
|
25
|
+
from typing import (
|
|
26
|
+
Any,
|
|
27
|
+
Callable,
|
|
28
|
+
Dict,
|
|
29
|
+
Iterable,
|
|
30
|
+
Iterator,
|
|
31
|
+
List,
|
|
32
|
+
Mapping,
|
|
33
|
+
Optional,
|
|
34
|
+
Sequence,
|
|
35
|
+
Tuple,
|
|
36
|
+
TypeVar,
|
|
37
|
+
Union,
|
|
38
|
+
)
|
|
39
|
+
|
|
40
|
+
import attr # vendor:skip
|
|
41
|
+
else:
|
|
42
|
+
from pex.third_party import attr
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
class TargetSystem(Enum["TargetSystem.Value"]):
|
|
46
|
+
class Value(Enum.Value):
|
|
47
|
+
pass
|
|
48
|
+
|
|
49
|
+
LINUX = Value("linux")
|
|
50
|
+
MAC = Value("mac")
|
|
51
|
+
WINDOWS = Value("windows")
|
|
52
|
+
|
|
53
|
+
@classmethod
|
|
54
|
+
def current(cls):
|
|
55
|
+
# type: () -> TargetSystem.Value
|
|
56
|
+
if LINUX:
|
|
57
|
+
return TargetSystem.LINUX
|
|
58
|
+
elif MAC:
|
|
59
|
+
return TargetSystem.MAC
|
|
60
|
+
elif WINDOWS:
|
|
61
|
+
return TargetSystem.WINDOWS
|
|
62
|
+
raise AssertionError(reportable_unexpected_error_msg("Unexpected os {os}", os=sys.platform))
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
TargetSystem.seal()
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
def _marker_items(marker):
|
|
69
|
+
# type:(Marker) -> Iterable[Any]
|
|
70
|
+
|
|
71
|
+
marker_items = getattr(marker, "_markers", None)
|
|
72
|
+
if marker_items is None:
|
|
73
|
+
raise AssertionError(
|
|
74
|
+
reportable_unexpected_error_msg(
|
|
75
|
+
"Expected packaging.markers.Marker to have a _markers attribute; found none in "
|
|
76
|
+
"{marker} of type {type}",
|
|
77
|
+
marker=marker,
|
|
78
|
+
type=type(marker).__name__,
|
|
79
|
+
)
|
|
80
|
+
)
|
|
81
|
+
production_assert(
|
|
82
|
+
hasattr(marker_items, "__iter__"),
|
|
83
|
+
"Expected packaging.markers.Marker._markers to be iterable; found {marker_items} of type "
|
|
84
|
+
"{type}",
|
|
85
|
+
marker_items=marker_items,
|
|
86
|
+
type=type(marker_items).__name__,
|
|
87
|
+
)
|
|
88
|
+
return cast("Iterable[Any]", marker._markers)
|
|
89
|
+
|
|
90
|
+
|
|
91
|
+
class MarkerVisitor(Generic["_C"]):
|
|
92
|
+
def visit_and(
|
|
93
|
+
self,
|
|
94
|
+
marker, # type: Marker
|
|
95
|
+
context, # type: _C
|
|
96
|
+
):
|
|
97
|
+
# type: (...) -> None
|
|
98
|
+
pass
|
|
99
|
+
|
|
100
|
+
def visit_or(
|
|
101
|
+
self,
|
|
102
|
+
marker, # type: Marker
|
|
103
|
+
context, # type: _C
|
|
104
|
+
):
|
|
105
|
+
# type: (...) -> None
|
|
106
|
+
pass
|
|
107
|
+
|
|
108
|
+
def begin_visit_group(
|
|
109
|
+
self,
|
|
110
|
+
group, # type: List[Any]
|
|
111
|
+
marker, # type: Marker
|
|
112
|
+
context, # type: _C
|
|
113
|
+
):
|
|
114
|
+
# type: (...) -> Optional[_C]
|
|
115
|
+
return None
|
|
116
|
+
|
|
117
|
+
def end_visit_group(
|
|
118
|
+
self,
|
|
119
|
+
group, # type: List[Any]
|
|
120
|
+
marker, # type: Marker
|
|
121
|
+
context, # type: _C
|
|
122
|
+
group_context, # type: Optional[_C]
|
|
123
|
+
):
|
|
124
|
+
# type: (...) -> None
|
|
125
|
+
pass
|
|
126
|
+
|
|
127
|
+
def visit_op(
|
|
128
|
+
self,
|
|
129
|
+
lhs, # type: Any
|
|
130
|
+
op, # type: Any
|
|
131
|
+
rhs, # type: Any
|
|
132
|
+
marker, # type: Marker
|
|
133
|
+
context, # type: _C
|
|
134
|
+
):
|
|
135
|
+
# type: (...) -> None
|
|
136
|
+
pass
|
|
137
|
+
|
|
138
|
+
|
|
139
|
+
if TYPE_CHECKING:
|
|
140
|
+
_C = TypeVar("_C")
|
|
141
|
+
|
|
142
|
+
|
|
143
|
+
class MarkerParser(Generic["_C"]):
|
|
144
|
+
def __init__(self, visitor):
|
|
145
|
+
# type: (MarkerVisitor["_C"]) -> None
|
|
146
|
+
self._visitor = visitor
|
|
147
|
+
|
|
148
|
+
def _parse_marker_item(
|
|
149
|
+
self,
|
|
150
|
+
item, # type: Union[str, List, Tuple]
|
|
151
|
+
marker, # type: Marker
|
|
152
|
+
context, # type: _C
|
|
153
|
+
):
|
|
154
|
+
# type: (...) -> None
|
|
155
|
+
|
|
156
|
+
if item == "and":
|
|
157
|
+
self._visitor.visit_and(marker, context)
|
|
158
|
+
elif item == "or":
|
|
159
|
+
self._visitor.visit_or(marker, context)
|
|
160
|
+
elif isinstance(item, list):
|
|
161
|
+
group_context = self._visitor.begin_visit_group(item, marker, context)
|
|
162
|
+
element_context = group_context if group_context is not None else context
|
|
163
|
+
for element in item:
|
|
164
|
+
self._parse_marker_item(element, marker, element_context)
|
|
165
|
+
self._visitor.end_visit_group(item, marker, context, group_context)
|
|
166
|
+
elif isinstance(item, tuple):
|
|
167
|
+
lhs, op, rhs = item
|
|
168
|
+
self._visitor.visit_op(lhs, op, rhs, marker, context)
|
|
169
|
+
else:
|
|
170
|
+
raise ValueError("Marker is invalid: {marker}".format(marker=marker))
|
|
171
|
+
|
|
172
|
+
def parse(
|
|
173
|
+
self,
|
|
174
|
+
marker, # type: Marker
|
|
175
|
+
context, # type: _C
|
|
176
|
+
):
|
|
177
|
+
# type: (...) -> _C
|
|
178
|
+
|
|
179
|
+
for item in _marker_items(marker):
|
|
180
|
+
self._parse_marker_item(item, marker, context)
|
|
181
|
+
return context
|
|
182
|
+
|
|
183
|
+
|
|
184
|
+
class HasMarkerVisitor(MarkerVisitor[None]):
|
|
185
|
+
def __init__(self, name):
|
|
186
|
+
# type: (str) -> None
|
|
187
|
+
self._name = name
|
|
188
|
+
self.has_marker = False
|
|
189
|
+
|
|
190
|
+
def visit_op(
|
|
191
|
+
self,
|
|
192
|
+
lhs, # type: Any
|
|
193
|
+
op, # type: Any
|
|
194
|
+
rhs, # type: Any
|
|
195
|
+
marker, # type: Marker
|
|
196
|
+
context, # type: None
|
|
197
|
+
):
|
|
198
|
+
# type: (...) -> None
|
|
199
|
+
if self.has_marker:
|
|
200
|
+
return
|
|
201
|
+
|
|
202
|
+
for term in lhs, rhs:
|
|
203
|
+
if is_variable(term) and self._name == str(term):
|
|
204
|
+
self.has_marker = True
|
|
205
|
+
break
|
|
206
|
+
|
|
207
|
+
|
|
208
|
+
def has_marker(
|
|
209
|
+
marker, # type: Marker
|
|
210
|
+
name, # type: str
|
|
211
|
+
):
|
|
212
|
+
# type: (...) -> bool
|
|
213
|
+
|
|
214
|
+
visitor = HasMarkerVisitor(name)
|
|
215
|
+
MarkerParser(visitor).parse(marker, None)
|
|
216
|
+
return visitor.has_marker
|
|
217
|
+
|
|
218
|
+
|
|
219
|
+
if TYPE_CHECKING:
|
|
220
|
+
EvalMarker = Callable[["MarkerEnv"], bool]
|
|
221
|
+
|
|
222
|
+
|
|
223
|
+
_OPERATORS = {
|
|
224
|
+
"in": lambda lhs, rhs: lhs in rhs,
|
|
225
|
+
"not in": lambda lhs, rhs: lhs not in rhs,
|
|
226
|
+
"<": operator.lt,
|
|
227
|
+
"<=": operator.le,
|
|
228
|
+
"==": operator.eq,
|
|
229
|
+
"!=": operator.ne,
|
|
230
|
+
">=": operator.ge,
|
|
231
|
+
">": operator.gt,
|
|
232
|
+
} # type: Mapping[str, Callable[[Any, Any], bool]]
|
|
233
|
+
|
|
234
|
+
|
|
235
|
+
_VERSION_MARKER_OP_FLIPPED = {
|
|
236
|
+
"<": ">",
|
|
237
|
+
"<=": ">=",
|
|
238
|
+
">=": "<=",
|
|
239
|
+
">": "<",
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
_VERSION_CMP_OPS = {
|
|
243
|
+
"<",
|
|
244
|
+
"<=",
|
|
245
|
+
"==",
|
|
246
|
+
"!=",
|
|
247
|
+
">=",
|
|
248
|
+
">",
|
|
249
|
+
"~=",
|
|
250
|
+
"===",
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
|
|
254
|
+
class _Op(object):
|
|
255
|
+
def __init__(self, lhs):
|
|
256
|
+
self.lhs = lhs # type: EvalMarker
|
|
257
|
+
self.rhs = None # type: Optional[EvalMarker]
|
|
258
|
+
|
|
259
|
+
|
|
260
|
+
class _And(_Op):
|
|
261
|
+
def __call__(self, marker_env):
|
|
262
|
+
# type: (MarkerEnv) -> bool
|
|
263
|
+
production_assert(self.rhs is not None)
|
|
264
|
+
return self.lhs(marker_env) and cast("EvalMarker", self.rhs)(marker_env)
|
|
265
|
+
|
|
266
|
+
|
|
267
|
+
class _Or(_Op):
|
|
268
|
+
def __call__(self, marker_env):
|
|
269
|
+
# type: (MarkerEnv) -> bool
|
|
270
|
+
production_assert(self.rhs is not None)
|
|
271
|
+
return self.lhs(marker_env) or cast("EvalMarker", self.rhs)(marker_env)
|
|
272
|
+
|
|
273
|
+
|
|
274
|
+
@attr.s(frozen=True)
|
|
275
|
+
class Values(object):
|
|
276
|
+
@classmethod
|
|
277
|
+
def from_dict(cls, data):
|
|
278
|
+
# type: (Dict[str, Any]) -> Values
|
|
279
|
+
return cls(
|
|
280
|
+
marker_name=data.pop("marker_name"),
|
|
281
|
+
values=tuple(data.pop("values", ())),
|
|
282
|
+
inclusive=data.pop("inclusive", True),
|
|
283
|
+
)
|
|
284
|
+
|
|
285
|
+
marker_name = attr.ib() # type: str
|
|
286
|
+
values = attr.ib(default=()) # type: Tuple[str, ...]
|
|
287
|
+
inclusive = attr.ib(default=True) # type: bool
|
|
288
|
+
|
|
289
|
+
def to_dict(self):
|
|
290
|
+
# type: () -> Dict[str, Any]
|
|
291
|
+
return {"marker_name": self.marker_name, "values": self.values, "inclusive": self.inclusive}
|
|
292
|
+
|
|
293
|
+
def apply(self, func):
|
|
294
|
+
# type: (Callable[[str], bool]) -> bool
|
|
295
|
+
if len(self.values) == 0:
|
|
296
|
+
return self.marker_name != "extra"
|
|
297
|
+
if self.inclusive:
|
|
298
|
+
return any(map(func, self.values))
|
|
299
|
+
return all((not result) for result in map(func, self.values))
|
|
300
|
+
|
|
301
|
+
def __len__(self):
|
|
302
|
+
# type: () -> int
|
|
303
|
+
return len(self.values)
|
|
304
|
+
|
|
305
|
+
def __iter__(self):
|
|
306
|
+
# type: () -> Iterator[str]
|
|
307
|
+
return iter(self.values)
|
|
308
|
+
|
|
309
|
+
|
|
310
|
+
def _get_values_func(marker_name):
|
|
311
|
+
# type: (str) -> Callable[[MarkerEnv], Values]
|
|
312
|
+
|
|
313
|
+
if marker_name == "extra":
|
|
314
|
+
return lambda marker_env: Values(marker_name, marker_env.extras)
|
|
315
|
+
elif marker_name == "os_name":
|
|
316
|
+
return lambda marker_env: Values(marker_name, marker_env.os_names)
|
|
317
|
+
elif marker_name == "platform_system":
|
|
318
|
+
return lambda marker_env: Values(marker_name, marker_env.platform_systems)
|
|
319
|
+
elif marker_name == "sys_platform":
|
|
320
|
+
return lambda marker_env: Values(marker_name, marker_env.sys_platforms)
|
|
321
|
+
elif marker_name == "platform_python_implementation":
|
|
322
|
+
return lambda marker_env: Values(marker_name, marker_env.platform_python_implementations)
|
|
323
|
+
elif marker_name == "python_version":
|
|
324
|
+
return lambda marker_env: Values(marker_name, marker_env.python_versions)
|
|
325
|
+
elif marker_name == "python_full_version":
|
|
326
|
+
return lambda marker_env: Values(marker_name, marker_env.python_full_versions)
|
|
327
|
+
return lambda marker_env: marker_env.extra_markers.get_values(marker_name)
|
|
328
|
+
|
|
329
|
+
|
|
330
|
+
class UniversalMarkerVisitor(MarkerVisitor["List[EvalMarker]"]):
|
|
331
|
+
@classmethod
|
|
332
|
+
def parse_marker(cls, marker):
|
|
333
|
+
# type: (Marker) -> EvalMarker
|
|
334
|
+
|
|
335
|
+
checks = MarkerParser(cls()).parse(marker, context=[])
|
|
336
|
+
production_assert(len(checks) == 1)
|
|
337
|
+
return checks[0]
|
|
338
|
+
|
|
339
|
+
def visit_and(
|
|
340
|
+
self,
|
|
341
|
+
marker, # type: Marker
|
|
342
|
+
context, # type: List[EvalMarker]
|
|
343
|
+
):
|
|
344
|
+
# type: (...) -> None
|
|
345
|
+
context.append(_And(context.pop()))
|
|
346
|
+
|
|
347
|
+
def visit_or(
|
|
348
|
+
self,
|
|
349
|
+
marker, # type: Marker
|
|
350
|
+
context, # type: List[EvalMarker]
|
|
351
|
+
):
|
|
352
|
+
# type: (...) -> None
|
|
353
|
+
context.append(_Or(context.pop()))
|
|
354
|
+
|
|
355
|
+
def begin_visit_group(
|
|
356
|
+
self,
|
|
357
|
+
group, # type: List[Any]
|
|
358
|
+
marker, # type: Marker
|
|
359
|
+
context, # type: List[EvalMarker]
|
|
360
|
+
):
|
|
361
|
+
# type: (...) -> Optional[List[EvalMarker]]
|
|
362
|
+
return []
|
|
363
|
+
|
|
364
|
+
def end_visit_group(
|
|
365
|
+
self,
|
|
366
|
+
group, # type: List[Any]
|
|
367
|
+
marker, # type: Marker
|
|
368
|
+
context, # type: List[EvalMarker]
|
|
369
|
+
group_context, # type: Optional[List[EvalMarker]]
|
|
370
|
+
):
|
|
371
|
+
# type: (...) -> None
|
|
372
|
+
|
|
373
|
+
if group_context is None or len(group_context) != 1:
|
|
374
|
+
raise AssertionError(reportable_unexpected_error_msg())
|
|
375
|
+
|
|
376
|
+
if context:
|
|
377
|
+
production_assert(isinstance(context[-1], _Op))
|
|
378
|
+
cast(_Op, context[-1]).rhs = group_context[0]
|
|
379
|
+
else:
|
|
380
|
+
context.extend(group_context)
|
|
381
|
+
|
|
382
|
+
def visit_op(
|
|
383
|
+
self,
|
|
384
|
+
lhs, # type: Any
|
|
385
|
+
op, # type: Any
|
|
386
|
+
rhs, # type: Any
|
|
387
|
+
marker, # type: Marker
|
|
388
|
+
context, # type: List[EvalMarker]
|
|
389
|
+
):
|
|
390
|
+
# type: (...) -> None
|
|
391
|
+
|
|
392
|
+
check = EvalMarkerFunc.create(lhs, op, rhs)
|
|
393
|
+
if context:
|
|
394
|
+
production_assert(isinstance(context[-1], _Op))
|
|
395
|
+
cast(_Op, context[-1]).rhs = check
|
|
396
|
+
else:
|
|
397
|
+
context.append(check)
|
|
398
|
+
|
|
399
|
+
|
|
400
|
+
_MARKER_CHECKS = {} # type: Dict[Union[Marker, str], EvalMarker]
|
|
401
|
+
|
|
402
|
+
|
|
403
|
+
def _parse_marker(marker):
|
|
404
|
+
# type: (Marker) -> EvalMarker
|
|
405
|
+
eval_marker = _MARKER_CHECKS.get(marker)
|
|
406
|
+
if not eval_marker:
|
|
407
|
+
marker_str = str(marker)
|
|
408
|
+
eval_marker = _MARKER_CHECKS.get(marker_str)
|
|
409
|
+
if not eval_marker:
|
|
410
|
+
eval_marker = UniversalMarkerVisitor.parse_marker(marker)
|
|
411
|
+
_MARKER_CHECKS[marker] = eval_marker
|
|
412
|
+
_MARKER_CHECKS[marker_str] = eval_marker
|
|
413
|
+
return eval_marker
|
|
414
|
+
|
|
415
|
+
|
|
416
|
+
def is_variable(value):
|
|
417
|
+
# type: (Any) -> bool
|
|
418
|
+
|
|
419
|
+
if isinstance(value, Variable):
|
|
420
|
+
return True
|
|
421
|
+
|
|
422
|
+
# N.B.: This allows interop with Pip vendored packaging which has the same types in a different
|
|
423
|
+
# namespace.
|
|
424
|
+
return type(value).__name__ == "Variable"
|
|
425
|
+
|
|
426
|
+
|
|
427
|
+
class EvalMarkerFunc(object):
|
|
428
|
+
@classmethod
|
|
429
|
+
def create(
|
|
430
|
+
cls,
|
|
431
|
+
lhs, # type: Any
|
|
432
|
+
op, # type: Any
|
|
433
|
+
rhs, # type: Any
|
|
434
|
+
):
|
|
435
|
+
# type: (...) -> Callable[[MarkerEnv], bool]
|
|
436
|
+
|
|
437
|
+
for var, operand, operand_side in ((lhs, rhs, "rhs"), (rhs, lhs, "lhs")):
|
|
438
|
+
if not is_variable(var):
|
|
439
|
+
continue
|
|
440
|
+
marker_name = str(var)
|
|
441
|
+
get_values = _get_values_func(marker_name)
|
|
442
|
+
value = str(operand)
|
|
443
|
+
if marker_name == "extra":
|
|
444
|
+
value = ProjectName(value).normalized
|
|
445
|
+
op_string = str(op)
|
|
446
|
+
operand_side_arg = {operand_side: value}
|
|
447
|
+
return cls(
|
|
448
|
+
get_values=get_values,
|
|
449
|
+
op=op_string,
|
|
450
|
+
is_version_comparison=(
|
|
451
|
+
marker_name
|
|
452
|
+
in ("python_version", "python_full_version", "implementation_version")
|
|
453
|
+
and op_string in _VERSION_CMP_OPS
|
|
454
|
+
),
|
|
455
|
+
**operand_side_arg
|
|
456
|
+
)
|
|
457
|
+
|
|
458
|
+
return lambda _: True
|
|
459
|
+
|
|
460
|
+
def __init__(
|
|
461
|
+
self,
|
|
462
|
+
get_values, # type: Callable[[MarkerEnv], Values]
|
|
463
|
+
op, # type: str
|
|
464
|
+
lhs=None, # type: Optional[str]
|
|
465
|
+
rhs=None, # type: Optional[str]
|
|
466
|
+
is_version_comparison=False, # type: bool
|
|
467
|
+
):
|
|
468
|
+
# type: (...) -> None
|
|
469
|
+
|
|
470
|
+
if lhs is not None:
|
|
471
|
+
if is_version_comparison:
|
|
472
|
+
flipped_op = _VERSION_MARKER_OP_FLIPPED.get(op, op)
|
|
473
|
+
version_specifier = Specifier(
|
|
474
|
+
"{flipped_op}{lhs}".format(lhs=lhs, flipped_op=flipped_op)
|
|
475
|
+
)
|
|
476
|
+
self._func = lambda value: cast(
|
|
477
|
+
bool,
|
|
478
|
+
version_specifier.contains(
|
|
479
|
+
# N.B.: This handles `implementation_version` for Python dev releases in the
|
|
480
|
+
# same way `packaging` does.
|
|
481
|
+
(value + "local") if value.endswith("+") else value,
|
|
482
|
+
prereleases=True,
|
|
483
|
+
),
|
|
484
|
+
)
|
|
485
|
+
else:
|
|
486
|
+
oper = _OPERATORS[op]
|
|
487
|
+
self._func = lambda value: oper(lhs, value)
|
|
488
|
+
elif rhs is not None:
|
|
489
|
+
if is_version_comparison:
|
|
490
|
+
version_specifier = Specifier("{op}{rhs}".format(op=op, rhs=rhs))
|
|
491
|
+
self._func = lambda value: cast(
|
|
492
|
+
bool,
|
|
493
|
+
version_specifier.contains(
|
|
494
|
+
# N.B.: This handles `implementation_version` for Python dev releases in the
|
|
495
|
+
# same way `packaging` does.
|
|
496
|
+
(value + "local") if value.endswith("+") else value,
|
|
497
|
+
prereleases=True,
|
|
498
|
+
),
|
|
499
|
+
)
|
|
500
|
+
else:
|
|
501
|
+
oper = _OPERATORS[op]
|
|
502
|
+
self._func = lambda value: oper(value, rhs)
|
|
503
|
+
else:
|
|
504
|
+
raise ValueError(
|
|
505
|
+
"Must be called with exactly one of lhs or rhs but not both. "
|
|
506
|
+
"Given lhs={lhs} and rhs={rhs}".format(lhs=lhs, rhs=rhs)
|
|
507
|
+
)
|
|
508
|
+
self._get_values = get_values
|
|
509
|
+
|
|
510
|
+
def __call__(self, marker_env):
|
|
511
|
+
# type: (MarkerEnv) -> bool
|
|
512
|
+
|
|
513
|
+
return self._get_values(marker_env).apply(self._func)
|
|
514
|
+
|
|
515
|
+
|
|
516
|
+
class ExtraMarkersVisitor(MarkerVisitor[str]):
|
|
517
|
+
def __init__(self):
|
|
518
|
+
# type: () -> None
|
|
519
|
+
self.conflicts = OrderedSet() # type: OrderedSet[str]
|
|
520
|
+
self._marker_values = {} # type: Dict[str, Tuple[str, OrderedSet[str], bool]]
|
|
521
|
+
|
|
522
|
+
def visit_op(
|
|
523
|
+
self,
|
|
524
|
+
lhs, # type: Any
|
|
525
|
+
op, # type: Any
|
|
526
|
+
rhs, # type: Any
|
|
527
|
+
marker, # type: Marker
|
|
528
|
+
context, # type: str
|
|
529
|
+
):
|
|
530
|
+
# type: (...) -> None
|
|
531
|
+
|
|
532
|
+
op_symbol = str(op)
|
|
533
|
+
if is_variable(lhs):
|
|
534
|
+
name = str(lhs)
|
|
535
|
+
value = str(rhs)
|
|
536
|
+
elif is_variable(rhs):
|
|
537
|
+
name = str(rhs)
|
|
538
|
+
value = str(lhs)
|
|
539
|
+
else:
|
|
540
|
+
return
|
|
541
|
+
|
|
542
|
+
if name in (
|
|
543
|
+
"extra",
|
|
544
|
+
"os_name",
|
|
545
|
+
"platform_system",
|
|
546
|
+
"sys_platform",
|
|
547
|
+
"platform_python_implementation",
|
|
548
|
+
"python_version",
|
|
549
|
+
"python_full_version",
|
|
550
|
+
):
|
|
551
|
+
return
|
|
552
|
+
|
|
553
|
+
if op_symbol == "==":
|
|
554
|
+
requirement, values, inclusive = self._marker_values.setdefault(
|
|
555
|
+
name, (context, OrderedSet(), True)
|
|
556
|
+
)
|
|
557
|
+
if not inclusive:
|
|
558
|
+
self.conflicts.add(
|
|
559
|
+
"The requirement {context} includes {value} for {name} but the requirement "
|
|
560
|
+
"{requirement} established {name} as an exclusive set with values: "
|
|
561
|
+
"{values}.".format(
|
|
562
|
+
context=context,
|
|
563
|
+
value=value,
|
|
564
|
+
name=name,
|
|
565
|
+
requirement=requirement,
|
|
566
|
+
values=" ".join(values),
|
|
567
|
+
)
|
|
568
|
+
)
|
|
569
|
+
else:
|
|
570
|
+
values.add(value)
|
|
571
|
+
elif op_symbol == "!=":
|
|
572
|
+
requirement, values, inclusive = self._marker_values.setdefault(
|
|
573
|
+
name, (context, OrderedSet(), False)
|
|
574
|
+
)
|
|
575
|
+
if inclusive:
|
|
576
|
+
self.conflicts.add(
|
|
577
|
+
"The requirement {context} excludes {value} for {name} but the requirement "
|
|
578
|
+
"{requirement} established {name} as an inclusive set with values: "
|
|
579
|
+
"{values}.".format(
|
|
580
|
+
context=context,
|
|
581
|
+
value=value,
|
|
582
|
+
name=name,
|
|
583
|
+
requirement=requirement,
|
|
584
|
+
values=" ".join(values),
|
|
585
|
+
)
|
|
586
|
+
)
|
|
587
|
+
else:
|
|
588
|
+
values.add(value)
|
|
589
|
+
else:
|
|
590
|
+
pex_warnings.warn(
|
|
591
|
+
"Cannot split universal lock on all clauses of the marker in `{requirement}`.\n"
|
|
592
|
+
"The clause `{lhs} {op} {rhs}` uses comparison `{op}` but only `==` and `!=` are "
|
|
593
|
+
"supported for splitting on '{name}'.\n"
|
|
594
|
+
"Ignoring this clause in split calculations; lock results may be "
|
|
595
|
+
"unexpected.".format(requirement=context, lhs=lhs, op=op, rhs=rhs, name=name)
|
|
596
|
+
)
|
|
597
|
+
|
|
598
|
+
def marker_values(self):
|
|
599
|
+
# type: () -> Tuple[Values, ...]
|
|
600
|
+
return tuple(
|
|
601
|
+
Values(marker_name=name, values=tuple(values), inclusive=inclusive)
|
|
602
|
+
for name, (_, values, inclusive) in self._marker_values.items()
|
|
603
|
+
)
|
|
604
|
+
|
|
605
|
+
|
|
606
|
+
@attr.s(frozen=True)
|
|
607
|
+
class ExtraMarkers(object):
|
|
608
|
+
@classmethod
|
|
609
|
+
def extract(cls, requirements):
|
|
610
|
+
# type: (Iterable[Tuple[Marker, str]]) -> Optional[ExtraMarkers]
|
|
611
|
+
|
|
612
|
+
visitor = ExtraMarkersVisitor()
|
|
613
|
+
marker_parser = MarkerParser(visitor)
|
|
614
|
+
|
|
615
|
+
markers = [] # type: List[Marker]
|
|
616
|
+
for marker, provenance in requirements:
|
|
617
|
+
marker_parser.parse(marker, context=provenance)
|
|
618
|
+
markers.append(marker)
|
|
619
|
+
|
|
620
|
+
if visitor.conflicts:
|
|
621
|
+
raise ValueError(
|
|
622
|
+
"Encountered {count} {conflicts} when extracting universal lock splits from "
|
|
623
|
+
"top-level requirement markers:\n{items}".format(
|
|
624
|
+
count=len(visitor.conflicts),
|
|
625
|
+
conflicts=pluralize(visitor.conflicts, "conflict"),
|
|
626
|
+
items="\n".join(
|
|
627
|
+
"{index}. {conflict}".format(index=index, conflict=conflict)
|
|
628
|
+
for index, conflict in enumerate(visitor.conflicts, start=1)
|
|
629
|
+
),
|
|
630
|
+
)
|
|
631
|
+
)
|
|
632
|
+
|
|
633
|
+
return cls(markers=tuple(markers), marker_values=visitor.marker_values())
|
|
634
|
+
|
|
635
|
+
@classmethod
|
|
636
|
+
def from_dict(cls, data):
|
|
637
|
+
# type: (Dict[str, Any]) -> ExtraMarkers
|
|
638
|
+
return cls(
|
|
639
|
+
markers=tuple(Marker(marker) for marker in data.pop("markers", ())),
|
|
640
|
+
marker_values=tuple(
|
|
641
|
+
Values.from_dict(marker_values) for marker_values in data.pop("marker_values", ())
|
|
642
|
+
),
|
|
643
|
+
)
|
|
644
|
+
|
|
645
|
+
markers = attr.ib(default=()) # type: Tuple[Marker, ...]
|
|
646
|
+
marker_values = attr.ib(default=()) # type: Tuple[Values, ...]
|
|
647
|
+
|
|
648
|
+
def to_dict(self):
|
|
649
|
+
# type: () -> Dict[str, Any]
|
|
650
|
+
return {
|
|
651
|
+
"markers": [str(marker) for marker in self.markers],
|
|
652
|
+
"marker_values": [values.to_dict() for values in self.marker_values],
|
|
653
|
+
}
|
|
654
|
+
|
|
655
|
+
def get_values(self, marker_name):
|
|
656
|
+
# type: (str) -> Values
|
|
657
|
+
for values in self.marker_values:
|
|
658
|
+
if marker_name == values.marker_name:
|
|
659
|
+
return values
|
|
660
|
+
return Values(marker_name)
|
|
661
|
+
|
|
662
|
+
def __iter__(self):
|
|
663
|
+
# type: () -> Iterator[Marker]
|
|
664
|
+
return iter(self.markers)
|
|
665
|
+
|
|
666
|
+
|
|
667
|
+
@attr.s(frozen=True)
|
|
668
|
+
class MarkerEnv(object):
|
|
669
|
+
@classmethod
|
|
670
|
+
def from_dict(cls, data):
|
|
671
|
+
# type: (Dict[str, Any]) -> MarkerEnv
|
|
672
|
+
return cls(**data)
|
|
673
|
+
|
|
674
|
+
@classmethod
|
|
675
|
+
def create(
|
|
676
|
+
cls,
|
|
677
|
+
extras, # type: Iterable[str]
|
|
678
|
+
universal_target=None, # type: Optional[UniversalTarget]
|
|
679
|
+
):
|
|
680
|
+
# type: (...) -> MarkerEnv
|
|
681
|
+
|
|
682
|
+
implementations = [] # type: List[InterpreterImplementation.Value]
|
|
683
|
+
if universal_target and universal_target.implementation:
|
|
684
|
+
implementations.append(universal_target.implementation)
|
|
685
|
+
else:
|
|
686
|
+
implementations.extend(InterpreterImplementation.values())
|
|
687
|
+
|
|
688
|
+
python_full_versions = (
|
|
689
|
+
list(iter_compatible_versions(universal_target.requires_python))
|
|
690
|
+
if universal_target
|
|
691
|
+
else []
|
|
692
|
+
)
|
|
693
|
+
python_versions = OrderedSet(
|
|
694
|
+
python_full_version[:2] for python_full_version in python_full_versions
|
|
695
|
+
)
|
|
696
|
+
|
|
697
|
+
os_names = []
|
|
698
|
+
platform_systems = []
|
|
699
|
+
sys_platforms = []
|
|
700
|
+
target_systems = universal_target.systems if universal_target else ()
|
|
701
|
+
for target_system in target_systems:
|
|
702
|
+
if target_system is TargetSystem.LINUX:
|
|
703
|
+
os_names.append("posix")
|
|
704
|
+
platform_systems.append("Linux")
|
|
705
|
+
sys_platforms.append("linux")
|
|
706
|
+
sys_platforms.append("linux2")
|
|
707
|
+
elif target_system is TargetSystem.MAC:
|
|
708
|
+
os_names.append("posix")
|
|
709
|
+
platform_systems.append("Darwin")
|
|
710
|
+
sys_platforms.append("darwin")
|
|
711
|
+
elif target_system is TargetSystem.WINDOWS:
|
|
712
|
+
os_names.append("nt")
|
|
713
|
+
platform_systems.append("Windows")
|
|
714
|
+
sys_platforms.append("win32")
|
|
715
|
+
|
|
716
|
+
return cls(
|
|
717
|
+
extras=SortedTuple(ProjectName(extra).normalized for extra in extras),
|
|
718
|
+
os_names=SortedTuple(os_names),
|
|
719
|
+
platform_systems=SortedTuple(platform_systems),
|
|
720
|
+
sys_platforms=SortedTuple(sys_platforms),
|
|
721
|
+
platform_python_implementations=SortedTuple(map(str, implementations)),
|
|
722
|
+
python_versions=SortedTuple(
|
|
723
|
+
".".join(map(str, python_version)) for python_version in python_versions
|
|
724
|
+
),
|
|
725
|
+
python_full_versions=SortedTuple(
|
|
726
|
+
".".join(map(str, python_full_version))
|
|
727
|
+
for python_full_version in python_full_versions
|
|
728
|
+
),
|
|
729
|
+
extra_markers=universal_target.extra_markers if universal_target else ExtraMarkers(),
|
|
730
|
+
)
|
|
731
|
+
|
|
732
|
+
extras = attr.ib() # type: SortedTuple[str]
|
|
733
|
+
os_names = attr.ib() # type: SortedTuple[str]
|
|
734
|
+
platform_systems = attr.ib() # type: SortedTuple[str]
|
|
735
|
+
sys_platforms = attr.ib() # type: SortedTuple[str]
|
|
736
|
+
platform_python_implementations = attr.ib() # type: SortedTuple[str]
|
|
737
|
+
python_versions = attr.ib() # type: SortedTuple[str]
|
|
738
|
+
python_full_versions = attr.ib() # type: SortedTuple[str]
|
|
739
|
+
extra_markers = attr.ib() # type: ExtraMarkers
|
|
740
|
+
|
|
741
|
+
def as_dict(self):
|
|
742
|
+
# type: () -> Dict[str, Any]
|
|
743
|
+
return attr.asdict(self)
|
|
744
|
+
|
|
745
|
+
def evaluate(self, marker):
|
|
746
|
+
# type: (Marker) -> bool
|
|
747
|
+
eval_marker = _parse_marker(marker)
|
|
748
|
+
return eval_marker(self)
|
|
749
|
+
|
|
750
|
+
|
|
751
|
+
def _as_platform_system_marker(system):
|
|
752
|
+
# type: (TargetSystem.Value) -> str
|
|
753
|
+
|
|
754
|
+
if system is TargetSystem.LINUX:
|
|
755
|
+
platform_system = "Linux"
|
|
756
|
+
elif system is TargetSystem.MAC:
|
|
757
|
+
platform_system = "Darwin"
|
|
758
|
+
else:
|
|
759
|
+
platform_system = "Windows"
|
|
760
|
+
|
|
761
|
+
return "platform_system == '{platform_system}'".format(platform_system=platform_system)
|
|
762
|
+
|
|
763
|
+
|
|
764
|
+
def _as_python_version_marker(specifier):
|
|
765
|
+
# type: (SpecifierSet) -> Optional[str]
|
|
766
|
+
|
|
767
|
+
clauses = [
|
|
768
|
+
"python_full_version {operator} '{version}'".format(
|
|
769
|
+
operator=spec.operator, version=spec.version
|
|
770
|
+
)
|
|
771
|
+
for spec in specifier
|
|
772
|
+
]
|
|
773
|
+
if not clauses:
|
|
774
|
+
return None
|
|
775
|
+
|
|
776
|
+
if len(clauses) == 1:
|
|
777
|
+
return clauses[0]
|
|
778
|
+
|
|
779
|
+
return "({clauses})".format(clauses=" and ".join(clauses))
|
|
780
|
+
|
|
781
|
+
|
|
782
|
+
@attr.s(frozen=True)
|
|
783
|
+
class UniversalTarget(object):
|
|
784
|
+
@classmethod
|
|
785
|
+
def from_dict(cls, data):
|
|
786
|
+
# type: (Dict[str, Any]) -> UniversalTarget
|
|
787
|
+
|
|
788
|
+
raw_implementation = data.pop("implementation", None)
|
|
789
|
+
implementation = None # type: Optional[InterpreterImplementation.Value]
|
|
790
|
+
if raw_implementation:
|
|
791
|
+
if not isinstance(raw_implementation, string):
|
|
792
|
+
raise AssertionError(
|
|
793
|
+
reportable_unexpected_error_msg(
|
|
794
|
+
"Expected UniversalTarget `implementation` value to be a str, found "
|
|
795
|
+
"{value} of type {type}.",
|
|
796
|
+
value=raw_implementation,
|
|
797
|
+
type=type(raw_implementation),
|
|
798
|
+
)
|
|
799
|
+
)
|
|
800
|
+
implementation = InterpreterImplementation.for_value(raw_implementation)
|
|
801
|
+
|
|
802
|
+
return cls(
|
|
803
|
+
implementation=implementation,
|
|
804
|
+
requires_python=tuple(
|
|
805
|
+
SpecifierSet(specifier) for specifier in data.pop("requires_python", ())
|
|
806
|
+
),
|
|
807
|
+
systems=tuple(TargetSystem.for_value(system) for system in data.pop("systems", ())),
|
|
808
|
+
extra_markers=ExtraMarkers.from_dict(data.pop("extra_markers", {})),
|
|
809
|
+
)
|
|
810
|
+
|
|
811
|
+
implementation = attr.ib(default=None) # type: Optional[InterpreterImplementation.Value]
|
|
812
|
+
requires_python = attr.ib(default=()) # type: Tuple[SpecifierSet, ...]
|
|
813
|
+
systems = attr.ib(default=()) # type: Tuple[TargetSystem.Value, ...]
|
|
814
|
+
extra_markers = attr.ib(default=ExtraMarkers()) # type: ExtraMarkers
|
|
815
|
+
|
|
816
|
+
def to_dict(self):
|
|
817
|
+
# type: () -> Dict[str, Any]
|
|
818
|
+
return {
|
|
819
|
+
"implementation": str(self.implementation) if self.implementation else None,
|
|
820
|
+
"requires_python": [str(specifier) for specifier in self.requires_python],
|
|
821
|
+
"systems": [str(system) for system in self.systems],
|
|
822
|
+
"extra_markers": self.extra_markers.to_dict(),
|
|
823
|
+
}
|
|
824
|
+
|
|
825
|
+
def iter_interpreter_constraints(self):
|
|
826
|
+
# type: () -> Iterator[InterpreterConstraint]
|
|
827
|
+
for specifier in self.requires_python:
|
|
828
|
+
yield InterpreterConstraint(specifier=specifier, implementation=self.implementation)
|
|
829
|
+
|
|
830
|
+
def are_exhaustive(self, markers):
|
|
831
|
+
# type: (Sequence[Marker]) -> bool
|
|
832
|
+
|
|
833
|
+
if len(markers) == 0:
|
|
834
|
+
return True
|
|
835
|
+
|
|
836
|
+
use_python_full_version = any(
|
|
837
|
+
has_marker(marker, "python_full_version") for marker in markers
|
|
838
|
+
)
|
|
839
|
+
python_full_versions = tuple(iter_compatible_versions(self.requires_python))
|
|
840
|
+
versions = (
|
|
841
|
+
python_full_versions
|
|
842
|
+
if use_python_full_version
|
|
843
|
+
else tuple(
|
|
844
|
+
OrderedSet(python_full_version[:2] for python_full_version in python_full_versions)
|
|
845
|
+
)
|
|
846
|
+
)
|
|
847
|
+
target_systems = self.systems or TargetSystem.values()
|
|
848
|
+
marker_envs = OrderedSet(
|
|
849
|
+
MarkerEnv.create(
|
|
850
|
+
extras=(),
|
|
851
|
+
universal_target=attr.evolve(
|
|
852
|
+
self,
|
|
853
|
+
requires_python=tuple(
|
|
854
|
+
[SpecifierSet("=={version}".format(version=".".join(map(str, version))))]
|
|
855
|
+
),
|
|
856
|
+
systems=tuple([target_system]),
|
|
857
|
+
),
|
|
858
|
+
)
|
|
859
|
+
for version in versions
|
|
860
|
+
for target_system in target_systems
|
|
861
|
+
)
|
|
862
|
+
|
|
863
|
+
for marker in markers:
|
|
864
|
+
eval_marker = _parse_marker(marker)
|
|
865
|
+
for marker_env in tuple(marker_envs):
|
|
866
|
+
if eval_marker(marker_env):
|
|
867
|
+
marker_envs.remove(marker_env)
|
|
868
|
+
return not marker_envs
|
|
869
|
+
|
|
870
|
+
def marker_env(self, *extras):
|
|
871
|
+
# type: (*str) -> MarkerEnv
|
|
872
|
+
return MarkerEnv.create(extras=extras, universal_target=self)
|
|
873
|
+
|
|
874
|
+
def marker(self):
|
|
875
|
+
# type: () -> Optional[Marker]
|
|
876
|
+
clauses = [] # type: List[str]
|
|
877
|
+
if self.systems and frozenset(self.systems) != frozenset(TargetSystem.values()):
|
|
878
|
+
if len(self.systems) == 1:
|
|
879
|
+
clauses.append(_as_platform_system_marker(self.systems[0]))
|
|
880
|
+
else:
|
|
881
|
+
clauses.append(
|
|
882
|
+
"({clauses})".format(
|
|
883
|
+
clauses=" or ".join(
|
|
884
|
+
_as_platform_system_marker(system) for system in self.systems
|
|
885
|
+
)
|
|
886
|
+
)
|
|
887
|
+
)
|
|
888
|
+
if self.implementation:
|
|
889
|
+
clauses.append(
|
|
890
|
+
"platform_python_implementation == '{implementation}'".format(
|
|
891
|
+
implementation=self.implementation
|
|
892
|
+
)
|
|
893
|
+
)
|
|
894
|
+
if len(self.requires_python) == 1:
|
|
895
|
+
python_version_marker = _as_python_version_marker(self.requires_python[0])
|
|
896
|
+
if python_version_marker:
|
|
897
|
+
clauses.append(python_version_marker)
|
|
898
|
+
elif self.requires_python:
|
|
899
|
+
python_version_markers = [] # type: List[str]
|
|
900
|
+
for requires_python in self.requires_python:
|
|
901
|
+
python_version_marker = _as_python_version_marker(requires_python)
|
|
902
|
+
if python_version_marker:
|
|
903
|
+
python_version_markers.append(python_version_marker)
|
|
904
|
+
clauses.append(
|
|
905
|
+
"({requires_pythons})".format(requires_pythons=" or ".join(python_version_markers))
|
|
906
|
+
)
|
|
907
|
+
clauses.extend("({marker})".format(marker=marker) for marker in self.extra_markers)
|
|
908
|
+
return Marker(" and ".join(clauses)) if clauses else None
|