__compat__.py 6.2 KB

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