Mercurial > repos > shellac > sam_consensus_v3
comparison env/lib/python3.9/site-packages/pkg_resources/_vendor/packaging/tags.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 | |
5 from __future__ import absolute_import | |
6 | |
7 import distutils.util | |
8 | |
9 try: | |
10 from importlib.machinery import EXTENSION_SUFFIXES | |
11 except ImportError: # pragma: no cover | |
12 import imp | |
13 | |
14 EXTENSION_SUFFIXES = [x[0] for x in imp.get_suffixes()] | |
15 del imp | |
16 import logging | |
17 import os | |
18 import platform | |
19 import re | |
20 import struct | |
21 import sys | |
22 import sysconfig | |
23 import warnings | |
24 | |
25 from ._typing import TYPE_CHECKING, cast | |
26 | |
27 if TYPE_CHECKING: # pragma: no cover | |
28 from typing import ( | |
29 Dict, | |
30 FrozenSet, | |
31 IO, | |
32 Iterable, | |
33 Iterator, | |
34 List, | |
35 Optional, | |
36 Sequence, | |
37 Tuple, | |
38 Union, | |
39 ) | |
40 | |
41 PythonVersion = Sequence[int] | |
42 MacVersion = Tuple[int, int] | |
43 GlibcVersion = Tuple[int, int] | |
44 | |
45 | |
46 logger = logging.getLogger(__name__) | |
47 | |
48 INTERPRETER_SHORT_NAMES = { | |
49 "python": "py", # Generic. | |
50 "cpython": "cp", | |
51 "pypy": "pp", | |
52 "ironpython": "ip", | |
53 "jython": "jy", | |
54 } # type: Dict[str, str] | |
55 | |
56 | |
57 _32_BIT_INTERPRETER = sys.maxsize <= 2 ** 32 | |
58 | |
59 | |
60 class Tag(object): | |
61 """ | |
62 A representation of the tag triple for a wheel. | |
63 | |
64 Instances are considered immutable and thus are hashable. Equality checking | |
65 is also supported. | |
66 """ | |
67 | |
68 __slots__ = ["_interpreter", "_abi", "_platform"] | |
69 | |
70 def __init__(self, interpreter, abi, platform): | |
71 # type: (str, str, str) -> None | |
72 self._interpreter = interpreter.lower() | |
73 self._abi = abi.lower() | |
74 self._platform = platform.lower() | |
75 | |
76 @property | |
77 def interpreter(self): | |
78 # type: () -> str | |
79 return self._interpreter | |
80 | |
81 @property | |
82 def abi(self): | |
83 # type: () -> str | |
84 return self._abi | |
85 | |
86 @property | |
87 def platform(self): | |
88 # type: () -> str | |
89 return self._platform | |
90 | |
91 def __eq__(self, other): | |
92 # type: (object) -> bool | |
93 if not isinstance(other, Tag): | |
94 return NotImplemented | |
95 | |
96 return ( | |
97 (self.platform == other.platform) | |
98 and (self.abi == other.abi) | |
99 and (self.interpreter == other.interpreter) | |
100 ) | |
101 | |
102 def __hash__(self): | |
103 # type: () -> int | |
104 return hash((self._interpreter, self._abi, self._platform)) | |
105 | |
106 def __str__(self): | |
107 # type: () -> str | |
108 return "{}-{}-{}".format(self._interpreter, self._abi, self._platform) | |
109 | |
110 def __repr__(self): | |
111 # type: () -> str | |
112 return "<{self} @ {self_id}>".format(self=self, self_id=id(self)) | |
113 | |
114 | |
115 def parse_tag(tag): | |
116 # type: (str) -> FrozenSet[Tag] | |
117 """ | |
118 Parses the provided tag (e.g. `py3-none-any`) into a frozenset of Tag instances. | |
119 | |
120 Returning a set is required due to the possibility that the tag is a | |
121 compressed tag set. | |
122 """ | |
123 tags = set() | |
124 interpreters, abis, platforms = tag.split("-") | |
125 for interpreter in interpreters.split("."): | |
126 for abi in abis.split("."): | |
127 for platform_ in platforms.split("."): | |
128 tags.add(Tag(interpreter, abi, platform_)) | |
129 return frozenset(tags) | |
130 | |
131 | |
132 def _warn_keyword_parameter(func_name, kwargs): | |
133 # type: (str, Dict[str, bool]) -> bool | |
134 """ | |
135 Backwards-compatibility with Python 2.7 to allow treating 'warn' as keyword-only. | |
136 """ | |
137 if not kwargs: | |
138 return False | |
139 elif len(kwargs) > 1 or "warn" not in kwargs: | |
140 kwargs.pop("warn", None) | |
141 arg = next(iter(kwargs.keys())) | |
142 raise TypeError( | |
143 "{}() got an unexpected keyword argument {!r}".format(func_name, arg) | |
144 ) | |
145 return kwargs["warn"] | |
146 | |
147 | |
148 def _get_config_var(name, warn=False): | |
149 # type: (str, bool) -> Union[int, str, None] | |
150 value = sysconfig.get_config_var(name) | |
151 if value is None and warn: | |
152 logger.debug( | |
153 "Config variable '%s' is unset, Python ABI tag may be incorrect", name | |
154 ) | |
155 return value | |
156 | |
157 | |
158 def _normalize_string(string): | |
159 # type: (str) -> str | |
160 return string.replace(".", "_").replace("-", "_") | |
161 | |
162 | |
163 def _abi3_applies(python_version): | |
164 # type: (PythonVersion) -> bool | |
165 """ | |
166 Determine if the Python version supports abi3. | |
167 | |
168 PEP 384 was first implemented in Python 3.2. | |
169 """ | |
170 return len(python_version) > 1 and tuple(python_version) >= (3, 2) | |
171 | |
172 | |
173 def _cpython_abis(py_version, warn=False): | |
174 # type: (PythonVersion, bool) -> List[str] | |
175 py_version = tuple(py_version) # To allow for version comparison. | |
176 abis = [] | |
177 version = _version_nodot(py_version[:2]) | |
178 debug = pymalloc = ucs4 = "" | |
179 with_debug = _get_config_var("Py_DEBUG", warn) | |
180 has_refcount = hasattr(sys, "gettotalrefcount") | |
181 # Windows doesn't set Py_DEBUG, so checking for support of debug-compiled | |
182 # extension modules is the best option. | |
183 # https://github.com/pypa/pip/issues/3383#issuecomment-173267692 | |
184 has_ext = "_d.pyd" in EXTENSION_SUFFIXES | |
185 if with_debug or (with_debug is None and (has_refcount or has_ext)): | |
186 debug = "d" | |
187 if py_version < (3, 8): | |
188 with_pymalloc = _get_config_var("WITH_PYMALLOC", warn) | |
189 if with_pymalloc or with_pymalloc is None: | |
190 pymalloc = "m" | |
191 if py_version < (3, 3): | |
192 unicode_size = _get_config_var("Py_UNICODE_SIZE", warn) | |
193 if unicode_size == 4 or ( | |
194 unicode_size is None and sys.maxunicode == 0x10FFFF | |
195 ): | |
196 ucs4 = "u" | |
197 elif debug: | |
198 # Debug builds can also load "normal" extension modules. | |
199 # We can also assume no UCS-4 or pymalloc requirement. | |
200 abis.append("cp{version}".format(version=version)) | |
201 abis.insert( | |
202 0, | |
203 "cp{version}{debug}{pymalloc}{ucs4}".format( | |
204 version=version, debug=debug, pymalloc=pymalloc, ucs4=ucs4 | |
205 ), | |
206 ) | |
207 return abis | |
208 | |
209 | |
210 def cpython_tags( | |
211 python_version=None, # type: Optional[PythonVersion] | |
212 abis=None, # type: Optional[Iterable[str]] | |
213 platforms=None, # type: Optional[Iterable[str]] | |
214 **kwargs # type: bool | |
215 ): | |
216 # type: (...) -> Iterator[Tag] | |
217 """ | |
218 Yields the tags for a CPython interpreter. | |
219 | |
220 The tags consist of: | |
221 - cp<python_version>-<abi>-<platform> | |
222 - cp<python_version>-abi3-<platform> | |
223 - cp<python_version>-none-<platform> | |
224 - cp<less than python_version>-abi3-<platform> # Older Python versions down to 3.2. | |
225 | |
226 If python_version only specifies a major version then user-provided ABIs and | |
227 the 'none' ABItag will be used. | |
228 | |
229 If 'abi3' or 'none' are specified in 'abis' then they will be yielded at | |
230 their normal position and not at the beginning. | |
231 """ | |
232 warn = _warn_keyword_parameter("cpython_tags", kwargs) | |
233 if not python_version: | |
234 python_version = sys.version_info[:2] | |
235 | |
236 interpreter = "cp{}".format(_version_nodot(python_version[:2])) | |
237 | |
238 if abis is None: | |
239 if len(python_version) > 1: | |
240 abis = _cpython_abis(python_version, warn) | |
241 else: | |
242 abis = [] | |
243 abis = list(abis) | |
244 # 'abi3' and 'none' are explicitly handled later. | |
245 for explicit_abi in ("abi3", "none"): | |
246 try: | |
247 abis.remove(explicit_abi) | |
248 except ValueError: | |
249 pass | |
250 | |
251 platforms = list(platforms or _platform_tags()) | |
252 for abi in abis: | |
253 for platform_ in platforms: | |
254 yield Tag(interpreter, abi, platform_) | |
255 if _abi3_applies(python_version): | |
256 for tag in (Tag(interpreter, "abi3", platform_) for platform_ in platforms): | |
257 yield tag | |
258 for tag in (Tag(interpreter, "none", platform_) for platform_ in platforms): | |
259 yield tag | |
260 | |
261 if _abi3_applies(python_version): | |
262 for minor_version in range(python_version[1] - 1, 1, -1): | |
263 for platform_ in platforms: | |
264 interpreter = "cp{version}".format( | |
265 version=_version_nodot((python_version[0], minor_version)) | |
266 ) | |
267 yield Tag(interpreter, "abi3", platform_) | |
268 | |
269 | |
270 def _generic_abi(): | |
271 # type: () -> Iterator[str] | |
272 abi = sysconfig.get_config_var("SOABI") | |
273 if abi: | |
274 yield _normalize_string(abi) | |
275 | |
276 | |
277 def generic_tags( | |
278 interpreter=None, # type: Optional[str] | |
279 abis=None, # type: Optional[Iterable[str]] | |
280 platforms=None, # type: Optional[Iterable[str]] | |
281 **kwargs # type: bool | |
282 ): | |
283 # type: (...) -> Iterator[Tag] | |
284 """ | |
285 Yields the tags for a generic interpreter. | |
286 | |
287 The tags consist of: | |
288 - <interpreter>-<abi>-<platform> | |
289 | |
290 The "none" ABI will be added if it was not explicitly provided. | |
291 """ | |
292 warn = _warn_keyword_parameter("generic_tags", kwargs) | |
293 if not interpreter: | |
294 interp_name = interpreter_name() | |
295 interp_version = interpreter_version(warn=warn) | |
296 interpreter = "".join([interp_name, interp_version]) | |
297 if abis is None: | |
298 abis = _generic_abi() | |
299 platforms = list(platforms or _platform_tags()) | |
300 abis = list(abis) | |
301 if "none" not in abis: | |
302 abis.append("none") | |
303 for abi in abis: | |
304 for platform_ in platforms: | |
305 yield Tag(interpreter, abi, platform_) | |
306 | |
307 | |
308 def _py_interpreter_range(py_version): | |
309 # type: (PythonVersion) -> Iterator[str] | |
310 """ | |
311 Yields Python versions in descending order. | |
312 | |
313 After the latest version, the major-only version will be yielded, and then | |
314 all previous versions of that major version. | |
315 """ | |
316 if len(py_version) > 1: | |
317 yield "py{version}".format(version=_version_nodot(py_version[:2])) | |
318 yield "py{major}".format(major=py_version[0]) | |
319 if len(py_version) > 1: | |
320 for minor in range(py_version[1] - 1, -1, -1): | |
321 yield "py{version}".format(version=_version_nodot((py_version[0], minor))) | |
322 | |
323 | |
324 def compatible_tags( | |
325 python_version=None, # type: Optional[PythonVersion] | |
326 interpreter=None, # type: Optional[str] | |
327 platforms=None, # type: Optional[Iterable[str]] | |
328 ): | |
329 # type: (...) -> Iterator[Tag] | |
330 """ | |
331 Yields the sequence of tags that are compatible with a specific version of Python. | |
332 | |
333 The tags consist of: | |
334 - py*-none-<platform> | |
335 - <interpreter>-none-any # ... if `interpreter` is provided. | |
336 - py*-none-any | |
337 """ | |
338 if not python_version: | |
339 python_version = sys.version_info[:2] | |
340 platforms = list(platforms or _platform_tags()) | |
341 for version in _py_interpreter_range(python_version): | |
342 for platform_ in platforms: | |
343 yield Tag(version, "none", platform_) | |
344 if interpreter: | |
345 yield Tag(interpreter, "none", "any") | |
346 for version in _py_interpreter_range(python_version): | |
347 yield Tag(version, "none", "any") | |
348 | |
349 | |
350 def _mac_arch(arch, is_32bit=_32_BIT_INTERPRETER): | |
351 # type: (str, bool) -> str | |
352 if not is_32bit: | |
353 return arch | |
354 | |
355 if arch.startswith("ppc"): | |
356 return "ppc" | |
357 | |
358 return "i386" | |
359 | |
360 | |
361 def _mac_binary_formats(version, cpu_arch): | |
362 # type: (MacVersion, str) -> List[str] | |
363 formats = [cpu_arch] | |
364 if cpu_arch == "x86_64": | |
365 if version < (10, 4): | |
366 return [] | |
367 formats.extend(["intel", "fat64", "fat32"]) | |
368 | |
369 elif cpu_arch == "i386": | |
370 if version < (10, 4): | |
371 return [] | |
372 formats.extend(["intel", "fat32", "fat"]) | |
373 | |
374 elif cpu_arch == "ppc64": | |
375 # TODO: Need to care about 32-bit PPC for ppc64 through 10.2? | |
376 if version > (10, 5) or version < (10, 4): | |
377 return [] | |
378 formats.append("fat64") | |
379 | |
380 elif cpu_arch == "ppc": | |
381 if version > (10, 6): | |
382 return [] | |
383 formats.extend(["fat32", "fat"]) | |
384 | |
385 formats.append("universal") | |
386 return formats | |
387 | |
388 | |
389 def mac_platforms(version=None, arch=None): | |
390 # type: (Optional[MacVersion], Optional[str]) -> Iterator[str] | |
391 """ | |
392 Yields the platform tags for a macOS system. | |
393 | |
394 The `version` parameter is a two-item tuple specifying the macOS version to | |
395 generate platform tags for. The `arch` parameter is the CPU architecture to | |
396 generate platform tags for. Both parameters default to the appropriate value | |
397 for the current system. | |
398 """ | |
399 version_str, _, cpu_arch = platform.mac_ver() # type: ignore | |
400 if version is None: | |
401 version = cast("MacVersion", tuple(map(int, version_str.split(".")[:2]))) | |
402 else: | |
403 version = version | |
404 if arch is None: | |
405 arch = _mac_arch(cpu_arch) | |
406 else: | |
407 arch = arch | |
408 for minor_version in range(version[1], -1, -1): | |
409 compat_version = version[0], minor_version | |
410 binary_formats = _mac_binary_formats(compat_version, arch) | |
411 for binary_format in binary_formats: | |
412 yield "macosx_{major}_{minor}_{binary_format}".format( | |
413 major=compat_version[0], | |
414 minor=compat_version[1], | |
415 binary_format=binary_format, | |
416 ) | |
417 | |
418 | |
419 # From PEP 513. | |
420 def _is_manylinux_compatible(name, glibc_version): | |
421 # type: (str, GlibcVersion) -> bool | |
422 # Check for presence of _manylinux module. | |
423 try: | |
424 import _manylinux # noqa | |
425 | |
426 return bool(getattr(_manylinux, name + "_compatible")) | |
427 except (ImportError, AttributeError): | |
428 # Fall through to heuristic check below. | |
429 pass | |
430 | |
431 return _have_compatible_glibc(*glibc_version) | |
432 | |
433 | |
434 def _glibc_version_string(): | |
435 # type: () -> Optional[str] | |
436 # Returns glibc version string, or None if not using glibc. | |
437 return _glibc_version_string_confstr() or _glibc_version_string_ctypes() | |
438 | |
439 | |
440 def _glibc_version_string_confstr(): | |
441 # type: () -> Optional[str] | |
442 """ | |
443 Primary implementation of glibc_version_string using os.confstr. | |
444 """ | |
445 # os.confstr is quite a bit faster than ctypes.DLL. It's also less likely | |
446 # to be broken or missing. This strategy is used in the standard library | |
447 # platform module. | |
448 # https://github.com/python/cpython/blob/fcf1d003bf4f0100c9d0921ff3d70e1127ca1b71/Lib/platform.py#L175-L183 | |
449 try: | |
450 # os.confstr("CS_GNU_LIBC_VERSION") returns a string like "glibc 2.17". | |
451 version_string = os.confstr( # type: ignore[attr-defined] # noqa: F821 | |
452 "CS_GNU_LIBC_VERSION" | |
453 ) | |
454 assert version_string is not None | |
455 _, version = version_string.split() # type: Tuple[str, str] | |
456 except (AssertionError, AttributeError, OSError, ValueError): | |
457 # os.confstr() or CS_GNU_LIBC_VERSION not available (or a bad value)... | |
458 return None | |
459 return version | |
460 | |
461 | |
462 def _glibc_version_string_ctypes(): | |
463 # type: () -> Optional[str] | |
464 """ | |
465 Fallback implementation of glibc_version_string using ctypes. | |
466 """ | |
467 try: | |
468 import ctypes | |
469 except ImportError: | |
470 return None | |
471 | |
472 # ctypes.CDLL(None) internally calls dlopen(NULL), and as the dlopen | |
473 # manpage says, "If filename is NULL, then the returned handle is for the | |
474 # main program". This way we can let the linker do the work to figure out | |
475 # which libc our process is actually using. | |
476 # | |
477 # Note: typeshed is wrong here so we are ignoring this line. | |
478 process_namespace = ctypes.CDLL(None) # type: ignore | |
479 try: | |
480 gnu_get_libc_version = process_namespace.gnu_get_libc_version | |
481 except AttributeError: | |
482 # Symbol doesn't exist -> therefore, we are not linked to | |
483 # glibc. | |
484 return None | |
485 | |
486 # Call gnu_get_libc_version, which returns a string like "2.5" | |
487 gnu_get_libc_version.restype = ctypes.c_char_p | |
488 version_str = gnu_get_libc_version() # type: str | |
489 # py2 / py3 compatibility: | |
490 if not isinstance(version_str, str): | |
491 version_str = version_str.decode("ascii") | |
492 | |
493 return version_str | |
494 | |
495 | |
496 # Separated out from have_compatible_glibc for easier unit testing. | |
497 def _check_glibc_version(version_str, required_major, minimum_minor): | |
498 # type: (str, int, int) -> bool | |
499 # Parse string and check against requested version. | |
500 # | |
501 # We use a regexp instead of str.split because we want to discard any | |
502 # random junk that might come after the minor version -- this might happen | |
503 # in patched/forked versions of glibc (e.g. Linaro's version of glibc | |
504 # uses version strings like "2.20-2014.11"). See gh-3588. | |
505 m = re.match(r"(?P<major>[0-9]+)\.(?P<minor>[0-9]+)", version_str) | |
506 if not m: | |
507 warnings.warn( | |
508 "Expected glibc version with 2 components major.minor," | |
509 " got: %s" % version_str, | |
510 RuntimeWarning, | |
511 ) | |
512 return False | |
513 return ( | |
514 int(m.group("major")) == required_major | |
515 and int(m.group("minor")) >= minimum_minor | |
516 ) | |
517 | |
518 | |
519 def _have_compatible_glibc(required_major, minimum_minor): | |
520 # type: (int, int) -> bool | |
521 version_str = _glibc_version_string() | |
522 if version_str is None: | |
523 return False | |
524 return _check_glibc_version(version_str, required_major, minimum_minor) | |
525 | |
526 | |
527 # Python does not provide platform information at sufficient granularity to | |
528 # identify the architecture of the running executable in some cases, so we | |
529 # determine it dynamically by reading the information from the running | |
530 # process. This only applies on Linux, which uses the ELF format. | |
531 class _ELFFileHeader(object): | |
532 # https://en.wikipedia.org/wiki/Executable_and_Linkable_Format#File_header | |
533 class _InvalidELFFileHeader(ValueError): | |
534 """ | |
535 An invalid ELF file header was found. | |
536 """ | |
537 | |
538 ELF_MAGIC_NUMBER = 0x7F454C46 | |
539 ELFCLASS32 = 1 | |
540 ELFCLASS64 = 2 | |
541 ELFDATA2LSB = 1 | |
542 ELFDATA2MSB = 2 | |
543 EM_386 = 3 | |
544 EM_S390 = 22 | |
545 EM_ARM = 40 | |
546 EM_X86_64 = 62 | |
547 EF_ARM_ABIMASK = 0xFF000000 | |
548 EF_ARM_ABI_VER5 = 0x05000000 | |
549 EF_ARM_ABI_FLOAT_HARD = 0x00000400 | |
550 | |
551 def __init__(self, file): | |
552 # type: (IO[bytes]) -> None | |
553 def unpack(fmt): | |
554 # type: (str) -> int | |
555 try: | |
556 (result,) = struct.unpack( | |
557 fmt, file.read(struct.calcsize(fmt)) | |
558 ) # type: (int, ) | |
559 except struct.error: | |
560 raise _ELFFileHeader._InvalidELFFileHeader() | |
561 return result | |
562 | |
563 self.e_ident_magic = unpack(">I") | |
564 if self.e_ident_magic != self.ELF_MAGIC_NUMBER: | |
565 raise _ELFFileHeader._InvalidELFFileHeader() | |
566 self.e_ident_class = unpack("B") | |
567 if self.e_ident_class not in {self.ELFCLASS32, self.ELFCLASS64}: | |
568 raise _ELFFileHeader._InvalidELFFileHeader() | |
569 self.e_ident_data = unpack("B") | |
570 if self.e_ident_data not in {self.ELFDATA2LSB, self.ELFDATA2MSB}: | |
571 raise _ELFFileHeader._InvalidELFFileHeader() | |
572 self.e_ident_version = unpack("B") | |
573 self.e_ident_osabi = unpack("B") | |
574 self.e_ident_abiversion = unpack("B") | |
575 self.e_ident_pad = file.read(7) | |
576 format_h = "<H" if self.e_ident_data == self.ELFDATA2LSB else ">H" | |
577 format_i = "<I" if self.e_ident_data == self.ELFDATA2LSB else ">I" | |
578 format_q = "<Q" if self.e_ident_data == self.ELFDATA2LSB else ">Q" | |
579 format_p = format_i if self.e_ident_class == self.ELFCLASS32 else format_q | |
580 self.e_type = unpack(format_h) | |
581 self.e_machine = unpack(format_h) | |
582 self.e_version = unpack(format_i) | |
583 self.e_entry = unpack(format_p) | |
584 self.e_phoff = unpack(format_p) | |
585 self.e_shoff = unpack(format_p) | |
586 self.e_flags = unpack(format_i) | |
587 self.e_ehsize = unpack(format_h) | |
588 self.e_phentsize = unpack(format_h) | |
589 self.e_phnum = unpack(format_h) | |
590 self.e_shentsize = unpack(format_h) | |
591 self.e_shnum = unpack(format_h) | |
592 self.e_shstrndx = unpack(format_h) | |
593 | |
594 | |
595 def _get_elf_header(): | |
596 # type: () -> Optional[_ELFFileHeader] | |
597 try: | |
598 with open(sys.executable, "rb") as f: | |
599 elf_header = _ELFFileHeader(f) | |
600 except (IOError, OSError, TypeError, _ELFFileHeader._InvalidELFFileHeader): | |
601 return None | |
602 return elf_header | |
603 | |
604 | |
605 def _is_linux_armhf(): | |
606 # type: () -> bool | |
607 # hard-float ABI can be detected from the ELF header of the running | |
608 # process | |
609 # https://static.docs.arm.com/ihi0044/g/aaelf32.pdf | |
610 elf_header = _get_elf_header() | |
611 if elf_header is None: | |
612 return False | |
613 result = elf_header.e_ident_class == elf_header.ELFCLASS32 | |
614 result &= elf_header.e_ident_data == elf_header.ELFDATA2LSB | |
615 result &= elf_header.e_machine == elf_header.EM_ARM | |
616 result &= ( | |
617 elf_header.e_flags & elf_header.EF_ARM_ABIMASK | |
618 ) == elf_header.EF_ARM_ABI_VER5 | |
619 result &= ( | |
620 elf_header.e_flags & elf_header.EF_ARM_ABI_FLOAT_HARD | |
621 ) == elf_header.EF_ARM_ABI_FLOAT_HARD | |
622 return result | |
623 | |
624 | |
625 def _is_linux_i686(): | |
626 # type: () -> bool | |
627 elf_header = _get_elf_header() | |
628 if elf_header is None: | |
629 return False | |
630 result = elf_header.e_ident_class == elf_header.ELFCLASS32 | |
631 result &= elf_header.e_ident_data == elf_header.ELFDATA2LSB | |
632 result &= elf_header.e_machine == elf_header.EM_386 | |
633 return result | |
634 | |
635 | |
636 def _have_compatible_manylinux_abi(arch): | |
637 # type: (str) -> bool | |
638 if arch == "armv7l": | |
639 return _is_linux_armhf() | |
640 if arch == "i686": | |
641 return _is_linux_i686() | |
642 return True | |
643 | |
644 | |
645 def _linux_platforms(is_32bit=_32_BIT_INTERPRETER): | |
646 # type: (bool) -> Iterator[str] | |
647 linux = _normalize_string(distutils.util.get_platform()) | |
648 if is_32bit: | |
649 if linux == "linux_x86_64": | |
650 linux = "linux_i686" | |
651 elif linux == "linux_aarch64": | |
652 linux = "linux_armv7l" | |
653 manylinux_support = [] | |
654 _, arch = linux.split("_", 1) | |
655 if _have_compatible_manylinux_abi(arch): | |
656 if arch in {"x86_64", "i686", "aarch64", "armv7l", "ppc64", "ppc64le", "s390x"}: | |
657 manylinux_support.append( | |
658 ("manylinux2014", (2, 17)) | |
659 ) # CentOS 7 w/ glibc 2.17 (PEP 599) | |
660 if arch in {"x86_64", "i686"}: | |
661 manylinux_support.append( | |
662 ("manylinux2010", (2, 12)) | |
663 ) # CentOS 6 w/ glibc 2.12 (PEP 571) | |
664 manylinux_support.append( | |
665 ("manylinux1", (2, 5)) | |
666 ) # CentOS 5 w/ glibc 2.5 (PEP 513) | |
667 manylinux_support_iter = iter(manylinux_support) | |
668 for name, glibc_version in manylinux_support_iter: | |
669 if _is_manylinux_compatible(name, glibc_version): | |
670 yield linux.replace("linux", name) | |
671 break | |
672 # Support for a later manylinux implies support for an earlier version. | |
673 for name, _ in manylinux_support_iter: | |
674 yield linux.replace("linux", name) | |
675 yield linux | |
676 | |
677 | |
678 def _generic_platforms(): | |
679 # type: () -> Iterator[str] | |
680 yield _normalize_string(distutils.util.get_platform()) | |
681 | |
682 | |
683 def _platform_tags(): | |
684 # type: () -> Iterator[str] | |
685 """ | |
686 Provides the platform tags for this installation. | |
687 """ | |
688 if platform.system() == "Darwin": | |
689 return mac_platforms() | |
690 elif platform.system() == "Linux": | |
691 return _linux_platforms() | |
692 else: | |
693 return _generic_platforms() | |
694 | |
695 | |
696 def interpreter_name(): | |
697 # type: () -> str | |
698 """ | |
699 Returns the name of the running interpreter. | |
700 """ | |
701 try: | |
702 name = sys.implementation.name # type: ignore | |
703 except AttributeError: # pragma: no cover | |
704 # Python 2.7 compatibility. | |
705 name = platform.python_implementation().lower() | |
706 return INTERPRETER_SHORT_NAMES.get(name) or name | |
707 | |
708 | |
709 def interpreter_version(**kwargs): | |
710 # type: (bool) -> str | |
711 """ | |
712 Returns the version of the running interpreter. | |
713 """ | |
714 warn = _warn_keyword_parameter("interpreter_version", kwargs) | |
715 version = _get_config_var("py_version_nodot", warn=warn) | |
716 if version: | |
717 version = str(version) | |
718 else: | |
719 version = _version_nodot(sys.version_info[:2]) | |
720 return version | |
721 | |
722 | |
723 def _version_nodot(version): | |
724 # type: (PythonVersion) -> str | |
725 if any(v >= 10 for v in version): | |
726 sep = "_" | |
727 else: | |
728 sep = "" | |
729 return sep.join(map(str, version)) | |
730 | |
731 | |
732 def sys_tags(**kwargs): | |
733 # type: (bool) -> Iterator[Tag] | |
734 """ | |
735 Returns the sequence of tag triples for the running interpreter. | |
736 | |
737 The order of the sequence corresponds to priority order for the | |
738 interpreter, from most to least important. | |
739 """ | |
740 warn = _warn_keyword_parameter("sys_tags", kwargs) | |
741 | |
742 interp_name = interpreter_name() | |
743 if interp_name == "cp": | |
744 for tag in cpython_tags(warn=warn): | |
745 yield tag | |
746 else: | |
747 for tag in generic_tags(): | |
748 yield tag | |
749 | |
750 for tag in compatible_tags(): | |
751 yield tag |