1# -*- coding: utf-8 -*- 2# Part of Odoo. See LICENSE file for full copyright and licensing details. 3 4__all__ = ['synchronized', 'lazy_classproperty', 'lazy_property', 5 'classproperty', 'conditional', 'lazy'] 6 7from functools import wraps 8from inspect import getsourcefile 9from json import JSONEncoder 10 11 12class lazy_property(object): 13 """ Decorator for a lazy property of an object, i.e., an object attribute 14 that is determined by the result of a method call evaluated once. To 15 reevaluate the property, simply delete the attribute on the object, and 16 get it again. 17 """ 18 def __init__(self, fget): 19 assert not fget.__name__.startswith('__'),\ 20 "lazy_property does not support mangled names" 21 self.fget = fget 22 23 def __get__(self, obj, cls): 24 if obj is None: 25 return self 26 value = self.fget(obj) 27 setattr(obj, self.fget.__name__, value) 28 return value 29 30 @property 31 def __doc__(self): 32 return self.fget.__doc__ 33 34 @staticmethod 35 def reset_all(obj): 36 """ Reset all lazy properties on the instance `obj`. """ 37 cls = type(obj) 38 obj_dict = vars(obj) 39 for name in list(obj_dict): 40 if isinstance(getattr(cls, name, None), lazy_property): 41 obj_dict.pop(name) 42 43class lazy_classproperty(lazy_property): 44 """ Similar to :class:`lazy_property`, but for classes. """ 45 def __get__(self, obj, cls): 46 val = self.fget(cls) 47 setattr(cls, self.fget.__name__, val) 48 return val 49 50def conditional(condition, decorator): 51 """ Decorator for a conditionally applied decorator. 52 53 Example: 54 55 @conditional(get_config('use_cache'), ormcache) 56 def fn(): 57 pass 58 """ 59 if condition: 60 return decorator 61 else: 62 return lambda fn: fn 63 64def synchronized(lock_attr='_lock'): 65 def decorator(func): 66 @wraps(func) 67 def wrapper(self, *args, **kwargs): 68 lock = getattr(self, lock_attr) 69 try: 70 lock.acquire() 71 return func(self, *args, **kwargs) 72 finally: 73 lock.release() 74 return wrapper 75 return decorator 76 77def frame_codeinfo(fframe, back=0): 78 """ Return a (filename, line) pair for a previous frame . 79 @return (filename, lineno) where lineno is either int or string=='' 80 """ 81 82 try: 83 if not fframe: 84 return "<unknown>", '' 85 for i in range(back): 86 fframe = fframe.f_back 87 try: 88 fname = getsourcefile(fframe) 89 except TypeError: 90 fname = '<builtin>' 91 lineno = fframe.f_lineno or '' 92 return fname, lineno 93 except Exception: 94 return "<unknown>", '' 95 96def compose(a, b): 97 """ Composes the callables ``a`` and ``b``. ``compose(a, b)(*args)`` is 98 equivalent to ``a(b(*args))``. 99 100 Can be used as a decorator by partially applying ``a``:: 101 102 @partial(compose, a) 103 def b(): 104 ... 105 """ 106 @wraps(b) 107 def wrapper(*args, **kwargs): 108 return a(b(*args, **kwargs)) 109 return wrapper 110 111 112class _ClassProperty(property): 113 def __get__(self, cls, owner): 114 return self.fget.__get__(None, owner)() 115 116def classproperty(func): 117 return _ClassProperty(classmethod(func)) 118 119 120class lazy(object): 121 """ A proxy to the (memoized) result of a lazy evaluation:: 122 123 foo = lazy(func, arg) # func(arg) is not called yet 124 bar = foo + 1 # eval func(arg) and add 1 125 baz = foo + 2 # use result of func(arg) and add 2 126 127 """ 128 __slots__ = ['_func', '_args', '_kwargs', '_cached_value'] 129 130 def __init__(self, func, *args, **kwargs): 131 # bypass own __setattr__ 132 object.__setattr__(self, '_func', func) 133 object.__setattr__(self, '_args', args) 134 object.__setattr__(self, '_kwargs', kwargs) 135 136 @property 137 def _value(self): 138 if self._func is not None: 139 value = self._func(*self._args, **self._kwargs) 140 object.__setattr__(self, '_func', None) 141 object.__setattr__(self, '_args', None) 142 object.__setattr__(self, '_kwargs', None) 143 object.__setattr__(self, '_cached_value', value) 144 return self._cached_value 145 146 def __getattr__(self, name): return getattr(self._value, name) 147 def __setattr__(self, name, value): return setattr(self._value, name, value) 148 def __delattr__(self, name): return delattr(self._value, name) 149 150 def __repr__(self): 151 return repr(self._value) if self._func is None else object.__repr__(self) 152 def __str__(self): return str(self._value) 153 def __bytes__(self): return bytes(self._value) 154 def __format__(self, format_spec): return format(self._value, format_spec) 155 156 def __lt__(self, other): return self._value < other 157 def __le__(self, other): return self._value <= other 158 def __eq__(self, other): return self._value == other 159 def __ne__(self, other): return self._value != other 160 def __gt__(self, other): return self._value > other 161 def __ge__(self, other): return self._value >= other 162 163 def __hash__(self): return hash(self._value) 164 def __bool__(self): return bool(self._value) 165 166 def __call__(self, *args, **kwargs): return self._value(*args, **kwargs) 167 168 def __len__(self): return len(self._value) 169 def __getitem__(self, key): return self._value[key] 170 def __missing__(self, key): return self._value.__missing__(key) 171 def __setitem__(self, key, value): self._value[key] = value 172 def __delitem__(self, key): del self._value[key] 173 def __iter__(self): return iter(self._value) 174 def __reversed__(self): return reversed(self._value) 175 def __contains__(self, key): return key in self._value 176 177 def __add__(self, other): return self._value.__add__(other) 178 def __sub__(self, other): return self._value.__sub__(other) 179 def __mul__(self, other): return self._value.__mul__(other) 180 def __matmul__(self, other): return self._value.__matmul__(other) 181 def __truediv__(self, other): return self._value.__truediv__(other) 182 def __floordiv__(self, other): return self._value.__floordiv__(other) 183 def __mod__(self, other): return self._value.__mod__(other) 184 def __divmod__(self, other): return self._value.__divmod__(other) 185 def __pow__(self, other): return self._value.__pow__(other) 186 def __lshift__(self, other): return self._value.__lshift__(other) 187 def __rshift__(self, other): return self._value.__rshift__(other) 188 def __and__(self, other): return self._value.__and__(other) 189 def __xor__(self, other): return self._value.__xor__(other) 190 def __or__(self, other): return self._value.__or__(other) 191 192 def __radd__(self, other): return self._value.__radd__(other) 193 def __rsub__(self, other): return self._value.__rsub__(other) 194 def __rmul__(self, other): return self._value.__rmul__(other) 195 def __rmatmul__(self, other): return self._value.__rmatmul__(other) 196 def __rtruediv__(self, other): return self._value.__rtruediv__(other) 197 def __rfloordiv__(self, other): return self._value.__rfloordiv__(other) 198 def __rmod__(self, other): return self._value.__rmod__(other) 199 def __rdivmod__(self, other): return self._value.__rdivmod__(other) 200 def __rpow__(self, other): return self._value.__rpow__(other) 201 def __rlshift__(self, other): return self._value.__rlshift__(other) 202 def __rrshift__(self, other): return self._value.__rrshift__(other) 203 def __rand__(self, other): return self._value.__rand__(other) 204 def __rxor__(self, other): return self._value.__rxor__(other) 205 def __ror__(self, other): return self._value.__ror__(other) 206 207 def __iadd__(self, other): return self._value.__iadd__(other) 208 def __isub__(self, other): return self._value.__isub__(other) 209 def __imul__(self, other): return self._value.__imul__(other) 210 def __imatmul__(self, other): return self._value.__imatmul__(other) 211 def __itruediv__(self, other): return self._value.__itruediv__(other) 212 def __ifloordiv__(self, other): return self._value.__ifloordiv__(other) 213 def __imod__(self, other): return self._value.__imod__(other) 214 def __ipow__(self, other): return self._value.__ipow__(other) 215 def __ilshift__(self, other): return self._value.__ilshift__(other) 216 def __irshift__(self, other): return self._value.__irshift__(other) 217 def __iand__(self, other): return self._value.__iand__(other) 218 def __ixor__(self, other): return self._value.__ixor__(other) 219 def __ior__(self, other): return self._value.__ior__(other) 220 221 def __neg__(self): return self._value.__neg__() 222 def __pos__(self): return self._value.__pos__() 223 def __abs__(self): return self._value.__abs__() 224 def __invert__(self): return self._value.__invert__() 225 226 def __complex__(self): return complex(self._value) 227 def __int__(self): return int(self._value) 228 def __float__(self): return float(self._value) 229 230 def __index__(self): return self._value.__index__() 231 232 def __round__(self): return self._value.__round__() 233 def __trunc__(self): return self._value.__trunc__() 234 def __floor__(self): return self._value.__floor__() 235 def __ceil__(self): return self._value.__ceil__() 236 237 def __enter__(self): return self._value.__enter__() 238 def __exit__(self, exc_type, exc_value, traceback): 239 return self._value.__exit__(exc_type, exc_value, traceback) 240 241 def __await__(self): return self._value.__await__() 242 def __aiter__(self): return self._value.__aiter__() 243 def __anext__(self): return self._value.__anext__() 244 def __aenter__(self): return self._value.__aenter__() 245 def __aexit__(self, exc_type, exc_value, traceback): 246 return self._value.__aexit__(exc_type, exc_value, traceback) 247