validators Module

This file is part of the web2py Web Framework
Copyrighted by Massimo Di Pierro <mdipierro@cs.depaul.edu>
Thanks to ga2arch for help with IS_IN_DB and IS_NOT_IN_DB on GAE

Validators

class gluon.validators.ANY_OF(subs)[source]

Bases: gluon.validators.Validator

Tests if any of the validators in a list returns successfully:

>>> ANY_OF([IS_EMAIL(),IS_ALPHANUMERIC()])('a@b.co')
('a@b.co', None)
>>> ANY_OF([IS_EMAIL(),IS_ALPHANUMERIC()])('abco')
('abco', None)
>>> ANY_OF([IS_EMAIL(),IS_ALPHANUMERIC()])('@ab.co')
('@ab.co', 'enter only letters, numbers, and underscore')
>>> ANY_OF([IS_ALPHANUMERIC(),IS_EMAIL()])('@ab.co')
('@ab.co', 'enter a valid email address')
formatter(value)[source]
class gluon.validators.CLEANUP(regex=None)[source]

Bases: gluon.validators.Validator

Examples

Use as:

INPUT(_type='text', _name='name', requires=CLEANUP())

removes special characters on validation

REGEX_CLEANUP = <_sre.SRE_Pattern object>
class gluon.validators.CRYPT(key=None, digest_alg='pbkdf2(1000, 20, sha512)', min_length=0, error_message='Too short', salt=True, max_length=1024)[source]

Bases: object

Examples

Use as:

INPUT(_type='text', _name='name', requires=CRYPT())

encodes the value on validation with a digest.

If no arguments are provided CRYPT uses the MD5 algorithm. If the key argument is provided the HMAC+MD5 algorithm is used. If the digest_alg is specified this is used to replace the MD5 with, for example, SHA512. The digest_alg can be the name of a hashlib algorithm as a string or the algorithm itself.

min_length is the minimal password length (default 4) - IS_STRONG for serious security error_message is the message if password is too short

Notice that an empty password is accepted but invalid. It will not allow login back. Stores junk as hashed password.

Specify an algorithm or by default we will use sha512.

Typical available algorithms:
md5, sha1, sha224, sha256, sha384, sha512

If salt, it hashes a password with a salt. If salt is True, this method will automatically generate one. Either case it returns an encrypted password string in the following format:

<algorithm>$<salt>$<hash>

Important: hashed password is returned as a LazyCrypt object and computed only if needed. The LasyCrypt object also knows how to compare itself with an existing salted password

Supports standard algorithms

>>> for alg in ('md5','sha1','sha256','sha384','sha512'):
...     print str(CRYPT(digest_alg=alg,salt=True)('test')[0])
md5$...$...
sha1$...$...
sha256$...$...
sha384$...$...
sha512$...$...

The syntax is always alg$salt$hash

Supports for pbkdf2

>>> alg = 'pbkdf2(1000,20,sha512)'
>>> print str(CRYPT(digest_alg=alg,salt=True)('test')[0])
pbkdf2(1000,20,sha512)$...$...

An optional hmac_key can be specified and it is used as salt prefix

>>> a = str(CRYPT(digest_alg='md5',key='mykey',salt=True)('test')[0])
>>> print a
md5$...$...

Even if the algorithm changes the hash can still be validated

>>> CRYPT(digest_alg='sha1',key='mykey',salt=True)('test')[0] == a
True

If no salt is specified CRYPT can guess the algorithms from length:

>>> a = str(CRYPT(digest_alg='sha1',salt=False)('test')[0])
>>> a
'sha1$$a94a8fe5ccb19ba61c4c0873d391e987982fbbd3'
>>> CRYPT(digest_alg='sha1',salt=False)('test')[0] == a
True
>>> CRYPT(digest_alg='sha1',salt=False)('test')[0] == a[6:]
True
>>> CRYPT(digest_alg='md5',salt=False)('test')[0] == a
True
>>> CRYPT(digest_alg='md5',salt=False)('test')[0] == a[6:]
True
class gluon.validators.IS_ALPHANUMERIC(error_message='Enter only letters, numbers, and underscore')[source]

Bases: gluon.validators.IS_MATCH

Example

Used as:

INPUT(_type='text', _name='name', requires=IS_ALPHANUMERIC())

>>> IS_ALPHANUMERIC()('1')
('1', None)
>>> IS_ALPHANUMERIC()('')
('', None)
>>> IS_ALPHANUMERIC()('A_a')
('A_a', None)
>>> IS_ALPHANUMERIC()('!')
('!', 'enter only letters, numbers, and underscore')
class gluon.validators.IS_DATE_IN_RANGE(minimum=None, maximum=None, format='%Y-%m-%d', error_message=None)[source]

Bases: gluon.validators.IS_DATE

Examples

Use as:

>>> v = IS_DATE_IN_RANGE(minimum=datetime.date(2008,1,1),                                      maximum=datetime.date(2009,12,31),                                      format="%m/%d/%Y",error_message="Oops")

>>> v('03/03/2008')
(datetime.date(2008, 3, 3), None)

>>> v('03/03/2010')
('03/03/2010', 'oops')

>>> v(datetime.date(2008,3,3))
(datetime.date(2008, 3, 3), None)

>>> v(datetime.date(2010,3,3))
(datetime.date(2010, 3, 3), 'oops')
class gluon.validators.IS_DATE(format='%Y-%m-%d', error_message='Enter date as %(format)s')[source]

Bases: gluon.validators.Validator

Examples

Use as:

INPUT(_type='text', _name='name', requires=IS_DATE())

date has to be in the ISO8960 format YYYY-MM-DD

formatter(value)[source]
class gluon.validators.IS_DATETIME_IN_RANGE(minimum=None, maximum=None, format='%Y-%m-%d %H:%M:%S', error_message=None, timezone=None)[source]

Bases: gluon.validators.IS_DATETIME

Examples

Use as::
>>> v = IS_DATETIME_IN_RANGE(                    minimum=datetime.datetime(2008,1,1,12,20),                     maximum=datetime.datetime(2009,12,31,12,20),                     format="%m/%d/%Y %H:%M",error_message="Oops")
>>> v('03/03/2008 12:40')
(datetime.datetime(2008, 3, 3, 12, 40), None)
>>> v('03/03/2010 10:34')
('03/03/2010 10:34', 'oops')
>>> v(datetime.datetime(2008,3,3,0,0))
(datetime.datetime(2008, 3, 3, 0, 0), None)
>>> v(datetime.datetime(2010,3,3,0,0))
(datetime.datetime(2010, 3, 3, 0, 0), 'oops')
class gluon.validators.IS_DATETIME(format='%Y-%m-%d %H:%M:%S', error_message='Enter date and time as %(format)s', timezone=None)[source]

Bases: gluon.validators.Validator

Examples

Use as:

INPUT(_type='text', _name='name', requires=IS_DATETIME())

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

formatter(value)[source]
isodatetime = '%Y-%m-%d %H:%M:%S'
static nice(format)[source]
class gluon.validators.IS_DECIMAL_IN_RANGE(minimum=None, maximum=None, error_message=None, dot='.')[source]

Bases: gluon.validators.Validator

Determines that the argument is (or can be represented as) a Python Decimal, and that it falls within the specified inclusive range. The comparison is made with Python Decimal arithmetic.

The minimum and maximum limits can be None, meaning no lower or upper limit, respectively.

Example

Used as:

INPUT(_type='text', _name='name', requires=IS_DECIMAL_IN_RANGE(0, 10))

>>> IS_DECIMAL_IN_RANGE(1,5)('4')
(Decimal('4'), None)
>>> IS_DECIMAL_IN_RANGE(1,5)(4)
(Decimal('4'), None)
>>> IS_DECIMAL_IN_RANGE(1,5)(1)
(Decimal('1'), None)
>>> IS_DECIMAL_IN_RANGE(1,5)(5.25)
(5.25, 'enter a number between 1 and 5')
>>> IS_DECIMAL_IN_RANGE(5.25,6)(5.25)
(Decimal('5.25'), None)
>>> IS_DECIMAL_IN_RANGE(5.25,6)('5.25')
(Decimal('5.25'), None)
>>> IS_DECIMAL_IN_RANGE(1,5)(6.0)
(6.0, 'enter a number between 1 and 5')
>>> IS_DECIMAL_IN_RANGE(1,5)(3.5)
(Decimal('3.5'), None)
>>> IS_DECIMAL_IN_RANGE(1.5,5.5)(3.5)
(Decimal('3.5'), None)
>>> IS_DECIMAL_IN_RANGE(1.5,5.5)(6.5)
(6.5, 'enter a number between 1.5 and 5.5')
>>> IS_DECIMAL_IN_RANGE(1.5,None)(6.5)
(Decimal('6.5'), None)
>>> IS_DECIMAL_IN_RANGE(1.5,None)(0.5)
(0.5, 'enter a number greater than or equal to 1.5')
>>> IS_DECIMAL_IN_RANGE(None,5.5)(4.5)
(Decimal('4.5'), None)
>>> IS_DECIMAL_IN_RANGE(None,5.5)(6.5)
(6.5, 'enter a number less than or equal to 5.5')
>>> IS_DECIMAL_IN_RANGE()(6.5)
(Decimal('6.5'), None)
>>> IS_DECIMAL_IN_RANGE(0,99)(123.123)
(123.123, 'enter a number between 0 and 99')
>>> IS_DECIMAL_IN_RANGE(0,99)('123.123')
('123.123', 'enter a number between 0 and 99')
>>> IS_DECIMAL_IN_RANGE(0,99)('12.34')
(Decimal('12.34'), None)
>>> IS_DECIMAL_IN_RANGE()('abc')
('abc', 'enter a number')
formatter(value)[source]
class gluon.validators.IS_EMAIL(banned=None, forced=None, error_message='Enter a valid email address')[source]

Bases: gluon.validators.Validator

Checks if field’s value is a valid email address. Can be set to disallow or force addresses from certain domain(s).

Email regex adapted from http://haacked.com/archive/2007/08/21/i-knew-how-to-validate-an-email-address-until-i.aspx, generally following the RFCs, except that we disallow quoted strings and permit underscores and leading numerics in subdomain labels

Parameters:
  • banned – regex text for disallowed address domains
  • forced – regex text for required address domains

Both arguments can also be custom objects with a match(value) method.

Example

Check for valid email address:

INPUT(_type='text', _name='name',
    requires=IS_EMAIL())

Check for valid email address that can’t be from a .com domain:

INPUT(_type='text', _name='name',
    requires=IS_EMAIL(banned='^.*\.com(|\..*)$'))

Check for valid email address that must be from a .edu domain:

INPUT(_type='text', _name='name',
    requires=IS_EMAIL(forced='^.*\.edu(|\..*)$'))

>>> IS_EMAIL()('a@b.com')
('a@b.com', None)
>>> IS_EMAIL()('abc@def.com')
('abc@def.com', None)
>>> IS_EMAIL()('abc@3def.com')
('abc@3def.com', None)
>>> IS_EMAIL()('abc@def.us')
('abc@def.us', None)
>>> IS_EMAIL()('abc@d_-f.us')
('abc@d_-f.us', None)
>>> IS_EMAIL()('@def.com')           # missing name
('@def.com', 'enter a valid email address')
>>> IS_EMAIL()('"abc@def".com')      # quoted name
('"abc@def".com', 'enter a valid email address')
>>> IS_EMAIL()('abc+def.com')        # no @
('abc+def.com', 'enter a valid email address')
>>> IS_EMAIL()('abc@def.x')          # one-char TLD
('abc@def.x', 'enter a valid email address')
>>> IS_EMAIL()('abc@def.12')         # numeric TLD
('abc@def.12', 'enter a valid email address')
>>> IS_EMAIL()('abc@def..com')       # double-dot in domain
('abc@def..com', 'enter a valid email address')
>>> IS_EMAIL()('abc@.def.com')       # dot starts domain
('abc@.def.com', 'enter a valid email address')
>>> IS_EMAIL()('abc@def.c_m')        # underscore in TLD
('abc@def.c_m', 'enter a valid email address')
>>> IS_EMAIL()('NotAnEmail')         # missing @
('NotAnEmail', 'enter a valid email address')
>>> IS_EMAIL()('abc@NotAnEmail')     # missing TLD
('abc@NotAnEmail', 'enter a valid email address')
>>> IS_EMAIL()('customer/department@example.com')
('customer/department@example.com', None)
>>> IS_EMAIL()('$A12345@example.com')
('$A12345@example.com', None)
>>> IS_EMAIL()('!def!xyz%abc@example.com')
('!def!xyz%abc@example.com', None)
>>> IS_EMAIL()('_Yosemite.Sam@example.com')
('_Yosemite.Sam@example.com', None)
>>> IS_EMAIL()('~@example.com')
('~@example.com', None)
>>> IS_EMAIL()('.wooly@example.com')       # dot starts name
('.wooly@example.com', 'enter a valid email address')
>>> IS_EMAIL()('wo..oly@example.com')      # adjacent dots in name
('wo..oly@example.com', 'enter a valid email address')
>>> IS_EMAIL()('pootietang.@example.com')  # dot ends name
('pootietang.@example.com', 'enter a valid email address')
>>> IS_EMAIL()('.@example.com')            # name is bare dot
('.@example.com', 'enter a valid email address')
>>> IS_EMAIL()('Ima.Fool@example.com')
('Ima.Fool@example.com', None)
>>> IS_EMAIL()('Ima Fool@example.com')     # space in name
('Ima Fool@example.com', 'enter a valid email address')
>>> IS_EMAIL()('localguy@localhost')       # localhost as domain
('localguy@localhost', None)
regex = <_sre.SRE_Pattern object at 0x279df50>
regex_proposed_but_failed = <_sre.SRE_Pattern object at 0x279ff60>
class gluon.validators.IS_LIST_OF_EMAILS(error_message='Invalid emails: %s')[source]

Bases: object

Example

Used as:

Field('emails','list:string',
      widget=SQLFORM.widgets.text.widget,
      requires=IS_LIST_OF_EMAILS(),
      represent=lambda v,r:                      SPAN(*[A(x,_href='mailto:'+x) for x in (v or [])])
      )
formatter(value, row=None)[source]
split_emails = <_sre.SRE_Pattern object>
class gluon.validators.IS_EMPTY_OR(other, null=None, empty_regex=None)[source]

Bases: gluon.validators.Validator

Dummy class for testing IS_EMPTY_OR:

>>> IS_EMPTY_OR(IS_EMAIL())('abc@def.com')
('abc@def.com', None)
>>> IS_EMPTY_OR(IS_EMAIL())('   ')
(None, None)
>>> IS_EMPTY_OR(IS_EMAIL(), null='abc')('   ')
('abc', None)
>>> IS_EMPTY_OR(IS_EMAIL(), null='abc', empty_regex='def')('def')
('abc', None)
>>> IS_EMPTY_OR(IS_EMAIL())('abc')
('abc', 'enter a valid email address')
>>> IS_EMPTY_OR(IS_EMAIL())(' abc ')
('abc', 'enter a valid email address')
formatter(value)[source]
set_self_id(id)[source]
class gluon.validators.IS_EXPR(expression, error_message='Invalid expression', environment=None)[source]

Bases: gluon.validators.Validator

Example

Used as:

INPUT(_type='text', _name='name',
    requires=IS_EXPR('5 < int(value) < 10'))

The argument of IS_EXPR must be python condition:

>>> IS_EXPR('int(value) < 2')('1')
('1', None)

>>> IS_EXPR('int(value) < 2')('2')
('2', 'invalid expression')
class gluon.validators.IS_FLOAT_IN_RANGE(minimum=None, maximum=None, error_message=None, dot='.')[source]

Bases: gluon.validators.Validator

Determines that the argument is (or can be represented as) a float, and that it falls within the specified inclusive range. The comparison is made with native arithmetic.

The minimum and maximum limits can be None, meaning no lower or upper limit, respectively.

Example

Used as:

INPUT(_type='text', _name='name', requires=IS_FLOAT_IN_RANGE(0, 10))

>>> IS_FLOAT_IN_RANGE(1,5)('4')
(4.0, None)
>>> IS_FLOAT_IN_RANGE(1,5)(4)
(4.0, None)
>>> IS_FLOAT_IN_RANGE(1,5)(1)
(1.0, None)
>>> IS_FLOAT_IN_RANGE(1,5)(5.25)
(5.25, 'enter a number between 1 and 5')
>>> IS_FLOAT_IN_RANGE(1,5)(6.0)
(6.0, 'enter a number between 1 and 5')
>>> IS_FLOAT_IN_RANGE(1,5)(3.5)
(3.5, None)
>>> IS_FLOAT_IN_RANGE(1,None)(3.5)
(3.5, None)
>>> IS_FLOAT_IN_RANGE(None,5)(3.5)
(3.5, None)
>>> IS_FLOAT_IN_RANGE(1,None)(0.5)
(0.5, 'enter a number greater than or equal to 1')
>>> IS_FLOAT_IN_RANGE(None,5)(6.5)
(6.5, 'enter a number less than or equal to 5')
>>> IS_FLOAT_IN_RANGE()(6.5)
(6.5, None)
>>> IS_FLOAT_IN_RANGE()('abc')
('abc', 'enter a number')
formatter(value)[source]
class gluon.validators.IS_IMAGE(extensions=('bmp', 'gif', 'jpeg', 'png'), maxsize=(10000, 10000), minsize=(0, 0), error_message='Invalid image')[source]

Bases: gluon.validators.Validator

Checks if file uploaded through file input was saved in one of selected image formats and has dimensions (width and height) within given boundaries.

Does not check for maximum file size (use IS_LENGTH for that). Returns validation failure if no data was uploaded.

Supported file formats: BMP, GIF, JPEG, PNG.

Code parts taken from http://mail.python.org/pipermail/python-list/2007-June/617126.html

Parameters:
  • extensions – iterable containing allowed lowercase image file extensions
  • extension of uploaded file counts as 'jpeg') (('jpg') –
  • maxsize – iterable containing maximum width and height of the image
  • minsize – iterable containing minimum width and height of the image

Use (-1, -1) as minsize to pass image size check.

Examples

Check if uploaded file is in any of supported image formats:

INPUT(_type=’file’, _name=’name’, requires=IS_IMAGE())

Check if uploaded file is either JPEG or PNG:

INPUT(_type=’file’, _name=’name’,
requires=IS_IMAGE(extensions=(‘jpeg’, ‘png’)))

Check if uploaded file is PNG with maximum size of 200x200 pixels:

INPUT(_type=’file’, _name=’name’,
requires=IS_IMAGE(extensions=(‘png’), maxsize=(200, 200)))
class gluon.validators.IS_IN_DB(dbset, field, label=None, error_message='Value not in database', orderby=None, groupby=None, distinct=None, cache=None, multiple=False, zero='', sort=False, _and=None, left=None, delimiter=None, auto_add=False)[source]

Bases: gluon.validators.Validator

Example

Used as:

INPUT(_type='text', _name='name',
      requires=IS_IN_DB(db, db.mytable.myfield, zero=''))

used for reference fields, rendered as a dropbox

build_set()[source]
maybe_add(table, fieldname, value)[source]
options(zero=True)[source]
set_self_id(id)[source]
class gluon.validators.IS_IN_SET(theset, labels=None, error_message='Value not allowed', multiple=False, zero='', sort=False)[source]

Bases: gluon.validators.Validator

Example

Used as:

INPUT(_type='text', _name='name',
      requires=IS_IN_SET(['max', 'john'],zero=''))

The argument of IS_IN_SET must be a list or set:

>>> IS_IN_SET(['max', 'john'])('max')
('max', None)
>>> IS_IN_SET(['max', 'john'])('massimo')
('massimo', 'value not allowed')
>>> IS_IN_SET(['max', 'john'], multiple=True)(('max', 'john'))
(('max', 'john'), None)
>>> IS_IN_SET(['max', 'john'], multiple=True)(('bill', 'john'))
(('bill', 'john'), 'value not allowed')
>>> IS_IN_SET(('id1','id2'), ['first label','second label'])('id1') # Traditional way
('id1', None)
>>> IS_IN_SET({'id1':'first label', 'id2':'second label'})('id1')
('id1', None)
>>> import itertools
>>> IS_IN_SET(itertools.chain(['1','3','5'],['2','4','6']))('1')
('1', None)
>>> IS_IN_SET([('id1','first label'), ('id2','second label')])('id1') # Redundant way
('id1', None)
options(zero=True)[source]
class gluon.validators.IS_INT_IN_RANGE(minimum=None, maximum=None, error_message=None)[source]

Bases: gluon.validators.Validator

Determines that the argument is (or can be represented as) an int, and that it falls within the specified range. The range is interpreted 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, respectively.

Example

Used as:

INPUT(_type='text', _name='name', requires=IS_INT_IN_RANGE(0, 10))

>>> IS_INT_IN_RANGE(1,5)('4')
(4, None)
>>> IS_INT_IN_RANGE(1,5)(4)
(4, None)
>>> IS_INT_IN_RANGE(1,5)(1)
(1, None)
>>> IS_INT_IN_RANGE(1,5)(5)
(5, 'enter an integer between 1 and 4')
>>> IS_INT_IN_RANGE(1,5)(5)
(5, 'enter an integer between 1 and 4')
>>> IS_INT_IN_RANGE(1,5)(3.5)
(3.5, 'enter an integer between 1 and 4')
>>> IS_INT_IN_RANGE(None,5)('4')
(4, None)
>>> IS_INT_IN_RANGE(None,5)('6')
('6', 'enter an integer less than or equal to 4')
>>> IS_INT_IN_RANGE(1,None)('4')
(4, None)
>>> IS_INT_IN_RANGE(1,None)('0')
('0', 'enter an integer greater than or equal to 1')
>>> IS_INT_IN_RANGE()(6)
(6, None)
>>> IS_INT_IN_RANGE()('abc')
('abc', 'enter an integer')
class gluon.validators.IS_IPV4(minip='0.0.0.0', maxip='255.255.255.255', invert=False, is_localhost=None, is_private=None, is_automatic=None, error_message='Enter valid IPv4 address')[source]

Bases: gluon.validators.Validator

Checks if field’s value is an IP version 4 address in decimal form. Can be set to force addresses from certain range.

IPv4 regex taken from: http://regexlib.com/REDetails.aspx?regexp_id=1411

Parameters:
  • minip

    lowest allowed address; accepts:

    • str, eg. 192.168.0.1
    • list or tuple of octets, eg. [192, 168, 0, 1]
  • maxip – highest allowed address; same as above
  • invert – True to allow addresses only from outside of given range; note that range boundaries are not matched this way
  • is_localhost

    localhost address treatment:

    • None (default): indifferent
    • True (enforce): query address must match localhost address (127.0.0.1)
    • False (forbid): query address must not match localhost address
  • is_private – same as above, except that query address is checked against two address ranges: 172.16.0.0 - 172.31.255.255 and 192.168.0.0 - 192.168.255.255
  • is_automatic – same as above, except that query address is checked against 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 forms (str, int, list / tuple), allowing setup of multiple address ranges:

minip = (minip1, minip2, ... minipN)
           |       |           |
           |       |           |
maxip = (maxip1, maxip2, ... maxipN)

Longer iterable will be truncated to match length of shorter one.

Examples

Check for valid IPv4 address:

INPUT(_type=’text’, _name=’name’, requires=IS_IPV4())

Check for valid IPv4 address belonging to specific range:

INPUT(_type=’text’, _name=’name’,
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 - 100.110.255.255 or 200.50.0.0 - 200.50.0.255 address range:

INPUT(_type=’text’, _name=’name’,
requires=IS_IPV4(minip=(‘100.110.0.0’, ‘200.50.0.0’),
maxip=(‘100.110.255.255’, ‘200.50.0.255’)))

Check for valid IPv4 address belonging to private address space:

INPUT(_type=’text’, _name=’name’, requires=IS_IPV4(is_private=True))

Check for valid IPv4 address that is not a localhost address:

INPUT(_type=’text’, _name=’name’, requires=IS_IPV4(is_localhost=False))

>>> IS_IPV4()('1.2.3.4')
('1.2.3.4', None)
>>> IS_IPV4()('255.255.255.255')
('255.255.255.255', None)
>>> IS_IPV4()('1.2.3.4 ')
('1.2.3.4 ', 'enter valid IPv4 address')
>>> IS_IPV4()('1.2.3.4.5')
('1.2.3.4.5', 'enter valid IPv4 address')
>>> IS_IPV4()('123.123')
('123.123', 'enter valid IPv4 address')
>>> IS_IPV4()('1111.2.3.4')
('1111.2.3.4', 'enter valid IPv4 address')
>>> IS_IPV4()('0111.2.3.4')
('0111.2.3.4', 'enter valid IPv4 address')
>>> IS_IPV4()('256.2.3.4')
('256.2.3.4', 'enter valid IPv4 address')
>>> IS_IPV4()('300.2.3.4')
('300.2.3.4', 'enter valid IPv4 address')
>>> IS_IPV4(minip='1.2.3.4', maxip='1.2.3.4')('1.2.3.4')
('1.2.3.4', None)
>>> IS_IPV4(minip='1.2.3.5', maxip='1.2.3.9', error_message='Bad ip')('1.2.3.4')
('1.2.3.4', 'bad ip')
>>> IS_IPV4(maxip='1.2.3.4', invert=True)('127.0.0.1')
('127.0.0.1', None)
>>> IS_IPV4(maxip='1.2.3.4', invert=True)('1.2.3.4')
('1.2.3.4', 'enter valid IPv4 address')
>>> IS_IPV4(is_localhost=True)('127.0.0.1')
('127.0.0.1', None)
>>> IS_IPV4(is_localhost=True)('1.2.3.4')
('1.2.3.4', 'enter valid IPv4 address')
>>> IS_IPV4(is_localhost=False)('127.0.0.1')
('127.0.0.1', 'enter valid IPv4 address')
>>> IS_IPV4(maxip='100.0.0.0', is_localhost=True)('127.0.0.1')
('127.0.0.1', 'enter valid IPv4 address')
automatic = (2851995648L, 2852061183L)
localhost = 2130706433
numbers = (16777216, 65536, 256, 1)
private = ((2886729728L, 2886795263L), (3232235520L, 3232301055L))
regex = <_sre.SRE_Pattern object at 0x27abf20>
class gluon.validators.IS_IPV6(is_private=None, is_link_local=None, is_reserved=None, is_multicast=None, is_routeable=None, is_6to4=None, is_teredo=None, subnets=None, error_message='Enter valid IPv6 address')[source]

Bases: gluon.validators.Validator

Checks if field’s value is an IP version 6 address. First attempts to use the ipaddress library and falls back to contrib/ipaddr.py from Google (https://code.google.com/p/ipaddr-py/)

Parameters:
  • is_private – None (default): indifferent True (enforce): address must be in fc00::/7 range False (forbid): address must NOT be in fc00::/7 range
  • is_link_local – Same as above but uses fe80::/10 range
  • is_reserved – Same as above but uses IETF reserved range
  • is_mulicast – Same as above but uses ff00::/8 range
  • is_routeable – Similar to above but enforces not private, link_local, reserved or multicast
  • is_6to4 – Same as above but uses 2002::/16 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

Examples

Check for valid IPv6 address:

INPUT(_type=’text’, _name=’name’, requires=IS_IPV6())

Check for valid IPv6 address is a link_local address:

INPUT(_type=’text’, _name=’name’, requires=IS_IPV6(is_link_local=True))

Check for valid IPv6 address that is Internet routeable:

INPUT(_type=’text’, _name=’name’, requires=IS_IPV6(is_routeable=True))

Check for valid IPv6 address in specified subnet:

INPUT(_type=’text’, _name=’name’, requires=IS_IPV6(subnets=[‘2001::/32’])

>>> IS_IPV6()('fe80::126c:8ffa:fe22:b3af')
('fe80::126c:8ffa:fe22:b3af', None)
>>> IS_IPV6()('192.168.1.1')
('192.168.1.1', 'enter valid IPv6 address')
>>> IS_IPV6(error_message='Bad ip')('192.168.1.1')
('192.168.1.1', 'bad ip')
>>> IS_IPV6(is_link_local=True)('fe80::126c:8ffa:fe22:b3af')
('fe80::126c:8ffa:fe22:b3af', None)
>>> IS_IPV6(is_link_local=False)('fe80::126c:8ffa:fe22:b3af')
('fe80::126c:8ffa:fe22:b3af', 'enter valid IPv6 address')
>>> IS_IPV6(is_link_local=True)('2001::126c:8ffa:fe22:b3af')
('2001::126c:8ffa:fe22:b3af', 'enter valid IPv6 address')
>>> IS_IPV6(is_multicast=True)('2001::126c:8ffa:fe22:b3af')
('2001::126c:8ffa:fe22:b3af', 'enter valid IPv6 address')
>>> IS_IPV6(is_multicast=True)('ff00::126c:8ffa:fe22:b3af')
('ff00::126c:8ffa:fe22:b3af', None)
>>> IS_IPV6(is_routeable=True)('2001::126c:8ffa:fe22:b3af')
('2001::126c:8ffa:fe22:b3af', None)
>>> IS_IPV6(is_routeable=True)('ff00::126c:8ffa:fe22:b3af')
('ff00::126c:8ffa:fe22:b3af', 'enter valid IPv6 address')
>>> IS_IPV6(subnets='2001::/32')('2001::8ffa:fe22:b3af')
('2001::8ffa:fe22:b3af', None)
>>> IS_IPV6(subnets='fb00::/8')('2001::8ffa:fe22:b3af')
('2001::8ffa:fe22:b3af', 'enter valid IPv6 address')
>>> IS_IPV6(subnets=['fc00::/8','2001::/32'])('2001::8ffa:fe22:b3af')
('2001::8ffa:fe22:b3af', None)
>>> IS_IPV6(subnets='invalidsubnet')('2001::8ffa:fe22:b3af')
('2001::8ffa:fe22:b3af', 'invalid subnet provided')
class gluon.validators.IS_IPADDRESS(minip='0.0.0.0', maxip='255.255.255.255', invert=False, is_localhost=None, is_private=None, is_automatic=None, is_ipv4=None, is_link_local=None, is_reserved=None, is_multicast=None, is_routeable=None, is_6to4=None, is_teredo=None, subnets=None, is_ipv6=None, error_message='Enter valid IP address')[source]

Bases: gluon.validators.Validator

Checks if field’s value is an IP Address (v4 or v6). Can be set to force addresses from within a specific range. Checks are done with the correct IS_IPV4 and IS_IPV6 validators.

Uses ipaddress library if found, falls back to PEP-3144 ipaddr.py from Google (in contrib).

Parameters:
  • minip – lowest allowed address; accepts: str, eg. 192.168.0.1 list or tuple of octets, eg. [192, 168, 0, 1]
  • maxip – highest allowed address; same as above
  • invert – True to allow addresses only from outside of given range; note that range boundaries are not matched this way

IPv4 specific arguments:

  • is_localhost: localhost address treatment:

    • None (default): indifferent
    • True (enforce): query address must match localhost address (127.0.0.1)
    • False (forbid): query address must not match localhost address
  • is_private: same as above, except that query address is checked against two address ranges: 172.16.0.0 - 172.31.255.255 and 192.168.0.0 - 192.168.255.255

  • is_automatic: same as above, except that query address is checked against one address range: 169.254.0.0 - 169.254.255.255

  • is_ipv4: either:

    • None (default): indifferent
    • True (enforce): must be an IPv4 address
    • False (forbid): must NOT be an IPv4 address

IPv6 specific arguments:

  • is_link_local: Same as above but uses fe80::/10 range

  • is_reserved: Same as above but uses IETF reserved range

  • is_mulicast: Same as above but uses ff00::/8 range

  • is_routeable: Similar to above but enforces not private, link_local, reserved or multicast

  • is_6to4: Same as above but uses 2002::/16 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

  • is_ipv6: either:

    • 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 forms (str, int, list / tuple), allowing setup of multiple address ranges:

minip = (minip1, minip2, ... minipN)
           |       |           |
           |       |           |
maxip = (maxip1, maxip2, ... maxipN)

Longer iterable will be truncated to match length of shorter one.

>>> IS_IPADDRESS()('192.168.1.5')
('192.168.1.5', None)
>>> IS_IPADDRESS(is_ipv6=False)('192.168.1.5')
('192.168.1.5', None)
>>> IS_IPADDRESS()('255.255.255.255')
('255.255.255.255', None)
>>> IS_IPADDRESS()('192.168.1.5 ')
('192.168.1.5 ', 'enter valid IP address')
>>> IS_IPADDRESS()('192.168.1.1.5')
('192.168.1.1.5', 'enter valid IP address')
>>> IS_IPADDRESS()('123.123')
('123.123', 'enter valid IP address')
>>> IS_IPADDRESS()('1111.2.3.4')
('1111.2.3.4', 'enter valid IP address')
>>> IS_IPADDRESS()('0111.2.3.4')
('0111.2.3.4', 'enter valid IP address')
>>> IS_IPADDRESS()('256.2.3.4')
('256.2.3.4', 'enter valid IP address')
>>> IS_IPADDRESS()('300.2.3.4')
('300.2.3.4', 'enter valid IP address')
>>> IS_IPADDRESS(minip='192.168.1.0', maxip='192.168.1.255')('192.168.1.100')
('192.168.1.100', None)
>>> IS_IPADDRESS(minip='1.2.3.5', maxip='1.2.3.9', error_message='Bad ip')('1.2.3.4')
('1.2.3.4', 'bad ip')
>>> IS_IPADDRESS(maxip='1.2.3.4', invert=True)('127.0.0.1')
('127.0.0.1', None)
>>> IS_IPADDRESS(maxip='192.168.1.4', invert=True)('192.168.1.4')
('192.168.1.4', 'enter valid IP address')
>>> IS_IPADDRESS(is_localhost=True)('127.0.0.1')
('127.0.0.1', None)
>>> IS_IPADDRESS(is_localhost=True)('192.168.1.10')
('192.168.1.10', 'enter valid IP address')
>>> IS_IPADDRESS(is_localhost=False)('127.0.0.1')
('127.0.0.1', 'enter valid IP address')
>>> IS_IPADDRESS(maxip='100.0.0.0', is_localhost=True)('127.0.0.1')
('127.0.0.1', 'enter valid IP address')
>>> IS_IPADDRESS()('fe80::126c:8ffa:fe22:b3af')
('fe80::126c:8ffa:fe22:b3af', None)
>>> IS_IPADDRESS(is_ipv4=False)('fe80::126c:8ffa:fe22:b3af')
('fe80::126c:8ffa:fe22:b3af', None)
>>> IS_IPADDRESS()('fe80::126c:8ffa:fe22:b3af  ')
('fe80::126c:8ffa:fe22:b3af  ', 'enter valid IP address')
>>> IS_IPADDRESS(is_ipv4=True)('fe80::126c:8ffa:fe22:b3af')
('fe80::126c:8ffa:fe22:b3af', 'enter valid IP address')
>>> IS_IPADDRESS(is_ipv6=True)('192.168.1.1')
('192.168.1.1', 'enter valid IP address')
>>> IS_IPADDRESS(is_ipv6=True, error_message='Bad ip')('192.168.1.1')
('192.168.1.1', 'bad ip')
>>> IS_IPADDRESS(is_link_local=True)('fe80::126c:8ffa:fe22:b3af')
('fe80::126c:8ffa:fe22:b3af', None)
>>> IS_IPADDRESS(is_link_local=False)('fe80::126c:8ffa:fe22:b3af')
('fe80::126c:8ffa:fe22:b3af', 'enter valid IP address')
>>> IS_IPADDRESS(is_link_local=True)('2001::126c:8ffa:fe22:b3af')
('2001::126c:8ffa:fe22:b3af', 'enter valid IP address')
>>> IS_IPADDRESS(is_multicast=True)('2001::126c:8ffa:fe22:b3af')
('2001::126c:8ffa:fe22:b3af', 'enter valid IP address')
>>> IS_IPADDRESS(is_multicast=True)('ff00::126c:8ffa:fe22:b3af')
('ff00::126c:8ffa:fe22:b3af', None)
>>> IS_IPADDRESS(is_routeable=True)('2001::126c:8ffa:fe22:b3af')
('2001::126c:8ffa:fe22:b3af', None)
>>> IS_IPADDRESS(is_routeable=True)('ff00::126c:8ffa:fe22:b3af')
('ff00::126c:8ffa:fe22:b3af', 'enter valid IP address')
>>> IS_IPADDRESS(subnets='2001::/32')('2001::8ffa:fe22:b3af')
('2001::8ffa:fe22:b3af', None)
>>> IS_IPADDRESS(subnets='fb00::/8')('2001::8ffa:fe22:b3af')
('2001::8ffa:fe22:b3af', 'enter valid IP address')
>>> IS_IPADDRESS(subnets=['fc00::/8','2001::/32'])('2001::8ffa:fe22:b3af')
('2001::8ffa:fe22:b3af', None)
>>> IS_IPADDRESS(subnets='invalidsubnet')('2001::8ffa:fe22:b3af')
('2001::8ffa:fe22:b3af', 'invalid subnet provided')
class gluon.validators.IS_LENGTH(maxsize=255, minsize=0, error_message='Enter from %(min)g to %(max)g characters')[source]

Bases: gluon.validators.Validator

Checks if length of field’s value fits between given boundaries. Works for both text and file inputs.

Parameters:
  • maxsize – maximum allowed length / size
  • minsize – minimum allowed length / size

Examples

Check if text string is shorter than 33 characters:

INPUT(_type='text', _name='name', requires=IS_LENGTH(32))

Check if password string is longer than 5 characters:

INPUT(_type='password', _name='name', requires=IS_LENGTH(minsize=6))

Check if uploaded file has size between 1KB and 1MB:

INPUT(_type='file', _name='name', requires=IS_LENGTH(1048576, 1024))

Other examples:

>>> IS_LENGTH()('')
('', None)
>>> IS_LENGTH()('1234567890')
('1234567890', None)
>>> IS_LENGTH(maxsize=5, minsize=0)('1234567890')  # too long
('1234567890', 'enter from 0 to 5 characters')
>>> IS_LENGTH(maxsize=50, minsize=20)('1234567890')  # too short
('1234567890', 'enter from 20 to 50 characters')
class gluon.validators.IS_LIST_OF(other=None, minimum=0, maximum=100, error_message=None)[source]

Bases: gluon.validators.Validator

class gluon.validators.IS_LOWER[source]

Bases: gluon.validators.Validator

Converts to lower case:

>>> IS_LOWER()('ABC')
('abc', None)
>>> IS_LOWER()('Ñ')
('\xc3\xb1', None)
class gluon.validators.IS_MATCH(expression, error_message='Invalid expression', strict=False, search=False, extract=False, is_unicode=False)[source]

Bases: gluon.validators.Validator

Example

Used as:

INPUT(_type='text', _name='name', requires=IS_MATCH('.+'))

The argument of IS_MATCH is a regular expression:

>>> IS_MATCH('.+')('hello')
('hello', None)

>>> IS_MATCH('hell')('hello')
('hello', None)

>>> IS_MATCH('hell.*', strict=False)('hello')
('hello', None)

>>> IS_MATCH('hello')('shello')
('shello', 'invalid expression')

>>> IS_MATCH('hello', search=True)('shello')
('shello', None)

>>> IS_MATCH('hello', search=True, strict=False)('shellox')
('shellox', None)

>>> IS_MATCH('.*hello.*', search=True, strict=False)('shellox')
('shellox', None)

>>> IS_MATCH('.+')('')
('', 'invalid expression')
class gluon.validators.IS_EQUAL_TO(expression, error_message='No match')[source]

Bases: gluon.validators.Validator

Example

Used as:

INPUT(_type='text', _name='password')
INPUT(_type='text', _name='password2',
      requires=IS_EQUAL_TO(request.vars.password))

The argument of IS_EQUAL_TO is a string:

>>> IS_EQUAL_TO('aaa')('aaa')
('aaa', None)

>>> IS_EQUAL_TO('aaa')('aab')
('aab', 'no match')
class gluon.validators.IS_NOT_EMPTY(error_message='Enter a value', empty_regex=None)[source]

Bases: gluon.validators.Validator

Example

Used as:

INPUT(_type='text', _name='name', requires=IS_NOT_EMPTY())

>>> IS_NOT_EMPTY()(1)
(1, None)
>>> IS_NOT_EMPTY()(0)
(0, None)
>>> IS_NOT_EMPTY()('x')
('x', None)
>>> IS_NOT_EMPTY()(' x ')
('x', None)
>>> IS_NOT_EMPTY()(None)
(None, 'enter a value')
>>> IS_NOT_EMPTY()('')
('', 'enter a value')
>>> IS_NOT_EMPTY()('  ')
('', 'enter a value')
>>> IS_NOT_EMPTY()(' \n\t')
('', 'enter a value')
>>> IS_NOT_EMPTY()([])
([], 'enter a value')
>>> IS_NOT_EMPTY(empty_regex='def')('def')
('', 'enter a value')
>>> IS_NOT_EMPTY(empty_regex='de[fg]')('deg')
('', 'enter a value')
>>> IS_NOT_EMPTY(empty_regex='def')('abc')
('abc', None)
class gluon.validators.IS_NOT_IN_DB(dbset, field, error_message='Value already in database or empty', allowed_override=[], ignore_common_filters=False)[source]

Bases: gluon.validators.Validator

Example

Used as:

INPUT(_type='text', _name='name', requires=IS_NOT_IN_DB(db, db.table))

makes the field unique

set_self_id(id)[source]
gluon.validators.IS_NULL_OR

alias of IS_EMPTY_OR

class gluon.validators.IS_SLUG(maxlen=80, check=False, error_message='Must be slug', keep_underscores=False)[source]

Bases: gluon.validators.Validator

converts arbitrary text string to a slug:

>>> IS_SLUG()('abc123')
('abc123', None)
>>> IS_SLUG()('ABC123')
('abc123', None)
>>> IS_SLUG()('abc-123')
('abc-123', None)
>>> IS_SLUG()('abc--123')
('abc-123', None)
>>> IS_SLUG()('abc 123')
('abc-123', None)
>>> IS_SLUG()('abc      _123')
('abc-123', None)
>>> IS_SLUG()('-abc-')
('abc', None)
>>> IS_SLUG()('--a--b--_ -c--')
('a-b-c', None)
>>> IS_SLUG()('abc&amp;123')
('abc123', None)
>>> IS_SLUG()('abc&amp;123&amp;def')
('abc123def', None)
>>> IS_SLUG()('ñ')
('n', None)
>>> IS_SLUG(maxlen=4)('abc123')
('abc1', None)
>>> IS_SLUG()('abc_123')
('abc-123', None)
>>> IS_SLUG(keep_underscores=False)('abc_123')
('abc-123', None)
>>> IS_SLUG(keep_underscores=True)('abc_123')
('abc_123', None)
>>> IS_SLUG(check=False)('abc')
('abc', None)
>>> IS_SLUG(check=True)('abc')
('abc', None)
>>> IS_SLUG(check=False)('a bc')
('a-bc', None)
>>> IS_SLUG(check=True)('a bc')
('a bc', 'must be slug')
static urlify(value, maxlen=80, keep_underscores=False)[source]
class gluon.validators.IS_STRONG(min=None, max=None, upper=None, lower=None, number=None, entropy=None, special=None, specials='~!@#$%^&*()_+-=?<>, .:;{}[]|', invalid=' "', error_message=None, es=False)[source]

Bases: object

Examples

Use as:

INPUT(_type='password', _name='passwd',
requires=IS_STRONG(min=10, special=2, upper=2))

enforces complexity requirements on a field

>>> IS_STRONG(es=True)('Abcd1234')
('Abcd1234',
 'Must include at least 1 of the following: ~!@#$%^&*()_+-=?<>,.:;{}[]|')
>>> IS_STRONG(es=True)('Abcd1234!')
('Abcd1234!', None)
>>> IS_STRONG(es=True, entropy=1)('a')
('a', None)
>>> IS_STRONG(es=True, entropy=1, min=2)('a')
('a', 'Minimum length is 2')
>>> IS_STRONG(es=True, entropy=100)('abc123')
('abc123', 'Entropy (32.35) less than required (100)')
>>> IS_STRONG(es=True, entropy=100)('and')
('and', 'Entropy (14.57) less than required (100)')
>>> IS_STRONG(es=True, entropy=100)('aaa')
('aaa', 'Entropy (14.42) less than required (100)')
>>> IS_STRONG(es=True, entropy=100)('a1d')
('a1d', 'Entropy (15.97) less than required (100)')
>>> IS_STRONG(es=True, entropy=100)('añd')
('a\xc3\xb1d', 'Entropy (18.13) less than required (100)')
class gluon.validators.IS_TIME(error_message='Enter time as hh:mm:ss (seconds, am, pm optional)')[source]

Bases: gluon.validators.Validator

Example

Use as:

INPUT(_type='text', _name='name', requires=IS_TIME())

understands the following formats hh:mm:ss [am/pm] hh:mm [am/pm] hh [am/pm]

[am/pm] is optional, ‘:’ can be replaced by any other non-space non-digit:

>>> IS_TIME()('21:30')
(datetime.time(21, 30), None)
>>> IS_TIME()('21-30')
(datetime.time(21, 30), None)
>>> IS_TIME()('21.30')
(datetime.time(21, 30), None)
>>> IS_TIME()('21:30:59')
(datetime.time(21, 30, 59), None)
>>> IS_TIME()('5:30')
(datetime.time(5, 30), None)
>>> IS_TIME()('5:30 am')
(datetime.time(5, 30), None)
>>> IS_TIME()('5:30 pm')
(datetime.time(17, 30), None)
>>> IS_TIME()('5:30 whatever')
('5:30 whatever', 'enter time as hh:mm:ss (seconds, am, pm optional)')
>>> IS_TIME()('5:30 20')
('5:30 20', 'enter time as hh:mm:ss (seconds, am, pm optional)')
>>> IS_TIME()('24:30')
('24:30', 'enter time as hh:mm:ss (seconds, am, pm optional)')
>>> IS_TIME()('21:60')
('21:60', 'enter time as hh:mm:ss (seconds, am, pm optional)')
>>> IS_TIME()('21:30::')
('21:30::', 'enter time as hh:mm:ss (seconds, am, pm optional)')
>>> IS_TIME()('')
('', 'enter time as hh:mm:ss (seconds, am, pm optional)')ù
class gluon.validators.IS_UPLOAD_FILENAME(filename=None, extension=None, lastdot=True, case=1, error_message='Enter valid filename')[source]

Bases: gluon.validators.Validator

Checks if name and extension of file uploaded through file input matches given criteria.

Does not ensure the file type in any way. Returns validation failure if no data was uploaded.

Parameters:
  • filename – filename (before dot) regex
  • extension – extension (after dot) regex
  • lastdot – which dot should be used as a filename / extension separator: True means last dot, eg. file.png -> file / png False means first dot, eg. file.tar.gz -> file / tar.gz
  • case – 0 - keep the case, 1 - transform the string into lowercase (default), 2 - transform the string into uppercase

If there is no dot present, extension checks will be done against empty string and filename checks against whole value.

Examples

Check if file has a pdf extension (case insensitive):

INPUT(_type=’file’, _name=’name’,
requires=IS_UPLOAD_FILENAME(extension=’pdf’))

Check if file has a tar.gz extension and name starting with backup:

INPUT(_type=’file’, _name=’name’,
requires=IS_UPLOAD_FILENAME(filename=’backup.*’, extension=’tar.gz’, lastdot=False))

Check if file has no extension and name matching README (case sensitive):

INPUT(_type=’file’, _name=’name’,
requires=IS_UPLOAD_FILENAME(filename=’^README$’, extension=’^$’, case=0)
class gluon.validators.IS_UPPER[source]

Bases: gluon.validators.Validator

Converts to upper case:

>>> IS_UPPER()('abc')
('ABC', None)
>>> IS_UPPER()('ñ')
('\xc3\x91', None)
class gluon.validators.IS_URL(error_message='Enter a valid URL', mode='http', allowed_schemes=None, prepend_scheme='http', allowed_tlds=None)[source]

Bases: gluon.validators.Validator

Rejects a URL string if any of the following is true:

  • The string is empty or None
  • The string uses characters that are not allowed in a URL
  • The string breaks any of the HTTP syntactic rules
  • The URL scheme specified (if one is specified) is not ‘http’ or ‘https’
  • The top-level domain (if a host name is specified) does not exist

(These rules are based on RFC 2616: http://www.faqs.org/rfcs/rfc2616.html)

This function only checks the URL’s syntax. It does not check that the URL points to a real document, for example, or that it otherwise makes sense semantically. This function does automatically prepend ‘http://‘ in front of a URL in the case of an abbreviated URL (e.g. ‘google.ca’).

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:

  • The string is empty or None
  • The string uses characters that are not allowed in a URL
  • The URL scheme specified (if one is specified) is not valid

(These rules are based on RFC 2396: http://www.faqs.org/rfcs/rfc2396.html)

The list of allowed schemes is customizable with the allowed_schemes parameter. If you exclude None from the list, then abbreviated URLs (lacking a scheme such as ‘http’) will be rejected.

The default prepended scheme is customizable with the prepend_scheme parameter. If you set prepend_scheme to None then prepending will be disabled. URLs that require prepending to parse will still be accepted, but the return value will not be modified.

IS_URL is compatible with the Internationalized Domain Name (IDN) standard specified in RFC 3490 (http://tools.ietf.org/html/rfc3490). As a result, URLs can be regular strings or unicode strings. If the URL’s domain component (e.g. google.ca) contains non-US-ASCII letters, then the domain will be converted into Punycode (defined in RFC 3492, http://tools.ietf.org/html/rfc3492). IS_URL goes a bit beyond the standards, and allows non-US-ASCII characters to be present in the path and query components of the URL as well. These non-US-ASCII characters will be escaped using the standard ‘%20’ type syntax. e.g. the unicode character with hex code 0x4e86 will become ‘%4e%86’

Parameters:
  • 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:

INPUT(_type='text', _name='name', requires=IS_URL())
>>> IS_URL()('abc.com')
('http://abc.com', None)

INPUT(_type='text', _name='name', requires=IS_URL(mode='generic'))
>>> IS_URL(mode='generic')('abc.com')
('abc.com', None)

INPUT(_type='text', _name='name',
    requires=IS_URL(allowed_schemes=['https'], prepend_scheme='https'))
>>> IS_URL(allowed_schemes=['https'], prepend_scheme='https')('https://abc.com')
('https://abc.com', None)

INPUT(_type='text', _name='name',
    requires=IS_URL(prepend_scheme='https'))
>>> IS_URL(prepend_scheme='https')('abc.com')
('https://abc.com', None)

INPUT(_type='text', _name='name',
    requires=IS_URL(mode='generic', allowed_schemes=['ftps', 'https'],
        prepend_scheme='https'))
>>> IS_URL(mode='generic', allowed_schemes=['ftps', 'https'], prepend_scheme='https')('https://abc.com')
('https://abc.com', None)
>>> IS_URL(mode='generic', allowed_schemes=['ftps', 'https', None], prepend_scheme='https')('abc.com')
('abc.com', None)

@author: Jonathan Benn

class gluon.validators.IS_JSON(error_message='Invalid json', native_json=False)[source]

Bases: gluon.validators.Validator

Example

Used as:

INPUT(_type='text', _name='name',
    requires=IS_JSON(error_message="This is not a valid json input")

>>> IS_JSON()('{"a": 100}')
({u'a': 100}, None)

>>> IS_JSON()('spam1234')
('spam1234', 'invalid json')
formatter(value)[source]