__compat__.py 6.1 KB

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