five.py 11 KB

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