validatos no longer depend on T

This commit is contained in:
mdipierro
2019-02-24 01:51:18 -08:00
parent afaf57f6da
commit b58b7da18f
13 changed files with 129 additions and 130 deletions
+8 -4
View File
@@ -24,8 +24,9 @@ from gluon.template import parse_template
from gluon.restricted import restricted, compile2
from gluon.fileutils import mktree, listdir, read_file, write_file
from gluon.myregex import regex_expose, regex_longcomments
from gluon.languages import translator
from gluon.languages import TranslatorFactory
from gluon.dal import DAL, Field
from gluon.validators import Validator
from pydal.base import BaseAdapter
from gluon.sqlhtml import SQLFORM, SQLTABLE
from gluon.cache import Cache
@@ -423,16 +424,19 @@ def build_environment(request, response, session, store_current=True):
r'^%s/%s/\w+\.py$' % (request.controller, request.function)
]
t = environment['T'] = translator(os.path.join(request.folder, 'languages'),
request.env.http_accept_language)
T = environment['T'] = TranslatorFactory(os.path.join(request.folder, 'languages'),
request.env.http_accept_language)
c = environment['cache'] = Cache(request)
# configure the validator to use the t translator
Validator.translator = T
if store_current:
current.globalenv = environment
current.request = request
current.response = response
current.session = session
current.T = t
current.T = T
current.cache = c
if is_jython: # jython hack
+3 -3
View File
@@ -457,7 +457,7 @@ def pickle_lazyT(c):
copyreg.pickle(lazyT, pickle_lazyT)
class translator(object):
class TranslatorFactory(object):
"""
This class is instantiated by gluon.compileapp.build_environment
as the T object
@@ -742,8 +742,8 @@ class translator(object):
try:
otherT = self.otherTs[index]
except KeyError:
otherT = self.otherTs[index] = translator(self.langpath,
self.http_accept_language)
otherT = self.otherTs[index] = TranslatorFactory(self.langpath,
self.http_accept_language)
if language:
otherT.force(language)
return otherT
+2 -2
View File
@@ -11,7 +11,7 @@ import unittest
from gluon.compileapp import run_controller_in, run_view_in, compile_application, remove_compiled_application
from gluon.languages import translator
from gluon.languages import TranslatorFactory
from gluon.storage import Storage, List
from gluon import fileutils
from gluon.dal import DAL, Field, Table
@@ -50,7 +50,7 @@ class TestAppAdmin(unittest.TestCase):
request.env.remote_addr = '127.0.0.1'
response = Response()
session = Session()
T = translator('', 'en')
T = TranslatorFactory('', 'en')
session.connect(request, response)
current.request = request
current.response = response
+2 -2
View File
@@ -5,7 +5,7 @@
import os
import unittest
from gluon.globals import Request, Response, Session
from gluon.languages import translator
from gluon.languages import TranslatorFactory
from gluon.dal import DAL, Field
from gluon.authapi import AuthAPI
from gluon.storage import Storage
@@ -24,7 +24,7 @@ class TestAuthAPI(unittest.TestCase):
self.request.folder = 'applications/admin'
self.response = Response()
self.session = Session()
T = translator('', 'en')
T = TranslatorFactory('', 'en')
self.session.connect(self.request, self.response)
from gluon.globals import current
self.current = current
+1 -1
View File
@@ -120,7 +120,7 @@ class TestCache(unittest.TestCase):
s = Storage({'application': 'admin',
'folder': 'applications/admin'})
cache = Cache(s)
db = DAL(check_reserved=['all'])
db = DAL('sqlite:memory', check_reserved=['all'])
db.define_table('t_a', Field('f_a'))
db.t_a.insert(f_a='test')
db.commit()
+1 -1
View File
@@ -32,7 +32,7 @@ class TestDALSubclass(unittest.TestCase):
def testSerialization(self):
from gluon._compat import pickle
db = DAL(check_reserved=['all'])
db = DAL('sqlite:memory', check_reserved=['all'])
db.define_table('t_a', Field('f_a'))
db.t_a.insert(f_a='test')
a = db(db.t_a.id > 0).select(cacheable=True)
+3 -3
View File
@@ -88,7 +88,7 @@ class TestTranslations(unittest.TestCase):
pass
def test_plain(self):
T = languages.translator(self.langpath, self.http_accept_language)
T = languages.TranslatorFactory(self.langpath, self.http_accept_language)
self.assertEqual(str(T('Hello World')),
'Hello World')
self.assertEqual(str(T('Hello World## comment')),
@@ -340,7 +340,7 @@ class TestMessages(unittest.TestCase):
pass
def test_decode(self):
T = languages.translator(self.langpath, self.http_accept_language)
T = languages.TranslatorFactory(self.langpath, self.http_accept_language)
messages = Messages(T)
messages.update({'email_sent':'Email sent', 'test': "ä"})
self.assertEqual(to_unicode(messages.email_sent, 'utf-8'), 'Email sent')
@@ -359,7 +359,7 @@ class TestHTMLTag(unittest.TestCase):
pass
def test_decode(self):
T = languages.translator(self.langpath, self.http_accept_language)
T = languages.TranslatorFactory(self.langpath, self.http_accept_language)
elem = SPAN(T("Complete"))
self.assertEqual(elem.flatten(), "Complete")
elem = SPAN(T("Cannot be empty", language="ru"))
+2 -2
View File
@@ -11,7 +11,7 @@ import datetime
import sys
from gluon.storage import Storage
from gluon.languages import translator
from gluon.languages import TranslatorFactory
from gluon.scheduler import JobGraph, Scheduler, CronParser
from gluon.dal import DAL
@@ -25,7 +25,7 @@ class BaseTestScheduler(unittest.TestCase):
'folder': 'applications/welcome',
'controller': 'default'})
current.request = s
T = translator('', 'en')
T = TranslatorFactory('', 'en')
current.T = T
self.db = DAL('sqlite://dummy2.db', check_reserved=['all'])
+2 -2
View File
@@ -13,7 +13,7 @@ import decimal
from gluon.serializers import *
from gluon.storage import Storage
# careful with the import path 'cause of isinstance() checks
from gluon.languages import translator
from gluon.languages import TranslatorFactory
from gluon.html import SPAN
@@ -46,7 +46,7 @@ class TestSerializers(unittest.TestCase):
obj = {'a': decimal.Decimal('4.312312312312')}
self.assertEqual(json(obj), u'{"a": "4.312312312312"}')
# lazyT translated
T = translator('', 'en')
T = TranslatorFactory('', 'en')
lazy_translation = T('abc')
self.assertEqual(json(lazy_translation), u'"abc"')
# html helpers are xml()ed before too
+3 -3
View File
@@ -18,7 +18,7 @@ from pydal.objects import Table
from gluon.tools import Auth, Mail
from gluon.globals import Request, Response, Session
from gluon.storage import Storage
from gluon.languages import translator
from gluon.languages import TranslatorFactory
from gluon.http import HTTP
from gluon.validators import *
@@ -254,7 +254,7 @@ class TestSQLFORM(unittest.TestCase):
request.folder = 'applications/admin'
response = Response()
session = Session()
T = translator('', 'en')
T = TranslatorFactory('', 'en')
session.connect(request, response)
from gluon.globals import current
current.request = request
@@ -355,7 +355,7 @@ class TestSQLTABLE(unittest.TestCase):
request.folder = 'applications/admin'
response = Response()
session = Session()
T = translator('', 'en')
T = TranslatorFactory('', 'en')
session.connect(request, response)
from gluon.globals import current
current.request = request
+4 -4
View File
@@ -21,7 +21,7 @@ from gluon.tools import Auth, Mail, Recaptcha2, prettydate, Expose
from gluon._compat import PY2, to_bytes
from gluon.globals import Request, Response, Session
from gluon.storage import Storage
from gluon.languages import translator
from gluon.languages import TranslatorFactory
from gluon.http import HTTP
from gluon import SPAN, H3, TABLE, TR, TD, A, URL, current
@@ -271,7 +271,7 @@ class TestAuthJWT(unittest.TestCase):
# request.folder = 'applications/admin'
# response = Response()
# session = Session()
# T = translator('', 'en')
# T = TranslatorFactory('', 'en')
# session.connect(request, response)
# from gluon.globals import current
# current.request = request
@@ -434,7 +434,7 @@ class TestAuthJWT(unittest.TestCase):
# # request.folder = 'applications/admin'
# # response = Response()
# # session = Session()
# # T = translator('', 'en')
# # T = TranslatorFactory('', 'en')
# # session.connect(request, response)
# # from gluon.globals import current
# # current.request = request
@@ -495,7 +495,7 @@ class TestAuth(unittest.TestCase):
self.request.folder = 'applications/admin'
self.response = Response()
self.session = Session()
T = translator('', 'en')
T = TranslatorFactory('', 'en')
self.session.connect(self.request, self.response)
from gluon.globals import current
self.current = current
+1 -2
View File
@@ -20,8 +20,7 @@ class TestValidators(unittest.TestCase):
def test_MISC(self):
""" Test miscelaneous utility functions and some general behavior guarantees """
from gluon.validators import translate, options_sorter, Validator, UTC
self.assertEqual(translate(None), None)
from gluon.validators import options_sorter, Validator, UTC
self.assertEqual(options_sorter(('a', 'a'), ('a', 'a')), -1)
self.assertEqual(options_sorter(('A', 'A'), ('a', 'a')), -1)
self.assertEqual(options_sorter(('b', 'b'), ('a', 'a')), 1)
+97 -101
View File
@@ -12,6 +12,7 @@ Validators
"""
import os
import re
import math
import datetime
import time
import cgi
@@ -19,17 +20,19 @@ import json
import struct
import decimal
import unicodedata
import encodings.idna
from gluon._compat import StringIO, integer_types, basestring, unicodeT, urllib_unquote, unichr, to_bytes, PY2, \
to_unicode, to_native, string_types, urlparse
from gluon.utils import simple_hash, web2py_uuid, DIGEST_ALG_BY_SIZE
from pydal.objects import Field, FieldVirtual, FieldMethod
from pydal._compat import StringIO, integer_types, basestring, unicodeT, urllib_unquote, \
unichr, to_bytes, PY2, to_unicode, to_native, string_types, urlparse
from pydal.objects import Field, FieldVirtual, FieldMethod, Table
from functools import reduce
from gluon.utils import simple_hash, web2py_uuid, DIGEST_ALG_BY_SIZE
from gluon._compat import ipaddress
regex_isint = re.compile('^[+-]?\d+$')
JSONErrors = (NameError, TypeError, ValueError, AttributeError,
KeyError)
JSONErrors = (NameError, TypeError, ValueError, AttributeError, KeyError)
__all__ = [
'ANY_OF',
@@ -70,25 +73,19 @@ __all__ = [
'IS_JSON',
]
try:
from gluon.globals import current
have_current = True
except ImportError:
have_current = False
def translate(text):
if text is None:
return None
elif isinstance(text, (str, unicodeT)) 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 translator(text):
if text is None:
return None
text = Validator.translator(text)
return str(text)
class ValidationError(Exception):
def __init__(self, error):
self.error = error
class Validator(object):
"""
@@ -128,6 +125,8 @@ class Validator(object):
Notice that default error messages are not translated.
"""
translator = staticmethod(lambda text: text)
def formatter(self, value):
"""
For some validators returns a formatted version (matching the validator)
@@ -135,9 +134,15 @@ class Validator(object):
"""
return value
def __call__(self, value):
def validate(self, value):
raise NotImplementedError
def __call__(self, value):
try:
return self.validate(value), None
except ValidationError as e:
return value, e.message
class IS_MATCH(Validator):
"""
@@ -210,7 +215,7 @@ class IS_MATCH(Validator):
match = self.regex.search(value.encode('utf8'))
if match is not None:
return (self.extract and match.group() or value, None)
return (value, translate(self.error_message))
return (value, translator(self.error_message))
class IS_EQUAL_TO(Validator):
@@ -239,7 +244,7 @@ class IS_EQUAL_TO(Validator):
def __call__(self, value):
if value == self.expression:
return (value, None)
return (value, translate(self.error_message))
return (value, translator(self.error_message))
class IS_EXPR(Validator):
@@ -273,7 +278,7 @@ class IS_EXPR(Validator):
exec('__ret__=' + self.expression, self.environment)
if self.environment['__ret__']:
return (value, None)
return (value, translate(self.error_message))
return (value, translator(self.error_message))
class IS_LENGTH(Validator):
@@ -352,8 +357,8 @@ class IS_LENGTH(Validator):
return (value, None)
elif self.minsize <= len(str(value)) <= self.maxsize:
return (str(value), None)
return (value, translate(self.error_message)
% dict(min=self.minsize, max=self.maxsize))
return (value, translator(self.error_message) %
dict(min=self.minsize, max=self.maxsize))
class IS_JSON(Validator):
@@ -383,7 +388,7 @@ class IS_JSON(Validator):
else:
return (json.loads(value), None)
except JSONErrors:
return (value, translate(self.error_message))
return (value, translator(self.error_message))
def formatter(self, value):
if value is None:
@@ -473,11 +478,11 @@ class IS_IN_SET(Validator):
thestrset = [str(x) for x in self.theset]
failures = [x for x in values if not str(x) in thestrset]
if failures and self.theset:
return (value, translate(self.error_message))
return (value, translator(self.error_message))
if self.multiple:
if isinstance(self.multiple, (tuple, list)) and \
not self.multiple[0] <= len(values) < self.multiple[1]:
return (values, translate(self.error_message))
return (values, translator(self.error_message))
return (values, None)
return (value, None)
@@ -515,7 +520,6 @@ class IS_IN_DB(Validator):
delimiter=None,
auto_add=False,
):
from pydal.objects import Table
if hasattr(dbset, 'define_table'):
self.dbset = dbset()
else:
@@ -636,13 +640,13 @@ class IS_IN_DB(Validator):
if self.auto_add:
value = str(self.maybe_add(table, self.fieldnames[0], value))
else:
return (values, translate(self.error_message))
return (values, translator(self.error_message))
new_values.append(value)
values = new_values
if isinstance(self.multiple, (tuple, list)) and \
not self.multiple[0] <= len(values) < self.multiple[1]:
return (values, translate(self.error_message))
return (values, translator(self.error_message))
if self.theset:
if not [v for v in values if v not in self.theset]:
return (values, None)
@@ -664,12 +668,12 @@ class IS_IN_DB(Validator):
elif self.auto_add:
value = self.maybe_add(table, self.fieldnames[0], value)
else:
return (value, translate(self.error_message))
return (value, translator(self.error_message))
try:
value = int(value)
except TypeError:
return (value, translate(self.error_message))
return (value, translator(self.error_message))
if self.theset:
if str(value) in self.theset:
@@ -683,7 +687,7 @@ class IS_IN_DB(Validator):
return self._and(value)
else:
return (value, None)
return (value, translate(self.error_message))
return (value, translator(self.error_message))
class IS_NOT_IN_DB(Validator):
@@ -704,8 +708,6 @@ class IS_NOT_IN_DB(Validator):
allowed_override=[],
ignore_common_filters=False,
):
from pydal.objects import Table
if isinstance(field, Table):
field = field._id
@@ -725,7 +727,7 @@ class IS_NOT_IN_DB(Validator):
def __call__(self, value):
value = to_native(str(value))
if not value.strip():
return (value, translate(self.error_message))
return (value, translator(self.error_message))
if value in self.allowed_override:
return (value, None)
(tablename, fieldname) = str(self.field).split('.')
@@ -738,11 +740,11 @@ class IS_NOT_IN_DB(Validator):
fields = [table[f] for f in id]
row = subset.select(*fields, **dict(limitby=(0, 1), orderby_on_limitby=False)).first()
if row and any(str(row[f]) != str(id[f]) for f in id):
return (value, translate(self.error_message))
return (value, translator(self.error_message))
else:
row = subset.select(table._id, field, limitby=(0, 1), orderby_on_limitby=False).first()
if row and str(row[table._id]) != str(id):
return (value, translate(self.error_message))
return (value, translator(self.error_message))
return (value, None)
@@ -758,7 +760,7 @@ def range_error_message(error_message, what_to_enter, minimum, maximum):
error_message += ' less than or equal to %(max)g'
if type(maximum) in integer_types:
maximum -= 1
return translate(error_message) % dict(min=minimum, max=maximum)
return translator(error_message) % dict(min=minimum, max=maximum)
class IS_INT_IN_RANGE(Validator):
@@ -1043,7 +1045,7 @@ class IS_NOT_EMPTY(Validator):
def __call__(self, value):
value, empty = is_empty(value, empty_regex=self.empty_regex)
if empty:
return (value, translate(self.error_message))
return (value, translator(self.error_message))
return (value, None)
@@ -1199,7 +1201,7 @@ class IS_EMAIL(Validator):
def __call__(self, value):
if not(isinstance(value, (basestring, unicodeT))) or not value or '@' not in value:
return (value, translate(self.error_message))
return (value, translator(self.error_message))
body, domain = value.rsplit('@', 1)
@@ -1222,7 +1224,7 @@ class IS_EMAIL(Validator):
if (not self.banned or not self.banned.match(domain)) \
and (not self.forced or self.forced.match(domain)):
return (value, None)
return (value, translate(self.error_message))
return (value, translator(self.error_message))
class IS_LIST_OF_EMAILS(object):
@@ -1253,7 +1255,7 @@ class IS_LIST_OF_EMAILS(object):
return (value, None)
else:
return (value,
translate(self.error_message) % ', '.join(bad_emails))
translator(self.error_message) % ', '.join(bad_emails))
def formatter(self, value, row=None):
return ', '.join(value or [])
@@ -1456,7 +1458,6 @@ def unicode_to_ascii_authority(authority):
# We use the ToASCII operation because we are about to put the authority
# into an IDN-unaware slot
asciiLabels = []
import encodings.idna
for label in labels:
if label:
asciiLabels.append(to_native(encodings.idna.ToASCII(label)))
@@ -1613,7 +1614,7 @@ class IS_GENERIC_URL(Validator):
# if we dont have anything or the URL misuses the '%' character
if not value or self.GENERIC_URL.search(value):
return (value, translate(self.error_message))
return (value, translator(self.error_message))
if '#' in value:
url, fragment_part = value.split('#')
@@ -1625,7 +1626,7 @@ class IS_GENERIC_URL(Validator):
try:
components = urlparse.urlparse(urllib_unquote(value))._asdict()
except ValueError:
return (value, translate(self.error_message))
return (value, translator(self.error_message))
# Clean up the scheme before we check it
scheme = components['scheme']
@@ -1653,7 +1654,7 @@ class IS_GENERIC_URL(Validator):
else:
return (value, None)
# else the URL is not valid
return (value, translate(self.error_message))
return (value, translator(self.error_message))
# Sources (obtained 2017-Nov-11):
# http://data.iana.org/TLD/tlds-alpha-by-domain.txt
@@ -2089,7 +2090,7 @@ class IS_HTTP_URL(Validator):
except:
pass
# else the HTTP URL is not valid
return (value, translate(self.error_message))
return (value, translator(self.error_message))
class IS_URL(Validator):
@@ -2239,7 +2240,7 @@ class IS_URL(Validator):
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))
return (value, translator(self.error_message))
methodResult = subMethod(asciiValue)
# if the validation of the US-ASCII version of the value failed
if not methodResult[1] is None:
@@ -2321,7 +2322,7 @@ class IS_TIME(Validator):
pass
except ValueError:
pass
return (ivalue, translate(self.error_message))
return (ivalue, translator(self.error_message))
# A UTC class.
@@ -2352,7 +2353,7 @@ class IS_DATE(Validator):
def __init__(self, format='%Y-%m-%d',
error_message='Enter date as %(format)s'):
self.format = translate(format)
self.format = translator(format)
self.error_message = str(error_message)
self.extremes = {}
@@ -2367,7 +2368,7 @@ class IS_DATE(Validator):
return (value, None)
except:
self.extremes.update(IS_DATETIME.nice(self.format))
return (ovalue, translate(self.error_message) % self.extremes)
return (ovalue, translator(self.error_message) % self.extremes)
def formatter(self, value):
if value is None:
@@ -2416,7 +2417,7 @@ class IS_DATETIME(Validator):
def __init__(self, format='%Y-%m-%d %H:%M:%S',
error_message='Enter date and time as %(format)s',
timezone=None):
self.format = translate(format)
self.format = translator(format)
self.error_message = str(error_message)
self.extremes = {}
self.timezone = timezone
@@ -2435,7 +2436,7 @@ class IS_DATETIME(Validator):
return (value, None)
except:
self.extremes.update(IS_DATETIME.nice(self.format))
return (ovalue, translate(self.error_message) % self.extremes)
return (ovalue, translator(self.error_message) % self.extremes)
def formatter(self, value):
if value is None:
@@ -2503,9 +2504,9 @@ class IS_DATE_IN_RANGE(IS_DATE):
if msg is not None:
return (value, msg)
if self.minimum and self.minimum > value:
return (ovalue, translate(self.error_message) % self.extremes)
return (ovalue, translator(self.error_message) % self.extremes)
if self.maximum and value > self.maximum:
return (ovalue, translate(self.error_message) % self.extremes)
return (ovalue, translator(self.error_message) % self.extremes)
return (value, None)
@@ -2559,9 +2560,9 @@ class IS_DATETIME_IN_RANGE(IS_DATETIME):
if msg is not None:
return (value, msg)
if self.minimum and self.minimum > value:
return (ovalue, translate(self.error_message) % self.extremes)
return (ovalue, translator(self.error_message) % self.extremes)
if self.maximum and value > self.maximum:
return (ovalue, translate(self.error_message) % self.extremes)
return (ovalue, translator(self.error_message) % self.extremes)
return (value, None)
@@ -2579,11 +2580,11 @@ class IS_LIST_OF(Validator):
ivalue = [ivalue]
ivalue = [i for i in ivalue if str(i).strip()]
if self.minimum is not None and len(ivalue) < self.minimum:
return (ivalue, translate(self.error_message or
'Minimum length is %(min)s') % dict(min=self.minimum, max=self.maximum))
return (ivalue, translator(self.error_message or 'Minimum length is %(min)s') %
dict(min=self.minimum, max=self.maximum))
if self.maximum is not None and len(ivalue) > self.maximum:
return (ivalue, translate(self.error_message or
'Maximum length is %(max)s') % dict(min=self.minimum, max=self.maximum))
return (ivalue, translator(self.error_message or 'Maximum length is %(max)s') %
dict(min=self.minimum, max=self.maximum))
new_value = []
other = self.other
if self.other:
@@ -2721,7 +2722,7 @@ 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 (value, translator(self.error_message))
return (urlify(value, self.maxlen, self.keep_underscores), None)
@@ -2750,7 +2751,7 @@ class ANY_OF(Validator):
if error is None:
break
if error is not None and self.error_message is not None:
error = translate(self.error_message)
error = translator(self.error_message)
return value, error
def formatter(self, value):
@@ -3038,7 +3039,7 @@ class CRYPT(object):
def __call__(self, value):
v = value and str(value)[:self.max_length]
if not v or len(v) < self.min_length:
return ('', translate(self.error_message))
return ('', translator(self.error_message))
if isinstance(value, LazyCrypt):
return (value, None)
return (LazyCrypt(self, value), None)
@@ -3056,7 +3057,6 @@ otherset = frozenset(
def calc_entropy(string):
""" calculates a simple entropy for a given string """
import math
alphabet = 0 # alphabet size
other = set()
seen = set()
@@ -3149,49 +3149,49 @@ 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)")
failures.append(translator("Entropy (%(have)s) less than required (%(need)s)")
% dict(have=entropy, need=self.entropy))
if isinstance(self.min, int) and self.min > 0:
if not len(value) >= self.min:
failures.append(translate("Minimum length is %s") % self.min)
failures.append(translator("Minimum length is %s") % self.min)
if isinstance(self.max, int) and self.max > 0:
if not len(value) <= self.max:
failures.append(translate("Maximum length is %s") % self.max)
failures.append(translator("Maximum length is %s") % self.max)
if isinstance(self.special, int):
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")
failures.append(translator("Must include at least %s of the following: %s")
% (self.special, self.specials))
elif self.special is 0:
if len(all_special) > 0:
failures.append(translate("May not contain any of the following: %s")
failures.append(translator("May not contain any of the following: %s")
% 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")
failures.append(translator("May not contain any of the following: %s")
% self.invalid)
if isinstance(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 uppercase")
failures.append(translator("Must include at least %s uppercase")
% str(self.upper))
elif self.upper is 0:
if len(all_upper) > 0:
failures.append(
translate("May not include any uppercase letters"))
translator("May not include any uppercase letters"))
if isinstance(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 lowercase")
failures.append(translator("Must include at least %s lowercase")
% str(self.lower))
elif self.lower is 0:
if len(all_lower) > 0:
failures.append(
translate("May not include any lowercase letters"))
translator("May not include any lowercase letters"))
if isinstance(self.number, int):
all_number = re.findall("[0-9]", value)
if self.number > 0:
@@ -3199,20 +3199,19 @@ 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")
failures.append(translator("Must include at least %s %s")
% (str(self.number), numbers))
elif self.number is 0:
if len(all_number) > 0:
failures.append(translate("May not include any numbers"))
failures.append(translator("May not include any numbers"))
if len(failures) == 0:
return (value, None)
if not self.error_message:
if self.estring:
return (value, '|'.join(failures))
from gluon.html import XML
return (value, XML('<br />'.join(failures)))
return (value, '|'.join(map(str, failures)))
return (value, ', '.join(failures))
else:
return (value, translate(self.error_message))
return (value, translator(self.error_message))
class IS_IMAGE(Validator):
@@ -3304,7 +3303,7 @@ class IS_IMAGE(Validator):
value.file.seek(0)
return (value, None)
except Exception as e:
return (value, translate(self.error_message))
return (value, translator(self.error_message))
def __bmp(self, stream):
if stream.read(2) == b'BM':
@@ -3397,7 +3396,7 @@ class IS_UPLOAD_FILENAME(Validator):
try:
string = value.filename
except:
return (value, translate(self.error_message))
return (value, translator(self.error_message))
if self.case == 1:
string = string.lower()
elif self.case == 2:
@@ -3409,9 +3408,9 @@ class IS_UPLOAD_FILENAME(Validator):
if dot == -1:
dot = len(string)
if self.filename and not self.filename.match(string[:dot]):
return (value, translate(self.error_message))
return (value, translator(self.error_message))
elif self.extension and not self.extension.match(string[dot + 1:]):
return (value, translate(self.error_message))
return (value, translator(self.error_message))
else:
return (value, None)
@@ -3581,7 +3580,7 @@ class IS_IPV4(Validator):
ok = False
if ok:
return (value, None)
return (value, translate(self.error_message))
return (value, translator(self.error_message))
class IS_IPV6(Validator):
@@ -3674,13 +3673,11 @@ class IS_IPV6(Validator):
self.error_message = error_message
def __call__(self, value):
from gluon._compat import ipaddress
try:
ip = ipaddress.IPv6Address(to_unicode(value))
ok = True
except ipaddress.AddressValueError:
return (value, translate(self.error_message))
return (value, translator(self.error_message))
if self.subnets:
# iterate through self.subnets to see if value is a member
@@ -3691,7 +3688,7 @@ class IS_IPV6(Validator):
try:
ipnet = ipaddress.IPv6Network(to_unicode(network))
except (ipaddress.NetmaskValueError, ipaddress.AddressValueError):
return (value, translate('invalid subnet provided'))
return (value, translator('invalid subnet provided'))
if ip in ipnet:
ok = True
@@ -3722,7 +3719,7 @@ class IS_IPV6(Validator):
if ok:
return (value, None)
return (value, translate(self.error_message))
return (value, translator(self.error_message))
class IS_IPADDRESS(Validator):
@@ -3897,7 +3894,6 @@ class IS_IPADDRESS(Validator):
self.error_message = error_message
def __call__(self, value):
from gluon._compat import ipaddress
IPAddress = ipaddress.ip_address
IPv6Address = ipaddress.IPv6Address
IPv4Address = ipaddress.IPv4Address
@@ -3905,12 +3901,12 @@ class IS_IPADDRESS(Validator):
try:
ip = IPAddress(to_unicode(value))
except ValueError:
return (value, translate(self.error_message))
return (value, translator(self.error_message))
if self.is_ipv4 and isinstance(ip, IPv6Address):
retval = (value, translate(self.error_message))
retval = (value, translator(self.error_message))
elif self.is_ipv6 and isinstance(ip, IPv4Address):
retval = (value, translate(self.error_message))
retval = (value, translator(self.error_message))
elif self.is_ipv4 or isinstance(ip, IPv4Address):
retval = IS_IPV4(
minip=self.minip,
@@ -3934,6 +3930,6 @@ class IS_IPADDRESS(Validator):
error_message=self.error_message
)(value)
else:
retval = (value, translate(self.error_message))
retval = (value, translator(self.error_message))
return retval