five.py 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374
  1. # -*- coding: utf-8 -*-
  2. """Python 2/3 compatibility.
  3. Compatibility implementations of features
  4. only available in newer Python versions.
  5. """
  6. from __future__ import absolute_import, unicode_literals
  7. import errno
  8. import io
  9. import sys
  10. try:
  11. from collections import Counter
  12. except ImportError: # pragma: no cover
  13. from collections import defaultdict
  14. def Counter(): # noqa
  15. """Create counter."""
  16. return defaultdict(int)
  17. try:
  18. buffer_t = buffer
  19. except NameError: # pragma: no cover
  20. # Py3 does not have buffer, only use this for isa checks.
  21. class buffer_t(object): # noqa
  22. """Python 3 does not have a buffer type."""
  23. bytes_t = bytes
  24. __all__ = [
  25. 'Counter', 'reload', 'UserList', 'UserDict',
  26. 'Callable', 'Iterable', 'Mapping',
  27. 'Queue', 'Empty', 'Full', 'LifoQueue', 'builtins', 'array',
  28. 'zip_longest', 'map', 'zip', 'string', 'string_t', 'bytes_t',
  29. 'bytes_if_py2', 'long_t', 'text_t', 'int_types', 'module_name_t',
  30. 'range', 'items', 'keys', 'values', 'nextfun', 'reraise',
  31. 'WhateverIO', 'with_metaclass', 'StringIO', 'getfullargspec',
  32. 'THREAD_TIMEOUT_MAX', 'format_d', 'monotonic', 'buffer_t',
  33. 'python_2_unicode_compatible',
  34. ]
  35. # ############# py3k ########################################################
  36. PY3 = sys.version_info[0] >= 3
  37. PY2 = sys.version_info[0] < 3
  38. try:
  39. reload = reload # noqa
  40. except NameError: # pragma: no cover
  41. try:
  42. from importlib import reload # noqa
  43. except ImportError: # pragma: no cover
  44. from imp import reload # noqa
  45. try:
  46. from collections import UserList # noqa
  47. except ImportError: # pragma: no cover
  48. from UserList import UserList # noqa
  49. try:
  50. from collections import UserDict # noqa
  51. except ImportError: # pragma: no cover
  52. from UserDict import UserDict # noqa
  53. try:
  54. from collections.abc import Callable # noqa
  55. except ImportError: # pragma: no cover
  56. from collections import Callable # noqa
  57. try:
  58. from collections.abc import Iterable # noqa
  59. except ImportError: # pragma: no cover
  60. from collections import Iterable # noqa
  61. try:
  62. from collections.abc import Mapping # noqa
  63. except ImportError: # pragma: no cover
  64. from collections import Mapping # noqa
  65. # ############# time.monotonic #############################################
  66. if sys.version_info < (3, 3):
  67. import platform
  68. SYSTEM = platform.system()
  69. try:
  70. import ctypes
  71. except ImportError: # pragma: no cover
  72. ctypes = None # noqa
  73. if SYSTEM == 'Darwin' and ctypes is not None:
  74. from ctypes.util import find_library
  75. libSystem = ctypes.CDLL(find_library('libSystem.dylib'))
  76. CoreServices = ctypes.CDLL(find_library('CoreServices'),
  77. use_errno=True)
  78. mach_absolute_time = libSystem.mach_absolute_time
  79. mach_absolute_time.restype = ctypes.c_uint64
  80. absolute_to_nanoseconds = CoreServices.AbsoluteToNanoseconds
  81. absolute_to_nanoseconds.restype = ctypes.c_uint64
  82. absolute_to_nanoseconds.argtypes = [ctypes.c_uint64]
  83. def _monotonic():
  84. return absolute_to_nanoseconds(mach_absolute_time()) * 1e-9
  85. elif SYSTEM == 'Linux' and ctypes is not None:
  86. # from stackoverflow:
  87. # questions/1205722/how-do-i-get-monotonic-time-durations-in-python
  88. import os
  89. CLOCK_MONOTONIC = 1 # see <linux/time.h>
  90. class timespec(ctypes.Structure):
  91. _fields_ = [
  92. ('tv_sec', ctypes.c_long),
  93. ('tv_nsec', ctypes.c_long),
  94. ]
  95. try:
  96. librt = ctypes.CDLL('librt.so.1', use_errno=True)
  97. except Exception:
  98. try:
  99. librt = ctypes.CDLL('librt.so.0', use_errno=True)
  100. except Exception as exc:
  101. error = OSError(
  102. "Could not detect working librt library: {0}".format(
  103. exc))
  104. error.errno = errno.ENOENT
  105. raise error
  106. clock_gettime = librt.clock_gettime
  107. clock_gettime.argtypes = [
  108. ctypes.c_int, ctypes.POINTER(timespec),
  109. ]
  110. def _monotonic(): # noqa
  111. t = timespec()
  112. if clock_gettime(CLOCK_MONOTONIC, ctypes.pointer(t)) != 0:
  113. errno_ = ctypes.get_errno()
  114. raise OSError(errno_, os.strerror(errno_))
  115. return t.tv_sec + t.tv_nsec * 1e-9
  116. else:
  117. from time import time as _monotonic
  118. try:
  119. from time import monotonic
  120. except ImportError:
  121. monotonic = _monotonic # noqa
  122. # ############# Py3 <-> Py2 #################################################
  123. if PY3: # pragma: no cover
  124. import builtins
  125. from array import array
  126. from queue import Queue, Empty, Full, LifoQueue
  127. from itertools import zip_longest
  128. map = map
  129. zip = zip
  130. string = str
  131. string_t = str
  132. long_t = int
  133. text_t = str
  134. range = range
  135. int_types = (int,)
  136. module_name_t = str
  137. def bytes_if_py2(s):
  138. """Convert str to bytes if running under Python 2."""
  139. return s
  140. def items(d):
  141. """Get dict items iterator."""
  142. return d.items()
  143. def keys(d):
  144. """Get dict keys iterator."""
  145. return d.keys()
  146. def values(d):
  147. """Get dict values iterator."""
  148. return d.values()
  149. def nextfun(it):
  150. """Get iterator next method."""
  151. return it.__next__
  152. exec_ = getattr(builtins, 'exec')
  153. def reraise(tp, value, tb=None):
  154. """Reraise exception."""
  155. if value.__traceback__ is not tb:
  156. raise value.with_traceback(tb)
  157. raise value
  158. else:
  159. import __builtin__ as builtins # noqa
  160. from array import array as _array
  161. from Queue import Queue, Empty, Full, LifoQueue # noqa
  162. from itertools import ( # noqa
  163. imap as map,
  164. izip as zip,
  165. izip_longest as zip_longest,
  166. )
  167. string = unicode # noqa
  168. string_t = basestring # noqa
  169. text_t = unicode
  170. long_t = long # noqa
  171. range = xrange
  172. module_name_t = str
  173. int_types = (int, long)
  174. def array(typecode, *args, **kwargs):
  175. """Create array."""
  176. if isinstance(typecode, unicode):
  177. typecode = typecode.encode()
  178. return _array(typecode, *args, **kwargs)
  179. def bytes_if_py2(s):
  180. """Convert str to bytes if running under Python 2."""
  181. if isinstance(s, unicode):
  182. return s.encode()
  183. return s
  184. def items(d): # noqa
  185. """Return dict items iterator."""
  186. return d.iteritems()
  187. def keys(d): # noqa
  188. """Return dict key iterator."""
  189. return d.iterkeys()
  190. def values(d): # noqa
  191. """Return dict values iterator."""
  192. return d.itervalues()
  193. def nextfun(it): # noqa
  194. """Return iterator next method."""
  195. return it.next
  196. def exec_(code, globs=None, locs=None): # pragma: no cover
  197. """Execute code in a namespace."""
  198. if globs is None:
  199. frame = sys._getframe(1)
  200. globs = frame.f_globals
  201. if locs is None:
  202. locs = frame.f_locals
  203. del frame
  204. elif locs is None:
  205. locs = globs
  206. exec("""exec code in globs, locs""")
  207. exec_("""def reraise(tp, value, tb=None): raise tp, value, tb""")
  208. def with_metaclass(Type, skip_attrs=None):
  209. """Class decorator to set metaclass.
  210. Works with both Python 2 and Python 3 and it does not add
  211. an extra class in the lookup order like ``six.with_metaclass`` does
  212. (that is -- it copies the original class instead of using inheritance).
  213. """
  214. if skip_attrs is None:
  215. skip_attrs = {'__dict__', '__weakref__'}
  216. def _clone_with_metaclass(Class):
  217. attrs = {key: value for key, value in items(vars(Class))
  218. if key not in skip_attrs}
  219. return Type(Class.__name__, Class.__bases__, attrs)
  220. return _clone_with_metaclass
  221. # ############# threading.TIMEOUT_MAX ########################################
  222. try:
  223. from threading import TIMEOUT_MAX as THREAD_TIMEOUT_MAX
  224. except ImportError:
  225. THREAD_TIMEOUT_MAX = 1e10 # noqa
  226. # ############# format(int, ',d') ############################################
  227. if sys.version_info >= (2, 7): # pragma: no cover
  228. def format_d(i):
  229. """Format number."""
  230. return format(i, ',d')
  231. else: # pragma: no cover
  232. def format_d(i): # noqa
  233. """Format number."""
  234. s = '%d' % i
  235. groups = []
  236. while s and s[-1].isdigit():
  237. groups.append(s[-3:])
  238. s = s[:-3]
  239. return s + ','.join(reversed(groups))
  240. StringIO = io.StringIO
  241. _SIO_write = StringIO.write
  242. _SIO_init = StringIO.__init__
  243. class WhateverIO(StringIO):
  244. """StringIO that takes bytes or str."""
  245. def __init__(self, v=None, *a, **kw):
  246. _SIO_init(self, v.decode() if isinstance(v, bytes) else v, *a, **kw)
  247. def write(self, data):
  248. _SIO_write(self, data.decode() if isinstance(data, bytes) else data)
  249. def python_2_unicode_compatible(cls):
  250. """Class decorator to ensure class is compatible with Python 2."""
  251. return python_2_non_unicode_str(python_2_non_unicode_repr(cls))
  252. def python_2_non_unicode_repr(cls):
  253. """Ensure cls.__repr__ returns unicode.
  254. A class decorator that ensures ``__repr__`` returns non-unicode
  255. when running under Python 2.
  256. """
  257. if PY2:
  258. try:
  259. cls.__dict__['__repr__']
  260. except KeyError:
  261. pass
  262. else:
  263. def __repr__(self, *args, **kwargs):
  264. return self.__unicode_repr__(*args, **kwargs).encode(
  265. 'utf-8', 'replace')
  266. cls.__unicode_repr__, cls.__repr__ = cls.__repr__, __repr__
  267. return cls
  268. def python_2_non_unicode_str(cls):
  269. """Python 2 class string compatibility.
  270. A class decorator that defines ``__unicode__`` and ``__str__`` methods
  271. under Python 2. Under Python 3 it does nothing.
  272. To support Python 2 and 3 with a single code base, define a ``__str__``
  273. method returning text and apply this decorator to the class.
  274. """
  275. if PY2:
  276. try:
  277. cls.__dict__['__str__']
  278. except KeyError:
  279. pass
  280. else:
  281. def __str__(self, *args, **kwargs):
  282. return self.__unicode__(*args, **kwargs).encode(
  283. 'utf-8', 'replace')
  284. cls.__unicode__, cls.__str__ = cls.__str__, __str__
  285. return cls
  286. try: # pragma: no cover
  287. from inspect import formatargspec, getfullargspec
  288. except ImportError: # Py2
  289. from collections import namedtuple
  290. from inspect import formatargspec, getargspec as _getargspec # noqa
  291. FullArgSpec = namedtuple('FullArgSpec', (
  292. 'args', 'varargs', 'varkw', 'defaults',
  293. 'kwonlyargs', 'kwonlydefaults', 'annotations',
  294. ))
  295. def getfullargspec(fun, _fill=(None, ) * 3): # noqa
  296. """For compatibility with Python 3."""
  297. s = _getargspec(fun)
  298. return FullArgSpec(*s + _fill)