pex 2.61.1__py2.py3-none-any.whl → 2.62.1__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/docs/html/_pagefind/fragment/en_1bbeb07.pf_fragment +0 -0
- pex/docs/html/_pagefind/fragment/{en_bf32fcd.pf_fragment → en_1befd43.pf_fragment} +0 -0
- pex/docs/html/_pagefind/fragment/en_45eea4b.pf_fragment +0 -0
- pex/docs/html/_pagefind/fragment/{en_c9714ee.pf_fragment → en_7822de6.pf_fragment} +0 -0
- pex/docs/html/_pagefind/fragment/en_87f76ba.pf_fragment +0 -0
- pex/docs/html/_pagefind/fragment/{en_4695b51.pf_fragment → en_a89f2ec.pf_fragment} +0 -0
- pex/docs/html/_pagefind/fragment/{en_57f2ab1.pf_fragment → en_c2a647e.pf_fragment} +0 -0
- pex/docs/html/_pagefind/fragment/en_d2f2c1b.pf_fragment +0 -0
- pex/docs/html/_pagefind/index/en_31a0754.pf_index +0 -0
- pex/docs/html/_pagefind/pagefind-entry.json +1 -1
- pex/docs/html/_pagefind/pagefind.en_32e8257caf.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/pep_427.py +23 -2
- pex/resolve/locker.py +6 -51
- pex/resolve/locker_patches.py +123 -209
- pex/resolve/lockfile/create.py +9 -10
- pex/resolve/lockfile/targets.py +292 -26
- pex/resolve/requirement_configuration.py +15 -8
- pex/resolve/target_system.py +512 -119
- pex/resolver.py +181 -90
- pex/vendor/__main__.py +2 -0
- pex/venv/venv_pex.py +1 -1
- pex/version.py +1 -1
- {pex-2.61.1.dist-info → pex-2.62.1.dist-info}/METADATA +4 -4
- {pex-2.61.1.dist-info → pex-2.62.1.dist-info}/RECORD +38 -38
- pex/docs/html/_pagefind/fragment/en_245699a.pf_fragment +0 -0
- pex/docs/html/_pagefind/fragment/en_aefc110.pf_fragment +0 -0
- pex/docs/html/_pagefind/fragment/en_b7fad62.pf_fragment +0 -0
- pex/docs/html/_pagefind/fragment/en_e6c0aae.pf_fragment +0 -0
- pex/docs/html/_pagefind/index/en_7e57d09.pf_index +0 -0
- pex/docs/html/_pagefind/pagefind.en_c578c4b677.pf_meta +0 -0
- {pex-2.61.1.dist-info → pex-2.62.1.dist-info}/WHEEL +0 -0
- {pex-2.61.1.dist-info → pex-2.62.1.dist-info}/entry_points.txt +0 -0
- {pex-2.61.1.dist-info → pex-2.62.1.dist-info}/licenses/LICENSE +0 -0
- {pex-2.61.1.dist-info → pex-2.62.1.dist-info}/pylock/pylock.toml +0 -0
- {pex-2.61.1.dist-info → pex-2.62.1.dist-info}/top_level.txt +0 -0
pex/resolve/target_system.py
CHANGED
|
@@ -6,6 +6,9 @@ from __future__ import absolute_import
|
|
|
6
6
|
import operator
|
|
7
7
|
import sys
|
|
8
8
|
|
|
9
|
+
from pex import pex_warnings
|
|
10
|
+
from pex.common import pluralize
|
|
11
|
+
from pex.compatibility import string
|
|
9
12
|
from pex.enum import Enum
|
|
10
13
|
from pex.exceptions import production_assert, reportable_unexpected_error_msg
|
|
11
14
|
from pex.interpreter_constraints import InterpreterConstraint, iter_compatible_versions
|
|
@@ -16,7 +19,7 @@ from pex.pep_503 import ProjectName
|
|
|
16
19
|
from pex.sorted_tuple import SortedTuple
|
|
17
20
|
from pex.third_party.packaging.markers import Marker, Variable
|
|
18
21
|
from pex.third_party.packaging.specifiers import Specifier, SpecifierSet
|
|
19
|
-
from pex.typing import TYPE_CHECKING, cast
|
|
22
|
+
from pex.typing import TYPE_CHECKING, Generic, cast
|
|
20
23
|
|
|
21
24
|
if TYPE_CHECKING:
|
|
22
25
|
from typing import (
|
|
@@ -30,6 +33,7 @@ if TYPE_CHECKING:
|
|
|
30
33
|
Optional,
|
|
31
34
|
Sequence,
|
|
32
35
|
Tuple,
|
|
36
|
+
TypeVar,
|
|
33
37
|
Union,
|
|
34
38
|
)
|
|
35
39
|
|
|
@@ -84,19 +88,132 @@ def _marker_items(marker):
|
|
|
84
88
|
return cast("Iterable[Any]", marker._markers)
|
|
85
89
|
|
|
86
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
|
+
|
|
87
208
|
def has_marker(
|
|
88
209
|
marker, # type: Marker
|
|
89
210
|
name, # type: str
|
|
90
211
|
):
|
|
91
212
|
# type: (...) -> bool
|
|
92
213
|
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
for term in lhs, rhs:
|
|
97
|
-
if isinstance(term, Variable) and name == str(term):
|
|
98
|
-
return True
|
|
99
|
-
return False
|
|
214
|
+
visitor = HasMarkerVisitor(name)
|
|
215
|
+
MarkerParser(visitor).parse(marker, None)
|
|
216
|
+
return visitor.has_marker
|
|
100
217
|
|
|
101
218
|
|
|
102
219
|
if TYPE_CHECKING:
|
|
@@ -122,6 +239,17 @@ _VERSION_MARKER_OP_FLIPPED = {
|
|
|
122
239
|
">": "<",
|
|
123
240
|
}
|
|
124
241
|
|
|
242
|
+
_VERSION_CMP_OPS = {
|
|
243
|
+
"<",
|
|
244
|
+
"<=",
|
|
245
|
+
"==",
|
|
246
|
+
"!=",
|
|
247
|
+
">=",
|
|
248
|
+
">",
|
|
249
|
+
"~=",
|
|
250
|
+
"===",
|
|
251
|
+
}
|
|
252
|
+
|
|
125
253
|
|
|
126
254
|
class _Op(object):
|
|
127
255
|
def __init__(self, lhs):
|
|
@@ -143,81 +271,159 @@ class _Or(_Op):
|
|
|
143
271
|
return self.lhs(marker_env) or cast("EvalMarker", self.rhs)(marker_env)
|
|
144
272
|
|
|
145
273
|
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
)
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
elif
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
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]
|
|
193
379
|
else:
|
|
194
|
-
|
|
195
|
-
else:
|
|
196
|
-
raise ValueError("Marker is invalid: {marker}".format(marker=marker))
|
|
380
|
+
context.extend(group_context)
|
|
197
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
|
|
198
391
|
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
return checks[0]
|
|
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)
|
|
206
398
|
|
|
207
399
|
|
|
208
|
-
_MARKER_CHECKS = {} # type: Dict[str, EvalMarker]
|
|
400
|
+
_MARKER_CHECKS = {} # type: Dict[Union[Marker, str], EvalMarker]
|
|
209
401
|
|
|
210
402
|
|
|
211
403
|
def _parse_marker(marker):
|
|
212
404
|
# type: (Marker) -> EvalMarker
|
|
213
|
-
|
|
214
|
-
eval_marker = _MARKER_CHECKS.get(maker_str)
|
|
405
|
+
eval_marker = _MARKER_CHECKS.get(marker)
|
|
215
406
|
if not eval_marker:
|
|
216
|
-
|
|
217
|
-
|
|
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
|
|
218
413
|
return eval_marker
|
|
219
414
|
|
|
220
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
|
+
|
|
221
427
|
class EvalMarkerFunc(object):
|
|
222
428
|
@classmethod
|
|
223
429
|
def create(
|
|
@@ -228,39 +434,32 @@ class EvalMarkerFunc(object):
|
|
|
228
434
|
):
|
|
229
435
|
# type: (...) -> Callable[[MarkerEnv], bool]
|
|
230
436
|
|
|
231
|
-
|
|
232
|
-
|
|
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)
|
|
233
441
|
get_values = _get_values_func(marker_name)
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
value = str(lhs)
|
|
250
|
-
if marker_name == "extra":
|
|
251
|
-
value = ProjectName(value).normalized
|
|
252
|
-
return cls(
|
|
253
|
-
get_values=get_values,
|
|
254
|
-
op=str(op),
|
|
255
|
-
lhs=value,
|
|
256
|
-
is_version_comparison=marker_name in ("python_version", "python_full_version"),
|
|
257
|
-
)
|
|
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
|
+
)
|
|
258
457
|
|
|
259
458
|
return lambda _: True
|
|
260
459
|
|
|
261
460
|
def __init__(
|
|
262
461
|
self,
|
|
263
|
-
get_values, # type: Callable[[MarkerEnv],
|
|
462
|
+
get_values, # type: Callable[[MarkerEnv], Values]
|
|
264
463
|
op, # type: str
|
|
265
464
|
lhs=None, # type: Optional[str]
|
|
266
465
|
rhs=None, # type: Optional[str]
|
|
@@ -275,7 +474,13 @@ class EvalMarkerFunc(object):
|
|
|
275
474
|
"{flipped_op}{lhs}".format(lhs=lhs, flipped_op=flipped_op)
|
|
276
475
|
)
|
|
277
476
|
self._func = lambda value: cast(
|
|
278
|
-
bool,
|
|
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
|
+
),
|
|
279
484
|
)
|
|
280
485
|
else:
|
|
281
486
|
oper = _OPERATORS[op]
|
|
@@ -284,7 +489,13 @@ class EvalMarkerFunc(object):
|
|
|
284
489
|
if is_version_comparison:
|
|
285
490
|
version_specifier = Specifier("{op}{rhs}".format(op=op, rhs=rhs))
|
|
286
491
|
self._func = lambda value: cast(
|
|
287
|
-
bool,
|
|
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
|
+
),
|
|
288
499
|
)
|
|
289
500
|
else:
|
|
290
501
|
oper = _OPERATORS[op]
|
|
@@ -299,8 +510,158 @@ class EvalMarkerFunc(object):
|
|
|
299
510
|
def __call__(self, marker_env):
|
|
300
511
|
# type: (MarkerEnv) -> bool
|
|
301
512
|
|
|
302
|
-
|
|
303
|
-
|
|
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)
|
|
304
665
|
|
|
305
666
|
|
|
306
667
|
@attr.s(frozen=True)
|
|
@@ -353,7 +714,7 @@ class MarkerEnv(object):
|
|
|
353
714
|
sys_platforms.append("win32")
|
|
354
715
|
|
|
355
716
|
return cls(
|
|
356
|
-
extras=SortedTuple(ProjectName(extra).normalized for extra in
|
|
717
|
+
extras=SortedTuple(ProjectName(extra).normalized for extra in extras),
|
|
357
718
|
os_names=SortedTuple(os_names),
|
|
358
719
|
platform_systems=SortedTuple(platform_systems),
|
|
359
720
|
sys_platforms=SortedTuple(sys_platforms),
|
|
@@ -365,23 +726,17 @@ class MarkerEnv(object):
|
|
|
365
726
|
".".join(map(str, python_full_version))
|
|
366
727
|
for python_full_version in python_full_versions
|
|
367
728
|
),
|
|
729
|
+
extra_markers=universal_target.extra_markers if universal_target else ExtraMarkers(),
|
|
368
730
|
)
|
|
369
731
|
|
|
370
|
-
extras = attr.ib(
|
|
371
|
-
os_names = attr.ib(
|
|
372
|
-
platform_systems = attr.ib(
|
|
373
|
-
|
|
374
|
-
) # type: SortedTuple[str]
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
) # type: SortedTuple[str]
|
|
379
|
-
python_versions = attr.ib(
|
|
380
|
-
converter=SortedTuple, default=SortedTuple()
|
|
381
|
-
) # type: SortedTuple[str]
|
|
382
|
-
python_full_versions = attr.ib(
|
|
383
|
-
converter=SortedTuple, default=SortedTuple()
|
|
384
|
-
) # type: SortedTuple[str]
|
|
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
|
|
385
740
|
|
|
386
741
|
def as_dict(self):
|
|
387
742
|
# type: () -> Dict[str, Any]
|
|
@@ -426,9 +781,46 @@ def _as_python_version_marker(specifier):
|
|
|
426
781
|
|
|
427
782
|
@attr.s(frozen=True)
|
|
428
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
|
+
|
|
429
811
|
implementation = attr.ib(default=None) # type: Optional[InterpreterImplementation.Value]
|
|
430
812
|
requires_python = attr.ib(default=()) # type: Tuple[SpecifierSet, ...]
|
|
431
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
|
+
}
|
|
432
824
|
|
|
433
825
|
def iter_interpreter_constraints(self):
|
|
434
826
|
# type: () -> Iterator[InterpreterConstraint]
|
|
@@ -456,8 +848,8 @@ class UniversalTarget(object):
|
|
|
456
848
|
marker_envs = OrderedSet(
|
|
457
849
|
MarkerEnv.create(
|
|
458
850
|
extras=(),
|
|
459
|
-
universal_target=
|
|
460
|
-
|
|
851
|
+
universal_target=attr.evolve(
|
|
852
|
+
self,
|
|
461
853
|
requires_python=tuple(
|
|
462
854
|
[SpecifierSet("=={version}".format(version=".".join(map(str, version))))]
|
|
463
855
|
),
|
|
@@ -512,4 +904,5 @@ class UniversalTarget(object):
|
|
|
512
904
|
clauses.append(
|
|
513
905
|
"({requires_pythons})".format(requires_pythons=" or ".join(python_version_markers))
|
|
514
906
|
)
|
|
907
|
+
clauses.extend("({marker})".format(marker=marker) for marker in self.extra_markers)
|
|
515
908
|
return Marker(" and ".join(clauses)) if clauses else None
|