* Added pagination
[django-tables2.git] / django_tables / proxies.py
1 from django.utils.functional import Promise
2
3
4 class AbstractProxy(object):
5     """Delegates all operations (except ``.__subject__``) to another object"""
6     __slots__ = ()
7
8     #def __call__(self, *args, **kw):
9     #    return self.__subject__(*args, **kw)
10
11     def __getattribute__(self, attr, oga=object.__getattribute__):
12         subject = oga(self,'__subject__')
13         if attr=='__subject__':
14             return subject
15         return getattr(subject,attr)
16
17     def __setattr__(self, attr, val, osa=object.__setattr__):
18         if attr == '__subject__':
19             osa(self, attr, val)
20         else:
21             setattr(self.__subject__, attr, val)
22
23     def __delattr__(self, attr, oda=object.__delattr__):
24         if attr=='__subject__':
25             oda(self,attr)
26         else:
27             delattr(self.__subject__, attr)
28
29     def __nonzero__(self):
30         return bool(self.__subject__)
31
32     def __getitem__(self, arg):
33         return self.__subject__[arg]
34
35     def __setitem__(self, arg, val):
36         self.__subject__[arg] = val
37
38     def __delitem__(self, arg):
39         del self.__subject__[arg]
40
41     def __getslice__(self, i, j):
42         return self.__subject__[i:j]
43
44
45     def __setslice__(self, i, j, val):
46         self.__subject__[i:j] = val
47
48     def __delslice__(self, i, j):
49         del self.__subject__[i:j]
50
51     def __contains__(self, ob):
52         return ob in self.__subject__
53
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)
56
57     for name in 'cmp', 'coerce', 'divmod':
58         exec "def __%s__(self,ob): return %s(self.__subject__,ob)" % (name, name)
59
60     for name, op in [
61         ('lt','<'), ('gt','>'), ('le','<='), ('ge','>='),
62         ('eq','=='), ('ne','!=')
63     ]:
64         exec "def __%s__(self,ob): return self.__subject__ %s ob" % (name, op)
65
66     for name, op in [('neg','-'), ('pos','+'), ('invert','~')]:
67         exec "def __%s__(self): return %s self.__subject__" % (name, op)
68
69     for name, op in [
70         ('or','|'),  ('and','&'), ('xor','^'), ('lshift','<<'), ('rshift','>>'),
71         ('add','+'), ('sub','-'), ('mul','*'), ('div','/'), ('mod','%'),
72         ('truediv','/'), ('floordiv','//')
73     ]:
74         exec (
75             "def __%(name)s__(self,ob):\n"
76             "    return self.__subject__ %(op)s ob\n"
77             "\n"
78             "def __r%(name)s__(self,ob):\n"
79             "    return ob %(op)s self.__subject__\n"
80             "\n"
81             "def __i%(name)s__(self,ob):\n"
82             "    self.__subject__ %(op)s=ob\n"
83             "    return self\n"
84         )  % locals()
85
86     del name, op
87
88     # Oddball signatures
89
90     def __rdivmod__(self,ob):
91         return divmod(ob, self.__subject__)
92
93     def __pow__(self, *args):
94         return pow(self.__subject__, *args)
95
96     def __ipow__(self, ob):
97         self.__subject__ **= ob
98         return self
99
100     def __rpow__(self, ob):
101         return pow(ob, self.__subject__)
102
103
104 class ObjectProxy(AbstractProxy):
105     """Proxy for a specific object"""
106
107     __slots__ = "__subject__"
108
109     def __init__(self, subject):
110         self.__subject__ = subject
111
112
113 class CallbackProxy(AbstractProxy):
114     """Proxy for a dynamically-chosen object"""
115
116     __slots__ = '__callback__'
117
118     def __init__(self, func):
119         set_callback(self, func)
120
121 set_callback = CallbackProxy.__callback__.__set__
122 get_callback = CallbackProxy.__callback__.__get__
123 CallbackProxy.__subject__ = property(lambda self, gc=get_callback: gc(self)())
124
125
126 class LazyProxy(CallbackProxy):
127     """Proxy for a lazily-obtained object, that is cached on first use"""
128     __slots__ = "__cache__"
129
130 get_cache = LazyProxy.__cache__.__get__
131 set_cache = LazyProxy.__cache__.__set__
132
133 def __subject__(self, get_cache=get_cache, set_cache=set_cache):
134     try:
135         return get_cache(self)
136     except AttributeError:
137         set_cache(self, get_callback(self)())
138         return get_cache(self)
139
140 LazyProxy.__subject__ = property(__subject__, set_cache)
141 del __subject__
142
143
144 class TemplateSafeLazyProxy(LazyProxy):
145     """
146     A version of LazyProxy suitable for use in Django templates.
147
148     It's important that an ``alters_data`` attribute returns :const:`False`.
149
150     """
151     def __getattribute__(self, attr, *args, **kwargs):
152         if attr == 'alters_data':
153             return False
154         return LazyProxy.__getattribute__(self, attr, *args, **kwargs)