Development of an internal social media platform with personalised dashboards for students
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.

pep425tags.py 11KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319
  1. # This file originally from pip:
  2. # https://github.com/pypa/pip/blob/8f4f15a5a95d7d5b511ceaee9ed261176c181970/src/pip/_internal/pep425tags.py
  3. """Generate and work with PEP 425 Compatibility Tags."""
  4. from __future__ import absolute_import
  5. import distutils.util
  6. from distutils import log
  7. import platform
  8. import re
  9. import sys
  10. import sysconfig
  11. import warnings
  12. from collections import OrderedDict
  13. from .extern import six
  14. from . import glibc
  15. _osx_arch_pat = re.compile(r'(.+)_(\d+)_(\d+)_(.+)')
  16. def get_config_var(var):
  17. try:
  18. return sysconfig.get_config_var(var)
  19. except IOError as e: # Issue #1074
  20. warnings.warn("{}".format(e), RuntimeWarning)
  21. return None
  22. def get_abbr_impl():
  23. """Return abbreviated implementation name."""
  24. if hasattr(sys, 'pypy_version_info'):
  25. pyimpl = 'pp'
  26. elif sys.platform.startswith('java'):
  27. pyimpl = 'jy'
  28. elif sys.platform == 'cli':
  29. pyimpl = 'ip'
  30. else:
  31. pyimpl = 'cp'
  32. return pyimpl
  33. def get_impl_ver():
  34. """Return implementation version."""
  35. impl_ver = get_config_var("py_version_nodot")
  36. if not impl_ver or get_abbr_impl() == 'pp':
  37. impl_ver = ''.join(map(str, get_impl_version_info()))
  38. return impl_ver
  39. def get_impl_version_info():
  40. """Return sys.version_info-like tuple for use in decrementing the minor
  41. version."""
  42. if get_abbr_impl() == 'pp':
  43. # as per https://github.com/pypa/pip/issues/2882
  44. return (sys.version_info[0], sys.pypy_version_info.major,
  45. sys.pypy_version_info.minor)
  46. else:
  47. return sys.version_info[0], sys.version_info[1]
  48. def get_impl_tag():
  49. """
  50. Returns the Tag for this specific implementation.
  51. """
  52. return "{}{}".format(get_abbr_impl(), get_impl_ver())
  53. def get_flag(var, fallback, expected=True, warn=True):
  54. """Use a fallback method for determining SOABI flags if the needed config
  55. var is unset or unavailable."""
  56. val = get_config_var(var)
  57. if val is None:
  58. if warn:
  59. log.debug("Config variable '%s' is unset, Python ABI tag may "
  60. "be incorrect", var)
  61. return fallback()
  62. return val == expected
  63. def get_abi_tag():
  64. """Return the ABI tag based on SOABI (if available) or emulate SOABI
  65. (CPython 2, PyPy)."""
  66. soabi = get_config_var('SOABI')
  67. impl = get_abbr_impl()
  68. if not soabi and impl in {'cp', 'pp'} and hasattr(sys, 'maxunicode'):
  69. d = ''
  70. m = ''
  71. u = ''
  72. if get_flag('Py_DEBUG',
  73. lambda: hasattr(sys, 'gettotalrefcount'),
  74. warn=(impl == 'cp')):
  75. d = 'd'
  76. if get_flag('WITH_PYMALLOC',
  77. lambda: impl == 'cp',
  78. warn=(impl == 'cp')):
  79. m = 'm'
  80. if get_flag('Py_UNICODE_SIZE',
  81. lambda: sys.maxunicode == 0x10ffff,
  82. expected=4,
  83. warn=(impl == 'cp' and
  84. six.PY2)) \
  85. and six.PY2:
  86. u = 'u'
  87. abi = '%s%s%s%s%s' % (impl, get_impl_ver(), d, m, u)
  88. elif soabi and soabi.startswith('cpython-'):
  89. abi = 'cp' + soabi.split('-')[1]
  90. elif soabi:
  91. abi = soabi.replace('.', '_').replace('-', '_')
  92. else:
  93. abi = None
  94. return abi
  95. def _is_running_32bit():
  96. return sys.maxsize == 2147483647
  97. def get_platform():
  98. """Return our platform name 'win32', 'linux_x86_64'"""
  99. if sys.platform == 'darwin':
  100. # distutils.util.get_platform() returns the release based on the value
  101. # of MACOSX_DEPLOYMENT_TARGET on which Python was built, which may
  102. # be significantly older than the user's current machine.
  103. release, _, machine = platform.mac_ver()
  104. split_ver = release.split('.')
  105. if machine == "x86_64" and _is_running_32bit():
  106. machine = "i386"
  107. elif machine == "ppc64" and _is_running_32bit():
  108. machine = "ppc"
  109. return 'macosx_{}_{}_{}'.format(split_ver[0], split_ver[1], machine)
  110. # XXX remove distutils dependency
  111. result = distutils.util.get_platform().replace('.', '_').replace('-', '_')
  112. if result == "linux_x86_64" and _is_running_32bit():
  113. # 32 bit Python program (running on a 64 bit Linux): pip should only
  114. # install and run 32 bit compiled extensions in that case.
  115. result = "linux_i686"
  116. return result
  117. def is_manylinux1_compatible():
  118. # Only Linux, and only x86-64 / i686
  119. if get_platform() not in {"linux_x86_64", "linux_i686"}:
  120. return False
  121. # Check for presence of _manylinux module
  122. try:
  123. import _manylinux
  124. return bool(_manylinux.manylinux1_compatible)
  125. except (ImportError, AttributeError):
  126. # Fall through to heuristic check below
  127. pass
  128. # Check glibc version. CentOS 5 uses glibc 2.5.
  129. return glibc.have_compatible_glibc(2, 5)
  130. def get_darwin_arches(major, minor, machine):
  131. """Return a list of supported arches (including group arches) for
  132. the given major, minor and machine architecture of an macOS machine.
  133. """
  134. arches = []
  135. def _supports_arch(major, minor, arch):
  136. # Looking at the application support for macOS versions in the chart
  137. # provided by https://en.wikipedia.org/wiki/OS_X#Versions it appears
  138. # our timeline looks roughly like:
  139. #
  140. # 10.0 - Introduces ppc support.
  141. # 10.4 - Introduces ppc64, i386, and x86_64 support, however the ppc64
  142. # and x86_64 support is CLI only, and cannot be used for GUI
  143. # applications.
  144. # 10.5 - Extends ppc64 and x86_64 support to cover GUI applications.
  145. # 10.6 - Drops support for ppc64
  146. # 10.7 - Drops support for ppc
  147. #
  148. # Given that we do not know if we're installing a CLI or a GUI
  149. # application, we must be conservative and assume it might be a GUI
  150. # application and behave as if ppc64 and x86_64 support did not occur
  151. # until 10.5.
  152. #
  153. # Note: The above information is taken from the "Application support"
  154. # column in the chart not the "Processor support" since I believe
  155. # that we care about what instruction sets an application can use
  156. # not which processors the OS supports.
  157. if arch == 'ppc':
  158. return (major, minor) <= (10, 5)
  159. if arch == 'ppc64':
  160. return (major, minor) == (10, 5)
  161. if arch == 'i386':
  162. return (major, minor) >= (10, 4)
  163. if arch == 'x86_64':
  164. return (major, minor) >= (10, 5)
  165. if arch in groups:
  166. for garch in groups[arch]:
  167. if _supports_arch(major, minor, garch):
  168. return True
  169. return False
  170. groups = OrderedDict([
  171. ("fat", ("i386", "ppc")),
  172. ("intel", ("x86_64", "i386")),
  173. ("fat64", ("x86_64", "ppc64")),
  174. ("fat32", ("x86_64", "i386", "ppc")),
  175. ])
  176. if _supports_arch(major, minor, machine):
  177. arches.append(machine)
  178. for garch in groups:
  179. if machine in groups[garch] and _supports_arch(major, minor, garch):
  180. arches.append(garch)
  181. arches.append('universal')
  182. return arches
  183. def get_supported(versions=None, noarch=False, platform=None,
  184. impl=None, abi=None):
  185. """Return a list of supported tags for each version specified in
  186. `versions`.
  187. :param versions: a list of string versions, of the form ["33", "32"],
  188. or None. The first version will be assumed to support our ABI.
  189. :param platform: specify the exact platform you want valid
  190. tags for, or None. If None, use the local system platform.
  191. :param impl: specify the exact implementation you want valid
  192. tags for, or None. If None, use the local interpreter impl.
  193. :param abi: specify the exact abi you want valid
  194. tags for, or None. If None, use the local interpreter abi.
  195. """
  196. supported = []
  197. # Versions must be given with respect to the preference
  198. if versions is None:
  199. versions = []
  200. version_info = get_impl_version_info()
  201. major = version_info[:-1]
  202. # Support all previous minor Python versions.
  203. for minor in range(version_info[-1], -1, -1):
  204. versions.append(''.join(map(str, major + (minor,))))
  205. impl = impl or get_abbr_impl()
  206. abis = []
  207. abi = abi or get_abi_tag()
  208. if abi:
  209. abis[0:0] = [abi]
  210. abi3s = set()
  211. import imp
  212. for suffix in imp.get_suffixes():
  213. if suffix[0].startswith('.abi'):
  214. abi3s.add(suffix[0].split('.', 2)[1])
  215. abis.extend(sorted(list(abi3s)))
  216. abis.append('none')
  217. if not noarch:
  218. arch = platform or get_platform()
  219. if arch.startswith('macosx'):
  220. # support macosx-10.6-intel on macosx-10.9-x86_64
  221. match = _osx_arch_pat.match(arch)
  222. if match:
  223. name, major, minor, actual_arch = match.groups()
  224. tpl = '{}_{}_%i_%s'.format(name, major)
  225. arches = []
  226. for m in reversed(range(int(minor) + 1)):
  227. for a in get_darwin_arches(int(major), m, actual_arch):
  228. arches.append(tpl % (m, a))
  229. else:
  230. # arch pattern didn't match (?!)
  231. arches = [arch]
  232. elif platform is None and is_manylinux1_compatible():
  233. arches = [arch.replace('linux', 'manylinux1'), arch]
  234. else:
  235. arches = [arch]
  236. # Current version, current API (built specifically for our Python):
  237. for abi in abis:
  238. for arch in arches:
  239. supported.append(('%s%s' % (impl, versions[0]), abi, arch))
  240. # abi3 modules compatible with older version of Python
  241. for version in versions[1:]:
  242. # abi3 was introduced in Python 3.2
  243. if version in {'31', '30'}:
  244. break
  245. for abi in abi3s: # empty set if not Python 3
  246. for arch in arches:
  247. supported.append(("%s%s" % (impl, version), abi, arch))
  248. # Has binaries, does not use the Python API:
  249. for arch in arches:
  250. supported.append(('py%s' % (versions[0][0]), 'none', arch))
  251. # No abi / arch, but requires our implementation:
  252. supported.append(('%s%s' % (impl, versions[0]), 'none', 'any'))
  253. # Tagged specifically as being cross-version compatible
  254. # (with just the major version specified)
  255. supported.append(('%s%s' % (impl, versions[0][0]), 'none', 'any'))
  256. # No abi / arch, generic Python
  257. for i, version in enumerate(versions):
  258. supported.append(('py%s' % (version,), 'none', 'any'))
  259. if i == 0:
  260. supported.append(('py%s' % (version[0]), 'none', 'any'))
  261. return supported
  262. implementation_tag = get_impl_tag()