Upgrade ipaddr from 2.1.11 to 2.2.0. Its now python 3 compatible

This commit is contained in:
Michiel van Baak 2020-09-03 16:46:37 +02:00
parent f24f4a4250
commit 137889dc9c

View file

@ -22,9 +22,14 @@ and networks.
""" """
__version__ = '2.1.11' __version__ = '2.2.0'
import struct import struct
import sys
if sys.version_info > (3,):
long = int
xrange = range
IPV4LENGTH = 32 IPV4LENGTH = 32
IPV6LENGTH = 128 IPV6LENGTH = 128
@ -156,16 +161,19 @@ def _find_address_range(addresses):
addresses: a list of IPv4 or IPv6 addresses. addresses: a list of IPv4 or IPv6 addresses.
Returns: Returns:
A tuple containing the first and last IP addresses in the sequence. A tuple containing the first and last IP addresses in the sequence,
and the index of the last IP address in the sequence.
""" """
first = last = addresses[0] first = last = addresses[0]
last_index = 0
for ip in addresses[1:]: for ip in addresses[1:]:
if ip._ip == last._ip + 1: if ip._ip == last._ip + 1:
last = ip last = ip
last_index += 1
else: else:
break break
return (first, last) return (first, last, last_index)
def _get_prefix_length(number1, number2, bits): def _get_prefix_length(number1, number2, bits):
"""Get the number of leading bits that are same for two numbers. """Get the number of leading bits that are same for two numbers.
@ -358,8 +366,8 @@ def collapse_address_list(addresses):
nets = sorted(set(nets)) nets = sorted(set(nets))
while i < len(ips): while i < len(ips):
(first, last) = _find_address_range(ips[i:]) (first, last, last_index) = _find_address_range(ips[i:])
i = ips.index(last) + 1 i += last_index + 1
addrs.extend(summarize_address_range(first, last)) addrs.extend(summarize_address_range(first, last))
return _collapse_address_list_recursive(sorted( return _collapse_address_list_recursive(sorted(
@ -876,6 +884,26 @@ class _BaseNet(_IPAddrBase):
else: else:
raise NetmaskValueError('Bit pattern does not match /1*0*/') raise NetmaskValueError('Bit pattern does not match /1*0*/')
def _prefix_from_prefix_int(self, prefixlen):
"""Validate and return a prefix length integer.
Args:
prefixlen: An integer containing the prefix length.
Returns:
The input, possibly converted from long to int.
Raises:
NetmaskValueError: If the input is not an integer, or out of range.
"""
if not isinstance(prefixlen, (int, long)):
raise NetmaskValueError('%r is not an integer' % prefixlen)
prefixlen = int(prefixlen)
if not (0 <= prefixlen <= self._max_prefixlen):
raise NetmaskValueError('%d is not a valid prefix length' %
prefixlen)
return prefixlen
def _prefix_from_prefix_string(self, prefixlen_str): def _prefix_from_prefix_string(self, prefixlen_str):
"""Turn a prefix length string into an integer. """Turn a prefix length string into an integer.
@ -893,12 +921,10 @@ class _BaseNet(_IPAddrBase):
if not _BaseV4._DECIMAL_DIGITS.issuperset(prefixlen_str): if not _BaseV4._DECIMAL_DIGITS.issuperset(prefixlen_str):
raise ValueError raise ValueError
prefixlen = int(prefixlen_str) prefixlen = int(prefixlen_str)
if not (0 <= prefixlen <= self._max_prefixlen):
raise ValueError
except ValueError: except ValueError:
raise NetmaskValueError('%s is not a valid prefix length' % raise NetmaskValueError('%s is not a valid prefix length' %
prefixlen_str) prefixlen_str)
return prefixlen return self._prefix_from_prefix_int(prefixlen)
def _prefix_from_ip_string(self, ip_str): def _prefix_from_ip_string(self, ip_str):
"""Turn a netmask/hostmask string into a prefix length. """Turn a netmask/hostmask string into a prefix length.
@ -1239,6 +1265,11 @@ class IPv4Address(_BaseV4, _BaseIP):
""" """
_BaseV4.__init__(self, address) _BaseV4.__init__(self, address)
# Efficient copy constructor.
if isinstance(address, IPv4Address):
self._ip = address._ip
return
# Efficient constructor from integer. # Efficient constructor from integer.
if isinstance(address, (int, long)): if isinstance(address, (int, long)):
self._ip = address self._ip = address
@ -1279,29 +1310,32 @@ class IPv4Network(_BaseV4, _BaseNet):
"""Instantiate a new IPv4 network object. """Instantiate a new IPv4 network object.
Args: Args:
address: A string or integer representing the IP [& network]. address: The IPv4 network as a string, 2-tuple, or any format
'192.168.1.1/24' supported by the IPv4Address constructor.
'192.168.1.1/255.255.255.0'
'192.168.1.1/0.0.0.255'
are all functionally the same in IPv4. Similarly,
'192.168.1.1'
'192.168.1.1/255.255.255.255'
'192.168.1.1/32'
are also functionaly equivalent. That is to say, failing to
provide a subnetmask will create an object with a mask of /32.
If the mask (portion after the / in the argument) is given in Strings typically use CIDR format, such as '192.0.2.0/24'.
dotted quad form, it is treated as a netmask if it starts with a If a dotted-quad is provided after the '/', it is treated as
non-zero field (e.g. /255.0.0.0 == /8) and as a hostmask if it a netmask if it starts with a nonzero bit (e.g. 255.0.0.0 == /8)
starts with a zero field (e.g. 0.255.255.255 == /8), with the or a hostmask if it starts with a zero bit
single exception of an all-zero mask which is treated as a (e.g. /0.0.0.255 == /8), with the single exception of an all-zero
netmask == /0. If no mask is given, a default of /32 is used. mask which is treated as /0.
Additionally, an integer can be passed, so The 2-tuple format consists of an (ip, prefixlen), where ip is any
IPv4Network('192.168.1.1') == IPv4Network(3232235777). format recognized by the IPv4Address constructor, and prefixlen is
or, more generally an integer from 0 through 32.
IPv4Network(int(IPv4Network('192.168.1.1'))) ==
IPv4Network('192.168.1.1') A plain IPv4 address (in any format) will be forwarded to the
IPv4Address constructor, with an implied prefixlen of 32.
For example, the following inputs are equivalent:
IPv4Network('192.0.2.1/32')
IPv4Network('192.0.2.1/255.255.255.255')
IPv4Network('192.0.2.1')
IPv4Network(0xc0000201)
IPv4Network(IPv4Address('192.0.2.1'))
IPv4Network(('192.0.2.1', 32))
IPv4Network((0xc0000201, 32))
IPv4Network((IPv4Address('192.0.2.1'), 32))
strict: A boolean. If true, ensure that we have been passed strict: A boolean. If true, ensure that we have been passed
A true network address, eg, 192.168.1.0/24 and not an A true network address, eg, 192.168.1.0/24 and not an
@ -1318,41 +1352,51 @@ class IPv4Network(_BaseV4, _BaseNet):
_BaseNet.__init__(self, address) _BaseNet.__init__(self, address)
_BaseV4.__init__(self, address) _BaseV4.__init__(self, address)
# Constructing from an integer or packed bytes. # Constructing from a single IP address.
if isinstance(address, (int, long, Bytes)): if isinstance(address, (int, long, Bytes, IPv4Address)):
self.ip = IPv4Address(address) self.ip = IPv4Address(address)
self._ip = self.ip._ip self._ip = self.ip._ip
self._prefixlen = self._max_prefixlen self._prefixlen = self._max_prefixlen
self.netmask = IPv4Address(self._ALL_ONES) self.netmask = IPv4Address(self._ALL_ONES)
return return
# Assume input argument to be string or any object representation # Constructing from an (ip, prefixlen) tuple.
# which converts into a formatted IP prefix string. if isinstance(address, tuple):
addr = str(address).split('/')
if len(addr) > 2:
raise AddressValueError(address)
self._ip = self._ip_int_from_string(addr[0])
self.ip = IPv4Address(self._ip)
if len(addr) == 2:
try: try:
# Check for a netmask in prefix length form. ip, prefixlen = address
self._prefixlen = self._prefix_from_prefix_string(addr[1]) except ValueError:
except NetmaskValueError: raise AddressValueError(address)
# Check for a netmask or hostmask in dotted-quad form. self.ip = IPv4Address(ip)
# This may raise NetmaskValueError. self._ip = self.ip._ip
self._prefixlen = self._prefix_from_ip_string(addr[1]) self._prefixlen = self._prefix_from_prefix_int(prefixlen)
else: else:
self._prefixlen = self._max_prefixlen # Assume input argument to be string or any object representation
# which converts into a formatted IP prefix string.
addr = str(address).split('/')
if len(addr) > 2:
raise AddressValueError(address)
self._ip = self._ip_int_from_string(addr[0])
self.ip = IPv4Address(self._ip)
if len(addr) == 2:
try:
# Check for a netmask in prefix length form.
self._prefixlen = self._prefix_from_prefix_string(addr[1])
except NetmaskValueError:
# Check for a netmask or hostmask in dotted-quad form.
# This may raise NetmaskValueError.
self._prefixlen = self._prefix_from_ip_string(addr[1])
else:
self._prefixlen = self._max_prefixlen
self.netmask = IPv4Address(self._ip_int_from_prefix(self._prefixlen)) self.netmask = IPv4Address(self._ip_int_from_prefix(self._prefixlen))
if strict: if strict:
if self.ip != self.network: if self.ip != self.network:
raise ValueError('%s has host bits set' % raise ValueError('%s has host bits set' % self.ip)
self.ip)
if self._prefixlen == (self._max_prefixlen - 1): if self._prefixlen == (self._max_prefixlen - 1):
self.iterhosts = self.__iter__ self.iterhosts = self.__iter__
@ -1447,7 +1491,7 @@ class _BaseV6(object):
try: try:
# Now, parse the hextets into a 128-bit integer. # Now, parse the hextets into a 128-bit integer.
ip_int = 0L ip_int = long(0)
for i in xrange(parts_hi): for i in xrange(parts_hi):
ip_int <<= 16 ip_int <<= 16
ip_int |= self._parse_hextet(parts[i]) ip_int |= self._parse_hextet(parts[i])
@ -1752,6 +1796,11 @@ class IPv6Address(_BaseV6, _BaseIP):
""" """
_BaseV6.__init__(self, address) _BaseV6.__init__(self, address)
# Efficient copy constructor.
if isinstance(address, IPv6Address):
self._ip = address._ip
return
# Efficient constructor from integer. # Efficient constructor from integer.
if isinstance(address, (int, long)): if isinstance(address, (int, long)):
self._ip = address self._ip = address
@ -1771,9 +1820,6 @@ class IPv6Address(_BaseV6, _BaseIP):
# Assume input argument to be string or any object representation # Assume input argument to be string or any object representation
# which converts into a formatted IP string. # which converts into a formatted IP string.
addr_str = str(address) addr_str = str(address)
if not addr_str:
raise AddressValueError('')
self._ip = self._ip_int_from_string(addr_str) self._ip = self._ip_int_from_string(addr_str)
@ -1793,28 +1839,34 @@ class IPv6Network(_BaseV6, _BaseNet):
def __init__(self, address, strict=False): def __init__(self, address, strict=False):
"""Instantiate a new IPv6 Network object. """Instantiate a new IPv6 network object.
Args: Args:
address: A string or integer representing the IPv6 network or the IP address: The IPv6 network as a string, 2-tuple, or any format
and prefix/netmask. supported by the IPv6Address constructor.
'2001:4860::/128'
'2001:4860:0000:0000:0000:0000:0000:0000/128'
'2001:4860::'
are all functionally the same in IPv6. That is to say,
failing to provide a subnetmask will create an object with
a mask of /128.
Additionally, an integer can be passed, so Strings should be in CIDR format, such as '2001:db8::/32'.
IPv6Network('2001:4860::') ==
IPv6Network(42541956101370907050197289607612071936L). The 2-tuple format consists of an (ip, prefixlen), where ip is any
or, more generally format recognized by the IPv6Address constructor, and prefixlen is
IPv6Network(IPv6Network('2001:4860::')._ip) == an integer from 0 through 128.
IPv6Network('2001:4860::')
A plain IPv6 address (in any format) will be forwarded to the
IPv6Address constructor, with an implied prefixlen of 128.
For example, the following inputs are equivalent:
IPv6Network('2001:db8::/128')
IPv6Network('2001:db8:0:0:0:0:0:0/128')
IPv6Network('2001:db8::')
IPv6Network(0x20010db8 << 96)
IPv6Network(IPv6Address('2001:db8::'))
IPv6Network(('2001:db8::', 128))
IPv6Network((0x20010db8 << 96, 128))
IPv6Network((IPv6Address('2001:db8::'), 128))
strict: A boolean. If true, ensure that we have been passed strict: A boolean. If true, ensure that we have been passed
A true network address, eg, 192.168.1.0/24 and not an A true network address, eg, 2001:db8::/32 and not an
IP address on a network, eg, 192.168.1.1/24. IP address on a network, eg, 2001:db8::1/32.
Raises: Raises:
AddressValueError: If address isn't a valid IPv6 address. AddressValueError: If address isn't a valid IPv6 address.
@ -1827,29 +1879,40 @@ class IPv6Network(_BaseV6, _BaseNet):
_BaseNet.__init__(self, address) _BaseNet.__init__(self, address)
_BaseV6.__init__(self, address) _BaseV6.__init__(self, address)
# Constructing from an integer or packed bytes. # Constructing from a single IP address.
if isinstance(address, (int, long, Bytes)): if isinstance(address, (int, long, Bytes, IPv6Address)):
self.ip = IPv6Address(address) self.ip = IPv6Address(address)
self._ip = self.ip._ip self._ip = self.ip._ip
self._prefixlen = self._max_prefixlen self._prefixlen = self._max_prefixlen
self.netmask = IPv6Address(self._ALL_ONES) self.netmask = IPv6Address(self._ALL_ONES)
return return
# Assume input argument to be string or any object representation # Constructing from an (ip, prefixlen) tuple.
# which converts into a formatted IP prefix string. if isinstance(address, tuple):
addr = str(address).split('/') try:
ip, prefixlen = address
except ValueError:
raise AddressValueError(address)
self.ip = IPv6Address(ip)
self._ip = self.ip._ip
self._prefixlen = self._prefix_from_prefix_int(prefixlen)
if len(addr) > 2:
raise AddressValueError(address)
self._ip = self._ip_int_from_string(addr[0])
self.ip = IPv6Address(self._ip)
if len(addr) == 2:
# This may raise NetmaskValueError
self._prefixlen = self._prefix_from_prefix_string(addr[1])
else: else:
self._prefixlen = self._max_prefixlen # Assume input argument to be string or any object representation
# which converts into a formatted IP prefix string.
addr = str(address).split('/')
if len(addr) > 2:
raise AddressValueError(address)
self._ip = self._ip_int_from_string(addr[0])
self.ip = IPv6Address(self._ip)
if len(addr) == 2:
# This may raise NetmaskValueError
self._prefixlen = self._prefix_from_prefix_string(addr[1])
else:
self._prefixlen = self._max_prefixlen
self.netmask = IPv6Address(self._ip_int_from_prefix(self._prefixlen)) self.netmask = IPv6Address(self._ip_int_from_prefix(self._prefixlen))