fix validators, updated gluon/contrib/ipaddr

This commit is contained in:
ilvalle
2016-06-07 19:50:49 +02:00
parent 92374741ff
commit fd850ab46f
9 changed files with 221 additions and 148 deletions
+33 -32
View File
@@ -21,7 +21,7 @@ import urllib
import struct
import decimal
import unicodedata
from gluon._compat import StringIO, long, unicodeT, to_unicode, urllib_unquote, unichr, to_bytes
from gluon._compat import StringIO, long, unicodeT, to_unicode, urllib_unquote, unichr, to_bytes, PY2, to_unicode, to_native
from gluon.utils import simple_hash, web2py_uuid, DIGEST_ALG_BY_SIZE
from pydal.objects import Field, FieldVirtual, FieldMethod
from functools import reduce
@@ -192,10 +192,13 @@ class IS_MATCH(Validator):
self.regex = re.compile(expression)
self.error_message = error_message
self.extract = extract
self.is_unicode = is_unicode
self.is_unicode = is_unicode or (not(PY2))
def __call__(self, value):
if self.is_unicode:
if not(PY2): # PY3 convert bytes to unicode
value = to_unicode(value)
if self.is_unicode or not(PY2):
if not isinstance(value, unicodeT):
match = self.regex.search(str(value).decode('utf8'))
else:
@@ -267,7 +270,7 @@ class IS_EXPR(Validator):
return (value, self.expression(value))
# for backward compatibility
self.environment.update(value=value)
exec ('__ret__=' + self.expression) in self.environment
exec ('__ret__=' + self.expression, self.environment)
if self.environment['__ret__']:
return (value, None)
return (value, translate(self.error_message))
@@ -333,7 +336,7 @@ class IS_LENGTH(Validator):
return (value, None)
elif isinstance(value, str):
try:
lvalue = len(value.decode('utf8'))
lvalue = len(to_unicode(value))
except:
lvalue = len(value)
if self.minsize <= lvalue <= self.maxsize:
@@ -341,6 +344,9 @@ class IS_LENGTH(Validator):
elif isinstance(value, unicodeT):
if self.minsize <= len(value) <= self.maxsize:
return (value.encode('utf8'), None)
elif isinstance(value, (bytes, bytearray)):
if self.minsize <= len(value) <= self.maxsize:
return (value, None)
elif isinstance(value, (tuple, list)):
if self.minsize <= len(value) <= self.maxsize:
return (value, None)
@@ -448,7 +454,7 @@ class IS_IN_SET(Validator):
else:
items = [(k, self.labels[i]) for (i, k) in enumerate(self.theset)]
if self.sort:
items.sort(options_sorter)
items.sort(key=lambda o: str(o[1]).upper())
if zero and not self.zero is None and not self.multiple:
items.insert(0, ('', self.zero))
return items
@@ -594,7 +600,7 @@ class IS_IN_DB(Validator):
self.build_set()
items = [(k, self.labels[i]) for (i, k) in enumerate(self.theset)]
if self.sort:
items.sort(options_sorter)
items.sort(key=lambda o: str(o[1]).upper())
if zero and self.zero is not None and not self.multiple:
items.insert(0, ('', self.zero))
return items
@@ -717,10 +723,7 @@ class IS_NOT_IN_DB(Validator):
self.record_id = id
def __call__(self, value):
if isinstance(value, unicodeT):
value = value.encode('utf8')
else:
value = str(value)
value = to_native(str(value))
if not value.strip():
return (value, translate(self.error_message))
if value in self.allowed_override:
@@ -1455,7 +1458,7 @@ def unicode_to_ascii_authority(authority):
import encodings.idna
for label in labels:
if label:
asciiLabels.append(encodings.idna.ToASCII(label))
asciiLabels.append(to_native(encodings.idna.ToASCII(label)))
else:
# encodings.idna.ToASCII does not accept an empty string, but
# it is necessary for us to allow for empty labels so that we
@@ -1525,6 +1528,7 @@ def unicode_to_ascii_url(url, prepend_scheme):
scheme = str(scheme) + '://'
else:
scheme = ''
return scheme + unicode_to_ascii_authority(authority) +\
escape_unicode(path) + escape_unicode(query) + str(fragment)
@@ -2083,7 +2087,6 @@ class IS_URL(Validator):
may be modified to (1) prepend a scheme, and/or (2) convert a
non-compliant unicode URL into a compliant US-ASCII version.
"""
if self.mode == 'generic':
subMethod = IS_GENERIC_URL(error_message=self.error_message,
allowed_schemes=self.allowed_schemes,
@@ -2101,7 +2104,7 @@ class IS_URL(Validator):
else:
try:
asciiValue = unicode_to_ascii_url(value, self.prepend_scheme)
except Exception:
except Exception as e:
# If we are not able to convert the unicode url into a
# US-ASCII URL, then the URL is not valid
return (value, translate(self.error_message))
@@ -2477,7 +2480,7 @@ class IS_LOWER(Validator):
"""
def __call__(self, value):
return (value.decode('utf8').lower().encode('utf8'), None)
return (to_bytes(to_unicode(value).lower()), None)
class IS_UPPER(Validator):
@@ -2492,7 +2495,7 @@ class IS_UPPER(Validator):
"""
def __call__(self, value):
return (value.decode('utf8').upper().encode('utf8'), None)
return (to_bytes(to_unicode(value).upper()), None)
def urlify(s, maxlen=80, keep_underscores=False):
@@ -2501,11 +2504,10 @@ def urlify(s, maxlen=80, keep_underscores=False):
if (keep_underscores): underscores are retained in the string
else: underscores are translated to hyphens (default)
"""
if isinstance(s, str):
s = s.decode('utf-8') # to unicode
s = to_unicode(s) # to unicode
s = s.lower() # to lowercase
s = unicodedata.normalize('NFKD', s) # replace special characters
s = s.encode('ascii', 'ignore') # encode as ASCII
s = to_native(s, charset='ascii', errors='ignore') # encode as ASCII
s = re.sub('&\w+?;', '', s) # strip html entities
if keep_underscores:
s = re.sub('\s+', '-', s) # whitespace to hyphens
@@ -2912,8 +2914,7 @@ def calc_entropy(string):
other = set()
seen = set()
lastset = None
if isinstance(string, str):
string = unicode(string, encoding='utf8')
string = to_unicode(string)
for c in string:
# classify this character
inset = otherset
@@ -3057,7 +3058,7 @@ class IS_STRONG(object):
if not self.error_message:
if self.estring:
return (value, '|'.join(failures))
from html import XML
from gluon.html import XML
return (value, XML('<br />'.join(failures)))
else:
return (value, translate(self.error_message))
@@ -3134,24 +3135,24 @@ class IS_IMAGE(Validator):
and self.minsize[1] <= height <= self.maxsize[1]
value.file.seek(0)
return (value, None)
except:
except Exception as e:
return (value, translate(self.error_message))
def __bmp(self, stream):
if stream.read(2) == 'BM':
if stream.read(2) == b'BM':
stream.read(16)
return struct.unpack("<LL", stream.read(8))
return (-1, -1)
def __gif(self, stream):
if stream.read(6) in ('GIF87a', 'GIF89a'):
if stream.read(6) in (b'GIF87a', b'GIF89a'):
stream = stream.read(5)
if len(stream) == 5:
return tuple(struct.unpack("<HHB", stream)[:-1])
return (-1, -1)
def __jpeg(self, stream):
if stream.read(2) == '\xFF\xD8':
if stream.read(2) == b'\xFF\xD8':
while True:
(marker, code, length) = struct.unpack("!BBH", stream.read(4))
if marker != 0xFF:
@@ -3164,9 +3165,9 @@ class IS_IMAGE(Validator):
return (-1, -1)
def __png(self, stream):
if stream.read(8) == '\211PNG\r\n\032\n':
if stream.read(8) == b'\211PNG\r\n\032\n':
stream.read(4)
if stream.read(4) == "IHDR":
if stream.read(4) == b"IHDR":
return struct.unpack("!LL", stream.read(8))
return (-1, -1)
@@ -3367,7 +3368,7 @@ class IS_IPV4(Validator):
if isinstance(value, str):
temp.append(value.split('.'))
elif isinstance(value, (list, tuple)):
if len(value) == len(filter(lambda item: isinstance(item, int), value)) == 4:
if len(value) == len(list(filter(lambda item: isinstance(item, int), value))) == 4:
temp.append(value)
else:
for item in value:
@@ -3510,7 +3511,7 @@ class IS_IPV6(Validator):
from gluon.contrib import ipaddr as ipaddress
try:
ip = ipaddress.IPv6Address(value.decode('utf-8'))
ip = ipaddress.IPv6Address(to_unicode(value))
ok = True
except ipaddress.AddressValueError:
return (value, translate(self.error_message))
@@ -3522,7 +3523,7 @@ class IS_IPV6(Validator):
self.subnets = [self.subnets]
for network in self.subnets:
try:
ipnet = ipaddress.IPv6Network(network.decode('utf-8'))
ipnet = ipaddress.IPv6Network(to_unicode(network))
except (ipaddress.NetmaskValueError, ipaddress.AddressValueError):
return (value, translate('invalid subnet provided'))
if ip in ipnet:
@@ -3739,7 +3740,7 @@ class IS_IPADDRESS(Validator):
IPv6Address)
try:
ip = IPAddress(value.decode('utf-8'))
ip = IPAddress(to_unicode(value))
except ValueError:
return (value, translate(self.error_message))