Merge github.com:web2py/web2py
This commit is contained in:
@@ -1 +1 @@
|
|||||||
Version 2.00.0 (2012-08-21 07:57:05) dev
|
Version 2.00.0 (2012-08-21 18:20:02) dev
|
||||||
|
|||||||
@@ -1379,6 +1379,7 @@ def errors():
|
|||||||
|
|
||||||
return dict(errors = [x[1] for x in decorated], app=app, method=method, db_ready=db_ready)
|
return dict(errors = [x[1] for x in decorated], app=app, method=method, db_ready=db_ready)
|
||||||
|
|
||||||
|
|
||||||
elif method == 'dbnew':
|
elif method == 'dbnew':
|
||||||
errors_path = apath('%s/errors' % app, r=request)
|
errors_path = apath('%s/errors' % app, r=request)
|
||||||
tk_db, tk_table = get_ticket_storage(app)
|
tk_db, tk_table = get_ticket_storage(app)
|
||||||
|
|||||||
@@ -294,7 +294,7 @@ div.error {
|
|||||||
margin-bottom:18px;
|
margin-bottom:18px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.web2py_breadcrumbs ul li {
|
li.w2p_grid_breadcrumb_elem {
|
||||||
display:inline-block;
|
display:inline-block;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+25
-17
@@ -1702,6 +1702,16 @@ class BaseAdapter(ConnectionPool):
|
|||||||
|
|
||||||
def parse_datetime(self, value, field_type):
|
def parse_datetime(self, value, field_type):
|
||||||
if not isinstance(value, datetime.datetime):
|
if not isinstance(value, datetime.datetime):
|
||||||
|
if '+' in value:
|
||||||
|
value,tz = value.split('+')
|
||||||
|
h,m = tz.split(':')
|
||||||
|
dt = datetime.timedelta(seconds=3600*int(h)+60*int(m))
|
||||||
|
elif '-' in value:
|
||||||
|
value,tz = value.split('-')
|
||||||
|
h,m = tz.split(':')
|
||||||
|
dt = -datetime.timedelta(seconds=3600*int(h)+60*int(m))
|
||||||
|
else:
|
||||||
|
dt = None
|
||||||
date_part, time_part = (
|
date_part, time_part = (
|
||||||
str(value).replace('T',' ')+' ').split(' ',1)
|
str(value).replace('T',' ')+' ').split(' ',1)
|
||||||
(y, m, d) = map(int,date_part.split('-'))
|
(y, m, d) = map(int,date_part.split('-'))
|
||||||
@@ -1710,6 +1720,8 @@ class BaseAdapter(ConnectionPool):
|
|||||||
time_items = map(int,time_parts)
|
time_items = map(int,time_parts)
|
||||||
(h, mi, s) = time_items
|
(h, mi, s) = time_items
|
||||||
value = datetime.datetime(y, m, d, h, mi, s)
|
value = datetime.datetime(y, m, d, h, mi, s)
|
||||||
|
if dt:
|
||||||
|
value = value + dt
|
||||||
return value
|
return value
|
||||||
|
|
||||||
def parse_blob(self, value, field_type):
|
def parse_blob(self, value, field_type):
|
||||||
@@ -6269,6 +6281,10 @@ class Row(dict):
|
|||||||
this is only used to store a Row
|
this is only used to store a Row
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
def __init__(self,*args,**kwargs):
|
||||||
|
dict.__init__(self,*args,**kwargs)
|
||||||
|
self.__dict__ = self
|
||||||
|
|
||||||
def __getitem__(self, key):
|
def __getitem__(self, key):
|
||||||
key=str(key)
|
key=str(key)
|
||||||
m = regex_table_field.match(key)
|
m = regex_table_field.match(key)
|
||||||
@@ -6287,12 +6303,6 @@ class Row(dict):
|
|||||||
def __setitem__(self, key, value):
|
def __setitem__(self, key, value):
|
||||||
dict.__setitem__(self, str(key), value)
|
dict.__setitem__(self, str(key), value)
|
||||||
|
|
||||||
def __getattr__(self, key):
|
|
||||||
return self[key]
|
|
||||||
|
|
||||||
def __setattr__(self, key, value):
|
|
||||||
self[key] = value
|
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
### this could be made smarter
|
### this could be made smarter
|
||||||
return '<Row ' + dict.__repr__(self) + '>'
|
return '<Row ' + dict.__repr__(self) + '>'
|
||||||
@@ -6562,6 +6572,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
|
||||||
if not decode_credentials:
|
if not decode_credentials:
|
||||||
credential_decoder = lambda cred: cred
|
credential_decoder = lambda cred: cred
|
||||||
else:
|
else:
|
||||||
@@ -6942,7 +6953,7 @@ def index():
|
|||||||
**args
|
**args
|
||||||
):
|
):
|
||||||
if self._common_fields:
|
if self._common_fields:
|
||||||
fields = fields + self._common_fields
|
fields = list(fields) + list(self._common_fields)
|
||||||
|
|
||||||
table_class = args.get('table_class',Table)
|
table_class = args.get('table_class',Table)
|
||||||
table = table_class(self, tablename, *fields, **args)
|
table = table_class(self, tablename, *fields, **args)
|
||||||
@@ -6973,6 +6984,9 @@ def index():
|
|||||||
|
|
||||||
def __getitem__(self, key):
|
def __getitem__(self, key):
|
||||||
key = str(key)
|
key = str(key)
|
||||||
|
return dict.__getitem__(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:
|
||||||
tablename, fields, args = self._LAZY_TABLES.pop(key)
|
tablename, fields, args = self._LAZY_TABLES.pop(key)
|
||||||
return self.lazy_define_table(tablename,*fields,**args)
|
return self.lazy_define_table(tablename,*fields,**args)
|
||||||
@@ -6981,14 +6995,11 @@ def index():
|
|||||||
def __setitem__(self, key, value):
|
def __setitem__(self, key, value):
|
||||||
dict.__setitem__(self, str(key), value)
|
dict.__setitem__(self, str(key), value)
|
||||||
|
|
||||||
def __getattr__(self, key):
|
|
||||||
return self[key]
|
|
||||||
|
|
||||||
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, \
|
raise SyntaxError, \
|
||||||
'Object %s exists and cannot be redefined' % key
|
'Object %s exists and cannot be redefined' % key
|
||||||
self[key] = value
|
dict.__setattr__(self,key,value)
|
||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
return '<DAL ' + dict.__repr__(self) + '>'
|
return '<DAL ' + dict.__repr__(self) + '>'
|
||||||
@@ -7190,7 +7201,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._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 \
|
||||||
@@ -7261,7 +7272,7 @@ class Table(dict):
|
|||||||
tmp = field.uploadfield = '%s_blob' % field.name
|
tmp = field.uploadfield = '%s_blob' % field.name
|
||||||
if isinstance(field.uploadfield,str) and \
|
if isinstance(field.uploadfield,str) and \
|
||||||
not [f for f in fields if f.name==field.uploadfield]:
|
not [f for f in fields if f.name==field.uploadfield]:
|
||||||
fields.append(self._db.Field(field.uploadfield,'blob',default=''))
|
fields.append(Field(field.uploadfield,'blob',default=''))
|
||||||
|
|
||||||
lower_fieldnames = set()
|
lower_fieldnames = set()
|
||||||
reserved = dir(Table) + ['fields']
|
reserved = dir(Table) + ['fields']
|
||||||
@@ -7460,13 +7471,10 @@ class Table(dict):
|
|||||||
elif not str(key).isdigit() or not self._db(self._id == key).delete():
|
elif not str(key).isdigit() or not self._db(self._id == key).delete():
|
||||||
raise SyntaxError, 'No such record: %s' % key
|
raise SyntaxError, 'No such record: %s' % key
|
||||||
|
|
||||||
def __getattr__(self, key):
|
|
||||||
return self[key]
|
|
||||||
|
|
||||||
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
|
||||||
self[key] = value
|
dict.__setattr__(self,key,value)
|
||||||
|
|
||||||
def __iter__(self):
|
def __iter__(self):
|
||||||
for fieldname in self.fields:
|
for fieldname in self.fields:
|
||||||
|
|||||||
+26
-4
@@ -83,6 +83,7 @@ class Request(Storage):
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
|
Storage.__init__(self)
|
||||||
self.wsgi = Storage() # hooks to environ and start_response
|
self.wsgi = Storage() # hooks to environ and start_response
|
||||||
self.env = Storage()
|
self.env = Storage()
|
||||||
self.cookies = Cookie.SimpleCookie()
|
self.cookies = Cookie.SimpleCookie()
|
||||||
@@ -165,6 +166,7 @@ class Response(Storage):
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
|
Storage.__init__(self)
|
||||||
self.status = 200
|
self.status = 200
|
||||||
self.headers = dict()
|
self.headers = dict()
|
||||||
self.headers['X-Powered-By'] = 'web2py'
|
self.headers['X-Powered-By'] = 'web2py'
|
||||||
@@ -274,6 +276,8 @@ class Response(Storage):
|
|||||||
stream,
|
stream,
|
||||||
chunk_size = DEFAULT_CHUNK_SIZE,
|
chunk_size = DEFAULT_CHUNK_SIZE,
|
||||||
request=None,
|
request=None,
|
||||||
|
attachment=False,
|
||||||
|
filename=None
|
||||||
):
|
):
|
||||||
"""
|
"""
|
||||||
if a controller function::
|
if a controller function::
|
||||||
@@ -281,7 +285,28 @@ class Response(Storage):
|
|||||||
return response.stream(file, 100)
|
return response.stream(file, 100)
|
||||||
|
|
||||||
the file content will be streamed at 100 bytes at the time
|
the file content will be streamed at 100 bytes at the time
|
||||||
|
|
||||||
|
Optional kwargs:
|
||||||
|
(for custom stream calls)
|
||||||
|
attachment=True # Send as attachment. Usually creates a
|
||||||
|
# pop-up download window on browsers
|
||||||
|
filename=None # The name for the attachment
|
||||||
|
|
||||||
|
Note: for using the stream name (filename) with attachments
|
||||||
|
the option must be explicitly set as function parameter(will
|
||||||
|
default to the last request argument otherwise)
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
# for attachment settings and backward compatibility
|
||||||
|
keys = [item.lower() for item in self.headers]
|
||||||
|
if attachment:
|
||||||
|
if filename is None:
|
||||||
|
attname = ""
|
||||||
|
else:
|
||||||
|
attname = filename
|
||||||
|
self.headers["Content-Disposition"] = \
|
||||||
|
"attachment;filename=%s" % attname
|
||||||
|
|
||||||
if not request:
|
if not request:
|
||||||
request = current.request
|
request = current.request
|
||||||
if isinstance(stream, (str, unicode)):
|
if isinstance(stream, (str, unicode)):
|
||||||
@@ -291,12 +316,9 @@ class Response(Storage):
|
|||||||
headers=self.headers)
|
headers=self.headers)
|
||||||
|
|
||||||
# ## the following is for backward compatibility
|
# ## the following is for backward compatibility
|
||||||
|
|
||||||
if hasattr(stream, 'name'):
|
if hasattr(stream, 'name'):
|
||||||
filename = stream.name
|
filename = stream.name
|
||||||
else:
|
|
||||||
filename = None
|
|
||||||
keys = [item.lower() for item in self.headers]
|
|
||||||
if filename and not 'content-type' in keys:
|
if filename and not 'content-type' in keys:
|
||||||
self.headers['Content-Type'] = contenttype(filename)
|
self.headers['Content-Type'] = contenttype(filename)
|
||||||
if filename and not 'content-length' in keys:
|
if filename and not 'content-length' in keys:
|
||||||
|
|||||||
+3
-2
@@ -446,8 +446,9 @@ def wsgibase(environ, responder):
|
|||||||
elif not request.is_local and \
|
elif not request.is_local and \
|
||||||
os.path.exists(os.path.join(request.folder,'DISABLED')):
|
os.path.exists(os.path.join(request.folder,'DISABLED')):
|
||||||
raise HTTP(503, "<html><body><h1>Temporarily down for maintenance</h1></body></html>")
|
raise HTTP(503, "<html><body><h1>Temporarily down for maintenance</h1></body></html>")
|
||||||
request.url = Url(r=request, args=request.args,
|
request.url = Url(r=request,
|
||||||
extension=request.raw_extension)
|
args=request.args,
|
||||||
|
extension=request.raw_extension)
|
||||||
|
|
||||||
# ##################################################
|
# ##################################################
|
||||||
# build missing folders
|
# build missing folders
|
||||||
|
|||||||
@@ -33,6 +33,7 @@ class TicketStorage(Storage):
|
|||||||
db=None,
|
db=None,
|
||||||
tablename='web2py_ticket'
|
tablename='web2py_ticket'
|
||||||
):
|
):
|
||||||
|
Storage.__init__(self)
|
||||||
self.db = db
|
self.db = db
|
||||||
self.tablename = tablename
|
self.tablename = tablename
|
||||||
|
|
||||||
|
|||||||
+35
-12
@@ -687,18 +687,40 @@ def formstyle_ul(form, fields):
|
|||||||
def formstyle_bootstrap(form, fields):
|
def formstyle_bootstrap(form, fields):
|
||||||
''' bootstrap format form layout '''
|
''' bootstrap format form layout '''
|
||||||
form['_class'] = 'form-horizontal'
|
form['_class'] = 'form-horizontal'
|
||||||
table = FIELDSET()
|
parent = FIELDSET()
|
||||||
for id, label, controls, help in fields:
|
for id, label, controls, help in fields:
|
||||||
if isinstance(controls, (INPUT, SELECT, TEXTAREA)):
|
# wrappers
|
||||||
|
_help = SPAN(help, _class='help-inline')
|
||||||
|
# embed _help into _controls
|
||||||
|
_controls = DIV(controls, _help, _class='controls')
|
||||||
|
# submit unflag by default
|
||||||
|
_submit = False
|
||||||
|
|
||||||
|
if isinstance(controls, INPUT):
|
||||||
controls['_class'] = 'input-xlarge'
|
controls['_class'] = 'input-xlarge'
|
||||||
|
if controls['_type'] == 'submit':
|
||||||
|
# flag submit button
|
||||||
|
_submit = True
|
||||||
|
controls['_class'] = 'btn btn-primary'
|
||||||
|
|
||||||
|
if isinstance(controls, SELECT):
|
||||||
|
controls['_class'] = 'input-xlarge'
|
||||||
|
|
||||||
|
if isinstance(controls, TEXTAREA):
|
||||||
|
controls['_class'] = 'input-xlarge'
|
||||||
|
|
||||||
if isinstance(label, LABEL):
|
if isinstance(label, LABEL):
|
||||||
label['_class'] = 'control-label'
|
label['_class'] = 'control-label'
|
||||||
# styles
|
|
||||||
_help = DIV(help, _class='help-block')
|
if _submit:
|
||||||
# embed _help into _controls don't wrap label
|
# submit button has unwrapped label and controls, different class
|
||||||
_controls = DIV(controls, _help, _class='controls')
|
parent.append(DIV(label, controls, _class='form-actions'))
|
||||||
table.append(DIV(label, _controls, _class='control-group',_id=id))
|
# unflag submit (possible side effect)
|
||||||
return table
|
_submit = False
|
||||||
|
else:
|
||||||
|
# unwrapped label
|
||||||
|
parent.append(DIV(label, _controls, _class='control-group'))
|
||||||
|
return parent
|
||||||
|
|
||||||
class SQLFORM(FORM):
|
class SQLFORM(FORM):
|
||||||
|
|
||||||
@@ -1086,7 +1108,8 @@ class SQLFORM(FORM):
|
|||||||
|
|
||||||
if callable(self.formstyle):
|
if callable(self.formstyle):
|
||||||
# backward compatibility, 4 argument function is the old style
|
# backward compatibility, 4 argument function is the old style
|
||||||
if len(inspect.getargspec(self.formstyle)[0]) == 4:
|
args, varargs, keywords, defaults = inspect.getargspec(self.formstyle)
|
||||||
|
if defaults and len(args) - len(defaults) == 4 or len(args) == 4:
|
||||||
table = TABLE()
|
table = TABLE()
|
||||||
for id,a,b,c in xfields:
|
for id,a,b,c in xfields:
|
||||||
raw_b = self.field_parent[id] = b
|
raw_b = self.field_parent[id] = b
|
||||||
@@ -2159,12 +2182,12 @@ class SQLFORM(FORM):
|
|||||||
LI(A(T(db[referee]._plural),
|
LI(A(T(db[referee]._plural),
|
||||||
_class=trap_class(),
|
_class=trap_class(),
|
||||||
_href=url()),
|
_href=url()),
|
||||||
SPAN(divider,_class='divider')))
|
SPAN(divider,_class='divider'),_class='w2p_grid_breadcrumb_elem'))
|
||||||
if kwargs.get('details',True):
|
if kwargs.get('details',True):
|
||||||
breadcrumbs.append(
|
breadcrumbs.append(
|
||||||
LI(A(name,_class=trap_class(),
|
LI(A(name,_class=trap_class(),
|
||||||
_href=url(args=['view',referee,id])),
|
_href=url(args=['view',referee,id])),
|
||||||
SPAN(divider,_class='divider')))
|
SPAN(divider,_class='divider'),_class='w2p_grid_breadcrumb_elem'))
|
||||||
nargs+=2
|
nargs+=2
|
||||||
else:
|
else:
|
||||||
break
|
break
|
||||||
@@ -2212,7 +2235,7 @@ class SQLFORM(FORM):
|
|||||||
if isinstance(grid,DIV):
|
if isinstance(grid,DIV):
|
||||||
header = table._plural + (field and ' for '+field.name or '')
|
header = table._plural + (field and ' for '+field.name or '')
|
||||||
breadcrumbs.append(LI(A(T(header),_class=trap_class(),
|
breadcrumbs.append(LI(A(T(header),_class=trap_class(),
|
||||||
_href=url()),_class='active'))
|
_href=url()),_class='active w2p_grid_breadcrumb_elem'))
|
||||||
grid.insert(0,DIV(UL(*breadcrumbs, **{'_class':breadcrumbs_class}),
|
grid.insert(0,DIV(UL(*breadcrumbs, **{'_class':breadcrumbs_class}),
|
||||||
_class='web2py_breadcrumbs'))
|
_class='web2py_breadcrumbs'))
|
||||||
return grid
|
return grid
|
||||||
|
|||||||
+66
-86
@@ -13,9 +13,8 @@ Provides:
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
import cPickle
|
import cPickle
|
||||||
import portalocker
|
|
||||||
|
|
||||||
__all__ = ['List', 'Storage', 'Settings', 'Messages', 'PickleableStorage',
|
__all__ = ['List', 'Storage', 'Settings', 'Messages',
|
||||||
'StorageList', 'load_storage', 'save_storage']
|
'StorageList', 'load_storage', 'save_storage']
|
||||||
|
|
||||||
|
|
||||||
@@ -25,7 +24,11 @@ class List(list):
|
|||||||
instead of IndexOutOfBounds
|
instead of IndexOutOfBounds
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __call__(self, i, default=None, cast=None, url_onerror=None):
|
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)
|
n = len(self)
|
||||||
if 0<=i<n or -n<=i<0:
|
if 0<=i<n or -n<=i<0:
|
||||||
value = self[i]
|
value = self[i]
|
||||||
@@ -36,14 +39,17 @@ class List(list):
|
|||||||
value = cast(value)
|
value = cast(value)
|
||||||
except (ValueError, TypeError):
|
except (ValueError, TypeError):
|
||||||
from http import HTTP, redirect
|
from http import HTTP, redirect
|
||||||
if url_onerror:
|
if otherwise is None:
|
||||||
redirect(url_onerror)
|
|
||||||
else:
|
|
||||||
raise HTTP(404)
|
raise HTTP(404)
|
||||||
|
elif isinstance(otherwise,str):
|
||||||
|
redirect(otherwise)
|
||||||
|
elif callable(otherwise):
|
||||||
|
return otherwise()
|
||||||
|
else:
|
||||||
|
raise RuntimeError, "invalid otherwise"
|
||||||
return value
|
return value
|
||||||
|
|
||||||
class Storage(dict):
|
class Storage(dict):
|
||||||
|
|
||||||
"""
|
"""
|
||||||
A Storage object is like a dictionary except `obj.foo` can be used
|
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.
|
in addition to `obj['foo']`, and setting obj.foo = None deletes item foo.
|
||||||
@@ -61,41 +67,33 @@ class Storage(dict):
|
|||||||
|
|
||||||
>>> del o.a
|
>>> del o.a
|
||||||
>>> print o.a
|
>>> print o.a
|
||||||
None
|
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
def __init__(self, *args, **kwargs):
|
||||||
def __getattr__(self, key):
|
dict.__init__(self, *args, **kwargs)
|
||||||
return dict.get(self, key, None)
|
self.__dict__ = self
|
||||||
|
def __getattr__(self,key):
|
||||||
def __setattr__(self, key, value):
|
return getattr(self,key) if key in self else None
|
||||||
if value is None:
|
def __getitem__(self,key):
|
||||||
if key in self:
|
return dict.get(self,key,None)
|
||||||
del self[key]
|
def copy(self):
|
||||||
else:
|
self.__dict__ = {}
|
||||||
self[key] = value
|
s = Storage(self)
|
||||||
|
self.__dict__ = self
|
||||||
def __delattr__(self, key):
|
return s
|
||||||
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):
|
def __repr__(self):
|
||||||
return '<Storage ' + dict.__repr__(self) + '>'
|
return '<Storage %s>' % dict.__repr__(self)
|
||||||
|
|
||||||
def __getstate__(self):
|
def __getstate__(self):
|
||||||
return dict(self)
|
return dict(self)
|
||||||
|
def __setstate__(self, sdict):
|
||||||
def __setstate__(self, value):
|
dict.__init__(self, sdict)
|
||||||
for (k, v) in value.items():
|
self.__dict__ = self
|
||||||
self[k] = v
|
def update(self, *args, **kwargs):
|
||||||
|
dict.__init__(self, *args, **kwargs)
|
||||||
def getlist(self, key):
|
self.__dict__ = self
|
||||||
"""Return a Storage value as a list.
|
def getlist(self,key):
|
||||||
|
"""
|
||||||
|
Return a Storage value as a list.
|
||||||
|
|
||||||
If the value is a list it will be returned as-is.
|
If the value is a list it will be returned as-is.
|
||||||
If object is None, an empty list will be returned.
|
If object is None, an empty list will be returned.
|
||||||
@@ -112,17 +110,13 @@ class Storage(dict):
|
|||||||
['abc', 'def']
|
['abc', 'def']
|
||||||
>>> request.vars.getlist('z')
|
>>> request.vars.getlist('z')
|
||||||
[]
|
[]
|
||||||
|
|
||||||
"""
|
"""
|
||||||
value = self.get(key, None)
|
value = getattr(self,key,[])
|
||||||
if isinstance(value, (list, tuple)):
|
return value if not value else \
|
||||||
return value
|
value if isinstance(value,(list,tuple)) else [value]
|
||||||
elif value is None:
|
def getfirst(self,key,default=None):
|
||||||
return []
|
"""
|
||||||
return [value]
|
Return the first or only value when given a request.vars-style key.
|
||||||
|
|
||||||
def getfirst(self, key):
|
|
||||||
"""Return the first or only value when given a request.vars-style key.
|
|
||||||
|
|
||||||
If the value is a list, its first item will be returned;
|
If the value is a list, its first item will be returned;
|
||||||
otherwise, the value will be returned as-is.
|
otherwise, the value will be returned as-is.
|
||||||
@@ -137,15 +131,13 @@ class Storage(dict):
|
|||||||
>>> request.vars.getfirst('y')
|
>>> request.vars.getfirst('y')
|
||||||
'abc'
|
'abc'
|
||||||
>>> request.vars.getfirst('z')
|
>>> request.vars.getfirst('z')
|
||||||
|
|
||||||
"""
|
"""
|
||||||
value = self.getlist(key)
|
values = self.getlist(default)
|
||||||
if len(value):
|
return values[0] if values else default
|
||||||
return value[0]
|
def getlast(self,key,default=None):
|
||||||
return None
|
"""
|
||||||
|
Returns the last or only single value when
|
||||||
def getlast(self, key):
|
given a request.vars-style key.
|
||||||
"""Returns the last or only single value when given a request.vars-style key.
|
|
||||||
|
|
||||||
If the value is a list, the last item will be returned;
|
If the value is a list, the last item will be returned;
|
||||||
otherwise, the value will be returned as-is.
|
otherwise, the value will be returned as-is.
|
||||||
@@ -160,33 +152,25 @@ class Storage(dict):
|
|||||||
>>> request.vars.getlast('y')
|
>>> request.vars.getlast('y')
|
||||||
'def'
|
'def'
|
||||||
>>> request.vars.getlast('z')
|
>>> request.vars.getlast('z')
|
||||||
|
|
||||||
"""
|
"""
|
||||||
value = self.getlist(key)
|
values = self.getlist(default)
|
||||||
if len(value):
|
return values[0] if values else default
|
||||||
return value[-1]
|
|
||||||
return None
|
|
||||||
|
|
||||||
def __getinitargs__(self):
|
|
||||||
return ()
|
|
||||||
|
|
||||||
def __getnewargs__(self):
|
|
||||||
return ()
|
|
||||||
|
|
||||||
PICKABLE = (str,int,long,float,bool,list,dict,tuple,set)
|
PICKABLE = (str,int,long,float,bool,list,dict,tuple,set)
|
||||||
def PickleableStorage(data):
|
|
||||||
return Storage(dict((k,v) for (k,v) in data.items() if isinstance(v,PICKABLE)))
|
|
||||||
|
|
||||||
class StorageList(Storage):
|
class StorageList(Storage):
|
||||||
"""
|
"""
|
||||||
like Storage but missing elements default to [] instead of None
|
like Storage but missing elements default to [] instead of None
|
||||||
"""
|
"""
|
||||||
|
def __getitem__(self,key):
|
||||||
|
return self.__gteattr__(key)
|
||||||
def __getattr__(self, key):
|
def __getattr__(self, key):
|
||||||
if key in self:
|
if key in self:
|
||||||
return self[key]
|
return getattr(self,key)
|
||||||
else:
|
else:
|
||||||
self[key] = []
|
r = []
|
||||||
return self[key]
|
setattr(self,key,r)
|
||||||
|
return r
|
||||||
|
|
||||||
def load_storage(filename):
|
def load_storage(filename):
|
||||||
fp = None
|
fp = None
|
||||||
@@ -197,7 +181,6 @@ def load_storage(filename):
|
|||||||
if fp: fp.close()
|
if fp: fp.close()
|
||||||
return Storage(storage)
|
return Storage(storage)
|
||||||
|
|
||||||
|
|
||||||
def save_storage(storage, filename):
|
def save_storage(storage, filename):
|
||||||
fp = None
|
fp = None
|
||||||
try:
|
try:
|
||||||
@@ -207,35 +190,31 @@ def save_storage(storage, filename):
|
|||||||
if fp: fp.close()
|
if fp: fp.close()
|
||||||
|
|
||||||
class Settings(Storage):
|
class Settings(Storage):
|
||||||
|
|
||||||
def __setattr__(self, key, value):
|
def __setattr__(self, key, value):
|
||||||
if key != 'lock_keys' and self.get('lock_keys', None)\
|
if key != 'lock_keys' and self.lock_keys and not key 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.get('lock_values', None):
|
if key != 'lock_values' and self.lock_values:
|
||||||
raise SyntaxError, 'setting value cannot be changed: %s' % key
|
raise SyntaxError, 'setting value cannot be changed: %s' % key
|
||||||
self[key] = value
|
Storage.__setattr__(self,key,value)
|
||||||
|
|
||||||
|
|
||||||
class Messages(Storage):
|
class Messages(Storage):
|
||||||
|
|
||||||
def __init__(self, T):
|
def __init__(self, T):
|
||||||
self['T'] = T
|
Storage.__init__(self,T=T)
|
||||||
|
|
||||||
def __setattr__(self, key, value):
|
def __setattr__(self, key, value):
|
||||||
if key != 'lock_keys' and self.get('lock_keys', None)\
|
if key != 'lock_keys' and self.lock_keys and not key 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.get('lock_values', None):
|
if key != 'lock_values' and self.lock_values:
|
||||||
raise SyntaxError, 'setting value cannot be changed: %s' % key
|
raise SyntaxError, 'setting value cannot be changed: %s' % key
|
||||||
self[key] = value
|
Storage.__setattr__(self,key,value)
|
||||||
|
|
||||||
def __getattr__(self, key):
|
def __getattr__(self, key):
|
||||||
value = self[key]
|
value = Storage.__getattr__(self,key)
|
||||||
if isinstance(value, str):
|
if isinstance(value, str):
|
||||||
return str(self['T'](value))
|
return str(self.T(value))
|
||||||
return value
|
return value
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
import doctest
|
import doctest
|
||||||
doctest.testmod()
|
doctest.testmod()
|
||||||
@@ -244,3 +223,4 @@ if __name__ == '__main__':
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
+1
-1
@@ -4519,7 +4519,7 @@ class Wiki(object):
|
|||||||
if tag: db.wiki_tag.insert(name=tag,wiki_page=page.id)
|
if tag: db.wiki_tag.insert(name=tag,wiki_page=page.id)
|
||||||
db.wiki_page._after_insert.append(update_tags_insert)
|
db.wiki_page._after_insert.append(update_tags_insert)
|
||||||
db.wiki_page._after_update.append(update_tags_update)
|
db.wiki_page._after_update.append(update_tags_update)
|
||||||
if check_credentials(current.request) and \
|
if auth.user and check_credentials(current.request) and \
|
||||||
not 'wiki_editor' in auth.user_groups.values():
|
not 'wiki_editor' in auth.user_groups.values():
|
||||||
group = db.auth_group(role='wiki_editor')
|
group = db.auth_group(role='wiki_editor')
|
||||||
gid = group.id if group else db.auth_group.insert(role='wiki_editor')
|
gid = group.id if group else db.auth_group.insert(role='wiki_editor')
|
||||||
|
|||||||
Reference in New Issue
Block a user