You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

752 lines
24KB

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