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.

__init__.py 12KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453
  1. """
  2. kombu.utils
  3. ===========
  4. Internal utilities.
  5. """
  6. from __future__ import absolute_import, print_function
  7. import importlib
  8. import numbers
  9. import random
  10. import sys
  11. from contextlib import contextmanager
  12. from itertools import count, repeat
  13. from functools import wraps
  14. from time import sleep
  15. from uuid import UUID, uuid4
  16. try:
  17. from uuid import _uuid_generate_random
  18. except ImportError:
  19. _uuid_generate_random = None
  20. from kombu.five import items, reraise, string_t
  21. from .encoding import default_encode, safe_repr as _safe_repr
  22. try:
  23. import ctypes
  24. except:
  25. ctypes = None # noqa
  26. try:
  27. from io import UnsupportedOperation
  28. FILENO_ERRORS = (AttributeError, ValueError, UnsupportedOperation)
  29. except ImportError: # pragma: no cover
  30. # Py2
  31. FILENO_ERRORS = (AttributeError, ValueError) # noqa
  32. __all__ = ['EqualityDict', 'say', 'uuid', 'kwdict', 'maybe_list',
  33. 'fxrange', 'fxrangemax', 'retry_over_time',
  34. 'emergency_dump_state', 'cached_property',
  35. 'reprkwargs', 'reprcall', 'nested', 'fileno', 'maybe_fileno']
  36. def symbol_by_name(name, aliases={}, imp=None, package=None,
  37. sep='.', default=None, **kwargs):
  38. """Get symbol by qualified name.
  39. The name should be the full dot-separated path to the class::
  40. modulename.ClassName
  41. Example::
  42. celery.concurrency.processes.TaskPool
  43. ^- class name
  44. or using ':' to separate module and symbol::
  45. celery.concurrency.processes:TaskPool
  46. If `aliases` is provided, a dict containing short name/long name
  47. mappings, the name is looked up in the aliases first.
  48. Examples:
  49. >>> symbol_by_name('celery.concurrency.processes.TaskPool')
  50. <class 'celery.concurrency.processes.TaskPool'>
  51. >>> symbol_by_name('default', {
  52. ... 'default': 'celery.concurrency.processes.TaskPool'})
  53. <class 'celery.concurrency.processes.TaskPool'>
  54. # Does not try to look up non-string names.
  55. >>> from celery.concurrency.processes import TaskPool
  56. >>> symbol_by_name(TaskPool) is TaskPool
  57. True
  58. """
  59. if imp is None:
  60. imp = importlib.import_module
  61. if not isinstance(name, string_t):
  62. return name # already a class
  63. name = aliases.get(name) or name
  64. sep = ':' if ':' in name else sep
  65. module_name, _, cls_name = name.rpartition(sep)
  66. if not module_name:
  67. cls_name, module_name = None, package if package else cls_name
  68. try:
  69. try:
  70. module = imp(module_name, package=package, **kwargs)
  71. except ValueError as exc:
  72. reraise(ValueError,
  73. ValueError("Couldn't import {0!r}: {1}".format(name, exc)),
  74. sys.exc_info()[2])
  75. return getattr(module, cls_name) if cls_name else module
  76. except (ImportError, AttributeError):
  77. if default is None:
  78. raise
  79. return default
  80. class HashedSeq(list):
  81. """type used for hash() to make sure the hash is not generated
  82. multiple times."""
  83. __slots__ = 'hashvalue'
  84. def __init__(self, *seq):
  85. self[:] = seq
  86. self.hashvalue = hash(seq)
  87. def __hash__(self):
  88. return self.hashvalue
  89. def eqhash(o):
  90. try:
  91. return o.__eqhash__()
  92. except AttributeError:
  93. return hash(o)
  94. class EqualityDict(dict):
  95. def __getitem__(self, key):
  96. h = eqhash(key)
  97. if h not in self:
  98. return self.__missing__(key)
  99. return dict.__getitem__(self, h)
  100. def __setitem__(self, key, value):
  101. return dict.__setitem__(self, eqhash(key), value)
  102. def __delitem__(self, key):
  103. return dict.__delitem__(self, eqhash(key))
  104. def say(m, *fargs, **fkwargs):
  105. print(str(m).format(*fargs, **fkwargs), file=sys.stderr)
  106. if ctypes and _uuid_generate_random: # pragma: no cover
  107. def uuid4():
  108. # Workaround for http://bugs.python.org/issue4607
  109. buffer = ctypes.create_string_buffer(16)
  110. _uuid_generate_random(buffer)
  111. return UUID(bytes=buffer.raw)
  112. def uuid():
  113. """Generate a unique id, having - hopefully - a very small chance of
  114. collision.
  115. For now this is provided by :func:`uuid.uuid4`.
  116. """
  117. return str(uuid4())
  118. gen_unique_id = uuid
  119. if sys.version_info >= (2, 6, 5):
  120. def kwdict(kwargs):
  121. return kwargs
  122. else:
  123. def kwdict(kwargs): # pragma: no cover # noqa
  124. """Make sure keyword arguments are not in Unicode.
  125. This should be fixed in newer Python versions,
  126. see: http://bugs.python.org/issue4978.
  127. """
  128. return dict((key.encode('utf-8'), value)
  129. for key, value in items(kwargs))
  130. def maybe_list(v):
  131. if v is None:
  132. return []
  133. if hasattr(v, '__iter__'):
  134. return v
  135. return [v]
  136. def fxrange(start=1.0, stop=None, step=1.0, repeatlast=False):
  137. cur = start * 1.0
  138. while 1:
  139. if not stop or cur <= stop:
  140. yield cur
  141. cur += step
  142. else:
  143. if not repeatlast:
  144. break
  145. yield cur - step
  146. def fxrangemax(start=1.0, stop=None, step=1.0, max=100.0):
  147. sum_, cur = 0, start * 1.0
  148. while 1:
  149. if sum_ >= max:
  150. break
  151. yield cur
  152. if stop:
  153. cur = min(cur + step, stop)
  154. else:
  155. cur += step
  156. sum_ += cur
  157. def retry_over_time(fun, catch, args=[], kwargs={}, errback=None,
  158. max_retries=None, interval_start=2, interval_step=2,
  159. interval_max=30, callback=None):
  160. """Retry the function over and over until max retries is exceeded.
  161. For each retry we sleep a for a while before we try again, this interval
  162. is increased for every retry until the max seconds is reached.
  163. :param fun: The function to try
  164. :param catch: Exceptions to catch, can be either tuple or a single
  165. exception class.
  166. :keyword args: Positional arguments passed on to the function.
  167. :keyword kwargs: Keyword arguments passed on to the function.
  168. :keyword errback: Callback for when an exception in ``catch`` is raised.
  169. The callback must take two arguments: ``exc`` and ``interval``, where
  170. ``exc`` is the exception instance, and ``interval`` is the time in
  171. seconds to sleep next..
  172. :keyword max_retries: Maximum number of retries before we give up.
  173. If this is not set, we will retry forever.
  174. :keyword interval_start: How long (in seconds) we start sleeping between
  175. retries.
  176. :keyword interval_step: By how much the interval is increased for each
  177. retry.
  178. :keyword interval_max: Maximum number of seconds to sleep between retries.
  179. """
  180. retries = 0
  181. interval_range = fxrange(interval_start,
  182. interval_max + interval_start,
  183. interval_step, repeatlast=True)
  184. for retries in count():
  185. try:
  186. return fun(*args, **kwargs)
  187. except catch as exc:
  188. if max_retries and retries >= max_retries:
  189. raise
  190. if callback:
  191. callback()
  192. tts = float(errback(exc, interval_range, retries) if errback
  193. else next(interval_range))
  194. if tts:
  195. for _ in range(int(tts)):
  196. if callback:
  197. callback()
  198. sleep(1.0)
  199. # sleep remainder after int truncation above.
  200. sleep(abs(int(tts) - tts))
  201. def emergency_dump_state(state, open_file=open, dump=None):
  202. from pprint import pformat
  203. from tempfile import mktemp
  204. if dump is None:
  205. import pickle
  206. dump = pickle.dump
  207. persist = mktemp()
  208. say('EMERGENCY DUMP STATE TO FILE -> {0} <-', persist)
  209. fh = open_file(persist, 'w')
  210. try:
  211. try:
  212. dump(state, fh, protocol=0)
  213. except Exception as exc:
  214. say('Cannot pickle state: {0!r}. Fallback to pformat.', exc)
  215. fh.write(default_encode(pformat(state)))
  216. finally:
  217. fh.flush()
  218. fh.close()
  219. return persist
  220. class cached_property(object):
  221. """Property descriptor that caches the return value
  222. of the get function.
  223. *Examples*
  224. .. code-block:: python
  225. @cached_property
  226. def connection(self):
  227. return Connection()
  228. @connection.setter # Prepares stored value
  229. def connection(self, value):
  230. if value is None:
  231. raise TypeError('Connection must be a connection')
  232. return value
  233. @connection.deleter
  234. def connection(self, value):
  235. # Additional action to do at del(self.attr)
  236. if value is not None:
  237. print('Connection {0!r} deleted'.format(value)
  238. """
  239. def __init__(self, fget=None, fset=None, fdel=None, doc=None):
  240. self.__get = fget
  241. self.__set = fset
  242. self.__del = fdel
  243. self.__doc__ = doc or fget.__doc__
  244. self.__name__ = fget.__name__
  245. self.__module__ = fget.__module__
  246. def __get__(self, obj, type=None):
  247. if obj is None:
  248. return self
  249. try:
  250. return obj.__dict__[self.__name__]
  251. except KeyError:
  252. value = obj.__dict__[self.__name__] = self.__get(obj)
  253. return value
  254. def __set__(self, obj, value):
  255. if obj is None:
  256. return self
  257. if self.__set is not None:
  258. value = self.__set(obj, value)
  259. obj.__dict__[self.__name__] = value
  260. def __delete__(self, obj):
  261. if obj is None:
  262. return self
  263. try:
  264. value = obj.__dict__.pop(self.__name__)
  265. except KeyError:
  266. pass
  267. else:
  268. if self.__del is not None:
  269. self.__del(obj, value)
  270. def setter(self, fset):
  271. return self.__class__(self.__get, fset, self.__del)
  272. def deleter(self, fdel):
  273. return self.__class__(self.__get, self.__set, fdel)
  274. def reprkwargs(kwargs, sep=', ', fmt='{0}={1}'):
  275. return sep.join(fmt.format(k, _safe_repr(v)) for k, v in items(kwargs))
  276. def reprcall(name, args=(), kwargs={}, sep=', '):
  277. return '{0}({1}{2}{3})'.format(
  278. name, sep.join(map(_safe_repr, args or ())),
  279. (args and kwargs) and sep or '',
  280. reprkwargs(kwargs, sep),
  281. )
  282. @contextmanager
  283. def nested(*managers): # pragma: no cover
  284. # flake8: noqa
  285. """Combine multiple context managers into a single nested
  286. context manager."""
  287. exits = []
  288. vars = []
  289. exc = (None, None, None)
  290. try:
  291. try:
  292. for mgr in managers:
  293. exit = mgr.__exit__
  294. enter = mgr.__enter__
  295. vars.append(enter())
  296. exits.append(exit)
  297. yield vars
  298. except:
  299. exc = sys.exc_info()
  300. finally:
  301. while exits:
  302. exit = exits.pop()
  303. try:
  304. if exit(*exc):
  305. exc = (None, None, None)
  306. except:
  307. exc = sys.exc_info()
  308. if exc != (None, None, None):
  309. # Don't rely on sys.exc_info() still containing
  310. # the right information. Another exception may
  311. # have been raised and caught by an exit method
  312. reraise(exc[0], exc[1], exc[2])
  313. finally:
  314. del(exc)
  315. def shufflecycle(it):
  316. it = list(it) # don't modify callers list
  317. shuffle = random.shuffle
  318. for _ in repeat(None):
  319. shuffle(it)
  320. yield it[0]
  321. def entrypoints(namespace):
  322. try:
  323. from pkg_resources import iter_entry_points
  324. except ImportError:
  325. return iter([])
  326. return ((ep, ep.load()) for ep in iter_entry_points(namespace))
  327. class ChannelPromise(object):
  328. def __init__(self, contract):
  329. self.__contract__ = contract
  330. def __call__(self):
  331. try:
  332. return self.__value__
  333. except AttributeError:
  334. value = self.__value__ = self.__contract__()
  335. return value
  336. def __repr__(self):
  337. try:
  338. return repr(self.__value__)
  339. except AttributeError:
  340. return '<promise: 0x{0:x}>'.format(id(self.__contract__))
  341. def escape_regex(p, white=''):
  342. # what's up with re.escape? that code must be neglected or someting
  343. return ''.join(c if c.isalnum() or c in white
  344. else ('\\000' if c == '\000' else '\\' + c)
  345. for c in p)
  346. def fileno(f):
  347. if isinstance(f, numbers.Integral):
  348. return f
  349. return f.fileno()
  350. def maybe_fileno(f):
  351. """Get object fileno, or :const:`None` if not defined."""
  352. try:
  353. return fileno(f)
  354. except FILENO_ERRORS:
  355. pass