__init__.py 7.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247
  1. from __future__ import generators
  2. """
  3. Utility functions
  4. """
  5. import time
  6. import operator
  7. try:
  8. import ctypes
  9. except ImportError:
  10. ctypes = None
  11. import importlib
  12. from uuid import UUID, uuid4, _uuid_generate_random
  13. from inspect import getargspec
  14. from itertools import islice
  15. from carrot.utils import rpartition
  16. from billiard.utils.functional import curry
  17. from celery.utils.compat import all, any, defaultdict
  18. from celery.utils.timeutils import timedelta_seconds # was here before
  19. def noop(*args, **kwargs):
  20. """No operation.
  21. Takes any arguments/keyword arguments and does nothing.
  22. """
  23. pass
  24. def first(predicate, iterable):
  25. """Returns the first element in ``iterable`` that ``predicate`` returns a
  26. ``True`` value for."""
  27. for item in iterable:
  28. if predicate(item):
  29. return item
  30. def chunks(it, n):
  31. """Split an iterator into chunks with ``n`` elements each.
  32. Examples
  33. # n == 2
  34. >>> x = chunks(iter([0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]), 2)
  35. >>> list(x)
  36. [[0, 1], [2, 3], [4, 5], [6, 7], [8, 9], [10]]
  37. # n == 3
  38. >>> x = chunks(iter([0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]), 3)
  39. >>> list(x)
  40. [[0, 1, 2], [3, 4, 5], [6, 7, 8], [9, 10]]
  41. """
  42. for first in it:
  43. yield [first] + list(islice(it, n - 1))
  44. def gen_unique_id():
  45. """Generate a unique id, having - hopefully - a very small chance of
  46. collission.
  47. For now this is provided by :func:`uuid.uuid4`.
  48. """
  49. # Workaround for http://bugs.python.org/issue4607
  50. if ctypes and _uuid_generate_random:
  51. buffer = ctypes.create_string_buffer(16)
  52. _uuid_generate_random(buffer)
  53. return str(UUID(bytes=buffer.raw))
  54. return str(uuid4())
  55. def padlist(container, size, default=None):
  56. """Pad list with default elements.
  57. Examples:
  58. >>> first, last, city = padlist(["George", "Constanza", "NYC"], 3)
  59. ("George", "Constanza", "NYC")
  60. >>> first, last, city = padlist(["George", "Constanza"], 3)
  61. ("George", "Constanza", None)
  62. >>> first, last, city, planet = padlist(["George", "Constanza",
  63. "NYC"], 4, default="Earth")
  64. ("George", "Constanza", "NYC", "Earth")
  65. """
  66. return list(container)[:size] + [default] * (size - len(container))
  67. def is_iterable(obj):
  68. try:
  69. iter(obj)
  70. except TypeError:
  71. return False
  72. return True
  73. def mitemgetter(*items):
  74. """Like :func:`operator.itemgetter` but returns ``None`` on missing items
  75. instead of raising :exc:`KeyError`."""
  76. return lambda container: map(container.get, items)
  77. def mattrgetter(*attrs):
  78. """Like :func:`operator.itemgetter` but returns ``None`` on missing
  79. attributes instead of raising :exc:`AttributeError`."""
  80. return lambda obj: dict((attr, getattr(obj, attr, None))
  81. for attr in attrs)
  82. def get_full_cls_name(cls):
  83. """With a class, get its full module and class name."""
  84. return ".".join([cls.__module__,
  85. cls.__name__])
  86. def repeatlast(it):
  87. """Iterate over all elements in the iterator, and when its exhausted
  88. yield the last value infinitely."""
  89. for item in it:
  90. yield item
  91. while 1: # pragma: no cover
  92. yield item
  93. def retry_over_time(fun, catch, args=[], kwargs={}, errback=noop,
  94. max_retries=None, interval_start=2, interval_step=2, interval_max=30):
  95. """Retry the function over and over until max retries is exceeded.
  96. For each retry we sleep a for a while before we try again, this interval
  97. is increased for every retry until the max seconds is reached.
  98. :param fun: The function to try
  99. :param catch: Exceptions to catch, can be either tuple or a single
  100. exception class.
  101. :keyword args: Positional arguments passed on to the function.
  102. :keyword kwargs: Keyword arguments passed on to the function.
  103. :keyword errback: Callback for when an exception in ``catch`` is raised.
  104. The callback must take two arguments: ``exc`` and ``interval``, where
  105. ``exc`` is the exception instance, and ``interval`` is the time in
  106. seconds to sleep next..
  107. :keyword max_retries: Maximum number of retries before we give up.
  108. If this is not set, we will retry forever.
  109. :keyword interval_start: How long (in seconds) we start sleeping between
  110. retries.
  111. :keyword interval_step: By how much the interval is increased for each
  112. retry.
  113. :keyword interval_max: Maximum number of seconds to sleep between retries.
  114. """
  115. retries = 0
  116. interval_range = xrange(interval_start,
  117. interval_max + interval_start,
  118. interval_step)
  119. for interval in repeatlast(interval_range):
  120. try:
  121. retval = fun(*args, **kwargs)
  122. except catch, exc:
  123. if max_retries and retries > max_retries:
  124. raise
  125. errback(exc, interval)
  126. retries += 1
  127. time.sleep(interval)
  128. else:
  129. return retval
  130. def fun_takes_kwargs(fun, kwlist=[]):
  131. """With a function, and a list of keyword arguments, returns arguments
  132. in the list which the function takes.
  133. If the object has an ``argspec`` attribute that is used instead
  134. of using the :meth:`inspect.getargspec`` introspection.
  135. :param fun: The function to inspect arguments of.
  136. :param kwlist: The list of keyword arguments.
  137. Examples
  138. >>> def foo(self, x, y, logfile=None, loglevel=None):
  139. ... return x * y
  140. >>> fun_takes_kwargs(foo, ["logfile", "loglevel", "task_id"])
  141. ["logfile", "loglevel"]
  142. >>> def foo(self, x, y, **kwargs):
  143. >>> fun_takes_kwargs(foo, ["logfile", "loglevel", "task_id"])
  144. ["logfile", "loglevel", "task_id"]
  145. """
  146. argspec = getattr(fun, "argspec", getargspec(fun))
  147. args, _varargs, keywords, _defaults = argspec
  148. if keywords != None:
  149. return kwlist
  150. return filter(curry(operator.contains, args), kwlist)
  151. def get_cls_by_name(name, aliases={}):
  152. """Get class by name.
  153. The name should be the full dot-separated path to the class::
  154. modulename.ClassName
  155. Example::
  156. celery.worker.pool.TaskPool
  157. ^- class name
  158. If ``aliases`` is provided, a dict containing short name/long name
  159. mappings, the name is looked up in the aliases first.
  160. Examples:
  161. >>> get_cls_by_name("celery.worker.pool.TaskPool")
  162. <class 'celery.worker.pool.TaskPool'>
  163. >>> get_cls_by_name("default", {
  164. ... "default": "celery.worker.pool.TaskPool"})
  165. <class 'celery.worker.pool.TaskPool'>
  166. # Does not try to look up non-string names.
  167. >>> from celery.worker.pool import TaskPool
  168. >>> get_cls_by_name(TaskPool) is TaskPool
  169. True
  170. """
  171. if not isinstance(name, basestring):
  172. return name # already a class
  173. name = aliases.get(name) or name
  174. module_name, _, cls_name = rpartition(name, ".")
  175. module = importlib.import_module(module_name)
  176. return getattr(module, cls_name)
  177. def instantiate(name, *args, **kwargs):
  178. """Instantiate class by name.
  179. See :func:`get_cls_by_name`.
  180. """
  181. return get_cls_by_name(name)(*args, **kwargs)