[Python-checkins] cpython: Issue 14814: Docs work showed some more cases of networks pretending to be
nick.coghlan
python-checkins at python.org
Sun Aug 5 14:02:29 CEST 2012
http://hg.python.org/cpython/rev/b513ad06d1fa
changeset: 78428:b513ad06d1fa
user: Nick Coghlan <ncoghlan at gmail.com>
date: Sun Aug 05 22:02:18 2012 +1000
summary:
Issue 14814: Docs work showed some more cases of networks pretending to be addresses and highlighted the weird approach to implementing the 'is_whatever' properties. Impl now illustrates far more clearly that networks have a property if both their network and broadcast addresses have that property
files:
Doc/library/ipaddress.rst | 464 +++++++++++++++++---
Lib/ipaddress.py | 554 +++++++++++++-----------
Lib/test/test_ipaddress.py | 4 +-
3 files changed, 688 insertions(+), 334 deletions(-)
diff --git a/Doc/library/ipaddress.rst b/Doc/library/ipaddress.rst
--- a/Doc/library/ipaddress.rst
+++ b/Doc/library/ipaddress.rst
@@ -9,17 +9,26 @@
--------------
-The :mod:`ipaddress` module provides the capabilities to create, manipulate and
+.. note::
+
+ The ``ipaddress`` module has been included in the standard library on a
+ :term:`provisional basis <provisional package>`. Backwards incompatible
+ changes (up to and including removal of the package) may occur if deemed
+ necessary by the core developers.
+
+:mod:`ipaddress` provides the capabilities to create, manipulate and
operate on IPv4 and IPv6 addresses and networks.
+The functions and classes in this module make it straightforward to handle
+various tasks related to IP addresses, including checking whether or not two
+hosts are on the same subnet, iterating over all hosts in a particular
+subnet, checking whether or not a string represents a valid IP address or
+network definition, and so on.
+
This is the full module API reference - for an overview and introduction,
see :ref:`ipaddress-howto`.
-The functions and classes in this module make it straightforward to handle
-various tasks related to IP addresses, including checking whether or not two
-hosts are on the same subnet, iterating over all hosts in a particular
-subnet, as well as checking whether or not a string represents a valid
-IP address or network definition.
+.. versionadded:: 3.3
Convenience factory functions
@@ -65,15 +74,24 @@
:exc:`ValueError` is raised if *address* does not represent a valid IPv4 or
IPv6 address.
+One downside of these convenience functions is that the need to handle both
+IPv4 and IPv6 formats means that error messages provide minimal
+information on the precise error, as the functions don't know whether the
+IPv4 or IPv6 format was intended. More detailed error reporting can be
+obtained by calling the appropriate version specific class constructors
+directly.
+
+
+IP Addresses
+------------
Address objects
----------------
+^^^^^^^^^^^^^^^
The :class:`IPv4Address` and :class:`IPv6Address` objects share a lot of common
attributes. Some attributes that are only meaningful for IPv6 addresses are
also implemented by :class:`IPv4Address` objects, in order to make it easier to
-write code that handles both IP versions correctly. To avoid duplication, all
-common attributes will only be documented for :class:`IPv4Address`.
+write code that handles both IP versions correctly.
.. class:: IPv4Address(address)
@@ -84,66 +102,79 @@
1. A string in decimal-dot notation, consisting of four decimal integers in
the inclusive range 0-255, separated by dots (e.g. ``192.168.0.1``). Each
- integer represents an octet (byte) in the address, big-endian.
+ integer represents an octet (byte) in the address. Leading zeroes are
+ tolerated only for values less then 8 (as there is no ambiguity
+ between the decimal and octal interpretations of such strings).
2. An integer that fits into 32 bits.
- 3. An integer packed into a :class:`bytes` object of length 4, big-endian.
+ 3. An integer packed into a :class:`bytes` object of length 4 (most
+ significant octet first).
>>> ipaddress.IPv4Address('192.168.0.1')
IPv4Address('192.168.0.1')
- >>> ipaddress.IPv4Address('192.0.2.1') == ipaddress.IPv4Address(3221225985)
- True
+ >>> ipaddress.IPv4Address(3221225985)
+ IPv4Address('192.168.0.1')
+ >>> ipaddress.IPv4Address(b'\xC0\xA8\x00\x01')
+ IPv4Address('192.168.0.1')
+ .. attribute:: version
+
+ The appropriate version number: ``4`` for IPv4, ``6`` for IPv6.
+
+ .. attribute:: max_prefixlen
+
+ The total number of bits in the address representation for this
+ version: ``32`` for IPv4, ``128`` for IPv6.
+
+ The prefix defines the number of leading bits in an address that
+ are compared to determine whether or not an address is part of a
+ network.
+
+ .. attribute:: compressed
.. attribute:: exploded
- The longhand version of the address as a string. Note: the
- exploded/compressed distinction is meaningful only for IPv6 addresses.
- For IPv4 addresses it is the same.
+ The string representation in dotted decimal notation. Leading zeroes
+ are never included in the representation.
- .. attribute:: compressed
-
- The shorthand version of the address as a string.
+ As IPv4 does not define a shorthand notation for addresses with octets
+ set to zero, these two attributes are always the same as ``str(addr)``
+ for IPv4 addresses. Exposing these attributes makes it easier to
+ write display code that can handle both IPv4 and IPv6 addresses.
.. attribute:: packed
- The binary representation of this address - a :class:`bytes` object.
-
- .. attribute:: version
-
- A numeric version number.
-
- .. attribute:: max_prefixlen
-
- Maximal length of the prefix (in bits). The prefix defines the number of
- leading bits in an address that are compared to determine whether or not an
- address is part of a network.
+ The binary representation of this address - a :class:`bytes` object of
+ the appropriate length (most significant octet first). This is 4 bytes
+ for IPv4 and 16 bytes for IPv6.
.. attribute:: is_multicast
- ``True`` if the address is reserved for multicast use. See :RFC:`3171` (for
- IPv4) or :RFC:`2373` (for IPv6).
+ ``True`` if the address is reserved for multicast use. See
+ :RFC:`3171` (for IPv4) or :RFC:`2373` (for IPv6).
.. attribute:: is_private
- ``True`` if the address is allocated for private networks. See :RFC:`1918`
- (for IPv4) or :RFC:`4193` (for IPv6).
+ ``True`` if the address is allocated for private networks. See
+ :RFC:`1918` (for IPv4) or :RFC:`4193` (for IPv6).
.. attribute:: is_unspecified
- ``True`` if the address is unspecified. See :RFC:`5375` (for IPv4) or
- :RFC:`2373` (for IPv6).
+ ``True`` if the address is unspecified. See :RFC:`5375` (for IPv4)
+ or :RFC:`2373` (for IPv6).
.. attribute:: is_reserved
- ``True`` if the address is otherwise IETF reserved.
+ ``True`` if the address is otherwise IETF reserved.
.. attribute:: is_loopback
- ``True`` if this is a loopback address. See :RFC:`3330` (for IPv4) or
- :RFC:`2373` (for IPv6).
+ ``True`` if this is a loopback address. See :RFC:`3330` (for IPv4)
+ or :RFC:`2373` (for IPv6).
.. attribute:: is_link_local
- ``True`` if the address is reserved for link-local. See :RFC:`3927`.
+ ``True`` if the address is reserved for link-local usage. See
+ :RFC:`3927`.
+
.. class:: IPv6Address(address)
@@ -165,31 +196,79 @@
>>> ipaddress.IPv6Address('2001:db8::1000')
IPv6Address('2001:db8::1000')
- All the attributes exposed by :class:`IPv4Address` are supported. In
- addition, the following attributs are exposed only by :class:`IPv6Address`.
+ All the attributes implemented by :class:`IPv4Address` are supported. In
+ addition, the following attributs are implemented only by
+ :class:`IPv6Address`.
+
+ .. attribute:: compressed
+
+ The short form of the address representation, with leading zeroes in
+ groups omitted and the longest sequence of groups consisting entirely of
+ zeroes collapsed to a single empty group.
+
+ This is also the value returned by ``str(addr)`` for IPv6 addresses.
+
+ .. attribute:: exploded
+
+ The long form of the address representation, with all leading zeroes and
+ groups consisting entirely of zeroes included.
+
+ .. attribute:: packed
+ .. attribute:: version
+ .. attribute:: max_prefixlen
+ .. attribute:: is_multicast
+ .. attribute:: is_private
+ .. attribute:: is_unspecified
+ .. attribute:: is_reserved
+ .. attribute:: is_loopback
+ .. attribute:: is_link_local
+
+ Refer to the corresponding attribute documentation in
+ :class:`IPv4Address`
.. attribute:: is_site_local
- ``True`` if the address is reserved for site-local. Note that the site-local
- address space has been deprecated by :RFC:`3879`. Use
- :attr:`~IPv4Address.is_private` to test if this address is in the space of
- unique local addresses as defined by :RFC:`4193`.
+ ``True`` if the address is reserved for site-local usage. Note that
+ the site-local address space has been deprecated by :RFC:`3879`. Use
+ :attr:`~IPv4Address.is_private` to test if this address is in the
+ space of unique local addresses as defined by :RFC:`4193`.
.. attribute:: ipv4_mapped
- If this address represents a IPv4 mapped address, return the IPv4 mapped
- address. Otherwise return ``None``.
+ For addresses that appear to be IPv4 mapped addresses (starting with
+ ``::FFFF/96``), this property will report the embedded IPv4 address.
+ For any other address, this property will be ``None``.
+
+ .. attribute:: sixtofour
+
+ For addresses that appear to be 6to4 addresses (starting with
+ ``2002::/16``) as defined by :RFC:`3056`, this property will report
+ the embedded IPv4 address. For any other address, this property will
+ be ``None``.
.. attribute:: teredo
- If this address appears to be a teredo address (starts with ``2001::/32``),
- return a tuple of embedded teredo IPs ``(server, client)`` pairs. Otherwise
- return ``None``.
+ For addresses that appear to be Teredo addresses (starting with
+ ``2001::/32``) as defined by :RFC:`4380`, this property will report
+ the embedded ``(server, client)`` IP address pair. For any other
+ address, this property will be ``None``.
- .. attribute:: sixtofour
- If this address appears to contain a 6to4 embedded address, return the
- embedded IPv4 address. Otherwise return ``None``.
+Conversion to Strings and Integers
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+To interoperate with networking interfaces such as the socket module,
+addresses must be converted to strings or integers. This is handled using
+the :func:`str` and :func:`int` builtin functions::
+
+ >>> str(ipaddress.IPv4Address('192.168.0.1'))
+ '192.168.0.1'
+ >>> int(ipaddress.IPv4Address('192.168.0.1'))
+ 3232235521
+ >>> str(ipaddress.IPv6Address('::1'))
+ '::1'
+ >>> int(ipaddress.IPv6Address('::1'))
+ 1
Operators
@@ -199,6 +278,7 @@
only be applied between compatible objects (i.e. IPv4 with IPv4, IPv6 with
IPv6).
+
Logical operators
"""""""""""""""""
@@ -212,6 +292,7 @@
>>> IPv4Address('127.0.0.2') != IPv4Address('127.0.0.1')
True
+
Arithmetic operators
""""""""""""""""""""
@@ -227,45 +308,274 @@
ipaddress.AddressValueError: 4294967296 (>= 2**32) is not permitted as an IPv4 address
+IP Network definitions
+----------------------
+
+The :class:`IPv4Network` and :class:`IPv6Network` objects provide a mechanism
+for defining and inspecting IP network definitions. A network definition
+consists of a *mask* and a *network address*, and as such defines a range of
+IP addresses that equal the network address when masked (binary AND) with the
+mask. For example, a network definition with the mask ``255.255.255.0`` and
+the network address ``192.168.1.0`` consists of IP addresses in the inclusive
+range ``192.168.1.0`` to ``192.168.1.255``.
+
+
+Prefix, net mask and host mask
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+There are several equivalent ways to specify IP network masks. A *prefix*
+``/<nbits>`` is a notation that denotes how many high-order bits are set in
+the network mask. A *net mask* is an IP address with some number of
+high-order bits set. Thus the prefix ``/24`` is equivalent to the net mask
+``255.255.255.0`` in IPv4, or ``ffff:ff00::`` in IPv6. In addition, a
+*host mask* is the logical inverse of a *net mask*, and is sometimes used
+(for example in Cisco access control lists) to denote a network mask. The
+host mask equivalent to ``/24`` in IPv4 is ``0.0.0.255``.
+
+
Network objects
----------------
+^^^^^^^^^^^^^^^
+
+All attributes implemented by address objects are implemented by network
+objects as well. In addition, network objects implement additional attributes.
+All of these are common between :class:`IPv4Network` and :class:`IPv6Network`,
+so to avoid duplication they are only documented for :class:`IPv4Network`.
.. class:: IPv4Network(address, strict=True)
- Construct an IPv4 network. *address* is a string or integer representing the
- IP address (and optionally the network). An :exc:`AddressValueError` is
- raised if *address* is not a valid IPv4 address. A :exc:`NetmaskValueError`
- is raised if the netmask is not valid for an IPv4 address.
+ Construct an IPv4 network definition. *address* can be one of the following:
+
+ 1. A string consisting of an IP address and an optional mask, separated by
+ a slash (``/``). The IP address is the network address, and the mask
+ can be either a single number, which means it's a *prefix*, or a string
+ representation of an IPv4 address. If it's the latter, the mask is
+ interpreted as a *net mask* if it starts with a non-zero field, or as
+ a *host mask* if it starts with a zero field. If no mask is provided,
+ it's considered to be ``/32``.
+
+ For example, the following *address* specifications are equivalent:
+ ``192.168.1.0/24``, ``192.168.1.0/255.255.255.0`` and
+ ``192.168.1.0/0.0.0.255``.
+
+ 2. An integer that fits into 32 bits. This is equivalent to a
+ single-address network, with the network address being *address* and
+ the mask being ``/32``.
+
+ 3. An integer packed into a :class:`bytes` object of length 4, big-endian.
+ The interpretation is similar to an integer *address*.
+
+ An :exc:`AddressValueError` is raised if *address* is not a valid IPv4
+ address. A :exc:`NetmaskValueError` is raised if the mask is not valid for
+ an IPv4 address.
If *strict* is ``True`` and host bits are set in the supplied address,
- then :exc:`ValueError` is raised. Otherwise, the host bits are masked out
+ then :exc:`ValueError` is raised. Otherwise, the host bits are masked out
to determine the appropriate network address.
- >>> ipaddress.IPv4Network('192.0.2.0/27')
- IPv4Network('192.0.2.0/27')
- >>> ipaddress.IPv4Network('192.0.2.0/27').netmask
- IPv4Address('255.255.255.224')
- >>> ipaddress.IPv4Network('192.0.2.5/27', strict=False)
- IPv4Network('192.0.2.0/27')
+ This class implements all the attributes of :class:`IPv4Address`, and also
+ the following attributes and methods. Unless stated otherwise, all methods
+ accepting other network / address objects will raise :exc:`TypeError` if
+ the argument's IP version is incompatible to ``self``:
+
+ .. attribute:: broadcast_address
+
+ The broadcast address for the network.
+
+ .. attribute:: host mask
+
+ The host mask, as a string.
+
+ .. attribute:: with_prefixlen
+
+ A string representation of the network, with the mask in prefix notation.
+
+ .. attribute:: with_netmask
+
+ A string representation of the network, with the mask in net mask notation.
+
+ .. attribute:: with_hostmask
+
+ A string representation of the network, with the mask in host mask notation.
+
+ .. attribute:: num_addresses
+
+ The total number of addresses in the network.
+
+ .. attribute:: prefixlen
+
+ Length of the prefix, in bits.
+
+ .. method:: hosts()
+
+ Generates an iterator over the usable hosts in the network. The usable hosts
+ are all the IP addresses that belong to the network, except the network
+ address itself and the network broadcast address.
+
+ >>> list(ip_network('192.0.2.0/29').hosts())
+ [IPv4Address('192.0.2.1'), IPv4Address('192.0.2.2'),
+ IPv4Address('192.0.2.3'), IPv4Address('192.0.2.4'),
+ IPv4Address('192.0.2.5'), IPv4Address('192.0.2.6')]
+
+ .. method:: overlaps(other)
+
+ ``True`` if this network is partly contained in *other*.
+
+ .. method:: address_exclude(network)
+
+ Computes the network defintions resulting from removing the given *network*
+ from this one. Returns a generator. Raises :exc:`ValueError` if *network*
+ is not completely contained in this network.
+
+ >>> n1 = ip_network('192.0.2.0/28')
+ >>> n2 = ip_network('192.0.2.1/32')
+ >>> list(n1.address_exclude(n2))
+ [IPv4Network('192.0.2.8/29'), IPv4Network('192.0.2.4/30'),
+ IPv4Network('192.0.2.2/31'), IPv4Network('192.0.2.0/32')]
+
+ .. method:: subnets(prefixlen_diff=1, new_prefix=None)
+
+ The subnets that join to make the current network definition, depending on
+ the argument values. *prefixlen_diff* is the amount our prefix length
+ should be increased by. *new_prefix* is the desired new prefix of the
+ subnets; it must be larger than our prefix. One and only one of
+ *prefixlen_diff* and *new_prefix* must be set. Returns an iterator of
+ network objects.
+
+ >>> list(ip_network('192.0.2.0/24').subnets())
+ [IPv4Network('192.0.2.0/25'), IPv4Network('192.0.2.128/25')]
+ >>> list(ip_network('192.0.2.0/24').subnets(prefixlen_diff=2))
+ [IPv4Network('192.0.2.0/26'), IPv4Network('192.0.2.64/26'),
+ IPv4Network('192.0.2.128/26'), IPv4Network('192.0.2.192/26')]
+ >>> list(ip_network('192.0.2.0/24').subnets(new_prefix=26))
+ [IPv4Network('192.0.2.0/26'), IPv4Network('192.0.2.64/26'),
+ IPv4Network('192.0.2.128/26'), IPv4Network('192.0.2.192/26')]
+ >>> list(ip_network('192.0.2.0/24').subnets(new_prefix=23))
+ Traceback (most recent call last):
+ File "<stdin>", line 1, in <module>
+ raise ValueError('new prefix must be longer')
+ ValueError: new prefix must be longer
+ >>> list(ip_network('192.0.2.0/24').subnets(new_prefix=25))
+ [IPv4Network('192.0.2.0/25'), IPv4Network('192.0.2.128/25')]
+ >>>
+
+ .. method:: supernet(prefixlen_diff=1, new_prefix=None)
+
+ The supernet containing this network definition, depending on the argument
+ values. *prefixlen_diff* is the amount our prefix length should be
+ decreased by. *new_prefix* is the desired new prefix of the supernet; it
+ must be smaller than our prefix. One and only one of *prefixlen_diff* and
+ *new_prefix* must be set. Returns a single network object.
+
+ >>> ip_network('192.0.2.0/24').supernet()
+ IPv4Network('192.0.2.0/23')
+ >>> ip_network('192.0.2.0/24').supernet(prefixlen_diff=2)
+ IPv4Network('192.0.0.0/22')
+ >>> ip_network('192.0.2.0/24').supernet(new_prefix=20)
+ IPv4Network('192.0.0.0/20')
+
+ .. method:: compare_networks(other)
+
+ Compare this network to *other*. In this comparison only the network
+ addresses are considered; host bits aren't. Returns either ``-1``, ``0``
+ or ``1``.
+
+ >>> ip_network('192.0.2.1/32').compare_networks(ip_network('192.0.2.2/32'))
+ -1
+ >>> ip_network('192.0.2.1/32').compare_networks(ip_network('192.0.2.0/32'))
+ 1
+ >>> ip_network('192.0.2.1/32').compare_networks(ip_network('192.0.2.1/32'))
+ 0
.. class:: IPv6Network(address, strict=True)
- Construct an IPv6 network. *address* is a string or integer representing the
- IP address (and optionally the network). An :exc:`AddressValueError` is
- raised if *address* is not a valid IPv6 address. A :exc:`NetmaskValueError`
- is raised if the netmask is not valid for an IPv6 address.
+ Construct an IPv6 network definition. *address* can be one of the following:
+
+ 1. A string consisting of an IP address and an optional mask, separated by
+ a slash (``/``). The IP addrses is the network address, and the mask
+ can be either a single number, which means it's a *prefix*, or a string
+ representation of an IPv6 address. If it's the latter, the mask is
+ interpreted as a *net mask*. If no mask is provided, it's considered to
+ be ``/128``.
+
+ For example, the following *address* specifications are equivalent:
+ ``2001:db00::0/24`` and ``2001:db00::0/ffff:ff00::``.
+
+ 2. An integer that fits into 128 bits. This is equivalent to a
+ single-address network, with the network address being *address* and
+ the mask being ``/128``.
+
+ 3. An integer packed into a :class:`bytes` object of length 16, bit-endian.
+ The interpretation is similar to an integer *address*.
+
+ An :exc:`AddressValueError` is raised if *address* is not a valid IPv6
+ address. A :exc:`NetmaskValueError` is raised if the mask is not valid for
+ an IPv6 address.
If *strict* is ``True`` and host bits are set in the supplied address,
- then :exc:`ValueError` is raised. Otherwise, the host bits are masked out
+ then :exc:`ValueError` is raised. Otherwise, the host bits are masked out
to determine the appropriate network address.
- >>> ipaddress.IPv6Network('2001:db8::/96')
- IPv6Network('2001:db8::/96')
- >>> ipaddress.IPv6Network('2001:db8::/96').netmask
- IPv6Address('ffff:ffff:ffff:ffff:ffff:ffff::')
- >>> ipaddress.IPv6Network('2001:db8::1000/96', strict=False)
- IPv6Network('2001:db8::/96')
+ .. describe:: Attributes and methods
+
+ All attributes and methods implemented by :class:`IPv4Network` and by
+ :class:`IPv6Address` are also implemented by :class:`IPv6Network`.
+
+
+Operators
+^^^^^^^^^
+
+Network objects support some operators. Unless stated otherwise, operators can
+only be applied between compatible objects (i.e. IPv4 with IPv4, IPv6 with
+IPv6).
+
+Logical operators
+"""""""""""""""""
+
+Network objects can be compared with the usual set of logical operators,
+similarly to address objects.
+
+Iteration
+"""""""""
+
+Network objects can be iterated to list all the addresses belonging to the
+network. For iteration, *all* hosts are returned, including unusable hosts
+(for usable hosts, use the :meth:`~IPv4Network.hosts` method). An
+example::
+
+ >>> for addr in IPv4Network('192.0.2.0/28'):
+ ... addr
+ ...
+ IPv4Address('192.0.2.0')
+ IPv4Address('192.0.2.1')
+ IPv4Address('192.0.2.2')
+ IPv4Address('192.0.2.3')
+ IPv4Address('192.0.2.4')
+ IPv4Address('192.0.2.5')
+ IPv4Address('192.0.2.6')
+ IPv4Address('192.0.2.7')
+ IPv4Address('192.0.2.8')
+ IPv4Address('192.0.2.9')
+ IPv4Address('192.0.2.10')
+ IPv4Address('192.0.2.11')
+ IPv4Address('192.0.2.12')
+ IPv4Address('192.0.2.13')
+ IPv4Address('192.0.2.14')
+ IPv4Address('192.0.2.15')
+
+Networks as containers of addresses
+"""""""""""""""""""""""""""""""""""
+
+Network objects can act as containers of addresses. Some examples::
+
+ >>> IPv4Network('192.0.2.0/28')[0]
+ IPv4Address('192.0.2.0')
+ >>> IPv4Network('192.0.2.0/28')[15]
+ IPv4Address('192.0.2.15')
+ >>> IPv4Address('192.0.2.6') in IPv4Network('192.0.2.0/28')
+ True
+ >>> IPv4Address('192.0.3.6') in IPv4Network('192.0.2.0/28')
+ False
Interface objects
diff --git a/Lib/ipaddress.py b/Lib/ipaddress.py
--- a/Lib/ipaddress.py
+++ b/Lib/ipaddress.py
@@ -497,6 +497,7 @@
prefixlen = self._prefixlen
return self._string_from_ip_int(self._ip_int_from_prefix(prefixlen))
+
class _BaseAddress(_IPAddressBase):
"""A generic IP object.
@@ -568,9 +569,6 @@
def __init__(self, address):
self._cache = {}
- def __int__(self):
- return int(self.network_address)
-
def __repr__(self):
return '%s(%r)' % (self.__class__.__name__, str(self))
@@ -937,6 +935,76 @@
strict=False)
return t.__class__('%s/%d' % (t.network_address, t.prefixlen))
+ @property
+ def is_multicast(self):
+ """Test if the address is reserved for multicast use.
+
+ Returns:
+ A boolean, True if the address is a multicast address.
+ See RFC 2373 2.7 for details.
+
+ """
+ return (self.network_address.is_multicast and
+ self.broadcast_address.is_multicast)
+
+ @property
+ def is_reserved(self):
+ """Test if the address is otherwise IETF reserved.
+
+ Returns:
+ A boolean, True if the address is within one of the
+ reserved IPv6 Network ranges.
+
+ """
+ return (self.network_address.is_reserved and
+ self.broadcast_address.is_reserved)
+
+ @property
+ def is_link_local(self):
+ """Test if the address is reserved for link-local.
+
+ Returns:
+ A boolean, True if the address is reserved per RFC 4291.
+
+ """
+ return (self.network_address.is_link_local and
+ self.broadcast_address.is_link_local)
+
+ @property
+ def is_private(self):
+ """Test if this address is allocated for private networks.
+
+ Returns:
+ A boolean, True if the address is reserved per RFC 4193.
+
+ """
+ return (self.network_address.is_private and
+ self.broadcast_address.is_private)
+
+ @property
+ def is_unspecified(self):
+ """Test if the address is unspecified.
+
+ Returns:
+ A boolean, True if this is the unspecified address as defined in
+ RFC 2373 2.5.2.
+
+ """
+ return (self.network_address.is_unspecified and
+ self.broadcast_address.is_unspecified)
+
+ @property
+ def is_loopback(self):
+ """Test if the address is a loopback address.
+
+ Returns:
+ A boolean, True if the address is a loopback address as defined in
+ RFC 2373 2.5.3.
+
+ """
+ return (self.network_address.is_loopback and
+ self.broadcast_address.is_loopback)
+
class _BaseV4:
@@ -1094,102 +1162,6 @@
def version(self):
return self._version
- @property
- def is_reserved(self):
- """Test if the address is otherwise IETF reserved.
-
- Returns:
- A boolean, True if the address is within the
- reserved IPv4 Network range.
-
- """
- reserved_network = IPv4Network('240.0.0.0/4')
- if isinstance(self, _BaseAddress):
- return self in reserved_network
- return (self.network_address in reserved_network and
- self.broadcast_address in reserved_network)
-
- @property
- def is_private(self):
- """Test if this address is allocated for private networks.
-
- Returns:
- A boolean, True if the address is reserved per RFC 1918.
-
- """
- private_10 = IPv4Network('10.0.0.0/8')
- private_172 = IPv4Network('172.16.0.0/12')
- private_192 = IPv4Network('192.168.0.0/16')
- if isinstance(self, _BaseAddress):
- return (self in private_10 or self in private_172 or
- self in private_192)
- else:
- return ((self.network_address in private_10 and
- self.broadcast_address in private_10) or
- (self.network_address in private_172 and
- self.broadcast_address in private_172) or
- (self.network_address in private_192 and
- self.broadcast_address in private_192))
-
- @property
- def is_multicast(self):
- """Test if the address is reserved for multicast use.
-
- Returns:
- A boolean, True if the address is multicast.
- See RFC 3171 for details.
-
- """
- multicast_network = IPv4Network('224.0.0.0/4')
- if isinstance(self, _BaseAddress):
- return self in IPv4Network('224.0.0.0/4')
- return (self.network_address in multicast_network and
- self.broadcast_address in multicast_network)
-
- @property
- def is_unspecified(self):
- """Test if the address is unspecified.
-
- Returns:
- A boolean, True if this is the unspecified address as defined in
- RFC 5735 3.
-
- """
- unspecified_address = IPv4Address('0.0.0.0')
- if isinstance(self, _BaseAddress):
- return self == unspecified_address
- return (self.network_address == self.broadcast_address ==
- unspecified_address)
-
- @property
- def is_loopback(self):
- """Test if the address is a loopback address.
-
- Returns:
- A boolean, True if the address is a loopback per RFC 3330.
-
- """
- loopback_address = IPv4Network('127.0.0.0/8')
- if isinstance(self, _BaseAddress):
- return self in loopback_address
-
- return (self.network_address in loopback_address and
- self.broadcast_address in loopback_address)
-
- @property
- def is_link_local(self):
- """Test if the address is reserved for link-local.
-
- Returns:
- A boolean, True if the address is link-local per RFC 3927.
-
- """
- linklocal_network = IPv4Network('169.254.0.0/16')
- if isinstance(self, _BaseAddress):
- return self in linklocal_network
- return (self.network_address in linklocal_network and
- self.broadcast_address in linklocal_network)
-
class IPv4Address(_BaseV4, _BaseAddress):
@@ -1236,6 +1208,79 @@
"""The binary representation of this address."""
return v4_int_to_packed(self._ip)
+ @property
+ def is_reserved(self):
+ """Test if the address is otherwise IETF reserved.
+
+ Returns:
+ A boolean, True if the address is within the
+ reserved IPv4 Network range.
+
+ """
+ reserved_network = IPv4Network('240.0.0.0/4')
+ return self in reserved_network
+
+ @property
+ def is_private(self):
+ """Test if this address is allocated for private networks.
+
+ Returns:
+ A boolean, True if the address is reserved per RFC 1918.
+
+ """
+ private_10 = IPv4Network('10.0.0.0/8')
+ private_172 = IPv4Network('172.16.0.0/12')
+ private_192 = IPv4Network('192.168.0.0/16')
+ return (self in private_10 or
+ self in private_172 or
+ self in private_192)
+
+ @property
+ def is_multicast(self):
+ """Test if the address is reserved for multicast use.
+
+ Returns:
+ A boolean, True if the address is multicast.
+ See RFC 3171 for details.
+
+ """
+ multicast_network = IPv4Network('224.0.0.0/4')
+ return self in multicast_network
+
+ @property
+ def is_unspecified(self):
+ """Test if the address is unspecified.
+
+ Returns:
+ A boolean, True if this is the unspecified address as defined in
+ RFC 5735 3.
+
+ """
+ unspecified_address = IPv4Address('0.0.0.0')
+ return self == unspecified_address
+
+ @property
+ def is_loopback(self):
+ """Test if the address is a loopback address.
+
+ Returns:
+ A boolean, True if the address is a loopback per RFC 3330.
+
+ """
+ loopback_network = IPv4Network('127.0.0.0/8')
+ return self in loopback_network
+
+ @property
+ def is_link_local(self):
+ """Test if the address is reserved for link-local.
+
+ Returns:
+ A boolean, True if the address is link-local per RFC 3927.
+
+ """
+ linklocal_network = IPv4Network('169.254.0.0/16')
+ return self in linklocal_network
+
class IPv4Interface(IPv4Address):
@@ -1674,162 +1719,6 @@
def version(self):
return self._version
- @property
- def is_multicast(self):
- """Test if the address is reserved for multicast use.
-
- Returns:
- A boolean, True if the address is a multicast address.
- See RFC 2373 2.7 for details.
-
- """
- multicast_network = IPv6Network('ff00::/8')
- if isinstance(self, _BaseAddress):
- return self in multicast_network
- return (self.network_address in multicast_network and
- self.broadcast_address in multicast_network)
-
- @property
- def is_reserved(self):
- """Test if the address is otherwise IETF reserved.
-
- Returns:
- A boolean, True if the address is within one of the
- reserved IPv6 Network ranges.
-
- """
- reserved_networks = [IPv6Network('::/8'), IPv6Network('100::/8'),
- IPv6Network('200::/7'), IPv6Network('400::/6'),
- IPv6Network('800::/5'), IPv6Network('1000::/4'),
- IPv6Network('4000::/3'), IPv6Network('6000::/3'),
- IPv6Network('8000::/3'), IPv6Network('A000::/3'),
- IPv6Network('C000::/3'), IPv6Network('E000::/4'),
- IPv6Network('F000::/5'), IPv6Network('F800::/6'),
- IPv6Network('FE00::/9')]
-
- if isinstance(self, _BaseAddress):
- return any(self in x for x in reserved_networks)
- return any(self.network_address in x and self.broadcast_address in x
- for x in reserved_networks)
-
- @property
- def is_link_local(self):
- """Test if the address is reserved for link-local.
-
- Returns:
- A boolean, True if the address is reserved per RFC 4291.
-
- """
- linklocal_network = IPv6Network('fe80::/10')
- if isinstance(self, _BaseAddress):
- return self in linklocal_network
- return (self.network_address in linklocal_network and
- self.broadcast_address in linklocal_network)
-
- @property
- def is_site_local(self):
- """Test if the address is reserved for site-local.
-
- Note that the site-local address space has been deprecated by RFC 3879.
- Use is_private to test if this address is in the space of unique local
- addresses as defined by RFC 4193.
-
- Returns:
- A boolean, True if the address is reserved per RFC 3513 2.5.6.
-
- """
- sitelocal_network = IPv6Network('fec0::/10')
- if isinstance(self, _BaseAddress):
- return self in sitelocal_network
- return (self.network_address in sitelocal_network and
- self.broadcast_address in sitelocal_network)
-
- @property
- def is_private(self):
- """Test if this address is allocated for private networks.
-
- Returns:
- A boolean, True if the address is reserved per RFC 4193.
-
- """
- private_network = IPv6Network('fc00::/7')
- if isinstance(self, _BaseAddress):
- return self in private_network
- return (self.network_address in private_network and
- self.broadcast_address in private_network)
-
- @property
- def ipv4_mapped(self):
- """Return the IPv4 mapped address.
-
- Returns:
- If the IPv6 address is a v4 mapped address, return the
- IPv4 mapped address. Return None otherwise.
-
- """
- if (self._ip >> 32) != 0xFFFF:
- return None
- return IPv4Address(self._ip & 0xFFFFFFFF)
-
- @property
- def teredo(self):
- """Tuple of embedded teredo IPs.
-
- Returns:
- Tuple of the (server, client) IPs or None if the address
- doesn't appear to be a teredo address (doesn't start with
- 2001::/32)
-
- """
- if (self._ip >> 96) != 0x20010000:
- return None
- return (IPv4Address((self._ip >> 64) & 0xFFFFFFFF),
- IPv4Address(~self._ip & 0xFFFFFFFF))
-
- @property
- def sixtofour(self):
- """Return the IPv4 6to4 embedded address.
-
- Returns:
- The IPv4 6to4-embedded address if present or None if the
- address doesn't appear to contain a 6to4 embedded address.
-
- """
- if (self._ip >> 112) != 0x2002:
- return None
- return IPv4Address((self._ip >> 80) & 0xFFFFFFFF)
-
- @property
- def is_unspecified(self):
- """Test if the address is unspecified.
-
- Returns:
- A boolean, True if this is the unspecified address as defined in
- RFC 2373 2.5.2.
-
- """
- if isinstance(self, (IPv6Network, IPv6Interface)):
- return int(self.network_address) == 0 and getattr(
- self, '_prefixlen', 128) == 128
- return self._ip == 0
-
- @property
- def is_loopback(self):
- """Test if the address is a loopback address.
-
- Returns:
- A boolean, True if the address is a loopback address as defined in
- RFC 2373 2.5.3.
-
- """
- if isinstance(self, IPv6Network):
- return int(self) == 1 and getattr(
- self, '_prefixlen', 128) == 128
- elif isinstance(self, IPv6Interface):
- return int(self.network.network_address) == 1 and getattr(
- self, '_prefixlen', 128) == 128
- return self._ip == 1
-
class IPv6Address(_BaseV6, _BaseAddress):
@@ -1878,6 +1767,138 @@
"""The binary representation of this address."""
return v6_int_to_packed(self._ip)
+ @property
+ def is_multicast(self):
+ """Test if the address is reserved for multicast use.
+
+ Returns:
+ A boolean, True if the address is a multicast address.
+ See RFC 2373 2.7 for details.
+
+ """
+ multicast_network = IPv6Network('ff00::/8')
+ return self in multicast_network
+
+ @property
+ def is_reserved(self):
+ """Test if the address is otherwise IETF reserved.
+
+ Returns:
+ A boolean, True if the address is within one of the
+ reserved IPv6 Network ranges.
+
+ """
+ reserved_networks = [IPv6Network('::/8'), IPv6Network('100::/8'),
+ IPv6Network('200::/7'), IPv6Network('400::/6'),
+ IPv6Network('800::/5'), IPv6Network('1000::/4'),
+ IPv6Network('4000::/3'), IPv6Network('6000::/3'),
+ IPv6Network('8000::/3'), IPv6Network('A000::/3'),
+ IPv6Network('C000::/3'), IPv6Network('E000::/4'),
+ IPv6Network('F000::/5'), IPv6Network('F800::/6'),
+ IPv6Network('FE00::/9')]
+
+ return any(self in x for x in reserved_networks)
+
+ @property
+ def is_link_local(self):
+ """Test if the address is reserved for link-local.
+
+ Returns:
+ A boolean, True if the address is reserved per RFC 4291.
+
+ """
+ linklocal_network = IPv6Network('fe80::/10')
+ return self in linklocal_network
+
+ @property
+ def is_site_local(self):
+ """Test if the address is reserved for site-local.
+
+ Note that the site-local address space has been deprecated by RFC 3879.
+ Use is_private to test if this address is in the space of unique local
+ addresses as defined by RFC 4193.
+
+ Returns:
+ A boolean, True if the address is reserved per RFC 3513 2.5.6.
+
+ """
+ sitelocal_network = IPv6Network('fec0::/10')
+ return self in sitelocal_network
+
+ @property
+ def is_private(self):
+ """Test if this address is allocated for private networks.
+
+ Returns:
+ A boolean, True if the address is reserved per RFC 4193.
+
+ """
+ private_network = IPv6Network('fc00::/7')
+ return self in private_network
+
+ @property
+ def is_unspecified(self):
+ """Test if the address is unspecified.
+
+ Returns:
+ A boolean, True if this is the unspecified address as defined in
+ RFC 2373 2.5.2.
+
+ """
+ return self._ip == 0
+
+ @property
+ def is_loopback(self):
+ """Test if the address is a loopback address.
+
+ Returns:
+ A boolean, True if the address is a loopback address as defined in
+ RFC 2373 2.5.3.
+
+ """
+ return self._ip == 1
+
+ @property
+ def ipv4_mapped(self):
+ """Return the IPv4 mapped address.
+
+ Returns:
+ If the IPv6 address is a v4 mapped address, return the
+ IPv4 mapped address. Return None otherwise.
+
+ """
+ if (self._ip >> 32) != 0xFFFF:
+ return None
+ return IPv4Address(self._ip & 0xFFFFFFFF)
+
+ @property
+ def teredo(self):
+ """Tuple of embedded teredo IPs.
+
+ Returns:
+ Tuple of the (server, client) IPs or None if the address
+ doesn't appear to be a teredo address (doesn't start with
+ 2001::/32)
+
+ """
+ if (self._ip >> 96) != 0x20010000:
+ return None
+ return (IPv4Address((self._ip >> 64) & 0xFFFFFFFF),
+ IPv4Address(~self._ip & 0xFFFFFFFF))
+
+ @property
+ def sixtofour(self):
+ """Return the IPv4 6to4 embedded address.
+
+ Returns:
+ The IPv4 6to4-embedded address if present or None if the
+ address doesn't appear to contain a 6to4 embedded address.
+
+ """
+ if (self._ip >> 112) != 0x2002:
+ return None
+ return IPv4Address((self._ip >> 80) & 0xFFFFFFFF)
+
class IPv6Interface(IPv6Address):
@@ -1946,6 +1967,14 @@
return '%s/%s' % (self._string_from_ip_int(self._ip),
self.hostmask)
+ @property
+ def is_unspecified(self):
+ return self._ip == 0 and self.network.is_unspecified
+
+ @property
+ def is_loopback(self):
+ return self._ip == 1 and self.network.is_loopback
+
class IPv6Network(_BaseV6, _BaseNetwork):
@@ -2054,3 +2083,18 @@
except ValueError:
return False
return 0 <= prefixlen <= self._max_prefixlen
+
+ @property
+ def is_site_local(self):
+ """Test if the address is reserved for site-local.
+
+ Note that the site-local address space has been deprecated by RFC 3879.
+ Use is_private to test if this address is in the space of unique local
+ addresses as defined by RFC 4193.
+
+ Returns:
+ A boolean, True if the address is reserved per RFC 3513 2.5.6.
+
+ """
+ return (self.network_address.is_site_local and
+ self.broadcast_address.is_site_local)
diff --git a/Lib/test/test_ipaddress.py b/Lib/test/test_ipaddress.py
--- a/Lib/test/test_ipaddress.py
+++ b/Lib/test/test_ipaddress.py
@@ -647,8 +647,8 @@
ipv4 = ipaddress.ip_network('1.2.3.4')
ipv6 = ipaddress.ip_network('2001:658:22a:cafe:200:0:0:1')
- self.assertEqual(ipv4, ipaddress.ip_network(int(ipv4)))
- self.assertEqual(ipv6, ipaddress.ip_network(int(ipv6)))
+ self.assertEqual(ipv4, ipaddress.ip_network(int(ipv4.network_address)))
+ self.assertEqual(ipv6, ipaddress.ip_network(int(ipv6.network_address)))
v6_int = 42540616829182469433547762482097946625
self.assertEqual(self.ipv6_interface._ip,
--
Repository URL: http://hg.python.org/cpython
More information about the Python-checkins
mailing list