comparison env/lib/python3.9/site-packages/packaging/markers.py @ 0:4f3585e2f14b draft default tip

"planemo upload commit 60cee0fc7c0cda8592644e1aad72851dec82c959"
author shellac
date Mon, 22 Mar 2021 18:12:50 +0000
parents
children
comparison
equal deleted inserted replaced
-1:000000000000 0:4f3585e2f14b
1 # This file is dual licensed under the terms of the Apache License, Version
2 # 2.0, and the BSD License. See the LICENSE file in the root of this repository
3 # for complete details.
4 from __future__ import absolute_import, division, print_function
5
6 import operator
7 import os
8 import platform
9 import sys
10
11 from pyparsing import ( # noqa: N817
12 Forward,
13 Group,
14 Literal as L,
15 ParseException,
16 ParseResults,
17 QuotedString,
18 ZeroOrMore,
19 stringEnd,
20 stringStart,
21 )
22
23 from ._compat import string_types
24 from ._typing import TYPE_CHECKING
25 from .specifiers import InvalidSpecifier, Specifier
26
27 if TYPE_CHECKING: # pragma: no cover
28 from typing import Any, Callable, Dict, List, Optional, Tuple, Union
29
30 Operator = Callable[[str, str], bool]
31
32
33 __all__ = [
34 "InvalidMarker",
35 "UndefinedComparison",
36 "UndefinedEnvironmentName",
37 "Marker",
38 "default_environment",
39 ]
40
41
42 class InvalidMarker(ValueError):
43 """
44 An invalid marker was found, users should refer to PEP 508.
45 """
46
47
48 class UndefinedComparison(ValueError):
49 """
50 An invalid operation was attempted on a value that doesn't support it.
51 """
52
53
54 class UndefinedEnvironmentName(ValueError):
55 """
56 A name was attempted to be used that does not exist inside of the
57 environment.
58 """
59
60
61 class Node(object):
62 def __init__(self, value):
63 # type: (Any) -> None
64 self.value = value
65
66 def __str__(self):
67 # type: () -> str
68 return str(self.value)
69
70 def __repr__(self):
71 # type: () -> str
72 return "<{0}({1!r})>".format(self.__class__.__name__, str(self))
73
74 def serialize(self):
75 # type: () -> str
76 raise NotImplementedError
77
78
79 class Variable(Node):
80 def serialize(self):
81 # type: () -> str
82 return str(self)
83
84
85 class Value(Node):
86 def serialize(self):
87 # type: () -> str
88 return '"{0}"'.format(self)
89
90
91 class Op(Node):
92 def serialize(self):
93 # type: () -> str
94 return str(self)
95
96
97 VARIABLE = (
98 L("implementation_version")
99 | L("platform_python_implementation")
100 | L("implementation_name")
101 | L("python_full_version")
102 | L("platform_release")
103 | L("platform_version")
104 | L("platform_machine")
105 | L("platform_system")
106 | L("python_version")
107 | L("sys_platform")
108 | L("os_name")
109 | L("os.name") # PEP-345
110 | L("sys.platform") # PEP-345
111 | L("platform.version") # PEP-345
112 | L("platform.machine") # PEP-345
113 | L("platform.python_implementation") # PEP-345
114 | L("python_implementation") # undocumented setuptools legacy
115 | L("extra") # PEP-508
116 )
117 ALIASES = {
118 "os.name": "os_name",
119 "sys.platform": "sys_platform",
120 "platform.version": "platform_version",
121 "platform.machine": "platform_machine",
122 "platform.python_implementation": "platform_python_implementation",
123 "python_implementation": "platform_python_implementation",
124 }
125 VARIABLE.setParseAction(lambda s, l, t: Variable(ALIASES.get(t[0], t[0])))
126
127 VERSION_CMP = (
128 L("===") | L("==") | L(">=") | L("<=") | L("!=") | L("~=") | L(">") | L("<")
129 )
130
131 MARKER_OP = VERSION_CMP | L("not in") | L("in")
132 MARKER_OP.setParseAction(lambda s, l, t: Op(t[0]))
133
134 MARKER_VALUE = QuotedString("'") | QuotedString('"')
135 MARKER_VALUE.setParseAction(lambda s, l, t: Value(t[0]))
136
137 BOOLOP = L("and") | L("or")
138
139 MARKER_VAR = VARIABLE | MARKER_VALUE
140
141 MARKER_ITEM = Group(MARKER_VAR + MARKER_OP + MARKER_VAR)
142 MARKER_ITEM.setParseAction(lambda s, l, t: tuple(t[0]))
143
144 LPAREN = L("(").suppress()
145 RPAREN = L(")").suppress()
146
147 MARKER_EXPR = Forward()
148 MARKER_ATOM = MARKER_ITEM | Group(LPAREN + MARKER_EXPR + RPAREN)
149 MARKER_EXPR << MARKER_ATOM + ZeroOrMore(BOOLOP + MARKER_EXPR)
150
151 MARKER = stringStart + MARKER_EXPR + stringEnd
152
153
154 def _coerce_parse_result(results):
155 # type: (Union[ParseResults, List[Any]]) -> List[Any]
156 if isinstance(results, ParseResults):
157 return [_coerce_parse_result(i) for i in results]
158 else:
159 return results
160
161
162 def _format_marker(marker, first=True):
163 # type: (Union[List[str], Tuple[Node, ...], str], Optional[bool]) -> str
164
165 assert isinstance(marker, (list, tuple, string_types))
166
167 # Sometimes we have a structure like [[...]] which is a single item list
168 # where the single item is itself it's own list. In that case we want skip
169 # the rest of this function so that we don't get extraneous () on the
170 # outside.
171 if (
172 isinstance(marker, list)
173 and len(marker) == 1
174 and isinstance(marker[0], (list, tuple))
175 ):
176 return _format_marker(marker[0])
177
178 if isinstance(marker, list):
179 inner = (_format_marker(m, first=False) for m in marker)
180 if first:
181 return " ".join(inner)
182 else:
183 return "(" + " ".join(inner) + ")"
184 elif isinstance(marker, tuple):
185 return " ".join([m.serialize() for m in marker])
186 else:
187 return marker
188
189
190 _operators = {
191 "in": lambda lhs, rhs: lhs in rhs,
192 "not in": lambda lhs, rhs: lhs not in rhs,
193 "<": operator.lt,
194 "<=": operator.le,
195 "==": operator.eq,
196 "!=": operator.ne,
197 ">=": operator.ge,
198 ">": operator.gt,
199 } # type: Dict[str, Operator]
200
201
202 def _eval_op(lhs, op, rhs):
203 # type: (str, Op, str) -> bool
204 try:
205 spec = Specifier("".join([op.serialize(), rhs]))
206 except InvalidSpecifier:
207 pass
208 else:
209 return spec.contains(lhs)
210
211 oper = _operators.get(op.serialize()) # type: Optional[Operator]
212 if oper is None:
213 raise UndefinedComparison(
214 "Undefined {0!r} on {1!r} and {2!r}.".format(op, lhs, rhs)
215 )
216
217 return oper(lhs, rhs)
218
219
220 class Undefined(object):
221 pass
222
223
224 _undefined = Undefined()
225
226
227 def _get_env(environment, name):
228 # type: (Dict[str, str], str) -> str
229 value = environment.get(name, _undefined) # type: Union[str, Undefined]
230
231 if isinstance(value, Undefined):
232 raise UndefinedEnvironmentName(
233 "{0!r} does not exist in evaluation environment.".format(name)
234 )
235
236 return value
237
238
239 def _evaluate_markers(markers, environment):
240 # type: (List[Any], Dict[str, str]) -> bool
241 groups = [[]] # type: List[List[bool]]
242
243 for marker in markers:
244 assert isinstance(marker, (list, tuple, string_types))
245
246 if isinstance(marker, list):
247 groups[-1].append(_evaluate_markers(marker, environment))
248 elif isinstance(marker, tuple):
249 lhs, op, rhs = marker
250
251 if isinstance(lhs, Variable):
252 lhs_value = _get_env(environment, lhs.value)
253 rhs_value = rhs.value
254 else:
255 lhs_value = lhs.value
256 rhs_value = _get_env(environment, rhs.value)
257
258 groups[-1].append(_eval_op(lhs_value, op, rhs_value))
259 else:
260 assert marker in ["and", "or"]
261 if marker == "or":
262 groups.append([])
263
264 return any(all(item) for item in groups)
265
266
267 def format_full_version(info):
268 # type: (sys._version_info) -> str
269 version = "{0.major}.{0.minor}.{0.micro}".format(info)
270 kind = info.releaselevel
271 if kind != "final":
272 version += kind[0] + str(info.serial)
273 return version
274
275
276 def default_environment():
277 # type: () -> Dict[str, str]
278 if hasattr(sys, "implementation"):
279 # Ignoring the `sys.implementation` reference for type checking due to
280 # mypy not liking that the attribute doesn't exist in Python 2.7 when
281 # run with the `--py27` flag.
282 iver = format_full_version(sys.implementation.version) # type: ignore
283 implementation_name = sys.implementation.name # type: ignore
284 else:
285 iver = "0"
286 implementation_name = ""
287
288 return {
289 "implementation_name": implementation_name,
290 "implementation_version": iver,
291 "os_name": os.name,
292 "platform_machine": platform.machine(),
293 "platform_release": platform.release(),
294 "platform_system": platform.system(),
295 "platform_version": platform.version(),
296 "python_full_version": platform.python_version(),
297 "platform_python_implementation": platform.python_implementation(),
298 "python_version": ".".join(platform.python_version_tuple()[:2]),
299 "sys_platform": sys.platform,
300 }
301
302
303 class Marker(object):
304 def __init__(self, marker):
305 # type: (str) -> None
306 try:
307 self._markers = _coerce_parse_result(MARKER.parseString(marker))
308 except ParseException as e:
309 err_str = "Invalid marker: {0!r}, parse error at {1!r}".format(
310 marker, marker[e.loc : e.loc + 8]
311 )
312 raise InvalidMarker(err_str)
313
314 def __str__(self):
315 # type: () -> str
316 return _format_marker(self._markers)
317
318 def __repr__(self):
319 # type: () -> str
320 return "<Marker({0!r})>".format(str(self))
321
322 def evaluate(self, environment=None):
323 # type: (Optional[Dict[str, str]]) -> bool
324 """Evaluate a marker.
325
326 Return the boolean from evaluating the given marker against the
327 environment. environment is an optional argument to override all or
328 part of the determined environment.
329
330 The environment is determined from the current Python process.
331 """
332 current_environment = default_environment()
333 if environment is not None:
334 current_environment.update(environment)
335
336 return _evaluate_markers(self._markers, current_environment)