PageRenderTime 24ms CodeModel.GetById 18ms RepoModel.GetById 0ms app.codeStats 0ms

/celery/utils/__init__.py

https://github.com/dctrwatson/celery
Python | 272 lines | 258 code | 6 blank | 8 comment | 0 complexity | 957bd66b301a58bf04d9e5d5b647661d MD5 | raw file
  1. # -*- coding: utf-8 -*-
  2. """
  3. celery.utils
  4. ~~~~~~~~~~~~
  5. Utility functions.
  6. """
  7. from __future__ import absolute_import, print_function
  8. import os
  9. import sys
  10. import traceback
  11. import warnings
  12. import datetime
  13. from functools import partial, wraps
  14. from inspect import getargspec
  15. from pprint import pprint
  16. from kombu.entity import Exchange, Queue
  17. from celery.exceptions import CPendingDeprecationWarning, CDeprecationWarning
  18. from celery.five import StringIO, items, reraise, string_t
  19. from .functional import noop
  20. PENDING_DEPRECATION_FMT = """
  21. {description} is scheduled for deprecation in \
  22. version {deprecation} and removal in version v{removal}. \
  23. {alternative}
  24. """
  25. DEPRECATION_FMT = """
  26. {description} is deprecated and scheduled for removal in
  27. version {removal}. {alternative}
  28. """
  29. #: Billiard sets this when execv is enabled.
  30. #: We use it to find out the name of the original ``__main__``
  31. #: module, so that we can properly rewrite the name of the
  32. #: task to be that of ``App.main``.
  33. MP_MAIN_FILE = os.environ.get('MP_MAIN_FILE') or None
  34. #: Exchange for worker direct queues.
  35. WORKER_DIRECT_EXCHANGE = Exchange('C.dq')
  36. #: Format for worker direct queue names.
  37. WORKER_DIRECT_QUEUE_FORMAT = '{hostname}.dq'
  38. NODENAME_SEP = '@'
  39. def worker_direct(hostname):
  40. if isinstance(hostname, Queue):
  41. return hostname
  42. return Queue(WORKER_DIRECT_QUEUE_FORMAT.format(hostname=hostname),
  43. WORKER_DIRECT_EXCHANGE,
  44. hostname,
  45. auto_delete=True)
  46. def warn_deprecated(description=None, deprecation=None,
  47. removal=None, alternative=None):
  48. ctx = {'description': description,
  49. 'deprecation': deprecation, 'removal': removal,
  50. 'alternative': alternative}
  51. if deprecation is not None:
  52. w = CPendingDeprecationWarning(PENDING_DEPRECATION_FMT.format(**ctx))
  53. else:
  54. w = CDeprecationWarning(DEPRECATION_FMT.format(**ctx))
  55. warnings.warn(w)
  56. def deprecated(description=None, deprecation=None,
  57. removal=None, alternative=None):
  58. def _inner(fun):
  59. @wraps(fun)
  60. def __inner(*args, **kwargs):
  61. from .imports import qualname
  62. warn_deprecated(description=description or qualname(fun),
  63. deprecation=deprecation,
  64. removal=removal,
  65. alternative=alternative)
  66. return fun(*args, **kwargs)
  67. return __inner
  68. return _inner
  69. def lpmerge(L, R):
  70. """In place left precedent dictionary merge.
  71. Keeps values from `L`, if the value in `R` is :const:`None`."""
  72. set = L.__setitem__
  73. [set(k, v) for k, v in items(R) if v is not None]
  74. return L
  75. def is_iterable(obj):
  76. try:
  77. iter(obj)
  78. except TypeError:
  79. return False
  80. return True
  81. def fun_takes_kwargs(fun, kwlist=[]):
  82. """With a function, and a list of keyword arguments, returns arguments
  83. in the list which the function takes.
  84. If the object has an `argspec` attribute that is used instead
  85. of using the :meth:`inspect.getargspec` introspection.
  86. :param fun: The function to inspect arguments of.
  87. :param kwlist: The list of keyword arguments.
  88. Examples
  89. >>> def foo(self, x, y, logfile=None, loglevel=None):
  90. ... return x * y
  91. >>> fun_takes_kwargs(foo, ['logfile', 'loglevel', 'task_id'])
  92. ['logfile', 'loglevel']
  93. >>> def foo(self, x, y, **kwargs):
  94. >>> fun_takes_kwargs(foo, ['logfile', 'loglevel', 'task_id'])
  95. ['logfile', 'loglevel', 'task_id']
  96. """
  97. S = getattr(fun, 'argspec', getargspec(fun))
  98. if S.keywords is not None:
  99. return kwlist
  100. return [kw for kw in kwlist if kw in S.args]
  101. def isatty(fh):
  102. # Fixes bug with mod_wsgi:
  103. # mod_wsgi.Log object has no attribute isatty.
  104. return getattr(fh, 'isatty', None) and fh.isatty()
  105. def cry(): # pragma: no cover
  106. """Return stacktrace of all active threads.
  107. From https://gist.github.com/737056
  108. """
  109. import threading
  110. tmap = {}
  111. main_thread = None
  112. # get a map of threads by their ID so we can print their names
  113. # during the traceback dump
  114. for t in threading.enumerate():
  115. if getattr(t, 'ident', None):
  116. tmap[t.ident] = t
  117. else:
  118. main_thread = t
  119. out = StringIO()
  120. P = partial(print, file=out)
  121. sep = '=' * 49
  122. for tid, frame in items(sys._current_frames()):
  123. thread = tmap.get(tid, main_thread)
  124. if not thread:
  125. # skip old junk (left-overs from a fork)
  126. continue
  127. P('{0.name}'.format(thread))
  128. P(sep)
  129. traceback.print_stack(frame, file=out)
  130. P(sep)
  131. P('LOCAL VARIABLES')
  132. P(sep)
  133. pprint(frame.f_locals, stream=out)
  134. P('\n')
  135. return out.getvalue()
  136. def maybe_reraise():
  137. """Reraise if an exception is currently being handled, or return
  138. otherwise."""
  139. exc_info = sys.exc_info()
  140. try:
  141. if exc_info[2]:
  142. reraise(exc_info[0], exc_info[1], exc_info[2])
  143. finally:
  144. # see http://docs.python.org/library/sys.html#sys.exc_info
  145. del(exc_info)
  146. def strtobool(term, table={'false': False, 'no': False, '0': False,
  147. 'true': True, 'yes': True, '1': True,
  148. 'on': True, 'off': False}):
  149. if isinstance(term, string_t):
  150. try:
  151. return table[term.lower()]
  152. except KeyError:
  153. raise TypeError('Cannot coerce {0!r} to type bool'.format(term))
  154. return term
  155. def jsonify(obj, builtin_types=(int, float, string_t)):
  156. """Transforms object making it suitable for json serialization"""
  157. if obj is None or isinstance(obj, builtin_types):
  158. return obj
  159. elif isinstance(obj, (tuple, list)):
  160. return [jsonify(o) for o in obj]
  161. elif isinstance(obj, dict):
  162. return dict((k, jsonify(v)) for k, v in items(obj))
  163. elif isinstance(obj, datetime.datetime):
  164. # See "Date Time String Format" in the ECMA-262 specification.
  165. r = obj.isoformat()
  166. if obj.microsecond:
  167. r = r[:23] + r[26:]
  168. if r.endswith('+00:00'):
  169. r = r[:-6] + 'Z'
  170. return r
  171. elif isinstance(obj, datetime.date):
  172. return obj.isoformat()
  173. elif isinstance(obj, datetime.time):
  174. r = obj.isoformat()
  175. if obj.microsecond:
  176. r = r[:12]
  177. return r
  178. elif isinstance(obj, datetime.timedelta):
  179. return str(obj)
  180. else:
  181. raise ValueError('Unsupported type: {0!r}'.format(type(obj)))
  182. def gen_task_name(app, name, module_name):
  183. try:
  184. module = sys.modules[module_name]
  185. except KeyError:
  186. # Fix for manage.py shell_plus (Issue #366)
  187. module = None
  188. if module is not None:
  189. module_name = module.__name__
  190. # - If the task module is used as the __main__ script
  191. # - we need to rewrite the module part of the task name
  192. # - to match App.main.
  193. if MP_MAIN_FILE and module.__file__ == MP_MAIN_FILE:
  194. # - see comment about :envvar:`MP_MAIN_FILE` above.
  195. module_name = '__main__'
  196. if module_name == '__main__' and app.main:
  197. return '.'.join([app.main, name])
  198. return '.'.join(p for p in [module_name, name] if p)
  199. def nodename(name, hostname):
  200. return NODENAME_SEP.join((name, hostname))
  201. def nodesplit(nodename):
  202. parts = nodename.split(NODENAME_SEP, 1)
  203. if len(parts) == 1:
  204. return None, parts[0]
  205. return parts
  206. # ------------------------------------------------------------------------ #
  207. # > XXX Compat
  208. from .log import LOG_LEVELS # noqa
  209. from .imports import ( # noqa
  210. qualname as get_full_cls_name, symbol_by_name as get_cls_by_name,
  211. instantiate, import_from_cwd
  212. )
  213. from .functional import chunks, noop # noqa
  214. from kombu.utils import cached_property, kwdict, uuid # noqa
  215. gen_unique_id = uuid