source: OpenRLabs-Git/deploy/rlabs-docker/web2py-rlabs/gluon/storage.py @ 42095c5

mainqndtest v1.1.1
Last change on this file since 42095c5 was 42bd667, checked in by David Fuertes <dfuertes@…>, 4 years ago

Historial Limpio

  • Property mode set to 100755
File size: 8.7 KB
Line 
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
9Provides:
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
15from pydal.contrib import portalocker
16from gluon._compat import copyreg, pickle, PY2
17
18__all__ = ['List', 'Storage', 'Settings', 'Messages',
19           'StorageList', 'load_storage', 'save_storage']
20
21DEFAULT = lambda: 0
22
23
24class Storage(dict):
25    """
26    A Storage object is like a dictionary except `obj.foo` can be used
27    in addition to `obj['foo']`, and setting obj.foo = None deletes item foo.
28
29    Example::
30
31        >>> o = Storage(a=1)
32        >>> print o.a
33        1
34
35        >>> o['a']
36        1
37
38        >>> o.a = 2
39        >>> print o['a']
40        2
41
42        >>> del o.a
43        >>> print o.a
44        None
45
46    """
47    __slots__ = ()
48    __setattr__ = dict.__setitem__
49    __delattr__ = dict.__delitem__
50    __getitem__ = dict.get
51    __getattr__ = dict.get
52    __getnewargs__ = lambda self: getattr(dict,self).__getnewargs__(self)
53    __repr__ = lambda self: '<Storage %s>' % dict.__repr__(self)
54    # http://stackoverflow.com/questions/5247250/why-does-pickle-getstate-accept-as-a-return-value-the-very-instance-it-requi
55    __getstate__ = lambda self: None
56    __copy__ = lambda self: Storage(self)
57
58    def getlist(self, key):
59        """
60        Returns a Storage value as a list.
61
62        If the value is a list it will be returned as-is.
63        If object is None, an empty list will be returned.
64        Otherwise, `[value]` will be returned.
65
66        Example output for a query string of `?x=abc&y=abc&y=def`::
67
68            >>> request = Storage()
69            >>> request.vars = Storage()
70            >>> request.vars.x = 'abc'
71            >>> request.vars.y = ['abc', 'def']
72            >>> request.vars.getlist('x')
73            ['abc']
74            >>> request.vars.getlist('y')
75            ['abc', 'def']
76            >>> request.vars.getlist('z')
77            []
78
79        """
80        value = self.get(key, [])
81        if value is None or isinstance(value, (list, tuple)):
82            return value
83        else:
84            return [value]
85
86    def getfirst(self, key, default=None):
87        """
88        Returns the first value of a list or the value itself when given a
89        `request.vars` style key.
90
91        If the value is a list, its first item will be returned;
92        otherwise, the value will be returned as-is.
93
94        Example output for a query string of `?x=abc&y=abc&y=def`::
95
96            >>> request = Storage()
97            >>> request.vars = Storage()
98            >>> request.vars.x = 'abc'
99            >>> request.vars.y = ['abc', 'def']
100            >>> request.vars.getfirst('x')
101            'abc'
102            >>> request.vars.getfirst('y')
103            'abc'
104            >>> request.vars.getfirst('z')
105
106        """
107        values = self.getlist(key)
108        return values[0] if values else default
109
110    def getlast(self, key, default=None):
111        """
112        Returns the last value of a list or value itself when given a
113        `request.vars` style key.
114
115        If the value is a list, the last item will be returned;
116        otherwise, the value will be returned as-is.
117
118        Simulated output with a query string of `?x=abc&y=abc&y=def`::
119
120            >>> request = Storage()
121            >>> request.vars = Storage()
122            >>> request.vars.x = 'abc'
123            >>> request.vars.y = ['abc', 'def']
124            >>> request.vars.getlast('x')
125            'abc'
126            >>> request.vars.getlast('y')
127            'def'
128            >>> request.vars.getlast('z')
129
130        """
131        values = self.getlist(key)
132        return values[-1] if values else default
133
134
135def pickle_storage(s):
136    return Storage, (dict(s),)
137
138copyreg.pickle(Storage, pickle_storage)
139if PY2:
140    PICKABLE = (str, int, long, float, bool, list, dict, tuple, set)
141else:
142    PICKABLE = (str, int, float, bool, list, dict, tuple, set)
143
144class StorageList(Storage):
145    """
146    Behaves like Storage but missing elements defaults to [] instead of None
147    """
148    def __getitem__(self, key):
149        return self.__getattr__(key)
150
151    def __getattr__(self, key):
152        if key in self:
153            return self.get(key)
154        else:
155            r = []
156            self[key] = r
157            return r
158
159
160def load_storage(filename):
161    fp = None
162    try:
163        fp = portalocker.LockedFile(filename, 'rb')
164        storage = pickle.load(fp)
165    finally:
166        if fp:
167            fp.close()
168    return Storage(storage)
169
170
171def save_storage(storage, filename):
172    fp = None
173    try:
174        fp = portalocker.LockedFile(filename, 'wb')
175        pickle.dump(dict(storage), fp)
176    finally:
177        if fp:
178            fp.close()
179
180
181class Settings(Storage):
182    def __setattr__(self, key, value):
183        if key != 'lock_keys' and self['lock_keys'] and key not in self:
184            raise SyntaxError('setting key \'%s\' does not exist' % key)
185        if key != 'lock_values' and self['lock_values']:
186            raise SyntaxError('setting value cannot be changed: %s' % key)
187        self[key] = value
188
189
190class Messages(Settings):
191    def __init__(self, T):
192        Storage.__init__(self, T=T)
193
194    def __getattr__(self, key):
195        value = self[key]
196        if isinstance(value, str):
197            return self.T(value)
198        return value
199
200
201class FastStorage(dict):
202    """
203    Eventually this should replace class Storage but causes memory leak
204    because of http://bugs.python.org/issue1469629
205
206        >>> s = FastStorage()
207        >>> s.a = 1
208        >>> s.a
209        1
210        >>> s['a']
211        1
212        >>> s.b
213        >>> s['b']
214        >>> s['b']=2
215        >>> s['b']
216        2
217        >>> s.b
218        2
219        >>> isinstance(s,dict)
220        True
221        >>> dict(s)
222        {'a': 1, 'b': 2}
223        >>> dict(FastStorage(s))
224        {'a': 1, 'b': 2}
225        >>> import pickle
226        >>> s = pickle.loads(pickle.dumps(s))
227        >>> dict(s)
228        {'a': 1, 'b': 2}
229        >>> del s.b
230        >>> del s.a
231        >>> s.a
232        >>> s.b
233        >>> s['a']
234        >>> s['b']
235
236    """
237    def __init__(self, *args, **kwargs):
238        dict.__init__(self, *args, **kwargs)
239        self.__dict__ = self
240
241    def __getattr__(self, key):
242        return getattr(self, key) if key in self else None
243
244    def __getitem__(self, key):
245        return dict.get(self, key, None)
246
247    def copy(self):
248        self.__dict__ = {}
249        s = FastStorage(self)
250        self.__dict__ = self
251        return s
252
253    def __repr__(self):
254        return '<Storage %s>' % dict.__repr__(self)
255
256    def __getstate__(self):
257        return dict(self)
258
259    def __setstate__(self, sdict):
260        dict.__init__(self, sdict)
261        self.__dict__ = self
262
263    def update(self, *args, **kwargs):
264        dict.__init__(self, *args, **kwargs)
265        self.__dict__ = self
266
267
268class List(list):
269
270    """
271        Like a regular python list but callable.
272        When  a(i) is called if i is out of bounds returns None
273        instead of `IndexError`.
274    """
275
276    def __call__(self, i, default=DEFAULT, cast=None, otherwise=None):
277        """Allows to use a special syntax for fast-check of
278        `request.args()` validity.
279        :params:
280            i: index
281            default: use this value if arg not found
282            cast: type cast
283            otherwise:
284                will be executed when:
285                    - casts fail
286                    - value not found, dont have default and otherwise is
287                    especified
288                can be:
289                    - None: results in a 404
290                    - str: redirect to this address
291                    - callable: calls the function (nothing is passed)
292        Example:
293            You can use::
294                request.args(0,default=0,cast=int,otherwise='http://error_url')
295                request.args(0,default=0,cast=int,otherwise=lambda:...)
296        """
297        n = len(self)
298        if 0 <= i < n or -n <= i < 0:
299            value = self[i]
300        elif default is DEFAULT:
301            value = None
302        else:
303            value, cast, otherwise = default, False, False
304        try:
305            if cast:
306                value = cast(value)
307            if not value and otherwise:
308                raise ValueError('Otherwise will raised.')
309        except (ValueError, TypeError):
310            from gluon.http import HTTP, redirect
311            if otherwise is None:
312                raise HTTP(404)
313            elif isinstance(otherwise, str):
314                redirect(otherwise)
315            elif callable(otherwise):
316                return otherwise()
317            else:
318                raise RuntimeError("invalid otherwise")
319        return value
320
321if __name__ == '__main__':
322    import doctest
323    doctest.testmod()
Note: See TracBrowser for help on using the repository browser.