bug detection for Storage, reverted improvements in dal :-(
This commit is contained in:
@@ -1 +1 @@
|
|||||||
Version 2.00.0 (2012-08-22 08:40:52) dev
|
Version 2.00.0 (2012-08-22 10:48:10) dev
|
||||||
|
|||||||
+23
-9
@@ -6281,9 +6281,16 @@ class Row(dict):
|
|||||||
this is only used to store a Row
|
this is only used to store a Row
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self,*args,**kwargs):
|
# IF NOT HAVE BUG http://bugs.python.org/issue1469629 uncommend these lines and comment __getattr__, __setattr__
|
||||||
dict.__init__(self,*args,**kwargs)
|
# def __init__(self,*args,**kwargs):
|
||||||
self.__dict__ = self
|
# dict.__init__(self,*args,**kwargs)
|
||||||
|
# self.__dict__ = self
|
||||||
|
|
||||||
|
def __getattr__(self, key):
|
||||||
|
return self[key]
|
||||||
|
|
||||||
|
def __setattr__(self, key, value):
|
||||||
|
self[key] = value
|
||||||
|
|
||||||
def __getitem__(self, key):
|
def __getitem__(self, key):
|
||||||
key=str(key)
|
key=str(key)
|
||||||
@@ -6572,7 +6579,7 @@ class DAL(dict):
|
|||||||
:fake_migrate_all (defaults to False). If sets to True fake migrates ALL tables
|
:fake_migrate_all (defaults to False). If sets to True fake migrates ALL tables
|
||||||
:attempts (defaults to 5). Number of times to attempt connecting
|
:attempts (defaults to 5). Number of times to attempt connecting
|
||||||
"""
|
"""
|
||||||
self.__dict__ = self
|
# self.__dict__ = self # http://bugs.python.org/issue1469629
|
||||||
if not decode_credentials:
|
if not decode_credentials:
|
||||||
credential_decoder = lambda cred: cred
|
credential_decoder = lambda cred: cred
|
||||||
else:
|
else:
|
||||||
@@ -6983,8 +6990,7 @@ def index():
|
|||||||
yield self[tablename]
|
yield self[tablename]
|
||||||
|
|
||||||
def __getitem__(self, key):
|
def __getitem__(self, key):
|
||||||
key = str(key)
|
return self.__getattr__(str(key))
|
||||||
return dict.__getitem__(self,key)
|
|
||||||
|
|
||||||
def __getattr__(self, key):
|
def __getattr__(self, key):
|
||||||
if not key is '_LAZY_TABLES' and key in self._LAZY_TABLES:
|
if not key is '_LAZY_TABLES' and key in self._LAZY_TABLES:
|
||||||
@@ -6999,7 +7005,9 @@ def index():
|
|||||||
if key[:1]!='_' and key in self:
|
if key[:1]!='_' and key in self:
|
||||||
raise SyntaxError, \
|
raise SyntaxError, \
|
||||||
'Object %s exists and cannot be redefined' % key
|
'Object %s exists and cannot be redefined' % key
|
||||||
dict.__setattr__(self,key,value)
|
dict.__setitem__(self,key,value)
|
||||||
|
# replace above line with below if not have bug http://bugs.python.org/issue1469629
|
||||||
|
# dict.__setattr__(self,key,value)
|
||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
return '<DAL ' + dict.__repr__(self) + '>'
|
return '<DAL ' + dict.__repr__(self) + '>'
|
||||||
@@ -7201,7 +7209,7 @@ class Table(dict):
|
|||||||
|
|
||||||
:raises SyntaxError: when a supplied field is of incorrect type.
|
:raises SyntaxError: when a supplied field is of incorrect type.
|
||||||
"""
|
"""
|
||||||
self.__dict__ = self
|
# self.__dict__ = self # http://bugs.python.org/issue1469629
|
||||||
self._actual = False # set to True by define_table()
|
self._actual = False # set to True by define_table()
|
||||||
self._tablename = tablename
|
self._tablename = tablename
|
||||||
self._sequence_name = args.get('sequence_name',None) or \
|
self._sequence_name = args.get('sequence_name',None) or \
|
||||||
@@ -7463,6 +7471,10 @@ class Table(dict):
|
|||||||
'value must be a dictionary: %s' % value
|
'value must be a dictionary: %s' % value
|
||||||
dict.__setitem__(self, str(key), value)
|
dict.__setitem__(self, str(key), value)
|
||||||
|
|
||||||
|
# comment if not have bug http://bugs.python.org/issue1469629
|
||||||
|
def __getattr__(self, key):
|
||||||
|
return self[key]
|
||||||
|
|
||||||
def __delitem__(self, key):
|
def __delitem__(self, key):
|
||||||
if isinstance(key, dict):
|
if isinstance(key, dict):
|
||||||
query = self._build_query(key)
|
query = self._build_query(key)
|
||||||
@@ -7474,7 +7486,9 @@ class Table(dict):
|
|||||||
def __setattr__(self, key, value):
|
def __setattr__(self, key, value):
|
||||||
if key[:1]!='_' and key in self:
|
if key[:1]!='_' and key in self:
|
||||||
raise SyntaxError, 'Object exists and cannot be redefined: %s' % key
|
raise SyntaxError, 'Object exists and cannot be redefined: %s' % key
|
||||||
dict.__setattr__(self,key,value)
|
self[key] = value
|
||||||
|
# replace with line below if have bug http://bugs.python.org/issue1469629
|
||||||
|
# dict.__setattr__(self,key,value)
|
||||||
|
|
||||||
def __iter__(self):
|
def __iter__(self):
|
||||||
for fieldname in self.fields:
|
for fieldname in self.fields:
|
||||||
|
|||||||
+105
-64
@@ -18,58 +18,25 @@ import portalocker
|
|||||||
__all__ = ['List', 'Storage', 'Settings', 'Messages',
|
__all__ = ['List', 'Storage', 'Settings', 'Messages',
|
||||||
'StorageList', 'load_storage', 'save_storage']
|
'StorageList', 'load_storage', 'save_storage']
|
||||||
|
|
||||||
|
def have_python_bug_1469629():
|
||||||
class List(list):
|
|
||||||
"""
|
"""
|
||||||
Like a regular python list but a[i] if i is out of bounds return None
|
http://bugs.python.org/issue1469629
|
||||||
instead of IndexOutOfBounds
|
|
||||||
|
because of this bug class Storage is slower on Python < 2.7.3
|
||||||
"""
|
"""
|
||||||
|
import weakref
|
||||||
|
class Test(dict):
|
||||||
|
def __init__(self):
|
||||||
|
self.__dict__ = self
|
||||||
|
s = Test()
|
||||||
|
w = weakref.ref(s)
|
||||||
|
del s
|
||||||
|
return w() is not None
|
||||||
|
|
||||||
def __call__(self, i, default=None, cast=None, otherwise=None):
|
HAVE_PYTHON_BUG_1469629 = have_python_bug_1469629()
|
||||||
"""
|
|
||||||
request.args(0,default=0,cast=int,otherwise='http://error_url')
|
|
||||||
request.args(0,default=0,cast=int,otherwise=lambda:...)
|
|
||||||
"""
|
|
||||||
n = len(self)
|
|
||||||
if 0<=i<n or -n<=i<0:
|
|
||||||
value = self[i]
|
|
||||||
else:
|
|
||||||
value = default
|
|
||||||
if cast:
|
|
||||||
try:
|
|
||||||
value = cast(value)
|
|
||||||
except (ValueError, TypeError):
|
|
||||||
from http import HTTP, redirect
|
|
||||||
if otherwise is None:
|
|
||||||
raise HTTP(404)
|
|
||||||
elif isinstance(otherwise,str):
|
|
||||||
redirect(otherwise)
|
|
||||||
elif callable(otherwise):
|
|
||||||
return otherwise()
|
|
||||||
else:
|
|
||||||
raise RuntimeError, "invalid otherwise"
|
|
||||||
return value
|
|
||||||
|
|
||||||
class Storage(dict):
|
|
||||||
"""
|
|
||||||
A Storage object is like a dictionary except `obj.foo` can be used
|
|
||||||
in addition to `obj['foo']`, and setting obj.foo = None deletes item foo.
|
|
||||||
|
|
||||||
>>> o = Storage(a=1)
|
class NewStorage(dict):
|
||||||
>>> print o.a
|
|
||||||
1
|
|
||||||
|
|
||||||
>>> o['a']
|
|
||||||
1
|
|
||||||
|
|
||||||
>>> o.a = 2
|
|
||||||
>>> print o['a']
|
|
||||||
2
|
|
||||||
|
|
||||||
>>> del o.a
|
|
||||||
>>> print o.a
|
|
||||||
|
|
||||||
"""
|
|
||||||
def __init__(self, *args, **kwargs):
|
def __init__(self, *args, **kwargs):
|
||||||
dict.__init__(self, *args, **kwargs)
|
dict.__init__(self, *args, **kwargs)
|
||||||
self.__dict__ = self
|
self.__dict__ = self
|
||||||
@@ -92,6 +59,54 @@ class Storage(dict):
|
|||||||
def update(self, *args, **kwargs):
|
def update(self, *args, **kwargs):
|
||||||
dict.__init__(self, *args, **kwargs)
|
dict.__init__(self, *args, **kwargs)
|
||||||
self.__dict__ = self
|
self.__dict__ = self
|
||||||
|
|
||||||
|
|
||||||
|
class OldStorage(dict):
|
||||||
|
def __getattr__(self, key):
|
||||||
|
return dict.get(self, key, None)
|
||||||
|
def __setattr__(self, key, value):
|
||||||
|
if value is None:
|
||||||
|
if key in self:
|
||||||
|
del self[key]
|
||||||
|
else:
|
||||||
|
self[key] = value
|
||||||
|
def __delattr__(self, key):
|
||||||
|
if key in self:
|
||||||
|
del self[key]
|
||||||
|
else:
|
||||||
|
raise AttributeError, "missing key=%s" % key
|
||||||
|
def __getitem__(self, key):
|
||||||
|
return dict.get(self, key, None)
|
||||||
|
def __repr__(self):
|
||||||
|
return '<Storage %s>' + dict.__repr__(self)
|
||||||
|
def __getstate__(self):
|
||||||
|
return dict(self)
|
||||||
|
def __setstate__(self, value):
|
||||||
|
for (k, v) in value.items():
|
||||||
|
self[k] = v
|
||||||
|
|
||||||
|
|
||||||
|
class Storage(OldStorage if HAVE_PYTHON_BUG_1469629 else NewStorage):
|
||||||
|
|
||||||
|
"""
|
||||||
|
A Storage object is like a dictionary except `obj.foo` can be used
|
||||||
|
in addition to `obj['foo']`, and setting obj.foo = None deletes item foo.
|
||||||
|
|
||||||
|
>>> o = Storage(a=1)
|
||||||
|
>>> print o.a
|
||||||
|
1
|
||||||
|
|
||||||
|
>>> o['a']
|
||||||
|
1
|
||||||
|
|
||||||
|
>>> o.a = 2
|
||||||
|
>>> print o['a']
|
||||||
|
2
|
||||||
|
|
||||||
|
>>> del o.a
|
||||||
|
>>> print o.a
|
||||||
|
None
|
||||||
|
"""
|
||||||
def getlist(self,key):
|
def getlist(self,key):
|
||||||
"""
|
"""
|
||||||
Return a Storage value as a list.
|
Return a Storage value as a list.
|
||||||
@@ -112,7 +127,7 @@ class Storage(dict):
|
|||||||
>>> request.vars.getlist('z')
|
>>> request.vars.getlist('z')
|
||||||
[]
|
[]
|
||||||
"""
|
"""
|
||||||
value = getattr(self,key,[])
|
value = self.get(key,[])
|
||||||
return value if not value else \
|
return value if not value else \
|
||||||
value if isinstance(value,(list,tuple)) else [value]
|
value if isinstance(value,(list,tuple)) else [value]
|
||||||
def getfirst(self,key,default=None):
|
def getfirst(self,key,default=None):
|
||||||
@@ -133,7 +148,7 @@ class Storage(dict):
|
|||||||
'abc'
|
'abc'
|
||||||
>>> request.vars.getfirst('z')
|
>>> request.vars.getfirst('z')
|
||||||
"""
|
"""
|
||||||
values = self.getlist(default)
|
values = self.getlist(key)
|
||||||
return values[0] if values else default
|
return values[0] if values else default
|
||||||
def getlast(self,key,default=None):
|
def getlast(self,key,default=None):
|
||||||
"""
|
"""
|
||||||
@@ -154,8 +169,8 @@ class Storage(dict):
|
|||||||
'def'
|
'def'
|
||||||
>>> request.vars.getlast('z')
|
>>> request.vars.getlast('z')
|
||||||
"""
|
"""
|
||||||
values = self.getlist(default)
|
values = self.getlist(key)
|
||||||
return values[0] if values else default
|
return values[-1] if values else default
|
||||||
|
|
||||||
PICKABLE = (str,int,long,float,bool,list,dict,tuple,set)
|
PICKABLE = (str,int,long,float,bool,list,dict,tuple,set)
|
||||||
|
|
||||||
@@ -190,31 +205,57 @@ def save_storage(storage, filename):
|
|||||||
finally:
|
finally:
|
||||||
if fp: fp.close()
|
if fp: fp.close()
|
||||||
|
|
||||||
|
setter = Storage.__setitem__ if HAVE_PYTHON_BUG_1469629 else Storage.__setattr__
|
||||||
|
getter = Storage.__getitem__ if HAVE_PYTHON_BUG_1469629 else Storage.__getattr__
|
||||||
|
|
||||||
class Settings(Storage):
|
class Settings(Storage):
|
||||||
def __setattr__(self, key, value):
|
def __setattr__(self, key, value):
|
||||||
if key != 'lock_keys' and self.lock_keys and not key in self:
|
if key != 'lock_keys' and 'lock_keys' in self and not key in self:
|
||||||
raise SyntaxError, 'setting key \'%s\' does not exist' % key
|
raise SyntaxError, 'setting key \'%s\' does not exist' % key
|
||||||
if key != 'lock_values' and self.lock_values:
|
if key != 'lock_values' and 'lock_values' in self:
|
||||||
raise SyntaxError, 'setting value cannot be changed: %s' % key
|
raise SyntaxError, 'setting value cannot be changed: %s' % key
|
||||||
Storage.__setattr__(self,key,value)
|
setter(self,key,value)
|
||||||
|
|
||||||
class Messages(Storage):
|
class Messages(Settings):
|
||||||
def __init__(self, T):
|
def __init__(self, T):
|
||||||
Storage.__init__(self,T=T)
|
Storage.__init__(self,T=T)
|
||||||
|
|
||||||
def __setattr__(self, key, value):
|
|
||||||
if key != 'lock_keys' and self.lock_keys and not key in self:
|
|
||||||
raise SyntaxError, 'setting key \'%s\' does not exist' % key
|
|
||||||
if key != 'lock_values' and self.lock_values:
|
|
||||||
raise SyntaxError, 'setting value cannot be changed: %s' % key
|
|
||||||
Storage.__setattr__(self,key,value)
|
|
||||||
|
|
||||||
def __getattr__(self, key):
|
def __getattr__(self, key):
|
||||||
value = Storage.__getattr__(self,key)
|
value = getter(self,key)
|
||||||
if isinstance(value, str):
|
if isinstance(value, str):
|
||||||
return str(self.T(value))
|
return str(self.T(value))
|
||||||
return value
|
return value
|
||||||
|
|
||||||
|
class List(list):
|
||||||
|
"""
|
||||||
|
Like a regular python list but a[i] if i is out of bounds return None
|
||||||
|
instead of IndexOutOfBounds
|
||||||
|
"""
|
||||||
|
|
||||||
|
def __call__(self, i, default=None, cast=None, otherwise=None):
|
||||||
|
"""
|
||||||
|
request.args(0,default=0,cast=int,otherwise='http://error_url')
|
||||||
|
request.args(0,default=0,cast=int,otherwise=lambda:...)
|
||||||
|
"""
|
||||||
|
n = len(self)
|
||||||
|
if 0<=i<n or -n<=i<0:
|
||||||
|
value = self[i]
|
||||||
|
else:
|
||||||
|
value = default
|
||||||
|
if cast:
|
||||||
|
try:
|
||||||
|
value = cast(value)
|
||||||
|
except (ValueError, TypeError):
|
||||||
|
from http import HTTP, redirect
|
||||||
|
if otherwise is None:
|
||||||
|
raise HTTP(404)
|
||||||
|
elif isinstance(otherwise,str):
|
||||||
|
redirect(otherwise)
|
||||||
|
elif callable(otherwise):
|
||||||
|
return otherwise()
|
||||||
|
else:
|
||||||
|
raise RuntimeError, "invalid otherwise"
|
||||||
|
return value
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
import doctest
|
import doctest
|
||||||
|
|||||||
Reference in New Issue
Block a user