Package Dropbox :: Package web2py :: Package gluon :: Module storage
[hide private]
[frames] | no frames]

Source Code for Module Dropbox.web2py.gluon.storage

  1  #!/usr/bin/env python 
  2  # -*- coding: utf-8 -*- 
  3   
  4  """ 
  5  This file is part of the web2py Web Framework 
  6  Copyrighted by Massimo Di Pierro <mdipierro@cs.depaul.edu> 
  7  License: LGPLv3 (http://www.gnu.org/licenses/lgpl.html) 
  8   
  9  Provides: 
 10   
 11  - List; like list but returns None instead of IndexOutOfBounds 
 12  - Storage; like dictionary allowing also for `obj.foo` for `obj['foo']` 
 13  """ 
 14   
 15  import cPickle 
 16  import portalocker 
 17   
 18  __all__ = ['List', 'Storage', 'Settings', 'Messages', 
 19             'StorageList', 'load_storage', 'save_storage'] 
 20   
 21   
22 -class Storage(dict):
23 """ 24 A Storage object is like a dictionary except `obj.foo` can be used 25 in addition to `obj['foo']`, and setting obj.foo = None deletes item foo. 26 27 >>> o = Storage(a=1) 28 >>> print o.a 29 1 30 31 >>> o['a'] 32 1 33 34 >>> o.a = 2 35 >>> print o['a'] 36 2 37 38 >>> del o.a 39 >>> print o.a 40 None 41 """ 42 __slots__ = () 43 __setattr__ = dict.__setitem__ 44 __delattr__ = dict.__delitem__ 45 __getitem__ = dict.get 46 __getattr__ = dict.get 47 __repr__ = lambda self: '<Storage %s>' % dict.__repr__(self) 48 # http://stackoverflow.com/questions/5247250/why-does-pickle-getstate-accept-as-a-return-value-the-very-instance-it-requi 49 __getstate__ = lambda self: None 50 __copy__ = lambda self: Storage(self) 51
52 - def getlist(self, key):
53 """ 54 Return a Storage value as a list. 55 56 If the value is a list it will be returned as-is. 57 If object is None, an empty list will be returned. 58 Otherwise, [value] will be returned. 59 60 Example output for a query string of ?x=abc&y=abc&y=def 61 >>> request = Storage() 62 >>> request.vars = Storage() 63 >>> request.vars.x = 'abc' 64 >>> request.vars.y = ['abc', 'def'] 65 >>> request.vars.getlist('x') 66 ['abc'] 67 >>> request.vars.getlist('y') 68 ['abc', 'def'] 69 >>> request.vars.getlist('z') 70 [] 71 """ 72 value = self.get(key, []) 73 if value is None or isinstance(value, (list, tuple)): 74 return value 75 else: 76 return [value]
77
78 - def getfirst(self, key, default=None):
79 """ 80 Return the first or only value when given a request.vars-style key. 81 82 If the value is a list, its first item will be returned; 83 otherwise, the value will be returned as-is. 84 85 Example output for a query string of ?x=abc&y=abc&y=def 86 >>> request = Storage() 87 >>> request.vars = Storage() 88 >>> request.vars.x = 'abc' 89 >>> request.vars.y = ['abc', 'def'] 90 >>> request.vars.getfirst('x') 91 'abc' 92 >>> request.vars.getfirst('y') 93 'abc' 94 >>> request.vars.getfirst('z') 95 """ 96 values = self.getlist(key) 97 return values[0] if values else default
98
99 - def getlast(self, key, default=None):
100 """ 101 Returns the last or only single value when 102 given a request.vars-style key. 103 104 If the value is a list, the last item will be returned; 105 otherwise, the value will be returned as-is. 106 107 Simulated output with a query string of ?x=abc&y=abc&y=def 108 >>> request = Storage() 109 >>> request.vars = Storage() 110 >>> request.vars.x = 'abc' 111 >>> request.vars.y = ['abc', 'def'] 112 >>> request.vars.getlast('x') 113 'abc' 114 >>> request.vars.getlast('y') 115 'def' 116 >>> request.vars.getlast('z') 117 """ 118 values = self.getlist(key) 119 return values[-1] if values else default
120 121 PICKABLE = (str, int, long, float, bool, list, dict, tuple, set) 122 123
124 -class StorageList(Storage):
125 """ 126 like Storage but missing elements default to [] instead of None 127 """
128 - def __getitem__(self, key):
129 return self.__getattr__(key)
130
131 - def __getattr__(self, key):
132 if key in self: 133 return getattr(self, key) 134 else: 135 r = [] 136 setattr(self, key, r) 137 return r
138 139
140 -def load_storage(filename):
141 fp = None 142 try: 143 fp = portalocker.LockedFile(filename, 'rb') 144 storage = cPickle.load(fp) 145 finally: 146 if fp: 147 fp.close() 148 return Storage(storage)
149 150
151 -def save_storage(storage, filename):
152 fp = None 153 try: 154 fp = portalocker.LockedFile(filename, 'wb') 155 cPickle.dump(dict(storage), fp) 156 finally: 157 if fp: 158 fp.close()
159 160
161 -class Settings(Storage):
162 - def __setattr__(self, key, value):
163 if key != 'lock_keys' and self['lock_keys'] and key not in self: 164 raise SyntaxError('setting key \'%s\' does not exist' % key) 165 if key != 'lock_values' and self['lock_values']: 166 raise SyntaxError('setting value cannot be changed: %s' % key) 167 self[key] = value
168 169
170 -class Messages(Settings):
171 - def __init__(self, T):
172 Storage.__init__(self, T=T)
173
174 - def __getattr__(self, key):
175 value = self[key] 176 if isinstance(value, str): 177 return str(self.T(value)) 178 return value
179 180
181 -class FastStorage(dict):
182 """ 183 Eventually this should replace class Storage but causes memory leak 184 because of http://bugs.python.org/issue1469629 185 186 >>> s = FastStorage() 187 >>> s.a = 1 188 >>> s.a 189 1 190 >>> s['a'] 191 1 192 >>> s.b 193 >>> s['b'] 194 >>> s['b']=2 195 >>> s['b'] 196 2 197 >>> s.b 198 2 199 >>> isinstance(s,dict) 200 True 201 >>> dict(s) 202 {'a': 1, 'b': 2} 203 >>> dict(FastStorage(s)) 204 {'a': 1, 'b': 2} 205 >>> import pickle 206 >>> s = pickle.loads(pickle.dumps(s)) 207 >>> dict(s) 208 {'a': 1, 'b': 2} 209 >>> del s.b 210 >>> del s.a 211 >>> s.a 212 >>> s.b 213 >>> s['a'] 214 >>> s['b'] 215 """
216 - def __init__(self, *args, **kwargs):
217 dict.__init__(self, *args, **kwargs) 218 self.__dict__ = self
219
220 - def __getattr__(self, key):
221 return getattr(self, key) if key in self else None
222
223 - def __getitem__(self, key):
224 return dict.get(self, key, None)
225
226 - def copy(self):
227 self.__dict__ = {} 228 s = FastStorage(self) 229 self.__dict__ = self 230 return s
231
232 - def __repr__(self):
233 return '<Storage %s>' % dict.__repr__(self)
234
235 - def __getstate__(self):
236 return dict(self)
237
238 - def __setstate__(self, sdict):
239 dict.__init__(self, sdict) 240 self.__dict__ = self
241
242 - def update(self, *args, **kwargs):
243 dict.__init__(self, *args, **kwargs) 244 self.__dict__ = self
245 246
247 -class List(list):
248 """ 249 Like a regular python list but a[i] if i is out of bounds return None 250 instead of IndexOutOfBounds 251 """ 252
253 - def __call__(self, i, default=None, cast=None, otherwise=None):
254 """ 255 request.args(0,default=0,cast=int,otherwise='http://error_url') 256 request.args(0,default=0,cast=int,otherwise=lambda:...) 257 """ 258 n = len(self) 259 if 0 <= i < n or -n <= i < 0: 260 value = self[i] 261 else: 262 value = default 263 if cast: 264 try: 265 value = cast(value) 266 except (ValueError, TypeError): 267 from http import HTTP, redirect 268 if otherwise is None: 269 raise HTTP(404) 270 elif isinstance(otherwise, str): 271 redirect(otherwise) 272 elif callable(otherwise): 273 return otherwise() 274 else: 275 raise RuntimeError("invalid otherwise") 276 return value
277 278 279 if __name__ == '__main__': 280 import doctest 281 doctest.testmod() 282