Coverage for /home/martinb/.local/share/virtualenvs/camcops/lib/python3.6/site-packages/celery/local.py : 15%

Hot-keys on this page
r m x p toggle line displays
j k next/prev highlighted chunk
0 (zero) top of page
1 (one) first highlighted chunk
1# -*- coding: utf-8 -*-
2"""Proxy/PromiseProxy implementation.
4This module contains critical utilities that needs to be loaded as
5soon as possible, and that shall not load any third party modules.
7Parts of this module is Copyright by Werkzeug Team.
8"""
9from __future__ import absolute_import, unicode_literals
11import operator
12import sys
13from functools import reduce
14from importlib import import_module
15from types import ModuleType
17from .five import PY3, bytes_if_py2, items, string, string_t
19__all__ = ('Proxy', 'PromiseProxy', 'try_import', 'maybe_evaluate')
21__module__ = __name__ # used by Proxy class body
24def _default_cls_attr(name, type_, cls_value):
25 # Proxy uses properties to forward the standard
26 # class attributes __module__, __name__ and __doc__ to the real
27 # object, but these needs to be a string when accessed from
28 # the Proxy class directly. This is a hack to make that work.
29 # -- See Issue #1087.
31 def __new__(cls, getter):
32 instance = type_.__new__(cls, cls_value)
33 instance.__getter = getter
34 return instance
36 def __get__(self, obj, cls=None):
37 return self.__getter(obj) if obj is not None else self
39 return type(bytes_if_py2(name), (type_,), {
40 '__new__': __new__, '__get__': __get__,
41 })
44def try_import(module, default=None):
45 """Try to import and return module.
47 Returns None if the module does not exist.
48 """
49 try:
50 return import_module(module)
51 except ImportError:
52 return default
55class Proxy(object):
56 """Proxy to another object."""
58 # Code stolen from werkzeug.local.Proxy.
59 __slots__ = ('__local', '__args', '__kwargs', '__dict__')
61 def __init__(self, local,
62 args=None, kwargs=None, name=None, __doc__=None):
63 object.__setattr__(self, '_Proxy__local', local)
64 object.__setattr__(self, '_Proxy__args', args or ())
65 object.__setattr__(self, '_Proxy__kwargs', kwargs or {})
66 if name is not None:
67 object.__setattr__(self, '__custom_name__', name)
68 if __doc__ is not None:
69 object.__setattr__(self, '__doc__', __doc__)
71 @_default_cls_attr('name', str, __name__)
72 def __name__(self):
73 try:
74 return self.__custom_name__
75 except AttributeError:
76 return self._get_current_object().__name__
78 @_default_cls_attr('qualname', str, __name__)
79 def __qualname__(self):
80 try:
81 return self.__custom_name__
82 except AttributeError:
83 return self._get_current_object().__qualname__
85 @_default_cls_attr('module', str, __module__)
86 def __module__(self):
87 return self._get_current_object().__module__
89 @_default_cls_attr('doc', str, __doc__)
90 def __doc__(self):
91 return self._get_current_object().__doc__
93 def _get_class(self):
94 return self._get_current_object().__class__
96 @property
97 def __class__(self):
98 return self._get_class()
100 def _get_current_object(self):
101 """Get current object.
103 This is useful if you want the real
104 object behind the proxy at a time for performance reasons or because
105 you want to pass the object into a different context.
106 """
107 loc = object.__getattribute__(self, '_Proxy__local')
108 if not hasattr(loc, '__release_local__'):
109 return loc(*self.__args, **self.__kwargs)
110 try: # pragma: no cover
111 # not sure what this is about
112 return getattr(loc, self.__name__)
113 except AttributeError: # pragma: no cover
114 raise RuntimeError('no object bound to {0.__name__}'.format(self))
116 @property
117 def __dict__(self):
118 try:
119 return self._get_current_object().__dict__
120 except RuntimeError: # pragma: no cover
121 raise AttributeError('__dict__')
123 def __repr__(self):
124 try:
125 obj = self._get_current_object()
126 except RuntimeError: # pragma: no cover
127 return '<{0} unbound>'.format(self.__class__.__name__)
128 return repr(obj)
130 def __bool__(self):
131 try:
132 return bool(self._get_current_object())
133 except RuntimeError: # pragma: no cover
134 return False
135 __nonzero__ = __bool__ # Py2
137 def __dir__(self):
138 try:
139 return dir(self._get_current_object())
140 except RuntimeError: # pragma: no cover
141 return []
143 def __getattr__(self, name):
144 if name == '__members__':
145 return dir(self._get_current_object())
146 return getattr(self._get_current_object(), name)
148 def __setitem__(self, key, value):
149 self._get_current_object()[key] = value
151 def __delitem__(self, key):
152 del self._get_current_object()[key]
154 def __setslice__(self, i, j, seq):
155 self._get_current_object()[i:j] = seq
157 def __delslice__(self, i, j):
158 del self._get_current_object()[i:j]
160 def __setattr__(self, name, value):
161 setattr(self._get_current_object(), name, value)
163 def __delattr__(self, name):
164 delattr(self._get_current_object(), name)
166 def __str__(self):
167 return str(self._get_current_object())
169 def __lt__(self, other):
170 return self._get_current_object() < other
172 def __le__(self, other):
173 return self._get_current_object() <= other
175 def __eq__(self, other):
176 return self._get_current_object() == other
178 def __ne__(self, other):
179 return self._get_current_object() != other
181 def __gt__(self, other):
182 return self._get_current_object() > other
184 def __ge__(self, other):
185 return self._get_current_object() >= other
187 def __hash__(self):
188 return hash(self._get_current_object())
190 def __call__(self, *a, **kw):
191 return self._get_current_object()(*a, **kw)
193 def __len__(self):
194 return len(self._get_current_object())
196 def __getitem__(self, i):
197 return self._get_current_object()[i]
199 def __iter__(self):
200 return iter(self._get_current_object())
202 def __contains__(self, i):
203 return i in self._get_current_object()
205 def __getslice__(self, i, j):
206 return self._get_current_object()[i:j]
208 def __add__(self, other):
209 return self._get_current_object() + other
211 def __sub__(self, other):
212 return self._get_current_object() - other
214 def __mul__(self, other):
215 return self._get_current_object() * other
217 def __floordiv__(self, other):
218 return self._get_current_object() // other
220 def __mod__(self, other):
221 return self._get_current_object() % other
223 def __divmod__(self, other):
224 return self._get_current_object().__divmod__(other)
226 def __pow__(self, other):
227 return self._get_current_object() ** other
229 def __lshift__(self, other):
230 return self._get_current_object() << other
232 def __rshift__(self, other):
233 return self._get_current_object() >> other
235 def __and__(self, other):
236 return self._get_current_object() & other
238 def __xor__(self, other):
239 return self._get_current_object() ^ other
241 def __or__(self, other):
242 return self._get_current_object() | other
244 def __div__(self, other):
245 return self._get_current_object().__div__(other)
247 def __truediv__(self, other):
248 return self._get_current_object().__truediv__(other)
250 def __neg__(self):
251 return -(self._get_current_object())
253 def __pos__(self):
254 return +(self._get_current_object())
256 def __abs__(self):
257 return abs(self._get_current_object())
259 def __invert__(self):
260 return ~(self._get_current_object())
262 def __complex__(self):
263 return complex(self._get_current_object())
265 def __int__(self):
266 return int(self._get_current_object())
268 def __float__(self):
269 return float(self._get_current_object())
271 def __oct__(self):
272 return oct(self._get_current_object())
274 def __hex__(self):
275 return hex(self._get_current_object())
277 def __index__(self):
278 return self._get_current_object().__index__()
280 def __coerce__(self, other):
281 return self._get_current_object().__coerce__(other)
283 def __enter__(self):
284 return self._get_current_object().__enter__()
286 def __exit__(self, *a, **kw):
287 return self._get_current_object().__exit__(*a, **kw)
289 def __reduce__(self):
290 return self._get_current_object().__reduce__()
292 if not PY3: # pragma: no cover
293 def __cmp__(self, other):
294 return cmp(self._get_current_object(), other) # noqa
296 def __long__(self):
297 return long(self._get_current_object()) # noqa
299 def __unicode__(self):
300 try:
301 return string(self._get_current_object())
302 except RuntimeError: # pragma: no cover
303 return repr(self)
306class PromiseProxy(Proxy):
307 """Proxy that evaluates object once.
309 :class:`Proxy` will evaluate the object each time, while the
310 promise will only evaluate it once.
311 """
313 __slots__ = ('__pending__', '__weakref__')
315 def _get_current_object(self):
316 try:
317 return object.__getattribute__(self, '__thing')
318 except AttributeError:
319 return self.__evaluate__()
321 def __then__(self, fun, *args, **kwargs):
322 if self.__evaluated__():
323 return fun(*args, **kwargs)
324 from collections import deque
325 try:
326 pending = object.__getattribute__(self, '__pending__')
327 except AttributeError:
328 pending = None
329 if pending is None:
330 pending = deque()
331 object.__setattr__(self, '__pending__', pending)
332 pending.append((fun, args, kwargs))
334 def __evaluated__(self):
335 try:
336 object.__getattribute__(self, '__thing')
337 except AttributeError:
338 return False
339 return True
341 def __maybe_evaluate__(self):
342 return self._get_current_object()
344 def __evaluate__(self,
345 _clean=('_Proxy__local',
346 '_Proxy__args',
347 '_Proxy__kwargs')):
348 try:
349 thing = Proxy._get_current_object(self)
350 except Exception:
351 raise
352 else:
353 object.__setattr__(self, '__thing', thing)
354 for attr in _clean:
355 try:
356 object.__delattr__(self, attr)
357 except AttributeError: # pragma: no cover
358 # May mask errors so ignore
359 pass
360 try:
361 pending = object.__getattribute__(self, '__pending__')
362 except AttributeError:
363 pass
364 else:
365 try:
366 while pending:
367 fun, args, kwargs = pending.popleft()
368 fun(*args, **kwargs)
369 finally:
370 try:
371 object.__delattr__(self, '__pending__')
372 except AttributeError: # pragma: no cover
373 pass
374 return thing
377def maybe_evaluate(obj):
378 """Attempt to evaluate promise, even if obj is not a promise."""
379 try:
380 return obj.__maybe_evaluate__()
381 except AttributeError:
382 return obj
384# ############# Module Generation ##########################
386# Utilities to dynamically
387# recreate modules, either for lazy loading or
388# to create old modules at runtime instead of
389# having them litter the source tree.
391# import fails in python 2.5. fallback to reduce in stdlib
394MODULE_DEPRECATED = """
395The module %s is deprecated and will be removed in a future version.
396"""
398DEFAULT_ATTRS = {'__file__', '__path__', '__doc__', '__all__'}
400# im_func is no longer available in Py3.
401# instead the unbound method itself can be used.
402if sys.version_info[0] == 3: # pragma: no cover
403 def fun_of_method(method):
404 return method
405else:
406 def fun_of_method(method): # noqa
407 return method.im_func
410def getappattr(path):
411 """Get attribute from current_app recursively.
413 Example: ``getappattr('amqp.get_task_consumer')``.
415 """
416 from celery import current_app
417 return current_app._rgetattr(path)
420def _compat_periodic_task_decorator(*args, **kwargs):
421 from celery.task import periodic_task
422 return periodic_task(*args, **kwargs)
425COMPAT_MODULES = {
426 'celery': {
427 'execute': {
428 'send_task': 'send_task',
429 },
430 'decorators': {
431 'task': 'task',
432 'periodic_task': _compat_periodic_task_decorator,
433 },
434 'log': {
435 'get_default_logger': 'log.get_default_logger',
436 'setup_logger': 'log.setup_logger',
437 'setup_logging_subsystem': 'log.setup_logging_subsystem',
438 'redirect_stdouts_to_logger': 'log.redirect_stdouts_to_logger',
439 },
440 'messaging': {
441 'TaskConsumer': 'amqp.TaskConsumer',
442 'establish_connection': 'connection',
443 'get_consumer_set': 'amqp.TaskConsumer',
444 },
445 'registry': {
446 'tasks': 'tasks',
447 },
448 },
449 'celery.task': {
450 'control': {
451 'broadcast': 'control.broadcast',
452 'rate_limit': 'control.rate_limit',
453 'time_limit': 'control.time_limit',
454 'ping': 'control.ping',
455 'revoke': 'control.revoke',
456 'discard_all': 'control.purge',
457 'inspect': 'control.inspect',
458 },
459 'schedules': 'celery.schedules',
460 'chords': 'celery.canvas',
461 }
462}
464#: We exclude these from dir(celery)
465DEPRECATED_ATTRS = set(COMPAT_MODULES['celery'].keys()) | {'subtask'}
468class class_property(object):
470 def __init__(self, getter=None, setter=None):
471 if getter is not None and not isinstance(getter, classmethod):
472 getter = classmethod(getter)
473 if setter is not None and not isinstance(setter, classmethod):
474 setter = classmethod(setter)
475 self.__get = getter
476 self.__set = setter
478 info = getter.__get__(object) # just need the info attrs.
479 self.__doc__ = info.__doc__
480 self.__name__ = info.__name__
481 self.__module__ = info.__module__
483 def __get__(self, obj, type=None):
484 if obj and type is None:
485 type = obj.__class__
486 return self.__get.__get__(obj, type)()
488 def __set__(self, obj, value):
489 if obj is None:
490 return self
491 return self.__set.__get__(obj)(value)
493 def setter(self, setter):
494 return self.__class__(self.__get, setter)
497def reclassmethod(method):
498 return classmethod(fun_of_method(method))
501class LazyModule(ModuleType):
502 _compat_modules = ()
503 _all_by_module = {}
504 _direct = {}
505 _object_origins = {}
507 def __getattr__(self, name):
508 if name in self._object_origins:
509 module = __import__(self._object_origins[name], None, None, [name])
510 for item in self._all_by_module[module.__name__]:
511 setattr(self, item, getattr(module, item))
512 return getattr(module, name)
513 elif name in self._direct: # pragma: no cover
514 module = __import__(self._direct[name], None, None, [name])
515 setattr(self, name, module)
516 return module
517 return ModuleType.__getattribute__(self, name)
519 def __dir__(self):
520 return [
521 attr for attr in set(self.__all__) | DEFAULT_ATTRS
522 if attr not in DEPRECATED_ATTRS
523 ]
525 def __reduce__(self):
526 return import_module, (self.__name__,)
529def create_module(name, attrs, cls_attrs=None, pkg=None,
530 base=LazyModule, prepare_attr=None):
531 fqdn = '.'.join([pkg.__name__, name]) if pkg else name
532 cls_attrs = {} if cls_attrs is None else cls_attrs
533 pkg, _, modname = name.rpartition('.')
534 cls_attrs['__module__'] = pkg
536 attrs = {
537 attr_name: (prepare_attr(attr) if prepare_attr else attr)
538 for attr_name, attr in items(attrs)
539 }
540 module = sys.modules[fqdn] = type(
541 bytes_if_py2(modname), (base,), cls_attrs)(bytes_if_py2(name))
542 module.__dict__.update(attrs)
543 return module
546def recreate_module(name, compat_modules=None, by_module=None, direct=None,
547 base=LazyModule, **attrs):
548 compat_modules = compat_modules or ()
549 by_module = by_module or {}
550 direct = direct or {}
551 old_module = sys.modules[name]
552 origins = get_origins(by_module)
553 compat_modules = COMPAT_MODULES.get(name, ())
555 _all = tuple(set(reduce(
556 operator.add,
557 [tuple(v) for v in [compat_modules, origins, direct, attrs]],
558 )))
559 if sys.version_info[0] < 3:
560 _all = [s.encode() for s in _all]
561 cattrs = {
562 '_compat_modules': compat_modules,
563 '_all_by_module': by_module, '_direct': direct,
564 '_object_origins': origins,
565 '__all__': _all,
566 }
567 new_module = create_module(name, attrs, cls_attrs=cattrs, base=base)
568 new_module.__dict__.update({
569 mod: get_compat_module(new_module, mod) for mod in compat_modules
570 })
571 return old_module, new_module
574def get_compat_module(pkg, name):
575 def prepare(attr):
576 if isinstance(attr, string_t):
577 return Proxy(getappattr, (attr,))
578 return attr
580 attrs = COMPAT_MODULES[pkg.__name__][name]
581 if isinstance(attrs, string_t):
582 fqdn = '.'.join([pkg.__name__, name])
583 module = sys.modules[fqdn] = import_module(attrs)
584 return module
585 attrs[bytes_if_py2('__all__')] = list(attrs)
586 return create_module(name, dict(attrs), pkg=pkg, prepare_attr=prepare)
589def get_origins(defs):
590 origins = {}
591 for module, attrs in items(defs):
592 origins.update({attr: module for attr in attrs})
593 return origins