Adds IS_IPADDRESS() to gluon/validators.py

IS_IPADDRESS() is mostly a meta function that will call IS_IPV4()
or IS_IPV6 accordingly based upon both dev-configured logic and
library checking of the address given. For instance:

 >>> IS_IPADDRESS()('192.168.1.5')
 ('192.168.1.5', None)

will run through the IS_IPV4() function since the ipaddr.py lib
recognizes it as an IPv4 address. Specific v4 or v6 validation
can be done by setting is_ipv4=True or is_ipv6=True:

 >>> 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')

The same arguments for IS_IPV4() and IS_IPV6() are supported and
no changes have been made to either of these two functions. The
goal of this function is to allow IPv4 or IPv6 addresses in a
textfield:

 INPUT(_type='text', _name='name', requires=IS_IPADDRESS())
This commit is contained in:
Kurt Grutzmacher
2013-04-05 09:14:37 -07:00
parent 721cb2b90a
commit 79a4693f34
+210
View File
@@ -3529,6 +3529,216 @@ class IS_IPV6(Validator):
return (value, translate(self.error_message))
class IS_IPADDRESS(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).
Universal arguments:
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: 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: 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')
"""
def __init__(
self,
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'):
self.minip = minip,
self.maxip = maxip,
self.invert = invert
self.is_localhost = is_localhost
self.is_private = is_private
self.is_automatic = is_automatic
self.is_ipv4 = is_ipv4
self.is_private = is_private
self.is_link_local = is_link_local
self.is_reserved = is_reserved
self.is_multicast = is_multicast
self.is_routeable = is_routeable
self.is_6to4 = is_6to4
self.is_teredo = is_teredo
self.subnets = subnets
self.is_ipv6 = is_ipv6
self.error_message = error_message
def __call__(self, value):
try:
import ipaddress
except ImportError:
from contrib import ipaddr as ipaddress
try:
ip = ipaddress.ip_address(value)
except ValueError, e:
return (value, translate(self.error_message))
if self.is_ipv4 and isinstance(ip, ipaddress.IPv6Address):
retval = (value, translate(self.error_message))
elif self.is_ipv6 and isinstance(ip, ipaddress.IPv4Address):
retval = (value, translate(self.error_message))
elif self.is_ipv4 or isinstance(ip, ipaddress.IPv4Address):
retval = IS_IPV4(
minip=self.minip,
maxip=self.maxip,
invert=self.invert,
is_localhost=self.is_localhost,
is_private=self.is_private,
is_automatic=self.is_automatic,
error_message=self.error_message
)(value)
elif self.is_ipv6 or isinstance(ip, ipaddress.IPv6Address):
retval = IS_IPV6(
is_private=self.is_private,
is_link_local=self.is_link_local,
is_reserved=self.is_reserved,
is_multicast=self.is_multicast,
is_routeable=self.is_routeable,
is_6to4=self.is_6to4,
is_teredo=self.is_teredo,
subnets=self.subnets,
error_message=self.error_message
)(value)
else:
retval = (value, translate(self.error_message))
return retval
if __name__ == '__main__':
import doctest
doctest.testmod(