1 from django.utils.functional import Promise
4 class AbstractProxy(object):
5 """Delegates all operations (except ``.__subject__``) to another object"""
8 #def __call__(self, *args, **kw):
9 # return self.__subject__(*args, **kw)
11 def __getattribute__(self, attr, oga=object.__getattribute__):
12 subject = oga(self,'__subject__')
13 if attr=='__subject__':
15 return getattr(subject,attr)
17 def __setattr__(self, attr, val, osa=object.__setattr__):
18 if attr == '__subject__':
21 setattr(self.__subject__, attr, val)
23 def __delattr__(self, attr, oda=object.__delattr__):
24 if attr=='__subject__':
27 delattr(self.__subject__, attr)
29 def __nonzero__(self):
30 return bool(self.__subject__)
32 def __getitem__(self, arg):
33 return self.__subject__[arg]
35 def __setitem__(self, arg, val):
36 self.__subject__[arg] = val
38 def __delitem__(self, arg):
39 del self.__subject__[arg]
41 def __getslice__(self, i, j):
42 return self.__subject__[i:j]
45 def __setslice__(self, i, j, val):
46 self.__subject__[i:j] = val
48 def __delslice__(self, i, j):
49 del self.__subject__[i:j]
51 def __contains__(self, ob):
52 return ob in self.__subject__
54 for name in 'repr str hash len abs complex int long float iter oct hex'.split():
55 exec "def __%s__(self): return %s(self.__subject__)" % (name, name)
57 for name in 'cmp', 'coerce', 'divmod':
58 exec "def __%s__(self,ob): return %s(self.__subject__,ob)" % (name, name)
61 ('lt','<'), ('gt','>'), ('le','<='), ('ge','>='),
62 ('eq','=='), ('ne','!=')
64 exec "def __%s__(self,ob): return self.__subject__ %s ob" % (name, op)
66 for name, op in [('neg','-'), ('pos','+'), ('invert','~')]:
67 exec "def __%s__(self): return %s self.__subject__" % (name, op)
70 ('or','|'), ('and','&'), ('xor','^'), ('lshift','<<'), ('rshift','>>'),
71 ('add','+'), ('sub','-'), ('mul','*'), ('div','/'), ('mod','%'),
72 ('truediv','/'), ('floordiv','//')
75 "def __%(name)s__(self,ob):\n"
76 " return self.__subject__ %(op)s ob\n"
78 "def __r%(name)s__(self,ob):\n"
79 " return ob %(op)s self.__subject__\n"
81 "def __i%(name)s__(self,ob):\n"
82 " self.__subject__ %(op)s=ob\n"
90 def __rdivmod__(self,ob):
91 return divmod(ob, self.__subject__)
93 def __pow__(self, *args):
94 return pow(self.__subject__, *args)
96 def __ipow__(self, ob):
97 self.__subject__ **= ob
100 def __rpow__(self, ob):
101 return pow(ob, self.__subject__)
104 class ObjectProxy(AbstractProxy):
105 """Proxy for a specific object"""
107 __slots__ = "__subject__"
109 def __init__(self, subject):
110 self.__subject__ = subject
113 class CallbackProxy(AbstractProxy):
114 """Proxy for a dynamically-chosen object"""
116 __slots__ = '__callback__'
118 def __init__(self, func):
119 set_callback(self, func)
121 set_callback = CallbackProxy.__callback__.__set__
122 get_callback = CallbackProxy.__callback__.__get__
123 CallbackProxy.__subject__ = property(lambda self, gc=get_callback: gc(self)())
126 class LazyProxy(CallbackProxy):
127 """Proxy for a lazily-obtained object, that is cached on first use"""
128 __slots__ = "__cache__"
130 get_cache = LazyProxy.__cache__.__get__
131 set_cache = LazyProxy.__cache__.__set__
133 def __subject__(self, get_cache=get_cache, set_cache=set_cache):
135 return get_cache(self)
136 except AttributeError:
137 set_cache(self, get_callback(self)())
138 return get_cache(self)
140 LazyProxy.__subject__ = property(__subject__, set_cache)
144 class TemplateSafeLazyProxy(LazyProxy):
146 A version of LazyProxy suitable for use in Django templates.
148 It's important that an ``alters_data`` attribute returns :const:`False`.
151 def __getattribute__(self, attr, *args, **kwargs):
152 if attr == 'alters_data':
154 return LazyProxy.__getattribute__(self, attr, *args, **kwargs)