]>
crepu.dev Git - config.git/blob - djavu-asus/elpy/rpc-venv/lib/python3.11/site-packages/packaging/markers.py
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.
9 from typing
import Any
, Callable
, Dict
, List
, Optional
, Tuple
, Union
11 from ._parser
import (
17 parse_marker
as _parse_marker
,
19 from ._tokenizer
import ParserSyntaxError
20 from .specifiers
import InvalidSpecifier
, Specifier
21 from .utils
import canonicalize_name
25 "UndefinedComparison",
26 "UndefinedEnvironmentName",
28 "default_environment",
31 Operator
= Callable
[[str, str], bool]
34 class InvalidMarker(ValueError):
36 An invalid marker was found, users should refer to PEP 508.
40 class UndefinedComparison(ValueError):
42 An invalid operation was attempted on a value that doesn't support it.
46 class UndefinedEnvironmentName(ValueError):
48 A name was attempted to be used that does not exist inside of the
53 def _normalize_extra_values(results
: Any
) -> Any
:
55 Normalize extra values.
57 if isinstance(results
[0], tuple):
58 lhs
, op
, rhs
= results
[0]
59 if isinstance(lhs
, Variable
) and lhs
.value
== "extra":
60 normalized_extra
= canonicalize_name(rhs
.value
)
61 rhs
= Value(normalized_extra
)
62 elif isinstance(rhs
, Variable
) and rhs
.value
== "extra":
63 normalized_extra
= canonicalize_name(lhs
.value
)
64 lhs
= Value(normalized_extra
)
65 results
[0] = lhs
, op
, rhs
70 marker
: Union
[List
[str], MarkerAtom
, str], first
: Optional
[bool] = True
73 assert isinstance(marker
, (list, tuple, str))
75 # Sometimes we have a structure like [[...]] which is a single item list
76 # where the single item is itself it's own list. In that case we want skip
77 # the rest of this function so that we don't get extraneous () on the
80 isinstance(marker
, list)
82 and isinstance(marker
[0], (list, tuple))
84 return _format_marker(marker
[0])
86 if isinstance(marker
, list):
87 inner
= (_format_marker(m
, first
=False) for m
in marker
)
89 return " ".join(inner
)
91 return "(" + " ".join(inner
) + ")"
92 elif isinstance(marker
, tuple):
93 return " ".join([m
.serialize() for m
in marker
])
98 _operators
: Dict
[str, Operator
] = {
99 "in": lambda lhs
, rhs
: lhs
in rhs
,
100 "not in": lambda lhs
, rhs
: lhs
not in rhs
,
110 def _eval_op(lhs
: str, op
: Op
, rhs
: str) -> bool:
112 spec
= Specifier("".join([op
.serialize(), rhs
]))
113 except InvalidSpecifier
:
116 return spec
.contains(lhs
, prereleases
=True)
118 oper
: Optional
[Operator
] = _operators
.get(op
.serialize())
120 raise UndefinedComparison(f
"Undefined {op!r} on {lhs!r} and {rhs!r}.")
122 return oper(lhs
, rhs
)
125 def _normalize(*values
: str, key
: str) -> Tuple
[str, ...]:
126 # PEP 685 – Comparison of extra names for optional distribution dependencies
127 # https://peps.python.org/pep-0685/
128 # > When comparing extra names, tools MUST normalize the names being
129 # > compared using the semantics outlined in PEP 503 for names
131 return tuple(canonicalize_name(v
) for v
in values
)
133 # other environment markers don't have such standards
137 def _evaluate_markers(markers
: MarkerList
, environment
: Dict
[str, str]) -> bool:
138 groups
: List
[List
[bool]] = [[]]
140 for marker
in markers
:
141 assert isinstance(marker
, (list, tuple, str))
143 if isinstance(marker
, list):
144 groups
[-1].append(_evaluate_markers(marker
, environment
))
145 elif isinstance(marker
, tuple):
146 lhs
, op
, rhs
= marker
148 if isinstance(lhs
, Variable
):
149 environment_key
= lhs
.value
150 lhs_value
= environment
[environment_key
]
151 rhs_value
= rhs
.value
153 lhs_value
= lhs
.value
154 environment_key
= rhs
.value
155 rhs_value
= environment
[environment_key
]
157 lhs_value
, rhs_value
= _normalize(lhs_value
, rhs_value
, key
=environment_key
)
158 groups
[-1].append(_eval_op(lhs_value
, op
, rhs_value
))
160 assert marker
in ["and", "or"]
164 return any(all(item
) for item
in groups
)
167 def format_full_version(info
: "sys._version_info") -> str:
168 version
= "{0.major}.{0.minor}.{0.micro}".format(info
)
169 kind
= info
.releaselevel
171 version
+= kind
[0] + str(info
.serial
)
175 def default_environment() -> Dict
[str, str]:
176 iver
= format_full_version(sys
.implementation
.version
)
177 implementation_name
= sys
.implementation
.name
179 "implementation_name": implementation_name
,
180 "implementation_version": iver
,
182 "platform_machine": platform
.machine(),
183 "platform_release": platform
.release(),
184 "platform_system": platform
.system(),
185 "platform_version": platform
.version(),
186 "python_full_version": platform
.python_version(),
187 "platform_python_implementation": platform
.python_implementation(),
188 "python_version": ".".join(platform
.python_version_tuple()[:2]),
189 "sys_platform": sys
.platform
,
194 def __init__(self
, marker
: str) -> None:
195 # Note: We create a Marker object without calling this constructor in
196 # packaging.requirements.Requirement. If any additional logic is
197 # added here, make sure to mirror/adapt Requirement.
199 self
._markers
= _normalize_extra_values(_parse_marker(marker
))
200 # The attribute `_markers` can be described in terms of a recursive type:
201 # MarkerList = List[Union[Tuple[Node, ...], str, MarkerList]]
203 # For example, the following expression:
204 # python_version > "3.6" or (python_version == "3.6" and os_name == "unix")
208 # (<Variable('python_version')>, <Op('>')>, <Value('3.6')>),
211 # (<Variable('python_version')>, <Op('==')>, <Value('3.6')>),
213 # (<Variable('os_name')>, <Op('==')>, <Value('unix')>)
216 except ParserSyntaxError
as e
:
217 raise InvalidMarker(str(e
)) from e
219 def __str__(self
) -> str:
220 return _format_marker(self
._markers
)
222 def __repr__(self
) -> str:
223 return f
"<Marker('{self}')>"
225 def __hash__(self
) -> int:
226 return hash((self
.__class
__.__name
__, str(self
)))
228 def __eq__(self
, other
: Any
) -> bool:
229 if not isinstance(other
, Marker
):
230 return NotImplemented
232 return str(self
) == str(other
)
234 def evaluate(self
, environment
: Optional
[Dict
[str, str]] = None) -> bool:
235 """Evaluate a marker.
237 Return the boolean from evaluating the given marker against the
238 environment. environment is an optional argument to override all or
239 part of the determined environment.
241 The environment is determined from the current Python process.
243 current_environment
= default_environment()
244 current_environment
["extra"] = ""
245 if environment
is not None:
246 current_environment
.update(environment
)
247 # The API used to allow setting extra to None. We need to handle this
248 # case for backwards compatibility.
249 if current_environment
["extra"] is None:
250 current_environment
["extra"] = ""
252 return _evaluate_markers(self
._markers
, current_environment
)