Merge pull request #411 from niphlod/docs/te-x

sphinx-compatible docstring (only DAL remains)
This commit is contained in:
mdipierro committed 2014-03-25 12:16:42 -05:00
commit 0c1fa92705
6 files changed
+575 -504

No files matched your search

+293 -289
View File
File diff suppressed because it is too large. Load diff
+27 -30
View File
@@ -1,15 +1,14 @@
#!/usr/bin/env python #!/usr/bin/env python
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
""" """
This file is part of the web2py Web Framework | This file is part of the web2py Web Framework
Copyrighted by Massimo Di Pierro <mdipierro@cs.depaul.edu> | Copyrighted by Massimo Di Pierro <mdipierro@cs.depaul.edu>
License: LGPLv3 (http://www.gnu.org/licenses/lgpl.html) | License: LGPLv3 (http://www.gnu.org/licenses/lgpl.html)
| Created by Vladyslav Kozlovskyy (Ukraine) <dbdevelop©gmail.com>
Created by Vladyslav Kozlovskyy (Ukraine) <dbdevelop©gmail.com> | for Web2py project
for Web2py project
Utilities and class for UTF8 strings managing Utilities and class for UTF8 strings managing
=========================================== ----------------------------------------------
""" """
import __builtin__ import __builtin__
__all__ = ['Utf8'] __all__ = ['Utf8']
@@ -34,7 +33,8 @@ def sort_key(s):
is used for utf-8 and unicode strings sorting and for utf-8 strings is used for utf-8 and unicode strings sorting and for utf-8 strings
comparison comparison
NOTE: pyuca is a very memory cost module! It loads the whole Note:
pyuca is a very memory cost module! It loads the whole
"allkey.txt" file (~2mb!) into the memory. But this "allkey.txt" file (~2mb!) into the memory. But this
functionality is needed only when sort_key() is called as a functionality is needed only when sort_key() is called as a
part of sort() function or when Utf8 strings are compared. part of sort() function or when Utf8 strings are compared.
@@ -56,8 +56,7 @@ def sort_key(s):
def ord(char): def ord(char):
""" returns unicode id for utf8 or unicode *char* character """Returns unicode id for utf8 or unicode *char* character
SUPPOSE that *char* is an utf-8 or unicode character only SUPPOSE that *char* is an utf-8 or unicode character only
""" """
if isinstance(char, unicode): if isinstance(char, unicode):
@@ -66,27 +65,28 @@ def ord(char):
def chr(code): def chr(code):
""" return utf8-character with *code* unicode id """ """Returns utf8-character with *code* unicode id """
return Utf8(unichr(code)) return Utf8(unichr(code))
def size(string): def size(string):
""" return length of utf-8 string in bytes """Returns length of utf-8 string in bytes
NOTE! The length of correspondent utf-8
string is returned for unicode string Note:
The length of correspondent utf-8 string is returned for unicode string
""" """
return Utf8(string).__size__() return Utf8(string).__size__()
def truncate(string, length, dots='...'): def truncate(string, length, dots='...'):
""" returns string of length < *length* or truncate """Returns string of length < *length* or truncate string with adding
string with adding *dots* suffix to the string's end *dots* suffix to the string's end
args: Args:
length (int): max length of string length (int): max length of string
dots (str or unicode): string suffix, when string is cutted dots (str or unicode): string suffix, when string is cutted
returns: Returns:
(utf8-str): original or cutted string (utf8-str): original or cutted string
""" """
text = unicode(string, 'utf-8') text = unicode(string, 'utf-8')
@@ -125,7 +125,7 @@ class Utf8(str):
def __repr__(self): def __repr__(self):
r''' # note that we use raw strings to avoid having to use double back slashes below r''' # note that we use raw strings to avoid having to use double back slashes below
NOTE! This function is a clone of web2py:gluon.languages.utf_repl() function NOTE! This function is a clone of web2py:gluon.languages.utf_repl() function::
utf8.__repr__() works same as str.repr() when processing ascii string utf8.__repr__() works same as str.repr() when processing ascii string
>>> repr(Utf8('abc')) == repr(Utf8("abc")) == repr('abc') == repr("abc") == "'abc'" >>> repr(Utf8('abc')) == repr(Utf8("abc")) == repr('abc') == repr("abc") == "'abc'"
@@ -139,7 +139,8 @@ class Utf8(str):
>>> repr(Utf8('a\r\nb')) == repr('a\r\nb') == "'a\\r\\nb'" # Test for \r, \n >>> repr(Utf8('a\r\nb')) == repr('a\r\nb') == "'a\\r\\nb'" # Test for \r, \n
True True
Unlike str.repr(), Utf8.__repr__() remains utf8 content when processing utf8 string Unlike str.repr(), Utf8.__repr__() remains utf8 content when processing utf8 string::
>>> repr(Utf8('中文字')) == repr(Utf8("中文字")) == "'中文字'" != repr('中文字') >>> repr(Utf8('中文字')) == repr(Utf8("中文字")) == "'中文字'" != repr('中文字')
True True
>>> repr(Utf8('中"文"字')) == "'中\"文\"字'" != repr('中"文"字') >>> repr(Utf8('中"文"字')) == "'中\"文\"字'" != repr('中"文"字')
@@ -578,11 +579,9 @@ if __name__ == '__main__':
7 7
>>> a=Utf8('а б ц д е а б ц д е а\\tб ц д е') >>> a=Utf8('а б ц д е а б ц д е а\\tб ц д е')
>>> a.split() >>> a.split()
['а', 'б', 'ц', 'д', 'е', 'а', 'б', 'ц', 'д', ['а', 'б', 'ц', 'д', 'е', 'а', 'б', 'ц', 'д', 'е', 'а', 'б', 'ц', 'д', 'е']
'е', 'а', 'б', 'ц', 'д', 'е']
>>> a.rsplit() >>> a.rsplit()
['а', 'б', 'ц', 'д', 'е', 'а', 'б', 'ц', 'д', ['а', 'б', 'ц', 'д', 'е', 'а', 'б', 'ц', 'д', 'е', 'а', 'б', 'ц', 'д', 'е']
'е', 'а', 'б', 'ц', 'д', 'е']
>>> a.expandtabs().split('б') >>> a.expandtabs().split('б')
['а ', ' ц д е а ', ' ц д е а ', ' ц д е'] ['а ', ' ц д е а ', ' ц д е а ', ' ц д е']
>>> a.expandtabs().rsplit('б') >>> a.expandtabs().rsplit('б')
@@ -630,8 +629,7 @@ if __name__ == '__main__':
1 1
>>> s.count('Є', 0, 5) >>> s.count('Є', 0, 5)
0 0
>>> Utf8( >>> Utf8("Parameters: '%(проба)s', %(probe)04d, %(проба2)s") % { u"проба": s,
"Parameters: '%(проба)s', %(probe)04d, %(проба2)s") % { u"проба": s,
... "not used": "???", "probe": 2, "проба2": u"ПРоба Probe" } ... "not used": "???", "probe": 2, "проба2": u"ПРоба Probe" }
"Parameters: 'ПРоба Є PRobe', 0002, ПРоба Probe" "Parameters: 'ПРоба Є PRobe', 0002, ПРоба Probe"
>>> a=Utf8(u"Параметр: (%s)-(%s)-[%s]") >>> a=Utf8(u"Параметр: (%s)-(%s)-[%s]")
@@ -694,8 +692,7 @@ if __name__ == '__main__':
аАбБвВгГґҐдДеЕєЄжЖзЗиИіІїЇйЙкКлЛмМнНоОпПрРсСтТуУфФхХцЦчЧшШщЩьЬюЮяЯ аАбБвВгГґҐдДеЕєЄжЖзЗиИіІїЇйЙкКлЛмМнНоОпПрРсСтТуУфФхХцЦчЧшШщЩьЬюЮяЯ
>>> Utf8().join(sorted(c.decode(), key=sort_key)) # convert to unicode for better performance >>> Utf8().join(sorted(c.decode(), key=sort_key)) # convert to unicode for better performance
'аАбБвВгГґҐдДеЕєЄжЖзЗиИіІїЇйЙкКлЛмМнНоОпПрРсСтТуУфФхХцЦчЧшШщЩьЬюЮяЯ' 'аАбБвВгГґҐдДеЕєЄжЖзЗиИіІїЇйЙкКлЛмМнНоОпПрРсСтТуУфФхХцЦчЧшШщЩьЬюЮяЯ'
>>> for result in sorted( >>> for result in sorted(["Іа", "Астро", u"гала", Utf8("Гоша"), "Єва", "шовк", "аякс", "Їжа",
["Іа", "Астро", u"гала", Utf8("Гоша"), "Єва", "шовк", "аякс", "Їжа",
... "ґанок", Utf8("Дар'я"), "білінг", "веб", u"Жужа", "проба", u"тест", ... "ґанок", Utf8("Дар'я"), "білінг", "веб", u"Жужа", "проба", u"тест",
... "абетка", "яблуко", "Юляся", "Київ", "лимонад", "ложка", "Матриця", ... "абетка", "яблуко", "Юляся", "Київ", "лимонад", "ложка", "Матриця",
... ], key=sort_key): ... ], key=sort_key):
@@ -722,6 +719,7 @@ if __name__ == '__main__':
шовк <type 'str'> шовк <type 'str'>
Юляся <type 'str'> Юляся <type 'str'>
яблуко <type 'str'> яблуко <type 'str'>
>>> a=Utf8("中文字") >>> a=Utf8("中文字")
>>> L=list(a) >>> L=list(a)
>>> L >>> L
@@ -734,8 +732,7 @@ if __name__ == '__main__':
>>> a="中文字" # standard str type >>> a="中文字" # standard str type
>>> L=list(a) >>> L=list(a)
>>> L >>> L
['\\xe4', '\\xb8', '\\xad', '\\xe6', '\\x96', '\\x87', ['\\xe4', '\\xb8', '\\xad', '\\xe6', '\\x96', '\\x87', '\\xe5', '\\xad', '\\x97']
'\\xe5', '\\xad', '\\x97']
>>> from string import maketrans >>> from string import maketrans
>>> str_tab=maketrans('PRobe','12345') >>> str_tab=maketrans('PRobe','12345')
>>> unicode_tab={ord(u'П'):ord(u'Ж'), >>> unicode_tab={ord(u'П'):ord(u'Ж'),
+12 -8
View File
@@ -2,11 +2,12 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
""" """
This file is part of the web2py Web Framework | This file is part of the web2py Web Framework
Copyrighted by Massimo Di Pierro <mdipierro@cs.depaul.edu> | Copyrighted by Massimo Di Pierro <mdipierro@cs.depaul.edu>
License: LGPLv3 (http://www.gnu.org/licenses/lgpl.html) | License: LGPLv3 (http://www.gnu.org/licenses/lgpl.html)
This file specifically includes utilities for security. This file specifically includes utilities for security.
--------------------------------------------------------
""" """
import threading import threading
@@ -65,7 +66,7 @@ def AES_new(key, IV=None):
def compare(a, b): def compare(a, b):
""" compares two strings and not vulnerable to timing attacks """ """ Compares two strings and not vulnerable to timing attacks """
if len(a) != len(b): if len(a) != len(b):
return False return False
result = 0 result = 0
@@ -75,7 +76,7 @@ def compare(a, b):
def md5_hash(text): def md5_hash(text):
""" Generate a md5 hash with the given text """ """ Generates a md5 hash with the given text """
return md5(text).hexdigest() return md5(text).hexdigest()
def simple_hash(text, key='', salt='', digest_alg='md5'): def simple_hash(text, key='', salt='', digest_alg='md5'):
@@ -177,7 +178,7 @@ def secure_loads(data, encryption_key, hash_key=None, compression_level=None):
def initialize_urandom(): def initialize_urandom():
""" """
This function and the web2py_uuid follow from the following discussion: This function and the web2py_uuid follow from the following discussion:
http://groups.google.com/group/web2py-developers/browse_thread/thread/7fd5789a7da3f09 `http://groups.google.com/group/web2py-developers/browse_thread/thread/7fd5789a7da3f09`
At startup web2py compute a unique ID that identifies the machine by adding At startup web2py compute a unique ID that identifies the machine by adding
uuid.getnode() + int(time.time() * 1e3) uuid.getnode() + int(time.time() * 1e3)
@@ -225,7 +226,7 @@ UNPACKED_CTOKENS, HAVE_URANDOM = initialize_urandom()
def fast_urandom16(urandom=[], locker=threading.RLock()): def fast_urandom16(urandom=[], locker=threading.RLock()):
""" """
this is 4x faster than calling os.urandom(16) and prevents This is 4x faster than calling os.urandom(16) and prevents
the "too many files open" issue with concurrent access to os.urandom() the "too many files open" issue with concurrent access to os.urandom()
""" """
try: try:
@@ -243,7 +244,7 @@ def fast_urandom16(urandom=[], locker=threading.RLock()):
def web2py_uuid(ctokens=UNPACKED_CTOKENS): def web2py_uuid(ctokens=UNPACKED_CTOKENS):
""" """
This function follows from the following discussion: This function follows from the following discussion:
http://groups.google.com/group/web2py-developers/browse_thread/thread/7fd5789a7da3f09 `http://groups.google.com/group/web2py-developers/browse_thread/thread/7fd5789a7da3f09`
It works like uuid.uuid4 except that tries to use os.urandom() if possible It works like uuid.uuid4 except that tries to use os.urandom() if possible
and it XORs the output with the tokens uniquely associated with this machine. and it XORs the output with the tokens uniquely associated with this machine.
@@ -263,6 +264,9 @@ REGEX_IPv4 = re.compile('(\d+)\.(\d+)\.(\d+)\.(\d+)')
def is_valid_ip_address(address): def is_valid_ip_address(address):
""" """
Examples:
Better than a thousand words::
>>> is_valid_ip_address('127.0') >>> is_valid_ip_address('127.0')
False False
>>> is_valid_ip_address('127.0.0.1') >>> is_valid_ip_address('127.0.0.1')
+226 -161
View File
@@ -2,11 +2,13 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
""" """
This file is part of the web2py Web Framework | This file is part of the web2py Web Framework
Copyrighted by Massimo Di Pierro <mdipierro@cs.depaul.edu> | Copyrighted by Massimo Di Pierro <mdipierro@cs.depaul.edu>
License: LGPLv3 (http://www.gnu.org/licenses/lgpl.html) | License: LGPLv3 (http://www.gnu.org/licenses/lgpl.html)
| Thanks to ga2arch for help with IS_IN_DB and IS_NOT_IN_DB on GAE
Thanks to ga2arch for help with IS_IN_DB and IS_NOT_IN_DB on GAE Validators
-----------
""" """
import os import os
@@ -144,11 +146,12 @@ class Validator(object):
class IS_MATCH(Validator): class IS_MATCH(Validator):
""" """
example:: Example:
Used as::
INPUT(_type='text', _name='name', requires=IS_MATCH('.+')) INPUT(_type='text', _name='name', requires=IS_MATCH('.+'))
the argument of IS_MATCH is a regular expression:: The argument of IS_MATCH is a regular expression::
>>> IS_MATCH('.+')('hello') >>> IS_MATCH('.+')('hello')
('hello', None) ('hello', None)
@@ -173,6 +176,7 @@ class IS_MATCH(Validator):
>>> IS_MATCH('.+')('') >>> IS_MATCH('.+')('')
('', 'invalid expression') ('', 'invalid expression')
""" """
def __init__(self, expression, error_message='Invalid expression', def __init__(self, expression, error_message='Invalid expression',
@@ -207,19 +211,21 @@ class IS_MATCH(Validator):
class IS_EQUAL_TO(Validator): class IS_EQUAL_TO(Validator):
""" """
example:: Example:
Used as::
INPUT(_type='text', _name='password') INPUT(_type='text', _name='password')
INPUT(_type='text', _name='password2', INPUT(_type='text', _name='password2',
requires=IS_EQUAL_TO(request.vars.password)) requires=IS_EQUAL_TO(request.vars.password))
the argument of IS_EQUAL_TO is a string The argument of IS_EQUAL_TO is a string::
>>> IS_EQUAL_TO('aaa')('aaa') >>> IS_EQUAL_TO('aaa')('aaa')
('aaa', None) ('aaa', None)
>>> IS_EQUAL_TO('aaa')('aab') >>> IS_EQUAL_TO('aaa')('aab')
('aab', 'no match') ('aab', 'no match')
""" """
def __init__(self, expression, error_message='No match'): def __init__(self, expression, error_message='No match'):
@@ -234,18 +240,20 @@ class IS_EQUAL_TO(Validator):
class IS_EXPR(Validator): class IS_EXPR(Validator):
""" """
example:: Example:
Used as::
INPUT(_type='text', _name='name', INPUT(_type='text', _name='name',
requires=IS_EXPR('5 < int(value) < 10')) requires=IS_EXPR('5 < int(value) < 10'))
the argument of IS_EXPR must be python condition:: The argument of IS_EXPR must be python condition::
>>> IS_EXPR('int(value) < 2')('1') >>> IS_EXPR('int(value) < 2')('1')
('1', None) ('1', None)
>>> IS_EXPR('int(value) < 2')('2') >>> IS_EXPR('int(value) < 2')('2')
('2', 'invalid expression') ('2', 'invalid expression')
""" """
def __init__(self, expression, error_message='Invalid expression', environment=None): def __init__(self, expression, error_message='Invalid expression', environment=None):
@@ -269,22 +277,25 @@ class IS_LENGTH(Validator):
Checks if length of field's value fits between given boundaries. Works Checks if length of field's value fits between given boundaries. Works
for both text and file inputs. for both text and file inputs.
Arguments: Args:
maxsize: maximum allowed length / size maxsize: maximum allowed length / size
minsize: minimum allowed length / size minsize: minimum allowed length / size
Examples:: Examples:
Check if text string is shorter than 33 characters::
#Check if text string is shorter than 33 characters:
INPUT(_type='text', _name='name', requires=IS_LENGTH(32)) INPUT(_type='text', _name='name', requires=IS_LENGTH(32))
#Check if password string is longer than 5 characters: Check if password string is longer than 5 characters::
INPUT(_type='password', _name='name', requires=IS_LENGTH(minsize=6)) INPUT(_type='password', _name='name', requires=IS_LENGTH(minsize=6))
#Check if uploaded file has size between 1KB and 1MB: Check if uploaded file has size between 1KB and 1MB::
INPUT(_type='file', _name='name', requires=IS_LENGTH(1048576, 1024)) INPUT(_type='file', _name='name', requires=IS_LENGTH(1048576, 1024))
Other examples::
>>> IS_LENGTH()('') >>> IS_LENGTH()('')
('', None) ('', None)
>>> IS_LENGTH()('1234567890') >>> IS_LENGTH()('1234567890')
@@ -339,7 +350,9 @@ class IS_LENGTH(Validator):
class IS_JSON(Validator): class IS_JSON(Validator):
""" """
example:: Example:
Used as::
INPUT(_type='text', _name='name', INPUT(_type='text', _name='name',
requires=IS_JSON(error_message="This is not a valid json input") requires=IS_JSON(error_message="This is not a valid json input")
@@ -371,12 +384,13 @@ class IS_JSON(Validator):
class IS_IN_SET(Validator): class IS_IN_SET(Validator):
""" """
example:: Example:
Used as::
INPUT(_type='text', _name='name', INPUT(_type='text', _name='name',
requires=IS_IN_SET(['max', 'john'],zero='')) requires=IS_IN_SET(['max', 'john'],zero=''))
the argument of IS_IN_SET must be a list or set The argument of IS_IN_SET must be a list or set::
>>> IS_IN_SET(['max', 'john'])('max') >>> IS_IN_SET(['max', 'john'])('max')
('max', None) ('max', None)
@@ -395,6 +409,7 @@ class IS_IN_SET(Validator):
('1', None) ('1', None)
>>> IS_IN_SET([('id1','first label'), ('id2','second label')])('id1') # Redundant way >>> IS_IN_SET([('id1','first label'), ('id2','second label')])('id1') # Redundant way
('id1', None) ('id1', None)
""" """
def __init__( def __init__(
@@ -463,7 +478,8 @@ regex2 = re.compile('%\(([^\)]+)\)\d*(?:\.\d+)?[a-zA-Z]')
class IS_IN_DB(Validator): class IS_IN_DB(Validator):
""" """
example:: Example:
Used as::
INPUT(_type='text', _name='name', INPUT(_type='text', _name='name',
requires=IS_IN_DB(db, db.mytable.myfield, zero='')) requires=IS_IN_DB(db, db.mytable.myfield, zero=''))
@@ -611,7 +627,8 @@ class IS_IN_DB(Validator):
class IS_NOT_IN_DB(Validator): class IS_NOT_IN_DB(Validator):
""" """
example:: Example:
Used as::
INPUT(_type='text', _name='name', requires=IS_NOT_IN_DB(db, db.table)) INPUT(_type='text', _name='name', requires=IS_NOT_IN_DB(db, db.table))
@@ -688,14 +705,15 @@ def range_error_message(error_message, what_to_enter, minimum, maximum):
class IS_INT_IN_RANGE(Validator): class IS_INT_IN_RANGE(Validator):
""" """
Determine that the argument is (or can be represented as) an int, Determines that the argument is (or can be represented as) an int,
and that it falls within the specified range. The range is interpreted and that it falls within the specified range. The range is interpreted
in the Pythonic way, so the test is: min <= value < max. in the Pythonic way, so the test is: min <= value < max.
The minimum and maximum limits can be None, meaning no lower or upper limit, The minimum and maximum limits can be None, meaning no lower or upper limit,
respectively. respectively.
example:: Example:
Used as::
INPUT(_type='text', _name='name', requires=IS_INT_IN_RANGE(0, 10)) INPUT(_type='text', _name='name', requires=IS_INT_IN_RANGE(0, 10))
@@ -756,14 +774,15 @@ def str2dec(number):
class IS_FLOAT_IN_RANGE(Validator): class IS_FLOAT_IN_RANGE(Validator):
""" """
Determine that the argument is (or can be represented as) a float, Determines that the argument is (or can be represented as) a float,
and that it falls within the specified inclusive range. and that it falls within the specified inclusive range.
The comparison is made with native arithmetic. The comparison is made with native arithmetic.
The minimum and maximum limits can be None, meaning no lower or upper limit, The minimum and maximum limits can be None, meaning no lower or upper limit,
respectively. respectively.
example:: Example:
Used as::
INPUT(_type='text', _name='name', requires=IS_FLOAT_IN_RANGE(0, 10)) INPUT(_type='text', _name='name', requires=IS_FLOAT_IN_RANGE(0, 10))
@@ -827,14 +846,15 @@ class IS_FLOAT_IN_RANGE(Validator):
class IS_DECIMAL_IN_RANGE(Validator): class IS_DECIMAL_IN_RANGE(Validator):
""" """
Determine that the argument is (or can be represented as) a Python Decimal, Determines that the argument is (or can be represented as) a Python Decimal,
and that it falls within the specified inclusive range. and that it falls within the specified inclusive range.
The comparison is made with Python Decimal arithmetic. The comparison is made with Python Decimal arithmetic.
The minimum and maximum limits can be None, meaning no lower or upper limit, The minimum and maximum limits can be None, meaning no lower or upper limit,
respectively. respectively.
example:: Example:
Used as::
INPUT(_type='text', _name='name', requires=IS_DECIMAL_IN_RANGE(0, 10)) INPUT(_type='text', _name='name', requires=IS_DECIMAL_IN_RANGE(0, 10))
@@ -923,7 +943,8 @@ def is_empty(value, empty_regex=None):
class IS_NOT_EMPTY(Validator): class IS_NOT_EMPTY(Validator):
""" """
example:: Example:
Used as::
INPUT(_type='text', _name='name', requires=IS_NOT_EMPTY()) INPUT(_type='text', _name='name', requires=IS_NOT_EMPTY())
@@ -969,7 +990,8 @@ class IS_NOT_EMPTY(Validator):
class IS_ALPHANUMERIC(IS_MATCH): class IS_ALPHANUMERIC(IS_MATCH):
""" """
example:: Example:
Used as::
INPUT(_type='text', _name='name', requires=IS_ALPHANUMERIC()) INPUT(_type='text', _name='name', requires=IS_ALPHANUMERIC())
@@ -997,24 +1019,25 @@ class IS_EMAIL(Validator):
generally following the RFCs, except that we disallow quoted strings generally following the RFCs, except that we disallow quoted strings
and permit underscores and leading numerics in subdomain labels and permit underscores and leading numerics in subdomain labels
Arguments: Args:
banned: regex text for disallowed address domains
- banned: regex text for disallowed address domains forced: regex text for required address domains
- forced: regex text for required address domains
Both arguments can also be custom objects with a match(value) method. Both arguments can also be custom objects with a match(value) method.
Examples:: Example:
Check for valid email address::
#Check for valid email address:
INPUT(_type='text', _name='name', INPUT(_type='text', _name='name',
requires=IS_EMAIL()) requires=IS_EMAIL())
#Check for valid email address that can't be from a .com domain: Check for valid email address that can't be from a .com domain::
INPUT(_type='text', _name='name', INPUT(_type='text', _name='name',
requires=IS_EMAIL(banned='^.*\.com(|\..*)$')) requires=IS_EMAIL(banned='^.*\.com(|\..*)$'))
#Check for valid email address that must be from a .edu domain: Check for valid email address that must be from a .edu domain::
INPUT(_type='text', _name='name', INPUT(_type='text', _name='name',
requires=IS_EMAIL(forced='^.*\.edu(|\..*)$')) requires=IS_EMAIL(forced='^.*\.edu(|\..*)$'))
@@ -1125,7 +1148,9 @@ class IS_EMAIL(Validator):
class IS_LIST_OF_EMAILS(object): class IS_LIST_OF_EMAILS(object):
""" """
use as follows: Example:
Used as::
Field('emails','list:string', Field('emails','list:string',
widget=SQLFORM.widgets.text.widget, widget=SQLFORM.widgets.text.widget,
requires=IS_LIST_OF_EMAILS(), requires=IS_LIST_OF_EMAILS(),
@@ -1311,10 +1336,12 @@ def escape_unicode(string):
converted into a URL escaped form based on its hexadecimal value. converted into a URL escaped form based on its hexadecimal value.
For example, the unicode character '\u4e86' will become the string '%4e%86' For example, the unicode character '\u4e86' will become the string '%4e%86'
:param string: unicode string, the unicode string to convert into an Args:
string: unicode string, the unicode string to convert into an
escaped US-ASCII form escaped US-ASCII form
:returns: the US-ASCII escaped form of the inputted string
:rtype: string Returns:
string: the US-ASCII escaped form of the inputted string
@author: Jonathan Benn @author: Jonathan Benn
''' '''
@@ -1338,12 +1365,16 @@ def unicode_to_ascii_authority(authority):
For example, u'www.Alliancefran\xe7aise.nu' will be converted into For example, u'www.Alliancefran\xe7aise.nu' will be converted into
'www.xn--alliancefranaise-npb.nu' 'www.xn--alliancefranaise-npb.nu'
:param authority: unicode string, the URL authority component to convert, Args:
authority: unicode string, the URL authority component to convert,
e.g. u'www.Alliancefran\xe7aise.nu' e.g. u'www.Alliancefran\xe7aise.nu'
:returns: the US-ASCII character equivalent to the inputed authority,
Returns:
string: the US-ASCII character equivalent to the inputed authority,
e.g. 'www.xn--alliancefranaise-npb.nu' e.g. 'www.xn--alliancefranaise-npb.nu'
:rtype: string
:raises Exception: if the function is not able to convert the inputed Raises:
Exception: if the function is not able to convert the inputed
authority authority
@author: Jonathan Benn @author: Jonathan Benn
@@ -1398,12 +1429,14 @@ def unicode_to_ascii_url(url, prepend_scheme):
converted into '%4E%2D'. Testing with Firefox v3.0.5 has shown that it can converted into '%4E%2D'. Testing with Firefox v3.0.5 has shown that it can
understand this kind of URI encoding. understand this kind of URI encoding.
:param url: unicode string, the URL to convert from unicode into US-ASCII Args:
:param prepend_scheme: string, a protocol scheme to prepend to the URL if url: unicode string, the URL to convert from unicode into US-ASCII
prepend_scheme: string, a protocol scheme to prepend to the URL if
we're having trouble parsing it. we're having trouble parsing it.
e.g. "http". Input None to disable this functionality e.g. "http". Input None to disable this functionality
:returns: a US-ASCII equivalent of the inputed url
:rtype: string Returns:
string: a US-ASCII equivalent of the inputed url
@author: Jonathan Benn @author: Jonathan Benn
''' '''
@@ -1467,6 +1500,14 @@ class IS_GENERIC_URL(Validator):
>>> IS_GENERIC_URL()('http://user@abc.com') >>> IS_GENERIC_URL()('http://user@abc.com')
('http://user@abc.com', None) ('http://user@abc.com', None)
Args:
error_message: a string, the error message to give the end user
if the URL does not validate
allowed_schemes: a list containing strings or None. Each element
is a scheme the inputed URL is allowed to use
prepend_scheme: a string, this scheme is prepended if it's
necessary to make the URL valid
""" """
def __init__( def __init__(
@@ -1475,14 +1516,6 @@ class IS_GENERIC_URL(Validator):
allowed_schemes=None, allowed_schemes=None,
prepend_scheme=None, prepend_scheme=None,
): ):
"""
:param error_message: a string, the error message to give the end user
if the URL does not validate
:param allowed_schemes: a list containing strings or None. Each element
is a scheme the inputed URL is allowed to use
:param prepend_scheme: a string, this scheme is prepended if it's
necessary to make the URL valid
"""
self.error_message = error_message self.error_message = error_message
if allowed_schemes is None: if allowed_schemes is None:
@@ -1499,8 +1532,11 @@ class IS_GENERIC_URL(Validator):
def __call__(self, value): def __call__(self, value):
""" """
:param value: a string, the URL to validate Args:
:returns: a tuple, where tuple[0] is the inputed value (possible value: a string, the URL to validate
Returns:
a tuple, where tuple[0] is the inputed value (possible
prepended with prepend_scheme), and tuple[1] is either prepended with prepend_scheme), and tuple[1] is either
None (success!) or the string error_message None (success!) or the string error_message
""" """
@@ -1881,6 +1917,13 @@ class IS_HTTP_URL(Validator):
>>> IS_HTTP_URL()('http://user@1.2.3.4') >>> IS_HTTP_URL()('http://user@1.2.3.4')
('http://user@1.2.3.4', None) ('http://user@1.2.3.4', None)
Args:
error_message: a string, the error message to give the end user
if the URL does not validate
allowed_schemes: a list containing strings or None. Each element
is a scheme the inputed URL is allowed to use
prepend_scheme: a string, this scheme is prepended if it's
necessary to make the URL valid
""" """
GENERIC_VALID_IP = re.compile( GENERIC_VALID_IP = re.compile(
@@ -1893,14 +1936,6 @@ class IS_HTTP_URL(Validator):
allowed_schemes=None, allowed_schemes=None,
prepend_scheme='http', prepend_scheme='http',
): ):
"""
:param error_message: a string, the error message to give the end user
if the URL does not validate
:param allowed_schemes: a list containing strings or None. Each element
is a scheme the inputed URL is allowed to use
:param prepend_scheme: a string, this scheme is prepended if it's
necessary to make the URL valid
"""
self.error_message = error_message self.error_message = error_message
if allowed_schemes is None: if allowed_schemes is None:
@@ -1920,8 +1955,11 @@ class IS_HTTP_URL(Validator):
def __call__(self, value): def __call__(self, value):
""" """
:param value: a string, the URL to validate Args:
:returns: a tuple, where tuple[0] is the inputed value value: a string, the URL to validate
Returns:
a tuple, where tuple[0] is the inputed value
(possible prepended with prepend_scheme), and tuple[1] is either (possible prepended with prepend_scheme), and tuple[1] is either
None (success!) or the string error_message None (success!) or the string error_message
""" """
@@ -1984,6 +2022,7 @@ class IS_HTTP_URL(Validator):
class IS_URL(Validator): class IS_URL(Validator):
""" """
Rejects a URL string if any of the following is true: Rejects a URL string if any of the following is true:
* The string is empty or None * The string is empty or None
* The string uses characters that are not allowed in a URL * The string uses characters that are not allowed in a URL
* The string breaks any of the HTTP syntactic rules * The string breaks any of the HTTP syntactic rules
@@ -1999,6 +2038,7 @@ class IS_URL(Validator):
If the parameter mode='generic' is used, then this function's behavior If the parameter mode='generic' is used, then this function's behavior
changes. It then rejects a URL string if any of the following is true: changes. It then rejects a URL string if any of the following is true:
* The string is empty or None * The string is empty or None
* The string uses characters that are not allowed in a URL * The string uses characters that are not allowed in a URL
* The URL scheme specified (if one is specified) is not valid * The URL scheme specified (if one is specified) is not valid
@@ -2025,6 +2065,14 @@ class IS_URL(Validator):
be escaped using the standard '%20' type syntax. e.g. the unicode be escaped using the standard '%20' type syntax. e.g. the unicode
character with hex code 0x4e86 will become '%4e%86' character with hex code 0x4e86 will become '%4e%86'
Args:
error_message: a string, the error message to give the end user
if the URL does not validate
allowed_schemes: a list containing strings or None. Each element
is a scheme the inputed URL is allowed to use
prepend_scheme: a string, this scheme is prepended if it's
necessary to make the URL valid
Code Examples:: Code Examples::
INPUT(_type='text', _name='name', requires=IS_URL()) INPUT(_type='text', _name='name', requires=IS_URL())
@@ -2063,14 +2111,6 @@ class IS_URL(Validator):
allowed_schemes=None, allowed_schemes=None,
prepend_scheme='http', prepend_scheme='http',
): ):
"""
:param error_message: a string, the error message to give the end user
if the URL does not validate
:param allowed_schemes: a list containing strings or None. Each element
is a scheme the inputed URL is allowed to use
:param prepend_scheme: a string, this scheme is prepended if it's
necessary to make the URL valid
"""
self.error_message = error_message self.error_message = error_message
self.mode = mode.lower() self.mode = mode.lower()
@@ -2090,8 +2130,11 @@ class IS_URL(Validator):
def __call__(self, value): def __call__(self, value):
""" """
:param value: a unicode or regular string, the URL to validate Args:
:returns: a (string, string) tuple, where tuple[0] is the modified value: a unicode or regular string, the URL to validate
Returns:
a (string, string) tuple, where tuple[0] is the modified
input value and tuple[1] is either None (success!) or the input value and tuple[1] is either None (success!) or the
string error_message. The input value will never be modified in the string error_message. The input value will never be modified in the
case of an error. However, if there is success then the input URL case of an error. However, if there is success then the input URL
@@ -2135,7 +2178,8 @@ regex_time = re.compile(
class IS_TIME(Validator): class IS_TIME(Validator):
""" """
example:: Example:
Use as::
INPUT(_type='text', _name='name', requires=IS_TIME()) INPUT(_type='text', _name='name', requires=IS_TIME())
@@ -2144,7 +2188,7 @@ class IS_TIME(Validator):
hh:mm [am/pm] hh:mm [am/pm]
hh [am/pm] hh [am/pm]
[am/pm] is optional, ':' can be replaced by any other non-space non-digit [am/pm] is optional, ':' can be replaced by any other non-space non-digit::
>>> IS_TIME()('21:30') >>> IS_TIME()('21:30')
(datetime.time(21, 30), None) (datetime.time(21, 30), None)
@@ -2171,7 +2215,8 @@ class IS_TIME(Validator):
>>> IS_TIME()('21:30::') >>> IS_TIME()('21:30::')
('21:30::', 'enter time as hh:mm:ss (seconds, am, pm optional)') ('21:30::', 'enter time as hh:mm:ss (seconds, am, pm optional)')
>>> IS_TIME()('') >>> IS_TIME()('')
('', 'enter time as hh:mm:ss (seconds, am, pm optional)') ('', 'enter time as hh:mm:ss (seconds, am, pm optional)')ù
""" """
def __init__(self, error_message='Enter time as hh:mm:ss (seconds, am, pm optional)'): def __init__(self, error_message='Enter time as hh:mm:ss (seconds, am, pm optional)'):
@@ -2215,19 +2260,18 @@ utc = UTC()
class IS_DATE(Validator): class IS_DATE(Validator):
""" """
example:: Examples:
Use as::
INPUT(_type='text', _name='name', requires=IS_DATE()) INPUT(_type='text', _name='name', requires=IS_DATE())
date has to be in the ISO8960 format YYYY-MM-DD date has to be in the ISO8960 format YYYY-MM-DD
timezome must be None or a pytz.timezone("America/Chicago") object
""" """
def __init__(self, format='%Y-%m-%d', def __init__(self, format='%Y-%m-%d',
error_message='Enter date as %(format)s', error_message='Enter date as %(format)s',
timezone = None): timezone = None):
"""
timezome must be None or a pytz.timezone("America/Chicago") object
"""
self.format = translate(format) self.format = translate(format)
self.error_message = str(error_message) self.error_message = str(error_message)
self.timezone = timezone self.timezone = timezone
@@ -2270,11 +2314,13 @@ class IS_DATE(Validator):
class IS_DATETIME(Validator): class IS_DATETIME(Validator):
""" """
example:: Examples:
Use as::
INPUT(_type='text', _name='name', requires=IS_DATETIME()) INPUT(_type='text', _name='name', requires=IS_DATETIME())
datetime has to be in the ISO8960 format YYYY-MM-DD hh:mm:ss datetime has to be in the ISO8960 format YYYY-MM-DD hh:mm:ss
timezome must be None or a pytz.timezone("America/Chicago") object
""" """
isodatetime = '%Y-%m-%d %H:%M:%S' isodatetime = '%Y-%m-%d %H:%M:%S'
@@ -2299,9 +2345,6 @@ class IS_DATETIME(Validator):
def __init__(self, format='%Y-%m-%d %H:%M:%S', def __init__(self, format='%Y-%m-%d %H:%M:%S',
error_message='Enter date and time as %(format)s', error_message='Enter date and time as %(format)s',
timezone=None): timezone=None):
"""
timezome must be None or a pytz.timezone("America/Chicago") object
"""
self.format = translate(format) self.format = translate(format)
self.error_message = str(error_message) self.error_message = str(error_message)
self.extremes = {} self.extremes = {}
@@ -2341,7 +2384,8 @@ class IS_DATETIME(Validator):
class IS_DATE_IN_RANGE(IS_DATE): class IS_DATE_IN_RANGE(IS_DATE):
""" """
example:: Examples:
Use as::
>>> v = IS_DATE_IN_RANGE(minimum=datetime.date(2008,1,1), \ >>> v = IS_DATE_IN_RANGE(minimum=datetime.date(2008,1,1), \
maximum=datetime.date(2009,12,31), \ maximum=datetime.date(2009,12,31), \
@@ -2396,8 +2440,8 @@ class IS_DATE_IN_RANGE(IS_DATE):
class IS_DATETIME_IN_RANGE(IS_DATETIME): class IS_DATETIME_IN_RANGE(IS_DATETIME):
""" """
example:: Examples:
Use as::
>>> v = IS_DATETIME_IN_RANGE(\ >>> v = IS_DATETIME_IN_RANGE(\
minimum=datetime.datetime(2008,1,1,12,20), \ minimum=datetime.datetime(2008,1,1,12,20), \
maximum=datetime.datetime(2009,12,31,12,20), \ maximum=datetime.datetime(2009,12,31,12,20), \
@@ -2413,6 +2457,7 @@ class IS_DATETIME_IN_RANGE(IS_DATETIME):
>>> v(datetime.datetime(2010,3,3,0,0)) >>> v(datetime.datetime(2010,3,3,0,0))
(datetime.datetime(2010, 3, 3, 0, 0), 'oops') (datetime.datetime(2010, 3, 3, 0, 0), 'oops')
""" """
def __init__(self, def __init__(self,
minimum=None, minimum=None,
@@ -2484,12 +2529,13 @@ class IS_LIST_OF(Validator):
class IS_LOWER(Validator): class IS_LOWER(Validator):
""" """
convert to lower case Converts to lower case::
>>> IS_LOWER()('ABC') >>> IS_LOWER()('ABC')
('abc', None) ('abc', None)
>>> IS_LOWER()('Ñ') >>> IS_LOWER()('Ñ')
('\\xc3\\xb1', None) ('\\xc3\\xb1', None)
""" """
def __call__(self, value): def __call__(self, value):
@@ -2498,12 +2544,13 @@ class IS_LOWER(Validator):
class IS_UPPER(Validator): class IS_UPPER(Validator):
""" """
convert to upper case Converts to upper case::
>>> IS_UPPER()('abc') >>> IS_UPPER()('abc')
('ABC', None) ('ABC', None)
>>> IS_UPPER()('ñ') >>> IS_UPPER()('ñ')
('\\xc3\\x91', None) ('\\xc3\\x91', None)
""" """
def __call__(self, value): def __call__(self, value):
@@ -2512,7 +2559,7 @@ class IS_UPPER(Validator):
def urlify(s, maxlen=80, keep_underscores=False): def urlify(s, maxlen=80, keep_underscores=False):
""" """
Convert incoming string to a simplified ASCII subset. Converts incoming string to a simplified ASCII subset.
if (keep_underscores): underscores are retained in the string if (keep_underscores): underscores are retained in the string
else: underscores are translated to hyphens (default) else: underscores are translated to hyphens (default)
""" """
@@ -2536,7 +2583,7 @@ def urlify(s, maxlen=80, keep_underscores=False):
class IS_SLUG(Validator): class IS_SLUG(Validator):
""" """
convert arbitrary text string to a slug converts arbitrary text string to a slug::
>>> IS_SLUG()('abc123') >>> IS_SLUG()('abc123')
('abc123', None) ('abc123', None)
@@ -2596,7 +2643,7 @@ class IS_SLUG(Validator):
class ANY_OF(Validator): class ANY_OF(Validator):
""" """
test if any of the validators in a list return successfully Tests if any of the validators in a list returns successfully::
>>> ANY_OF([IS_EMAIL(),IS_ALPHANUMERIC()])('a@b.co') >>> ANY_OF([IS_EMAIL(),IS_ALPHANUMERIC()])('a@b.co')
('a@b.co', None) ('a@b.co', None)
@@ -2606,6 +2653,7 @@ class ANY_OF(Validator):
('@ab.co', 'enter only letters, numbers, and underscore') ('@ab.co', 'enter only letters, numbers, and underscore')
>>> ANY_OF([IS_ALPHANUMERIC(),IS_EMAIL()])('@ab.co') >>> ANY_OF([IS_ALPHANUMERIC(),IS_EMAIL()])('@ab.co')
('@ab.co', 'enter a valid email address') ('@ab.co', 'enter a valid email address')
""" """
def __init__(self, subs): def __init__(self, subs):
@@ -2628,7 +2676,7 @@ class ANY_OF(Validator):
class IS_EMPTY_OR(Validator): class IS_EMPTY_OR(Validator):
""" """
dummy class for testing IS_EMPTY_OR Dummy class for testing IS_EMPTY_OR::
>>> IS_EMPTY_OR(IS_EMAIL())('abc@def.com') >>> IS_EMPTY_OR(IS_EMAIL())('abc@def.com')
('abc@def.com', None) ('abc@def.com', None)
@@ -2694,7 +2742,8 @@ IS_NULL_OR = IS_EMPTY_OR # for backward compatibility
class CLEANUP(Validator): class CLEANUP(Validator):
""" """
example:: Examples:
Use as::
INPUT(_type='text', _name='name', requires=CLEANUP()) INPUT(_type='text', _name='name', requires=CLEANUP())
@@ -2800,7 +2849,8 @@ class LazyCrypt(object):
class CRYPT(object): class CRYPT(object):
""" """
example:: Examples:
Use as::
INPUT(_type='text', _name='name', requires=CRYPT()) INPUT(_type='text', _name='name', requires=CRYPT())
@@ -2914,7 +2964,7 @@ otherset = frozenset(
def calc_entropy(string): def calc_entropy(string):
" calculate a simple entropy for a given string " " calculates a simple entropy for a given string "
import math import math
alphabet = 0 # alphabet size alphabet = 0 # alphabet size
other = set() other = set()
@@ -2946,7 +2996,8 @@ def calc_entropy(string):
class IS_STRONG(object): class IS_STRONG(object):
""" """
example:: Examples:
Use as::
INPUT(_type='password', _name='passwd', INPUT(_type='password', _name='passwd',
requires=IS_STRONG(min=10, special=2, upper=2)) requires=IS_STRONG(min=10, special=2, upper=2))
@@ -3098,8 +3149,7 @@ class IS_IMAGE(Validator):
Code parts taken from Code parts taken from
http://mail.python.org/pipermail/python-list/2007-June/617126.html http://mail.python.org/pipermail/python-list/2007-June/617126.html
Arguments: Args:
extensions: iterable containing allowed *lowercase* image file extensions extensions: iterable containing allowed *lowercase* image file extensions
('jpg' extension of uploaded file counts as 'jpeg') ('jpg' extension of uploaded file counts as 'jpeg')
maxsize: iterable containing maximum width and height of the image maxsize: iterable containing maximum width and height of the image
@@ -3107,16 +3157,18 @@ class IS_IMAGE(Validator):
Use (-1, -1) as minsize to pass image size check. Use (-1, -1) as minsize to pass image size check.
Examples:: Examples:
Check if uploaded file is in any of supported image formats:
#Check if uploaded file is in any of supported image formats:
INPUT(_type='file', _name='name', requires=IS_IMAGE()) INPUT(_type='file', _name='name', requires=IS_IMAGE())
#Check if uploaded file is either JPEG or PNG: Check if uploaded file is either JPEG or PNG:
INPUT(_type='file', _name='name', INPUT(_type='file', _name='name',
requires=IS_IMAGE(extensions=('jpeg', 'png'))) requires=IS_IMAGE(extensions=('jpeg', 'png')))
#Check if uploaded file is PNG with maximum size of 200x200 pixels: Check if uploaded file is PNG with maximum size of 200x200 pixels:
INPUT(_type='file', _name='name', INPUT(_type='file', _name='name',
requires=IS_IMAGE(extensions=('png'), maxsize=(200, 200))) requires=IS_IMAGE(extensions=('png'), maxsize=(200, 200)))
""" """
@@ -3200,8 +3252,7 @@ class IS_UPLOAD_FILENAME(Validator):
Does *not* ensure the file type in any way. Returns validation failure Does *not* ensure the file type in any way. Returns validation failure
if no data was uploaded. if no data was uploaded.
Arguments:: Args:
filename: filename (before dot) regex filename: filename (before dot) regex
extension: extension (after dot) regex extension: extension (after dot) regex
lastdot: which dot should be used as a filename / extension separator: lastdot: which dot should be used as a filename / extension separator:
@@ -3213,22 +3264,25 @@ class IS_UPLOAD_FILENAME(Validator):
If there is no dot present, extension checks will be done against empty If there is no dot present, extension checks will be done against empty
string and filename checks against whole value. string and filename checks against whole value.
Examples:: Examples:
Check if file has a pdf extension (case insensitive):
#Check if file has a pdf extension (case insensitive):
INPUT(_type='file', _name='name', INPUT(_type='file', _name='name',
requires=IS_UPLOAD_FILENAME(extension='pdf')) requires=IS_UPLOAD_FILENAME(extension='pdf'))
#Check if file has a tar.gz extension and name starting with backup: Check if file has a tar.gz extension and name starting with backup:
INPUT(_type='file', _name='name', INPUT(_type='file', _name='name',
requires=IS_UPLOAD_FILENAME(filename='backup.*', requires=IS_UPLOAD_FILENAME(filename='backup.*',
extension='tar.gz', lastdot=False)) extension='tar.gz', lastdot=False))
#Check if file has no extension and name matching README Check if file has no extension and name matching README
#(case sensitive): (case sensitive):
INPUT(_type='file', _name='name', INPUT(_type='file', _name='name',
requires=IS_UPLOAD_FILENAME(filename='^README$', requires=IS_UPLOAD_FILENAME(filename='^README$',
extension='^$', case=0)) extension='^$', case=0)
""" """
def __init__(self, filename=None, extension=None, lastdot=True, case=1, def __init__(self, filename=None, extension=None, lastdot=True, case=1,
@@ -3273,20 +3327,20 @@ class IS_IPV4(Validator):
IPv4 regex taken from: http://regexlib.com/REDetails.aspx?regexp_id=1411 IPv4 regex taken from: http://regexlib.com/REDetails.aspx?regexp_id=1411
Arguments: Args:
minip: lowest allowed address; accepts: minip: lowest allowed address; accepts:
str, eg. 192.168.0.1
list or tuple of octets, eg. [192, 168, 0, 1] - str, eg. 192.168.0.1
- list or tuple of octets, eg. [192, 168, 0, 1]
maxip: highest allowed address; same as above maxip: highest allowed address; same as above
invert: True to allow addresses only from outside of given range; note invert: True to allow addresses only from outside of given range; note
that range boundaries are not matched this way that range boundaries are not matched this way
is_localhost: localhost address treatment: is_localhost: localhost address treatment:
None (default): indifferent
True (enforce): query address must match localhost address - None (default): indifferent
(127.0.0.1) - True (enforce): query address must match localhost address (127.0.0.1)
False (forbid): query address must not match localhost - False (forbid): query address must not match localhost address
address
is_private: same as above, except that query address is checked against is_private: same as above, except that query address is checked against
two address ranges: 172.16.0.0 - 172.31.255.255 and two address ranges: 172.16.0.0 - 172.31.255.255 and
192.168.0.0 - 192.168.255.255 192.168.0.0 - 192.168.255.255
@@ -3294,7 +3348,7 @@ class IS_IPV4(Validator):
one address range: 169.254.0.0 - 169.254.255.255 one address range: 169.254.0.0 - 169.254.255.255
Minip and maxip may also be lists or tuples of addresses in all above Minip and maxip may also be lists or tuples of addresses in all above
forms (str, int, list / tuple), allowing setup of multiple address ranges: forms (str, int, list / tuple), allowing setup of multiple address ranges::
minip = (minip1, minip2, ... minipN) minip = (minip1, minip2, ... minipN)
| | | | | |
@@ -3303,25 +3357,29 @@ class IS_IPV4(Validator):
Longer iterable will be truncated to match length of shorter one. Longer iterable will be truncated to match length of shorter one.
Examples:: Examples:
Check for valid IPv4 address:
#Check for valid IPv4 address:
INPUT(_type='text', _name='name', requires=IS_IPV4()) INPUT(_type='text', _name='name', requires=IS_IPV4())
#Check for valid IPv4 address belonging to specific range: Check for valid IPv4 address belonging to specific range:
INPUT(_type='text', _name='name', INPUT(_type='text', _name='name',
requires=IS_IPV4(minip='100.200.0.0', maxip='100.200.255.255')) requires=IS_IPV4(minip='100.200.0.0', maxip='100.200.255.255'))
#Check for valid IPv4 address belonging to either 100.110.0.0 - Check for valid IPv4 address belonging to either 100.110.0.0 -
#100.110.255.255 or 200.50.0.0 - 200.50.0.255 address range: 100.110.255.255 or 200.50.0.0 - 200.50.0.255 address range:
INPUT(_type='text', _name='name', INPUT(_type='text', _name='name',
requires=IS_IPV4(minip=('100.110.0.0', '200.50.0.0'), requires=IS_IPV4(minip=('100.110.0.0', '200.50.0.0'),
maxip=('100.110.255.255', '200.50.0.255'))) maxip=('100.110.255.255', '200.50.0.255')))
#Check for valid IPv4 address belonging to private address space: Check for valid IPv4 address belonging to private address space:
INPUT(_type='text', _name='name', requires=IS_IPV4(is_private=True)) INPUT(_type='text', _name='name', requires=IS_IPV4(is_private=True))
#Check for valid IPv4 address that is not a localhost address: Check for valid IPv4 address that is not a localhost address:
INPUT(_type='text', _name='name', requires=IS_IPV4(is_localhost=False)) INPUT(_type='text', _name='name', requires=IS_IPV4(is_localhost=False))
>>> IS_IPV4()('1.2.3.4') >>> IS_IPV4()('1.2.3.4')
@@ -3358,6 +3416,7 @@ class IS_IPV4(Validator):
('127.0.0.1', 'enter valid IPv4 address') ('127.0.0.1', 'enter valid IPv4 address')
>>> IS_IPV4(maxip='100.0.0.0', is_localhost=True)('127.0.0.1') >>> IS_IPV4(maxip='100.0.0.0', is_localhost=True)('127.0.0.1')
('127.0.0.1', 'enter valid IPv4 address') ('127.0.0.1', 'enter valid IPv4 address')
""" """
regex = re.compile( regex = re.compile(
@@ -3433,7 +3492,7 @@ class IS_IPV6(Validator):
use the ipaddress library and falls back to contrib/ipaddr.py from Google use the ipaddress library and falls back to contrib/ipaddr.py from Google
(https://code.google.com/p/ipaddr-py/) (https://code.google.com/p/ipaddr-py/)
Arguments: Args:
is_private: None (default): indifferent is_private: None (default): indifferent
True (enforce): address must be in fc00::/7 range True (enforce): address must be in fc00::/7 range
False (forbid): address must NOT be in fc00::/7 range False (forbid): address must NOT be in fc00::/7 range
@@ -3447,17 +3506,20 @@ class IS_IPV6(Validator):
subnets: value must be a member of at least one from list of subnets subnets: value must be a member of at least one from list of subnets
Examples: Examples:
Check for valid IPv6 address:
#Check for valid IPv6 address:
INPUT(_type='text', _name='name', requires=IS_IPV6()) INPUT(_type='text', _name='name', requires=IS_IPV6())
#Check for valid IPv6 address is a link_local address: Check for valid IPv6 address is a link_local address:
INPUT(_type='text', _name='name', requires=IS_IPV6(is_link_local=True)) INPUT(_type='text', _name='name', requires=IS_IPV6(is_link_local=True))
#Check for valid IPv6 address that is Internet routeable: Check for valid IPv6 address that is Internet routeable:
INPUT(_type='text', _name='name', requires=IS_IPV6(is_routeable=True)) INPUT(_type='text', _name='name', requires=IS_IPV6(is_routeable=True))
#Check for valid IPv6 address in specified subnet: Check for valid IPv6 address in specified subnet:
INPUT(_type='text', _name='name', requires=IS_IPV6(subnets=['2001::/32']) INPUT(_type='text', _name='name', requires=IS_IPV6(subnets=['2001::/32'])
>>> IS_IPV6()('fe80::126c:8ffa:fe22:b3af') >>> IS_IPV6()('fe80::126c:8ffa:fe22:b3af')
@@ -3577,8 +3639,7 @@ class IS_IPADDRESS(Validator):
Uses ipaddress library if found, falls back to PEP-3144 ipaddr.py from Uses ipaddress library if found, falls back to PEP-3144 ipaddr.py from
Google (in contrib). Google (in contrib).
Universal arguments: Args:
minip: lowest allowed address; accepts: minip: lowest allowed address; accepts:
str, eg. 192.168.0.1 str, eg. 192.168.0.1
list or tuple of octets, eg. [192, 168, 0, 1] list or tuple of octets, eg. [192, 168, 0, 1]
@@ -3588,37 +3649,41 @@ class IS_IPADDRESS(Validator):
IPv4 specific arguments: IPv4 specific arguments:
is_localhost: localhost address treatment: - is_localhost: localhost address treatment:
None (default): indifferent
True (enforce): query address must match localhost address - None (default): indifferent
- True (enforce): query address must match localhost address
(127.0.0.1) (127.0.0.1)
False (forbid): query address must not match localhost - False (forbid): query address must not match localhost address
address - is_private: same as above, except that query address is checked against
is_private: same as above, except that query address is checked against
two address ranges: 172.16.0.0 - 172.31.255.255 and two address ranges: 172.16.0.0 - 172.31.255.255 and
192.168.0.0 - 192.168.255.255 192.168.0.0 - 192.168.255.255
is_automatic: same as above, except that query address is checked against - is_automatic: same as above, except that query address is checked against
one address range: 169.254.0.0 - 169.254.255.255 one address range: 169.254.0.0 - 169.254.255.255
is_ipv4: None (default): indifferent - is_ipv4: either:
True (enforce): must be an IPv4 address
False (forbid): must NOT be an IPv4 address - None (default): indifferent
- True (enforce): must be an IPv4 address
- False (forbid): must NOT be an IPv4 address
IPv6 specific arguments: IPv6 specific arguments:
is_link_local: Same as above but uses fe80::/10 range - is_link_local: Same as above but uses fe80::/10 range
is_reserved: Same as above but uses IETF reserved range - is_reserved: Same as above but uses IETF reserved range
is_mulicast: Same as above but uses ff00::/8 range - is_mulicast: Same as above but uses ff00::/8 range
is_routeable: Similar to above but enforces not private, link_local, - is_routeable: Similar to above but enforces not private, link_local,
reserved or multicast reserved or multicast
is_6to4: Same as above but uses 2002::/16 range - is_6to4: Same as above but uses 2002::/16 range
is_teredo: Same as above but uses 2001::/32 range - is_teredo: Same as above but uses 2001::/32 range
subnets: value must be a member of at least one from list of subnets - subnets: value must be a member of at least one from list of subnets
is_ipv6: None (default): indifferent - is_ipv6: either:
True (enforce): must be an IPv6 address
False (forbid): must NOT be an IPv6 address - None (default): indifferent
- True (enforce): must be an IPv6 address
- False (forbid): must NOT be an IPv6 address
Minip and maxip may also be lists or tuples of addresses in all above Minip and maxip may also be lists or tuples of addresses in all above
forms (str, int, list / tuple), allowing setup of multiple address ranges: forms (str, int, list / tuple), allowing setup of multiple address ranges::
minip = (minip1, minip2, ... minipN) minip = (minip1, minip2, ... minipN)
| | | | | |
+14 -13
View File
@@ -2,11 +2,12 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
""" """
This file is part of the web2py Web Framework | This file is part of the web2py Web Framework
Copyrighted by Massimo Di Pierro <mdipierro@cs.depaul.edu> | Copyrighted by Massimo Di Pierro <mdipierro@cs.depaul.edu>
License: LGPLv3 (http://www.gnu.org/licenses/lgpl.html) | License: LGPLv3 (http://www.gnu.org/licenses/lgpl.html)
The widget is called from web2py. The widget is called from web2py
----------------------------------
""" """
import datetime import datetime
@@ -379,7 +380,7 @@ class web2pyDialog(object):
t.start() t.start()
def checkTaskBar(self): def checkTaskBar(self):
""" Check taskbar status """ """ Checks taskbar status """
if self.tb.status: if self.tb.status:
if self.tb.status[0] == self.tb.EnumStatus.QUIT: if self.tb.status[0] == self.tb.EnumStatus.QUIT:
@@ -401,7 +402,7 @@ class web2pyDialog(object):
self.root.after(1000, self.checkTaskBar) self.root.after(1000, self.checkTaskBar)
def update(self, text): def update(self, text):
""" Update app text """ """ Updates app text """
try: try:
self.text.configure(state='normal') self.text.configure(state='normal')
@@ -411,7 +412,7 @@ class web2pyDialog(object):
pass # ## this should only happen in case app is destroyed pass # ## this should only happen in case app is destroyed
def connect_pages(self): def connect_pages(self):
""" Connect pages """ """ Connects pages """
#reset the menu #reset the menu
available_apps = [arq for arq in os.listdir('applications/') available_apps = [arq for arq in os.listdir('applications/')
if os.path.exists( if os.path.exists(
@@ -423,7 +424,7 @@ class web2pyDialog(object):
label=url, command=lambda u=url: start_browser(u)) label=url, command=lambda u=url: start_browser(u))
def quit(self, justHide=False): def quit(self, justHide=False):
""" Finish the program execution """ """ Finishes the program execution """
if justHide: if justHide:
self.root.withdraw() self.root.withdraw()
else: else:
@@ -450,13 +451,13 @@ class web2pyDialog(object):
sys.exit(0) sys.exit(0)
def error(self, message): def error(self, message):
""" Show error message """ """ Shows error message """
import tkMessageBox import tkMessageBox
tkMessageBox.showerror('web2py start server', message) tkMessageBox.showerror('web2py start server', message)
def start(self): def start(self):
""" Start web2py server """ """ Starts web2py server """
password = self.password.get() password = self.password.get()
@@ -536,7 +537,7 @@ class web2pyDialog(object):
return False return False
def stop(self): def stop(self):
""" Stop web2py server """ """ Stops web2py server """
self.button_start.configure(state='normal') self.button_start.configure(state='normal')
self.button_stop.configure(state='disabled') self.button_stop.configure(state='disabled')
@@ -549,7 +550,7 @@ class web2pyDialog(object):
self.tb.SetServerStopped() self.tb.SetServerStopped()
def update_canvas(self): def update_canvas(self):
""" Update canvas """ """ Updates canvas """
try: try:
t1 = os.path.getsize('httpserver.log') t1 = os.path.getsize('httpserver.log')
@@ -1054,7 +1055,7 @@ def start_schedulers(options):
def start(cron=True): def start(cron=True):
""" Start server """ """ Starts server """
# ## get command line arguments # ## get command line arguments
+3 -3
View File
@@ -2,9 +2,9 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
""" """
This file is part of the web2py Web Framework | This file is part of the web2py Web Framework
Copyrighted by Massimo Di Pierro <mdipierro@cs.depaul.edu> | Copyrighted by Massimo Di Pierro <mdipierro@cs.depaul.edu>
License: LGPLv3 (http://www.gnu.org/licenses/lgpl.html) | License: LGPLv3 (http://www.gnu.org/licenses/lgpl.html)
""" """
from SimpleXMLRPCServer import SimpleXMLRPCDispatcher from SimpleXMLRPCServer import SimpleXMLRPCDispatcher