many pep8 improvements
This commit is contained in:
+197
-173
@@ -53,7 +53,7 @@ __all__ = [
|
||||
'IS_UPLOAD_FILENAME',
|
||||
'IS_UPPER',
|
||||
'IS_URL',
|
||||
]
|
||||
]
|
||||
|
||||
try:
|
||||
from globals import current
|
||||
@@ -61,16 +61,19 @@ try:
|
||||
except ImportError:
|
||||
have_current = False
|
||||
|
||||
|
||||
def translate(text):
|
||||
if text is None:
|
||||
return None
|
||||
elif isinstance(text,(str,unicode)) and have_current:
|
||||
if hasattr(current,'T'):
|
||||
elif isinstance(text, (str, unicode)) and have_current:
|
||||
if hasattr(current, 'T'):
|
||||
return str(current.T(text))
|
||||
return str(text)
|
||||
|
||||
def options_sorter(x,y):
|
||||
return (str(x[1]).upper()>str(y[1]).upper() and 1) or -1
|
||||
|
||||
def options_sorter(x, y):
|
||||
return (str(x[1]).upper() > str(y[1]).upper() and 1) or -1
|
||||
|
||||
|
||||
class Validator(object):
|
||||
"""
|
||||
@@ -117,7 +120,7 @@ class Validator(object):
|
||||
"""
|
||||
return value
|
||||
|
||||
def __call__(self,value):
|
||||
def __call__(self, value):
|
||||
raise NotImplementedError
|
||||
return (value, None)
|
||||
|
||||
@@ -277,7 +280,7 @@ class IS_LENGTH(Validator):
|
||||
value.file.seek(0, os.SEEK_END)
|
||||
length = value.file.tell()
|
||||
value.file.seek(0, os.SEEK_SET)
|
||||
elif hasattr(value,'value'):
|
||||
elif hasattr(value, 'value'):
|
||||
val = value.value
|
||||
if val:
|
||||
length = len(val)
|
||||
@@ -294,8 +297,8 @@ class IS_LENGTH(Validator):
|
||||
return (value, None)
|
||||
except:
|
||||
pass
|
||||
return (value, translate(self.error_message) \
|
||||
% dict(min=self.minsize, max=self.maxsize))
|
||||
return (value, translate(self.error_message)
|
||||
% dict(min=self.minsize, max=self.maxsize))
|
||||
|
||||
|
||||
class IS_IN_SET(Validator):
|
||||
@@ -334,15 +337,15 @@ class IS_IN_SET(Validator):
|
||||
multiple=False,
|
||||
zero='',
|
||||
sort=False,
|
||||
):
|
||||
):
|
||||
self.multiple = multiple
|
||||
if isinstance(theset, dict):
|
||||
self.theset = [str(item) for item in theset]
|
||||
self.labels = theset.values()
|
||||
elif theset and isinstance(theset, (tuple,list)) \
|
||||
and isinstance(theset[0], (tuple,list)) and len(theset[0])==2:
|
||||
self.theset = [str(item) for item,label in theset]
|
||||
self.labels = [str(label) for item,label in theset]
|
||||
elif theset and isinstance(theset, (tuple, list)) \
|
||||
and isinstance(theset[0], (tuple, list)) and len(theset[0]) == 2:
|
||||
self.theset = [str(item) for item, label in theset]
|
||||
self.labels = [str(label) for item, label in theset]
|
||||
else:
|
||||
self.theset = [str(item) for item in theset]
|
||||
self.labels = labels
|
||||
@@ -350,7 +353,7 @@ class IS_IN_SET(Validator):
|
||||
self.zero = zero
|
||||
self.sort = sort
|
||||
|
||||
def options(self,zero=True):
|
||||
def options(self, zero=True):
|
||||
if not self.labels:
|
||||
items = [(k, k) for (i, k) in enumerate(self.theset)]
|
||||
else:
|
||||
@@ -358,7 +361,7 @@ class IS_IN_SET(Validator):
|
||||
if self.sort:
|
||||
items.sort(options_sorter)
|
||||
if zero and not self.zero is None and not self.multiple:
|
||||
items.insert(0,('',self.zero))
|
||||
items.insert(0, ('', self.zero))
|
||||
return items
|
||||
|
||||
def __call__(self, value):
|
||||
@@ -379,8 +382,8 @@ class IS_IN_SET(Validator):
|
||||
return ([], None)
|
||||
return (value, translate(self.error_message))
|
||||
if self.multiple:
|
||||
if isinstance(self.multiple,(tuple,list)) and \
|
||||
not self.multiple[0]<=len(values)<self.multiple[1]:
|
||||
if isinstance(self.multiple, (tuple, list)) and \
|
||||
not self.multiple[0] <= len(values) < self.multiple[1]:
|
||||
return (values, translate(self.error_message))
|
||||
return (values, None)
|
||||
return (value, None)
|
||||
@@ -414,9 +417,10 @@ class IS_IN_DB(Validator):
|
||||
zero='',
|
||||
sort=False,
|
||||
_and=None,
|
||||
):
|
||||
):
|
||||
from dal import Table
|
||||
if isinstance(field,Table): field = field._id
|
||||
if isinstance(field, Table):
|
||||
field = field._id
|
||||
|
||||
if hasattr(dbset, 'define_table'):
|
||||
self.dbset = dbset()
|
||||
@@ -425,7 +429,7 @@ class IS_IN_DB(Validator):
|
||||
(ktable, kfield) = str(field).split('.')
|
||||
if not label:
|
||||
label = '%%(%s)s' % kfield
|
||||
if isinstance(label,str):
|
||||
if isinstance(label, str):
|
||||
if regex1.match(str(label)):
|
||||
label = '%%(%s)s' % str(label).split('.')[-1]
|
||||
ks = regex2.findall(label)
|
||||
@@ -462,7 +466,7 @@ class IS_IN_DB(Validator):
|
||||
else:
|
||||
fields = [table[k] for k in self.fields]
|
||||
if self.dbset.db._dbname != 'gae':
|
||||
orderby = self.orderby or reduce(lambda a,b:a|b,fields)
|
||||
orderby = self.orderby or reduce(lambda a, b: a | b, fields)
|
||||
groupby = self.groupby
|
||||
distinct = self.distinct
|
||||
dd = dict(orderby=orderby, groupby=groupby,
|
||||
@@ -471,11 +475,12 @@ class IS_IN_DB(Validator):
|
||||
records = self.dbset(table).select(*fields, **dd)
|
||||
else:
|
||||
orderby = self.orderby or \
|
||||
reduce(lambda a,b:a|b,(f for f in fields if not f.name=='id'))
|
||||
reduce(lambda a, b: a | b, (
|
||||
f for f in fields if not f.name == 'id'))
|
||||
dd = dict(orderby=orderby, cache=self.cache, cacheable=True)
|
||||
records = self.dbset(table).select(table.ALL, **dd)
|
||||
self.theset = [str(r[self.kfield]) for r in records]
|
||||
if isinstance(self.label,str):
|
||||
if isinstance(self.label, str):
|
||||
self.labels = [self.label % dict(r) for r in records]
|
||||
else:
|
||||
self.labels = [self.label(r) for r in records]
|
||||
@@ -486,7 +491,7 @@ class IS_IN_DB(Validator):
|
||||
if self.sort:
|
||||
items.sort(options_sorter)
|
||||
if zero and not self.zero is None and not self.multiple:
|
||||
items.insert(0,('',self.zero))
|
||||
items.insert(0, ('', self.zero))
|
||||
return items
|
||||
|
||||
def __call__(self, value):
|
||||
@@ -495,25 +500,26 @@ class IS_IN_DB(Validator):
|
||||
if self.multiple:
|
||||
if self._and:
|
||||
raise NotImplementedError
|
||||
if isinstance(value,list):
|
||||
values=value
|
||||
if isinstance(value, list):
|
||||
values = value
|
||||
elif value:
|
||||
values = [value]
|
||||
else:
|
||||
values = []
|
||||
if isinstance(self.multiple,(tuple,list)) and \
|
||||
not self.multiple[0]<=len(values)<self.multiple[1]:
|
||||
if isinstance(self.multiple, (tuple, list)) and \
|
||||
not self.multiple[0] <= len(values) < self.multiple[1]:
|
||||
return (values, translate(self.error_message))
|
||||
if self.theset:
|
||||
if not [v for v in values if not v in self.theset]:
|
||||
return (values, None)
|
||||
else:
|
||||
from dal import GoogleDatastoreAdapter
|
||||
|
||||
def count(values, s=self.dbset, f=field):
|
||||
return s(f.belongs(map(int,values))).count()
|
||||
return s(f.belongs(map(int, values))).count()
|
||||
if isinstance(self.dbset.db._adapter, GoogleDatastoreAdapter):
|
||||
range_ids = range(0,len(values),30)
|
||||
total = sum(count(values[i:i+30]) for i in range_ids)
|
||||
range_ids = range(0, len(values), 30)
|
||||
total = sum(count(values[i:i + 30]) for i in range_ids)
|
||||
if total == len(values):
|
||||
return (values, None)
|
||||
elif count(values) == len(values):
|
||||
@@ -549,10 +555,11 @@ class IS_NOT_IN_DB(Validator):
|
||||
error_message='value already in database or empty',
|
||||
allowed_override=[],
|
||||
ignore_common_filters=False,
|
||||
):
|
||||
):
|
||||
|
||||
from dal import Table
|
||||
if isinstance(field,Table): field = field._id
|
||||
if isinstance(field, Table):
|
||||
field = field._id
|
||||
|
||||
if hasattr(dbset, 'define_table'):
|
||||
self.dbset = dbset()
|
||||
@@ -568,7 +575,7 @@ class IS_NOT_IN_DB(Validator):
|
||||
self.record_id = id
|
||||
|
||||
def __call__(self, value):
|
||||
value=str(value)
|
||||
value = str(value)
|
||||
if not value.strip():
|
||||
return (value, translate(self.error_message))
|
||||
if value in self.allowed_override:
|
||||
@@ -576,7 +583,7 @@ class IS_NOT_IN_DB(Validator):
|
||||
(tablename, fieldname) = str(self.field).split('.')
|
||||
table = self.dbset.db[tablename]
|
||||
field = table[fieldname]
|
||||
rows = self.dbset(field == value, ignore_common_filters = self.ignore_common_filters).select(limitby=(0, 1))
|
||||
rows = self.dbset(field == value, ignore_common_filters=self.ignore_common_filters).select(limitby=(0, 1))
|
||||
if len(rows) > 0:
|
||||
if isinstance(self.record_id, dict):
|
||||
for f in self.record_id:
|
||||
@@ -631,7 +638,7 @@ class IS_INT_IN_RANGE(Validator):
|
||||
minimum=None,
|
||||
maximum=None,
|
||||
error_message=None,
|
||||
):
|
||||
):
|
||||
self.minimum = self.maximum = None
|
||||
if minimum is None:
|
||||
if maximum is None:
|
||||
@@ -640,19 +647,21 @@ class IS_INT_IN_RANGE(Validator):
|
||||
self.maximum = int(maximum)
|
||||
if error_message is None:
|
||||
error_message = 'enter an integer less than or equal to %(max)g'
|
||||
self.error_message = translate(error_message) % dict(max=self.maximum-1)
|
||||
self.error_message = translate(
|
||||
error_message) % dict(max=self.maximum - 1)
|
||||
elif maximum is None:
|
||||
self.minimum = int(minimum)
|
||||
if error_message is None:
|
||||
error_message = 'enter an integer greater than or equal to %(min)g'
|
||||
self.error_message = translate(error_message) % dict(min=self.minimum)
|
||||
self.error_message = translate(
|
||||
error_message) % dict(min=self.minimum)
|
||||
else:
|
||||
self.minimum = int(minimum)
|
||||
self.maximum = int(maximum)
|
||||
if error_message is None:
|
||||
error_message = 'enter an integer between %(min)g and %(max)g'
|
||||
self.error_message = translate(error_message) \
|
||||
% dict(min=self.minimum, max=self.maximum-1)
|
||||
% dict(min=self.minimum, max=self.maximum - 1)
|
||||
|
||||
def __call__(self, value):
|
||||
try:
|
||||
@@ -672,12 +681,16 @@ class IS_INT_IN_RANGE(Validator):
|
||||
pass
|
||||
return (value, self.error_message)
|
||||
|
||||
|
||||
def str2dec(number):
|
||||
s = str(number)
|
||||
if not '.' in s: s+='.00'
|
||||
else: s+='0'*(2-len(s.split('.')[1]))
|
||||
if not '.' in s:
|
||||
s += '.00'
|
||||
else:
|
||||
s += '0' * (2 - len(s.split('.')[1]))
|
||||
return s
|
||||
|
||||
|
||||
class IS_FLOAT_IN_RANGE(Validator):
|
||||
"""
|
||||
Determine that the argument is (or can be represented as) a float,
|
||||
@@ -723,7 +736,7 @@ class IS_FLOAT_IN_RANGE(Validator):
|
||||
maximum=None,
|
||||
error_message=None,
|
||||
dot='.'
|
||||
):
|
||||
):
|
||||
self.minimum = self.maximum = None
|
||||
self.dot = dot
|
||||
if minimum is None:
|
||||
@@ -748,10 +761,10 @@ class IS_FLOAT_IN_RANGE(Validator):
|
||||
|
||||
def __call__(self, value):
|
||||
try:
|
||||
if self.dot=='.':
|
||||
if self.dot == '.':
|
||||
fvalue = float(value)
|
||||
else:
|
||||
fvalue = float(str(value).replace(self.dot,'.'))
|
||||
fvalue = float(str(value).replace(self.dot, '.'))
|
||||
if self.minimum is None:
|
||||
if self.maximum is None or fvalue <= self.maximum:
|
||||
return (fvalue, None)
|
||||
@@ -764,8 +777,8 @@ class IS_FLOAT_IN_RANGE(Validator):
|
||||
pass
|
||||
return (value, self.error_message)
|
||||
|
||||
def formatter(self,value):
|
||||
return str2dec(value).replace('.',self.dot)
|
||||
def formatter(self, value):
|
||||
return str2dec(value).replace('.', self.dot)
|
||||
|
||||
|
||||
class IS_DECIMAL_IN_RANGE(Validator):
|
||||
@@ -827,7 +840,7 @@ class IS_DECIMAL_IN_RANGE(Validator):
|
||||
maximum=None,
|
||||
error_message=None,
|
||||
dot='.'
|
||||
):
|
||||
):
|
||||
self.minimum = self.maximum = None
|
||||
self.dot = dot
|
||||
if minimum is None:
|
||||
@@ -852,10 +865,10 @@ class IS_DECIMAL_IN_RANGE(Validator):
|
||||
|
||||
def __call__(self, value):
|
||||
try:
|
||||
if isinstance(value,decimal.Decimal):
|
||||
if isinstance(value, decimal.Decimal):
|
||||
v = value
|
||||
else:
|
||||
v = decimal.Decimal(str(value).replace(self.dot,'.'))
|
||||
v = decimal.Decimal(str(value).replace(self.dot, '.'))
|
||||
if self.minimum is None:
|
||||
if self.maximum is None or v <= self.maximum:
|
||||
return (v, None)
|
||||
@@ -869,7 +882,8 @@ class IS_DECIMAL_IN_RANGE(Validator):
|
||||
return (value, self.error_message)
|
||||
|
||||
def formatter(self, value):
|
||||
return str2dec(value).replace('.',self.dot)
|
||||
return str2dec(value).replace('.', self.dot)
|
||||
|
||||
|
||||
def is_empty(value, empty_regex=None):
|
||||
"test empty field"
|
||||
@@ -881,6 +895,7 @@ def is_empty(value, empty_regex=None):
|
||||
return (value, True)
|
||||
return (value, False)
|
||||
|
||||
|
||||
class IS_NOT_EMPTY(Validator):
|
||||
"""
|
||||
example::
|
||||
@@ -1048,7 +1063,8 @@ class IS_EMAIL(Validator):
|
||||
localhost
|
||||
|
|
||||
(
|
||||
[a-z0-9] # [sub]domain begins with alphanumeric
|
||||
[a-z0-9]
|
||||
# [sub]domain begins with alphanumeric
|
||||
(
|
||||
[-\w]* # alphanumeric, underscore, dot, hyphen
|
||||
[a-z0-9] # ending alphanumeric
|
||||
@@ -1057,9 +1073,9 @@ class IS_EMAIL(Validator):
|
||||
)+
|
||||
[a-z]{2,} # TLD alpha-only
|
||||
)$
|
||||
''', re.VERBOSE|re.IGNORECASE)
|
||||
''', re.VERBOSE | re.IGNORECASE)
|
||||
|
||||
regex_proposed_but_failed = re.compile('^([\w\!\#$\%\&\'\*\+\-\/\=\?\^\`{\|\}\~]+\.)*[\w\!\#$\%\&\'\*\+\-\/\=\?\^\`{\|\}\~]+@((((([a-z0-9]{1}[a-z0-9\-]{0,62}[a-z0-9]{1})|[a-z])\.)+[a-z]{2,6})|(\d{1,3}\.){3}\d{1,3}(\:\d{1,5})?)$',re.VERBOSE|re.IGNORECASE)
|
||||
regex_proposed_but_failed = re.compile('^([\w\!\#$\%\&\'\*\+\-\/\=\?\^\`{\|\}\~]+\.)*[\w\!\#$\%\&\'\*\+\-\/\=\?\^\`{\|\}\~]+@((((([a-z0-9]{1}[a-z0-9\-]{0,62}[a-z0-9]{1})|[a-z])\.)+[a-z]{2,6})|(\d{1,3}\.){3}\d{1,3}(\:\d{1,5})?)$', re.VERBOSE | re.IGNORECASE)
|
||||
|
||||
def __init__(self,
|
||||
banned=None,
|
||||
@@ -1153,7 +1169,7 @@ official_url_schemes = [
|
||||
'xmpp',
|
||||
'z39.50r',
|
||||
'z39.50s',
|
||||
]
|
||||
]
|
||||
unofficial_url_schemes = [
|
||||
'about',
|
||||
'adiumxtra',
|
||||
@@ -1207,7 +1223,7 @@ unofficial_url_schemes = [
|
||||
'xfire',
|
||||
'xri',
|
||||
'ymsgr',
|
||||
]
|
||||
]
|
||||
all_url_schemes = [None] + official_url_schemes + unofficial_url_schemes
|
||||
http_schemes = [None, 'http', 'https']
|
||||
|
||||
@@ -1298,7 +1314,7 @@ def unicode_to_ascii_authority(authority):
|
||||
#don't modify the URL
|
||||
asciiLabels.append('')
|
||||
except:
|
||||
asciiLabels=[str(label) for label in labels]
|
||||
asciiLabels = [str(label) for label in labels]
|
||||
#RFC 3490, Section 4, Step 5
|
||||
return str(reduce(lambda x, y: x + unichr(0x002E) + y, asciiLabels))
|
||||
|
||||
@@ -1345,8 +1361,8 @@ def unicode_to_ascii_url(url, prepend_scheme):
|
||||
unicode(scheme_to_prepend) + u'://' + url).groups()
|
||||
#if we still can't find the authority
|
||||
if not groups[3]:
|
||||
raise Exception('No authority component found, '+ \
|
||||
'could not decode unicode to US-ASCII')
|
||||
raise Exception('No authority component found, ' +
|
||||
'could not decode unicode to US-ASCII')
|
||||
|
||||
#We're here if we found an authority, let's rebuild the URL
|
||||
scheme = groups[1]
|
||||
@@ -1395,13 +1411,12 @@ class IS_GENERIC_URL(Validator):
|
||||
|
||||
"""
|
||||
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
error_message='enter a valid URL',
|
||||
allowed_schemes=None,
|
||||
prepend_scheme=None,
|
||||
):
|
||||
):
|
||||
"""
|
||||
:param error_message: a string, the error message to give the end user
|
||||
if the URL does not validate
|
||||
@@ -1418,9 +1433,8 @@ class IS_GENERIC_URL(Validator):
|
||||
self.allowed_schemes = allowed_schemes
|
||||
self.prepend_scheme = prepend_scheme
|
||||
if self.prepend_scheme not in self.allowed_schemes:
|
||||
raise SyntaxError, \
|
||||
"prepend_scheme='%s' is not in allowed_schemes=%s" \
|
||||
% (self.prepend_scheme, self.allowed_schemes)
|
||||
raise SyntaxError("prepend_scheme='%s' is not in allowed_schemes=%s"
|
||||
% (self.prepend_scheme, self.allowed_schemes))
|
||||
|
||||
GENERIC_URL = re.compile(r"%[^0-9A-Fa-f]{2}|%[^0-9A-Fa-f][0-9A-Fa-f]|%[0-9A-Fa-f][^0-9A-Fa-f]|%$|%[0-9A-Fa-f]$|%[^0-9A-Fa-f]$")
|
||||
GENERIC_URL_VALID = re.compile(r"[A-Za-z0-9;/?:@&=+$,\-_\.!~*'\(\)%#]+$")
|
||||
@@ -1452,7 +1466,7 @@ class IS_GENERIC_URL(Validator):
|
||||
# ports, check to see if adding a valid scheme fixes
|
||||
# the problem (but only do this if it doesn't have
|
||||
# one already!)
|
||||
if value.find('://')<0 and None in self.allowed_schemes:
|
||||
if value.find('://') < 0 and None in self.allowed_schemes:
|
||||
schemeToUse = self.prepend_scheme or 'http'
|
||||
prependTest = self.__call__(
|
||||
schemeToUse + '://' + value)
|
||||
@@ -1763,7 +1777,7 @@ official_top_level_domains = [
|
||||
'za',
|
||||
'zm',
|
||||
'zw',
|
||||
]
|
||||
]
|
||||
|
||||
|
||||
class IS_HTTP_URL(Validator):
|
||||
@@ -1810,7 +1824,8 @@ class IS_HTTP_URL(Validator):
|
||||
|
||||
"""
|
||||
|
||||
GENERIC_VALID_IP = re.compile("([\w.!~*'|;:&=+$,-]+@)?\d+\.\d+\.\d+\.\d+(:\d*)*$")
|
||||
GENERIC_VALID_IP = re.compile(
|
||||
"([\w.!~*'|;:&=+$,-]+@)?\d+\.\d+\.\d+\.\d+(:\d*)*$")
|
||||
GENERIC_VALID_DOMAIN = re.compile("([\w.!~*'|;:&=+$,-]+@)?(([A-Za-z0-9]+[A-Za-z0-9\-]*[A-Za-z0-9]+\.)*([A-Za-z0-9]+\.)*)*([A-Za-z]+[A-Za-z0-9\-]*[A-Za-z0-9]+)\.?(:\d*)*$")
|
||||
|
||||
def __init__(
|
||||
@@ -1818,7 +1833,7 @@ class IS_HTTP_URL(Validator):
|
||||
error_message='enter a valid URL',
|
||||
allowed_schemes=None,
|
||||
prepend_scheme='http',
|
||||
):
|
||||
):
|
||||
"""
|
||||
:param error_message: a string, the error message to give the end user
|
||||
if the URL does not validate
|
||||
@@ -1837,14 +1852,12 @@ class IS_HTTP_URL(Validator):
|
||||
|
||||
for i in self.allowed_schemes:
|
||||
if i not in http_schemes:
|
||||
raise SyntaxError, \
|
||||
"allowed_scheme value '%s' is not in %s" % \
|
||||
(i, http_schemes)
|
||||
raise SyntaxError("allowed_scheme value '%s' is not in %s" %
|
||||
(i, http_schemes))
|
||||
|
||||
if self.prepend_scheme not in self.allowed_schemes:
|
||||
raise SyntaxError, \
|
||||
"prepend_scheme='%s' is not in allowed_schemes=%s" % \
|
||||
(self.prepend_scheme, self.allowed_schemes)
|
||||
raise SyntaxError("prepend_scheme='%s' is not in allowed_schemes=%s" %
|
||||
(self.prepend_scheme, self.allowed_schemes))
|
||||
|
||||
def __call__(self, value):
|
||||
"""
|
||||
@@ -1870,11 +1883,12 @@ class IS_HTTP_URL(Validator):
|
||||
return (value, None)
|
||||
else:
|
||||
# else if authority is a valid domain name
|
||||
domainMatch = self.GENERIC_VALID_DOMAIN.match(authority)
|
||||
domainMatch = self.GENERIC_VALID_DOMAIN.match(
|
||||
authority)
|
||||
if domainMatch:
|
||||
# if the top-level domain really exists
|
||||
if domainMatch.group(5).lower()\
|
||||
in official_top_level_domains:
|
||||
in official_top_level_domains:
|
||||
# Then this HTTP URL is valid
|
||||
return (value, None)
|
||||
else:
|
||||
@@ -1889,10 +1903,10 @@ class IS_HTTP_URL(Validator):
|
||||
else:
|
||||
# abbreviated case: if we haven't already, prepend a
|
||||
# scheme and see if it fixes the problem
|
||||
if value.find('://')<0:
|
||||
if value.find('://') < 0:
|
||||
schemeToUse = self.prepend_scheme or 'http'
|
||||
prependTest = self.__call__(schemeToUse
|
||||
+ '://' + value)
|
||||
+ '://' + value)
|
||||
# if the prepend test succeeded
|
||||
if prependTest[1] is None:
|
||||
# if prepending in the output is enabled
|
||||
@@ -1989,7 +2003,7 @@ class IS_URL(Validator):
|
||||
mode='http',
|
||||
allowed_schemes=None,
|
||||
prepend_scheme='http',
|
||||
):
|
||||
):
|
||||
"""
|
||||
:param error_message: a string, the error message to give the end user
|
||||
if the URL does not validate
|
||||
@@ -2002,14 +2016,13 @@ class IS_URL(Validator):
|
||||
self.error_message = error_message
|
||||
self.mode = mode.lower()
|
||||
if not self.mode in ['generic', 'http']:
|
||||
raise SyntaxError, "invalid mode '%s' in IS_URL" % self.mode
|
||||
raise SyntaxError("invalid mode '%s' in IS_URL" % self.mode)
|
||||
self.allowed_schemes = allowed_schemes
|
||||
|
||||
if self.allowed_schemes:
|
||||
if prepend_scheme not in self.allowed_schemes:
|
||||
raise SyntaxError, \
|
||||
"prepend_scheme='%s' is not in allowed_schemes=%s" \
|
||||
% (prepend_scheme, self.allowed_schemes)
|
||||
raise SyntaxError("prepend_scheme='%s' is not in allowed_schemes=%s"
|
||||
% (prepend_scheme, self.allowed_schemes))
|
||||
|
||||
# if allowed_schemes is None, then we will defer testing
|
||||
# prepend_scheme's validity to a sub-method
|
||||
@@ -2036,7 +2049,7 @@ class IS_URL(Validator):
|
||||
allowed_schemes=self.allowed_schemes,
|
||||
prepend_scheme=self.prepend_scheme)
|
||||
else:
|
||||
raise SyntaxError, "invalid mode '%s' in IS_URL" % self.mode
|
||||
raise SyntaxError("invalid mode '%s' in IS_URL" % self.mode)
|
||||
|
||||
if type(value) != unicode:
|
||||
return subMethod(value)
|
||||
@@ -2117,9 +2130,8 @@ class IS_TIME(Validator):
|
||||
if value.group('d') == 'pm' and 0 < h < 12:
|
||||
h = h + 12
|
||||
if not (h in range(24) and m in range(60) and s
|
||||
in range(60)):
|
||||
raise ValueError\
|
||||
('Hours or minutes or seconds are outside of allowed range')
|
||||
in range(60)):
|
||||
raise ValueError('Hours or minutes or seconds are outside of allowed range')
|
||||
value = datetime.time(h, m, s)
|
||||
return (value, None)
|
||||
except AttributeError:
|
||||
@@ -2145,8 +2157,8 @@ class IS_DATE(Validator):
|
||||
self.extremes = {}
|
||||
|
||||
def __call__(self, value):
|
||||
if isinstance(value,datetime.date):
|
||||
return (value,None)
|
||||
if isinstance(value, datetime.date):
|
||||
return (value, None)
|
||||
try:
|
||||
(y, m, d, hh, mm, ss, t0, t1, t2) = \
|
||||
time.strptime(value, str(self.format))
|
||||
@@ -2160,11 +2172,11 @@ class IS_DATE(Validator):
|
||||
format = self.format
|
||||
year = value.year
|
||||
y = '%.4i' % year
|
||||
format = format.replace('%y',y[-2:])
|
||||
format = format.replace('%Y',y)
|
||||
if year<1900:
|
||||
format = format.replace('%y', y[-2:])
|
||||
format = format.replace('%Y', y)
|
||||
if year < 1900:
|
||||
year = 2000
|
||||
d = datetime.date(year,value.month,value.day)
|
||||
d = datetime.date(year, value.month, value.day)
|
||||
return d.strftime(format)
|
||||
|
||||
|
||||
@@ -2181,19 +2193,19 @@ class IS_DATETIME(Validator):
|
||||
|
||||
@staticmethod
|
||||
def nice(format):
|
||||
code=(('%Y','1963'),
|
||||
('%y','63'),
|
||||
('%d','28'),
|
||||
('%m','08'),
|
||||
('%b','Aug'),
|
||||
('%B','August'),
|
||||
('%H','14'),
|
||||
('%I','02'),
|
||||
('%p','PM'),
|
||||
('%M','30'),
|
||||
('%S','59'))
|
||||
for (a,b) in code:
|
||||
format=format.replace(a,b)
|
||||
code = (('%Y', '1963'),
|
||||
('%y', '63'),
|
||||
('%d', '28'),
|
||||
('%m', '08'),
|
||||
('%b', 'Aug'),
|
||||
('%B', 'August'),
|
||||
('%H', '14'),
|
||||
('%I', '02'),
|
||||
('%p', 'PM'),
|
||||
('%M', '30'),
|
||||
('%S', '59'))
|
||||
for (a, b) in code:
|
||||
format = format.replace(a, b)
|
||||
return dict(format=format)
|
||||
|
||||
def __init__(self, format='%Y-%m-%d %H:%M:%S',
|
||||
@@ -2203,8 +2215,8 @@ class IS_DATETIME(Validator):
|
||||
self.extremes = {}
|
||||
|
||||
def __call__(self, value):
|
||||
if isinstance(value,datetime.datetime):
|
||||
return (value,None)
|
||||
if isinstance(value, datetime.datetime):
|
||||
return (value, None)
|
||||
try:
|
||||
(y, m, d, hh, mm, ss, t0, t1, t2) = \
|
||||
time.strptime(value, str(self.format))
|
||||
@@ -2214,19 +2226,19 @@ class IS_DATETIME(Validator):
|
||||
self.extremes.update(IS_DATETIME.nice(self.format))
|
||||
return (value, translate(self.error_message) % self.extremes)
|
||||
|
||||
|
||||
def formatter(self, value):
|
||||
format = self.format
|
||||
year = value.year
|
||||
y = '%.4i' % year
|
||||
format = format.replace('%y',y[-2:])
|
||||
format = format.replace('%Y',y)
|
||||
if year<1900:
|
||||
format = format.replace('%y', y[-2:])
|
||||
format = format.replace('%Y', y)
|
||||
if year < 1900:
|
||||
year = 2000
|
||||
d = datetime.datetime(year,value.month,value.day,
|
||||
value.hour,value.minute,value.second)
|
||||
d = datetime.datetime(year, value.month, value.day,
|
||||
value.hour, value.minute, value.second)
|
||||
return d.strftime(format)
|
||||
|
||||
|
||||
class IS_DATE_IN_RANGE(IS_DATE):
|
||||
"""
|
||||
example::
|
||||
@@ -2249,10 +2261,10 @@ class IS_DATE_IN_RANGE(IS_DATE):
|
||||
|
||||
"""
|
||||
def __init__(self,
|
||||
minimum = None,
|
||||
maximum = None,
|
||||
minimum=None,
|
||||
maximum=None,
|
||||
format='%Y-%m-%d',
|
||||
error_message = None):
|
||||
error_message=None):
|
||||
self.minimum = minimum
|
||||
self.maximum = maximum
|
||||
if error_message is None:
|
||||
@@ -2263,12 +2275,12 @@ class IS_DATE_IN_RANGE(IS_DATE):
|
||||
else:
|
||||
error_message = "enter date in range %(min)s %(max)s"
|
||||
IS_DATE.__init__(self,
|
||||
format = format,
|
||||
error_message = error_message)
|
||||
format=format,
|
||||
error_message=error_message)
|
||||
self.extremes = dict(min=minimum, max=maximum)
|
||||
|
||||
def __call__(self, value):
|
||||
(value, msg) = IS_DATE.__call__(self,value)
|
||||
(value, msg) = IS_DATE.__call__(self, value)
|
||||
if msg is not None:
|
||||
return (value, msg)
|
||||
if self.minimum and self.minimum > value:
|
||||
@@ -2299,10 +2311,10 @@ class IS_DATETIME_IN_RANGE(IS_DATETIME):
|
||||
(datetime.datetime(2010, 3, 3, 0, 0), 'oops')
|
||||
"""
|
||||
def __init__(self,
|
||||
minimum = None,
|
||||
maximum = None,
|
||||
format = '%Y-%m-%d %H:%M:%S',
|
||||
error_message = None):
|
||||
minimum=None,
|
||||
maximum=None,
|
||||
format='%Y-%m-%d %H:%M:%S',
|
||||
error_message=None):
|
||||
self.minimum = minimum
|
||||
self.maximum = maximum
|
||||
if error_message is None:
|
||||
@@ -2313,9 +2325,9 @@ class IS_DATETIME_IN_RANGE(IS_DATETIME):
|
||||
else:
|
||||
error_message = "enter date and time in range %(min)s %(max)s"
|
||||
IS_DATETIME.__init__(self,
|
||||
format = format,
|
||||
error_message = error_message)
|
||||
self.extremes = dict(min = minimum, max = maximum)
|
||||
format=format,
|
||||
error_message=error_message)
|
||||
self.extremes = dict(min=minimum, max=maximum)
|
||||
|
||||
def __call__(self, value):
|
||||
(value, msg) = IS_DATETIME.__call__(self, value)
|
||||
@@ -2331,7 +2343,7 @@ class IS_DATETIME_IN_RANGE(IS_DATETIME):
|
||||
class IS_LIST_OF(Validator):
|
||||
|
||||
def __init__(self, other=None, minimum=0, maximum=100,
|
||||
error_message = None):
|
||||
error_message=None):
|
||||
self.other = other
|
||||
self.minimum = minimum
|
||||
self.maximum = maximum
|
||||
@@ -2341,10 +2353,10 @@ class IS_LIST_OF(Validator):
|
||||
ivalue = value
|
||||
if not isinstance(value, list):
|
||||
ivalue = [ivalue]
|
||||
if not self.minimum is None and len(ivalue)<self.minimum:
|
||||
return (ivalue, translate(self.error_message) % dict(min=self.minimum,max=self.maximum))
|
||||
if not self.maximum is None and len(ivalue)>self.maximum:
|
||||
return (ivalue, translate(self.error_message) % dict(min=self.minimum,max=self.maximum))
|
||||
if not self.minimum is None and len(ivalue) < self.minimum:
|
||||
return (ivalue, translate(self.error_message) % dict(min=self.minimum, max=self.maximum))
|
||||
if not self.maximum is None and len(ivalue) > self.maximum:
|
||||
return (ivalue, translate(self.error_message) % dict(min=self.minimum, max=self.maximum))
|
||||
new_value = []
|
||||
if self.other:
|
||||
for item in ivalue:
|
||||
@@ -2399,7 +2411,8 @@ def urlify(value, maxlen=80, keep_underscores=False):
|
||||
s = re.sub('&\w+;', '', s) # strip html entities
|
||||
if keep_underscores:
|
||||
s = re.sub('\s+', '-', s) # whitespace to hyphens
|
||||
s = re.sub('[^\w\-]', '', s) # strip all but alphanumeric/underscore/hyphen
|
||||
s = re.sub('[^\w\-]', '', s)
|
||||
# strip all but alphanumeric/underscore/hyphen
|
||||
else:
|
||||
s = re.sub('[\s_]+', '-', s) # whitespace & underscores to hyphens
|
||||
s = re.sub('[^a-z0-9\-]', '', s) # strip all but alphanumeric/hyphen
|
||||
@@ -2465,7 +2478,8 @@ class IS_SLUG(Validator):
|
||||
def __call__(self, value):
|
||||
if self.check and value != urlify(value, self.maxlen, self.keep_underscores):
|
||||
return (value, translate(self.error_message))
|
||||
return (urlify(value,self.maxlen, self.keep_underscores), None)
|
||||
return (urlify(value, self.maxlen, self.keep_underscores), None)
|
||||
|
||||
|
||||
class IS_EMPTY_OR(Validator):
|
||||
"""
|
||||
@@ -2494,12 +2508,12 @@ class IS_EMPTY_OR(Validator):
|
||||
if hasattr(other, 'multiple'):
|
||||
self.multiple = other.multiple
|
||||
if hasattr(other, 'options'):
|
||||
self.options=self._options
|
||||
self.options = self._options
|
||||
|
||||
def _options(self):
|
||||
options = self.other.options()
|
||||
if (not options or options[0][0]!='') and not self.multiple:
|
||||
options.insert(0,('',''))
|
||||
if (not options or options[0][0] != '') and not self.multiple:
|
||||
options.insert(0, ('', ''))
|
||||
return options
|
||||
|
||||
def set_self_id(self, id):
|
||||
@@ -2519,7 +2533,8 @@ class IS_EMPTY_OR(Validator):
|
||||
error = None
|
||||
for item in self.other:
|
||||
value, error = item(value)
|
||||
if error: break
|
||||
if error:
|
||||
break
|
||||
return value, error
|
||||
else:
|
||||
return self.other(value)
|
||||
@@ -2547,14 +2562,15 @@ class CLEANUP(Validator):
|
||||
else re.compile(regex)
|
||||
|
||||
def __call__(self, value):
|
||||
v = self.regex.sub('',str(value).strip())
|
||||
v = self.regex.sub('', str(value).strip())
|
||||
return (v, None)
|
||||
|
||||
|
||||
class LazyCrypt(object):
|
||||
"""
|
||||
Stores a lazy password hash
|
||||
"""
|
||||
def __init__(self,crypt,password):
|
||||
def __init__(self, crypt, password):
|
||||
"""
|
||||
crypt is an instance of the CRYPT validator,
|
||||
password is the password as inserted by the user
|
||||
@@ -2585,14 +2601,14 @@ class LazyCrypt(object):
|
||||
return self.crypted
|
||||
if self.crypt.key:
|
||||
if ':' in self.crypt.key:
|
||||
digest_alg, key = self.crypt.key.split(':',1)
|
||||
digest_alg, key = self.crypt.key.split(':', 1)
|
||||
else:
|
||||
digest_alg, key = self.crypt.digest_alg, self.crypt.key
|
||||
else:
|
||||
digest_alg, key = self.crypt.digest_alg, ''
|
||||
if self.crypt.salt:
|
||||
if self.crypt.salt == True:
|
||||
salt = str(web2py_uuid()).replace('-','')[-16:]
|
||||
salt = str(web2py_uuid()).replace('-', '')[-16:]
|
||||
else:
|
||||
salt = self.crypt.salt
|
||||
else:
|
||||
@@ -2614,13 +2630,13 @@ class LazyCrypt(object):
|
||||
key = ''
|
||||
if stored_password is None:
|
||||
return False
|
||||
elif stored_password.count('$')==2:
|
||||
elif stored_password.count('$') == 2:
|
||||
(digest_alg, salt, hash) = stored_password.split('$')
|
||||
h = simple_hash(self.password, key, salt, digest_alg)
|
||||
temp_pass = '%s$%s$%s' % (digest_alg, salt, h)
|
||||
else: # no salting
|
||||
else: # no salting
|
||||
# guess digest_alg
|
||||
digest_alg = DIGEST_ALG_BY_SIZE.get(len(stored_password),None)
|
||||
digest_alg = DIGEST_ALG_BY_SIZE.get(len(stored_password), None)
|
||||
if not digest_alg:
|
||||
return False
|
||||
else:
|
||||
@@ -2725,9 +2741,9 @@ class CRYPT(object):
|
||||
self.salt = salt
|
||||
|
||||
def __call__(self, value):
|
||||
if len(value)<self.min_length:
|
||||
if len(value) < self.min_length:
|
||||
return ('', translate(self.error_message))
|
||||
return (LazyCrypt(self,value),None)
|
||||
return (LazyCrypt(self, value), None)
|
||||
|
||||
# entropy calculator for IS_STRONG
|
||||
#
|
||||
@@ -2736,7 +2752,9 @@ upperset = frozenset(unicode('ABCDEFGHIJKLMNOPQRSTUVWXYZ'))
|
||||
numberset = frozenset(unicode('0123456789'))
|
||||
sym1set = frozenset(unicode('!@#$%^&*()'))
|
||||
sym2set = frozenset(unicode('~`-_=+[]{}\\|;:\'",.<>?/'))
|
||||
otherset = frozenset(unicode('0123456789abcdefghijklmnopqrstuvwxyz')) # anything else
|
||||
otherset = frozenset(
|
||||
unicode('0123456789abcdefghijklmnopqrstuvwxyz')) # anything else
|
||||
|
||||
|
||||
def calc_entropy(string):
|
||||
" calculate a simple entropy for a given string "
|
||||
@@ -2764,9 +2782,11 @@ def calc_entropy(string):
|
||||
if inset is not lastset:
|
||||
alphabet += 1 # credit for set transitions
|
||||
lastset = cset
|
||||
entropy = len(string) * math.log(alphabet) / 0.6931471805599453 # math.log(2)
|
||||
entropy = len(
|
||||
string) * math.log(alphabet) / 0.6931471805599453 # math.log(2)
|
||||
return round(entropy, 2)
|
||||
|
||||
|
||||
class IS_STRONG(object):
|
||||
"""
|
||||
example::
|
||||
@@ -2777,7 +2797,8 @@ class IS_STRONG(object):
|
||||
enforces complexity requirements on a field
|
||||
|
||||
>>> IS_STRONG(es=True)('Abcd1234')
|
||||
('Abcd1234', 'Must include at least 1 of the following: ~!@#$%^&*()_+-=?<>,.:;{}[]|')
|
||||
('Abcd1234',
|
||||
'Must include at least 1 of the following: ~!@#$%^&*()_+-=?<>,.:;{}[]|')
|
||||
>>> IS_STRONG(es=True)('Abcd1234!')
|
||||
('Abcd1234!', None)
|
||||
>>> IS_STRONG(es=True, entropy=1)('a')
|
||||
@@ -2828,8 +2849,8 @@ class IS_STRONG(object):
|
||||
if self.entropy is not None:
|
||||
entropy = calc_entropy(value)
|
||||
if entropy < self.entropy:
|
||||
failures.append(translate("Entropy (%(have)s) less than required (%(need)s)") \
|
||||
% dict(have=entropy, need=self.entropy))
|
||||
failures.append(translate("Entropy (%(have)s) less than required (%(need)s)")
|
||||
% dict(have=entropy, need=self.entropy))
|
||||
if type(self.min) == int and self.min > 0:
|
||||
if not len(value) >= self.min:
|
||||
failures.append(translate("Minimum length is %s") % self.min)
|
||||
@@ -2840,31 +2861,33 @@ class IS_STRONG(object):
|
||||
all_special = [ch in value for ch in self.specials]
|
||||
if self.special > 0:
|
||||
if not all_special.count(True) >= self.special:
|
||||
failures.append(translate("Must include at least %s of the following: %s") \
|
||||
% (self.special, self.specials))
|
||||
failures.append(translate("Must include at least %s of the following: %s")
|
||||
% (self.special, self.specials))
|
||||
if self.invalid:
|
||||
all_invalid = [ch in value for ch in self.invalid]
|
||||
if all_invalid.count(True) > 0:
|
||||
failures.append(translate("May not contain any of the following: %s") \
|
||||
% self.invalid)
|
||||
failures.append(translate("May not contain any of the following: %s")
|
||||
% self.invalid)
|
||||
if type(self.upper) == int:
|
||||
all_upper = re.findall("[A-Z]", value)
|
||||
if self.upper > 0:
|
||||
if not len(all_upper) >= self.upper:
|
||||
failures.append(translate("Must include at least %s upper case") \
|
||||
% str(self.upper))
|
||||
failures.append(translate("Must include at least %s upper case")
|
||||
% str(self.upper))
|
||||
else:
|
||||
if len(all_upper) > 0:
|
||||
failures.append(translate("May not include any upper case letters"))
|
||||
failures.append(
|
||||
translate("May not include any upper case letters"))
|
||||
if type(self.lower) == int:
|
||||
all_lower = re.findall("[a-z]", value)
|
||||
if self.lower > 0:
|
||||
if not len(all_lower) >= self.lower:
|
||||
failures.append(translate("Must include at least %s lower case") \
|
||||
% str(self.lower))
|
||||
failures.append(translate("Must include at least %s lower case")
|
||||
% str(self.lower))
|
||||
else:
|
||||
if len(all_lower) > 0:
|
||||
failures.append(translate("May not include any lower case letters"))
|
||||
failures.append(
|
||||
translate("May not include any lower case letters"))
|
||||
if type(self.number) == int:
|
||||
all_number = re.findall("[0-9]", value)
|
||||
if self.number > 0:
|
||||
@@ -2872,8 +2895,8 @@ class IS_STRONG(object):
|
||||
if self.number > 1:
|
||||
numbers = "numbers"
|
||||
if not len(all_number) >= self.number:
|
||||
failures.append(translate("Must include at least %s %s") \
|
||||
% (str(self.number), numbers))
|
||||
failures.append(translate("Must include at least %s %s")
|
||||
% (str(self.number), numbers))
|
||||
else:
|
||||
if len(all_number) > 0:
|
||||
failures.append(translate("May not include any numbers"))
|
||||
@@ -3050,7 +3073,7 @@ class IS_UPLOAD_FILENAME(Validator):
|
||||
"""
|
||||
|
||||
def __init__(self, filename=None, extension=None, lastdot=True, case=1,
|
||||
error_message='enter valid filename'):
|
||||
error_message='enter valid filename'):
|
||||
if isinstance(filename, str):
|
||||
filename = re.compile(filename)
|
||||
if isinstance(extension, str):
|
||||
@@ -3193,7 +3216,7 @@ class IS_IPV4(Validator):
|
||||
is_localhost=None,
|
||||
is_private=None,
|
||||
is_automatic=None,
|
||||
error_message='enter valid IPv4 address'):
|
||||
error_message='enter valid IPv4 address'):
|
||||
for n, value in enumerate((minip, maxip)):
|
||||
temp = []
|
||||
if isinstance(value, str):
|
||||
@@ -3232,14 +3255,14 @@ class IS_IPV4(Validator):
|
||||
for bottom, top in zip(self.minip, self.maxip):
|
||||
if self.invert != (bottom <= number <= top):
|
||||
ok = True
|
||||
if not (self.is_localhost is None or self.is_localhost == \
|
||||
(number == self.localhost)):
|
||||
if not (self.is_localhost is None or self.is_localhost ==
|
||||
(number == self.localhost)):
|
||||
ok = False
|
||||
if not (self.is_private is None or self.is_private == \
|
||||
(sum([number[0] <= number <= number[1] for number in self.private]) > 0)):
|
||||
if not (self.is_private is None or self.is_private ==
|
||||
(sum([number[0] <= number <= number[1] for number in self.private]) > 0)):
|
||||
ok = False
|
||||
if not (self.is_automatic is None or self.is_automatic == \
|
||||
(self.automatic[0] <= number <= self.automatic[1])):
|
||||
if not (self.is_automatic is None or self.is_automatic ==
|
||||
(self.automatic[0] <= number <= self.automatic[1])):
|
||||
ok = False
|
||||
if ok:
|
||||
return (value, None)
|
||||
@@ -3247,4 +3270,5 @@ class IS_IPV4(Validator):
|
||||
|
||||
if __name__ == '__main__':
|
||||
import doctest
|
||||
doctest.testmod(optionflags=doctest.NORMALIZE_WHITESPACE|doctest.ELLIPSIS)
|
||||
doctest.testmod(
|
||||
optionflags=doctest.NORMALIZE_WHITESPACE | doctest.ELLIPSIS)
|
||||
|
||||
Reference in New Issue
Block a user