__compat__.py 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200
  1. # -*- coding: utf-8 -*-
  2. """
  3. celery.__compat__
  4. ~~~~~~~~~~~~~~~~~
  5. This module contains utilities to dynamically
  6. recreate modules, either for lazy loading or
  7. to create old modules at runtime instead of
  8. having them litter the source tree.
  9. """
  10. from __future__ import absolute_import
  11. import operator
  12. import sys
  13. from functools import reduce
  14. from future_builtins import map
  15. from importlib import import_module
  16. from types import ModuleType
  17. from .local import Proxy
  18. MODULE_DEPRECATED = """
  19. The module %s is deprecated and will be removed in a future version.
  20. """
  21. DEFAULT_ATTRS = set(['__file__', '__path__', '__doc__', '__all__'])
  22. # im_func is no longer available in Py3.
  23. # instead the unbound method itself can be used.
  24. if sys.version_info[0] == 3: # pragma: no cover
  25. def fun_of_method(method):
  26. return method
  27. else:
  28. def fun_of_method(method): # noqa
  29. return method.im_func
  30. def getappattr(path):
  31. """Gets attribute from the current_app recursively,
  32. e.g. getappattr('amqp.get_task_consumer')``."""
  33. from celery import current_app
  34. return current_app._rgetattr(path)
  35. def _compat_task_decorator(*args, **kwargs):
  36. from celery import current_app
  37. kwargs.setdefault('accept_magic_kwargs', True)
  38. return current_app.task(*args, **kwargs)
  39. def _compat_periodic_task_decorator(*args, **kwargs):
  40. from celery.task import periodic_task
  41. kwargs.setdefault('accept_magic_kwargs', True)
  42. return periodic_task(*args, **kwargs)
  43. COMPAT_MODULES = {
  44. 'celery': {
  45. 'execute': {
  46. 'send_task': 'send_task',
  47. },
  48. 'decorators': {
  49. 'task': _compat_task_decorator,
  50. 'periodic_task': _compat_periodic_task_decorator,
  51. },
  52. 'log': {
  53. 'get_default_logger': 'log.get_default_logger',
  54. 'setup_logger': 'log.setup_logger',
  55. 'setup_loggig_subsystem': 'log.setup_logging_subsystem',
  56. 'redirect_stdouts_to_logger': 'log.redirect_stdouts_to_logger',
  57. },
  58. 'messaging': {
  59. 'TaskPublisher': 'amqp.TaskPublisher',
  60. 'TaskConsumer': 'amqp.TaskConsumer',
  61. 'establish_connection': 'connection',
  62. 'with_connection': 'with_default_connection',
  63. 'get_consumer_set': 'amqp.TaskConsumer',
  64. },
  65. 'registry': {
  66. 'tasks': 'tasks',
  67. },
  68. },
  69. 'celery.task': {
  70. 'control': {
  71. 'broadcast': 'control.broadcast',
  72. 'rate_limit': 'control.rate_limit',
  73. 'time_limit': 'control.time_limit',
  74. 'ping': 'control.ping',
  75. 'revoke': 'control.revoke',
  76. 'discard_all': 'control.purge',
  77. 'inspect': 'control.inspect',
  78. },
  79. 'schedules': 'celery.schedules',
  80. 'chords': 'celery.canvas',
  81. }
  82. }
  83. class class_property(object):
  84. def __init__(self, fget=None, fset=None):
  85. assert fget and isinstance(fget, classmethod)
  86. assert isinstance(fset, classmethod) if fset else True
  87. self.__get = fget
  88. self.__set = fset
  89. info = fget.__get__(object) # just need the info attrs.
  90. self.__doc__ = info.__doc__
  91. self.__name__ = info.__name__
  92. self.__module__ = info.__module__
  93. def __get__(self, obj, type=None):
  94. if obj and type is None:
  95. type = obj.__class__
  96. return self.__get.__get__(obj, type)()
  97. def __set__(self, obj, value):
  98. if obj is None:
  99. return self
  100. return self.__set.__get__(obj)(value)
  101. def reclassmethod(method):
  102. return classmethod(fun_of_method(method))
  103. class MagicModule(ModuleType):
  104. _compat_modules = ()
  105. _all_by_module = {}
  106. _direct = {}
  107. _object_origins = {}
  108. def __getattr__(self, name):
  109. if name in self._object_origins:
  110. module = __import__(self._object_origins[name], None, None, [name])
  111. for item in self._all_by_module[module.__name__]:
  112. setattr(self, item, getattr(module, item))
  113. return getattr(module, name)
  114. elif name in self._direct:
  115. module = __import__(self._direct[name], None, None, [name])
  116. setattr(self, name, module)
  117. return module
  118. return ModuleType.__getattribute__(self, name)
  119. def __dir__(self):
  120. return list(set(self.__all__) | DEFAULT_ATTRS)
  121. def create_module(name, attrs, cls_attrs=None, pkg=None, base=MagicModule,
  122. prepare_attr=None):
  123. fqdn = '.'.join([pkg.__name__, name]) if pkg else name
  124. cls_attrs = {} if cls_attrs is None else cls_attrs
  125. attrs = dict((attr_name, prepare_attr(attr) if prepare_attr else attr)
  126. for attr_name, attr in attrs.iteritems())
  127. module = sys.modules[fqdn] = type(name, (base, ), cls_attrs)(fqdn)
  128. module.__dict__.update(attrs)
  129. return module
  130. def recreate_module(name, compat_modules=(), by_module={}, direct={},
  131. base=MagicModule, **attrs):
  132. old_module = sys.modules[name]
  133. origins = get_origins(by_module)
  134. compat_modules = COMPAT_MODULES.get(name, ())
  135. cattrs = dict(_compat_modules=compat_modules,
  136. _all_by_module=by_module, _direct=direct,
  137. _object_origins=origins,
  138. __all__=tuple(set(reduce(operator.add, map(tuple, [
  139. compat_modules, origins, direct, attrs])))))
  140. new_module = create_module(name, attrs, cls_attrs=cattrs, base=base)
  141. new_module.__dict__.update(dict((mod, get_compat_module(new_module, mod))
  142. for mod in compat_modules))
  143. return old_module, new_module
  144. def get_compat_module(pkg, name):
  145. def prepare(attr):
  146. if isinstance(attr, basestring):
  147. return Proxy(getappattr, (attr, ))
  148. return attr
  149. attrs = COMPAT_MODULES[pkg.__name__][name]
  150. if isinstance(attrs, basestring):
  151. fqdn = '.'.join([pkg.__name__, name])
  152. module = sys.modules[fqdn] = import_module(attrs)
  153. return module
  154. attrs['__all__'] = list(attrs)
  155. return create_module(name, dict(attrs), pkg=pkg, prepare_attr=prepare)
  156. def get_origins(defs):
  157. origins = {}
  158. for module, items in defs.iteritems():
  159. origins.update(dict((item, module) for item in items))
  160. return origins