[Python-checkins] cpython (merge default -> default): merge heads

benjamin.peterson python-checkins at python.org
Mon Aug 6 00:06:00 CEST 2012


http://hg.python.org/cpython/rev/a8b05f3c14fc
changeset:   78441:a8b05f3c14fc
parent:      78440:cde674716de4
parent:      78439:80a1ae3a1b39
user:        Benjamin Peterson <benjamin at python.org>
date:        Sun Aug 05 15:05:53 2012 -0700
summary:
  merge heads

files:
  Doc/library/ipaddress.rst    |  523 +++++++++++++++++---
  Doc/library/os.rst           |    6 +-
  Doc/whatsnew/3.3.rst         |  279 +++++++---
  Lib/gzip.py                  |    6 +-
  Lib/ipaddress.py             |  570 ++++++++++++----------
  Lib/test/test_httpservers.py |   12 +-
  Lib/test/test_ipaddress.py   |   25 +-
  Misc/NEWS                    |    8 +-
  8 files changed, 962 insertions(+), 467 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,75 @@
    >>> 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`.
+   .. 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 +274,7 @@
 only be applied between compatible objects (i.e. IPv4 with IPv4, IPv6 with
 IPv6).
 
+
 Logical operators
 """""""""""""""""
 
@@ -212,6 +288,7 @@
    >>> IPv4Address('127.0.0.2') != IPv4Address('127.0.0.1')
    True
 
+
 Arithmetic operators
 """"""""""""""""""""
 
@@ -227,45 +304,337 @@
    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')
+   Unless stated otherwise, all network methods accepting other network/address
+   objects will raise :exc:`TypeError` if the argument's IP version is
+   incompatible to ``self``
+
+   .. attribute:: version
+   .. attribute:: max_prefixlen
+
+      Refer to the corresponding attribute documentation in
+      :class:`IPv4Address`
+
+   .. attribute:: is_multicast
+   .. attribute:: is_private
+   .. attribute:: is_unspecified
+   .. attribute:: is_reserved
+   .. attribute:: is_loopback
+   .. attribute:: is_link_local
+
+      These attributes are true for the network as a whole if they are true
+      true for both the network address and the broadcast address
+
+   .. attribute:: network_address
+
+      The network address for the network. The network address and the
+      prefix length together uniquely define a network.
+
+   .. attribute:: broadcast_address
+
+      The broadcast address for the network. Packets sent to the broadcast
+      address should be received by every host on the network.
+
+   .. attribute:: host mask
+
+      The host mask, as a string.
+
+   .. attribute:: with_prefixlen
+   .. attribute:: compressed
+   .. attribute:: exploded
+
+      A string representation of the network, with the mask in prefix
+      notation.
+
+      ``with_prefixlen`` and ``compressed`` are always the same as
+      ``str(network)``.
+      ``exploded`` uses the exploded form the network address.
+
+   .. 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 network prefix, in bits.
+
+   .. method:: hosts()
+
+      Returns 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 or wholly contained in *other* or
+      or *other* is wholly contained in this network.
+
+   .. method:: address_exclude(network)
+
+      Computes the network definitions resulting from removing the given
+      *network* from this one.  Returns an iterator of network objects.
+      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 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 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')
+   .. attribute:: version
+   .. attribute:: max_prefixlen
+   .. attribute:: is_multicast
+   .. attribute:: is_private
+   .. attribute:: is_unspecified
+   .. attribute:: is_reserved
+   .. attribute:: is_loopback
+   .. attribute:: is_link_local
+   .. attribute:: network_address
+   .. attribute:: broadcast_address
+   .. attribute:: host mask
+   .. attribute:: with_prefixlen
+   .. attribute:: compressed
+   .. attribute:: exploded
+   .. attribute:: with_netmask
+   .. attribute:: with_hostmask
+   .. attribute:: num_addresses
+   .. attribute:: prefixlen
+   .. method:: hosts()
+   .. method:: overlaps(other)
+   .. method:: address_exclude(network)
+   .. method:: subnets(prefixlen_diff=1, new_prefix=None)
+   .. method:: supernet(prefixlen_diff=1, new_prefix=None)
+   .. method:: compare_networks(other)
+
+      Refer to the corresponding attribute documentation in
+      :class:`IPv4Network`
+
+   .. attribute:: is_site_local
+
+      These attribute is true for the network as a whole if it is true
+      true for both the network address and the broadcast address
+
+
+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/Doc/library/os.rst b/Doc/library/os.rst
--- a/Doc/library/os.rst
+++ b/Doc/library/os.rst
@@ -2248,7 +2248,7 @@
               dirs.remove('CVS')  # don't visit CVS directories
 
    In the next example, walking the tree bottom-up is essential:
-   :func:`unlinkat` doesn't allow deleting a directory before the directory is
+   :func:`rmdir` doesn't allow deleting a directory before the directory is
    empty::
 
       # Delete everything reachable from the directory named in "top",
@@ -2258,9 +2258,9 @@
       import os
       for root, dirs, files, rootfd in os.fwalk(top, topdown=False):
           for name in files:
-              os.unlinkat(rootfd, name)
+              os.unlink(name, dir_fd=rootfd)
           for name in dirs:
-              os.unlinkat(rootfd, name, os.AT_REMOVEDIR)
+              os.rmdir(name, dir_fd=rootfd)
 
    Availability: Unix.
 
diff --git a/Doc/whatsnew/3.3.rst b/Doc/whatsnew/3.3.rst
--- a/Doc/whatsnew/3.3.rst
+++ b/Doc/whatsnew/3.3.rst
@@ -53,6 +53,18 @@
    release, so it's worth checking back even after reading earlier versions.
 
 
+Summary
+=======
+
+Major changes since Python 3.2:
+
+ * 4 new modules: :mod:`faulthandler`, :mod:`ipaddress`, :mod:`lzma` and :mod:`venv`.
+ * Syntax changes:
+
+   - ``u'unicode'`` syntax is accepted again
+   - Add ``yield from`` syntax
+
+
 PEP 405: Virtual Environments
 =============================
 
@@ -786,8 +798,71 @@
 (contributed by Antoine Pitrou in :issue:`9260`.)
 
 
-New and Improved Modules
-========================
+Builtin functions and types
+===========================
+
+* :func:`open` gets a new *opener* parameter: the underlying file descriptor
+  for the file object is then obtained by calling *opener* with (*file*,
+  *flags*). It can be used to use custom flags like :data:`os.O_CLOEXEC` for
+  example. The ``'x'`` mode was added: open for exclusive creation, failing if
+  the file already exists.
+* :func:`print`: added the *flush* keyword argument. If the *flush* keyword
+  argument is true, the stream is forcibly flushed.
+* :func:`hash`: hash randomization is enabled by default, see
+  :meth:`object.__hash__` and :envvar:`PYTHONHASHSEED`.
+* The :class:`str` type gets a new :meth:`~str.casefold` method: return a
+  casefolded copy of the string, casefolded strings may be used for caseless
+  matching. For example, ``'ß'.casefold()`` returns ``'ss'``.
+
+
+New Modules
+===========
+
+faulthandler
+------------
+
+This new debug module contains functions to dump Python tracebacks explicitly,
+on a fault (a crash like a segmentation fault), after a timeout, or on a user
+signal. Call :func:`faulthandler.enable` to install fault handlers for the
+:const:`SIGSEGV`, :const:`SIGFPE`, :const:`SIGABRT`, :const:`SIGBUS`, and
+:const:`SIGILL` signals. You can also enable them at startup by setting the
+:envvar:`PYTHONFAULTHANDLER` environment variable or by using :option:`-X`
+``faulthandler`` command line option.
+
+Example of a segmentation fault on Linux: ::
+
+    $ python -q -X faulthandler
+    >>> import ctypes
+    >>> ctypes.string_at(0)
+    Fatal Python error: Segmentation fault
+
+    Current thread 0x00007fb899f39700:
+      File "/home/python/cpython/Lib/ctypes/__init__.py", line 486 in string_at
+      File "<stdin>", line 1 in <module>
+    Segmentation fault
+
+
+ipaddress
+---------
+
+The new :mod:`ipaddress` module provides tools for creating and manipulating
+objects representing IPv4 and IPv6 addresses, networks and interfaces (i.e.
+an IP address associated with a specific IP subnet).
+
+(Contributed by Google and Peter Moody in :pep:`3144`)
+
+lzma
+----
+
+The newly-added :mod:`lzma` module provides data compression and decompression
+using the LZMA algorithm, including support for the ``.xz`` and ``.lzma``
+file formats.
+
+(Contributed by Nadeem Vawda and Per Øyvind Karlsen in :issue:`6715`)
+
+
+Improved Modules
+================
 
 abc
 ---
@@ -815,12 +890,22 @@
 (Contributed by Oren Tirosh and Hirokazu Yamamoto in :issue:`1172711`)
 
 
+base64, binascii
+----------------
+
+ASCII-only Unicode strings are now accepted by the decoding functions of the
+modern interface. For example, ``base64.b64decode('YWJj')`` returns ``b'abc'``.
+
+
 bz2
 ---
 
 The :mod:`bz2` module has been rewritten from scratch. In the process, several
 new features have been added:
 
+* New :func:`bz2.open` function: open a bzip2-compressed file in binary or
+  text mode.
+
 * :class:`bz2.BZ2File` can now read from and write to arbitrary file-like
   objects, by means of its constructor's *fileobj* argument.
 
@@ -910,7 +995,7 @@
 crypt
 -----
 
-Addition of salt and modular crypt format and the :func:`~crypt.mksalt`
+Addition of salt and modular crypt format (hashing method) and the :func:`~crypt.mksalt`
 function to the :mod:`crypt` module.
 
 (:issue:`10924`)
@@ -931,6 +1016,17 @@
 
 (Contributed by Iñigo Serna in :issue:`6755`)
 
+datetime
+--------
+
+ * Equality comparisons between naive and aware :class:`~datetime.datetime`
+   instances don't raise :exc:`TypeError`.
+ * New :meth:`datetime.datetime.timestamp` method: Return POSIX timestamp
+   corresponding to the :class:`~datetime.datetime` instance.
+ * The :meth:`datetime.datetime.strftime` method supports formatting years
+   older than 1000.
+
+
 decimal
 -------
 
@@ -1024,14 +1120,6 @@
   changed to match the order displayed by :func:`repr`.
 
 
-faulthandler
-------------
-
-New module: :mod:`faulthandler`.
-
- * :envvar:`PYTHONFAULTHANDLER`
- * :option:`-X` ``faulthandler``
-
 ftplib
 ------
 
@@ -1043,6 +1131,13 @@
 (Contributed by Giampaolo Rodolà in :issue:`12139`)
 
 
+gc
+--
+
+It is now possible to register callbacks invoked by the garbage collector
+before and after collection using the new :`data:`~gc.callbacks` list.
+
+
 hmac
 ----
 
@@ -1087,24 +1182,11 @@
 
 (Contributed by David Townshend in :issue:`12760`)
 
-
-ipaddress
----------
-
-The new :mod:`ipaddress` module provides tools for creating and manipulating
-objects representing IPv4 and IPv6 addresses, networks and interfaces (i.e.
-an IP address associated with a specific IP subnet).
-
-(Contributed by Google and Peter Moody in :pep:`3144`)
-
-lzma
-----
-
-The newly-added :mod:`lzma` module provides data compression and decompression
-using the LZMA algorithm, including support for the ``.xz`` and ``.lzma``
-file formats.
-
-(Contributed by Nadeem Vawda and Per Øyvind Karlsen in :issue:`6715`)
+The constructor of the :class:`~io.TextIOWrapper` class has a new
+*write_through* optional argument. If *write_through* is ``True``, calls to
+:meth:`~io.TextIOWrapper.write` are guaranteed not to be buffered: any data
+written on the :class:`~io.TextIOWrapper` object is immediately handled to its
+underlying binary buffer.
 
 
 math
@@ -1163,6 +1245,30 @@
 
   (Patch submitted by Ross Lagerwall and Giampaolo Rodolà in :issue:`10882`.)
 
+* To avoid race conditions like symlink attacks and issues with temporary
+  files and directories, it is more reliable (and also faster) to manipulate
+  file descriptors instead of file names. Python 3.3 enhances existing functions
+  and introduces new functions to work on file descriptors (:issue:`4761`,
+  :issue:`10755`).
+
+  - The :mod:`os` module has a new :func:`~os.fwalk` function similar to
+    :func:`~os.walk` except that it also yields file descriptors referring to the
+    directories visited. This is especially useful to avoid symlink races.
+
+  - The following functions get new optional *dir_fd* (:ref:`paths relative to
+    directory descriptors <dir_fd>`) and/or *follow_symlinks* (:ref:`not
+    following symlinks <follow_symlinks>`):
+    :func:`~os.access`, :func:`~os.chflags`, :func:`~os.chmod`, :func:`~os.chown`,
+    :func:`~os.link`, :func:`~os.lstat`, :func:`~os.mkdir`, :func:`~os.mkfifo`,
+    :func:`~os.mknod`, :func:`~os.open`, :func:`~os.readlink`, :func:`~os.remove`,
+    :func:`~os.rename`, :func:`~os.replace`, :func:`~os.rmdir`, :func:`~os.stat`,
+    :func:`~os.symlink`, :func:`~os.unlink`, :func:`~os.utime`.
+
+  - The following functions now support a file descriptor for their path argument:
+    :func:`~os.chdir`, :func:`~os.chmod`, :func:`~os.chown`,
+    :func:`~os.execve`, :func:`~os.listdir`, :func:`~os.pathconf`, :func:`~os.path.exists`,
+    :func:`~os.stat`, :func:`~os.statvfs`, :func:`~os.utime`.
+
 * The :mod:`os` module has two new functions: :func:`~os.getpriority` and
   :func:`~os.setpriority`. They can be used to get or set process
   niceness/priority in a fashion similar to :func:`os.nice` but extended to all
@@ -1170,10 +1276,6 @@
 
   (Patch submitted by Giampaolo Rodolà in :issue:`10784`.)
 
-* The :mod:`os` module has a new :func:`~os.fwalk` function similar to
-  :func:`~os.walk` except that it also yields file descriptors referring to the
-  directories visited. This is especially useful to avoid symlink races.
-
 * The new :func:`os.replace` function allows cross-platform renaming of a
   file with overwriting the destination.  With :func:`os.rename`, an existing
   destination file is overwritten under POSIX, but raises an error under
@@ -1181,78 +1283,51 @@
   (Contributed by Antoine Pitrou in :issue:`8828`.)
 
 * The new :func:`os.get_terminal_size` function queries the size of the
-  terminal attached to a file descriptor.
+  terminal attached to a file descriptor. See also
+  :func:`shutil.get_terminal_size`.
   (Contributed by Zbigniew Jędrzejewski-Szmek in :issue:`13609`.)
 
 .. XXX sort out this mess after beta1
 
-  * "at" functions (:issue:`4761`):
+* New functions to support Linux extended attributes (:issue:`12720`):
+  :func:`~os.getxattr`, :func:`~os.listxattr`, :func:`~os.removexattr`,
+  :func:`~os.setxattr`.
 
-    * :func:`~os.faccessat`
-    * :func:`~os.fchmodat`
-    * :func:`~os.fchownat`
-    * :func:`~os.fstatat`
-    * :func:`~os.futimesat`
-    * :func:`~os.linkat`
-    * :func:`~os.mkdirat`
-    * :func:`~os.mkfifoat`
-    * :func:`~os.mknodat`
-    * :func:`~os.openat`
-    * :func:`~os.readlinkat`
-    * :func:`~os.renameat`
-    * :func:`~os.symlinkat`
-    * :func:`~os.unlinkat`
-    * :func:`~os.utimensat`
+* New interface to the scheduler. These functions
+  control how a process is allocated CPU time by the operating system. New
+  functions:
+  :func:`~os.sched_get_priority_max`, :func:`~os.sched_get_priority_min`,
+  :func:`~os.sched_getaffinity`, :func:`~os.sched_getparam`,
+  :func:`~os.sched_getscheduler`, :func:`~os.sched_rr_get_interval`,
+  :func:`~os.sched_setaffinity`, :func:`~os.sched_setparam`,
+  :func:`~os.sched_setscheduler`, :func:`~os.sched_yield`,
 
-  * extended attributes (:issue:`12720`):
+* New functions to control the file system:
 
-    * :func:`~os.fgetxattr`
-    * :func:`~os.flistxattr`
-    * :func:`~os.fremovexattr`
-    * :func:`~os.fsetxattr`
-    * :func:`~os.getxattr`
-    * :func:`~os.lgetxattr`
-    * :func:`~os.listxattr`
-    * :func:`~os.llistxattr`
-    * :func:`~os.lremovexattr`
-    * :func:`~os.lsetxattr`
-    * :func:`~os.removexattr`
-    * :func:`~os.setxattr`
+  * :func:`~os.posix_fadvise`: Announces an intention to access data in a
+    specific pattern thus allowing the kernel to make optimizations.
+  * :func:`~os.posix_fallocate`: Ensures that enough disk space is allocated
+    for a file.
+  * :func:`~os.sync`: Force write of everything to disk.
 
-  * Scheduler functions (:issue:`12655`):
+* Add some extra posix functions to the os module:
 
-    * :func:`~os.sched_get_priority_max`
-    * :func:`~os.sched_get_priority_min`
-    * :func:`~os.sched_getaffinity`
-    * :func:`~os.sched_getparam`
-    * :func:`~os.sched_getscheduler`
-    * :func:`~os.sched_rr_get_interval`
-    * :func:`~os.sched_setaffinity`
-    * :func:`~os.sched_setparam`
-    * :func:`~os.sched_setscheduler`
-    * :func:`~os.sched_yield`
+  * :func:`~os.lockf`: Apply, test or remove a POSIX lock on an open file descriptor.
+  * :func:`~os.pread`: Read from a file descriptor at an offset, the file
+    offset remains unchanged.
+  * :func:`~os.pwrite`: Write to a file descriptor from an offset, leaving
+    the file offset unchanged.
+  * :func:`~os.readv`: Read from a file descriptor into a number of writable buffers.
+  * :func:`~os.truncate`: Truncate the file corresponding to *path*, so that
+    it is at most *length* bytes in size.
+  * :func:`~os.waitid`: Wait for the completion of one or more child processes.
+  * :func:`~os.writev`: Write the contents of *buffers* to a file descriptor,
+    where *buffers* is an arbitrary sequence of buffers.
+  * :func:`~os.getgrouplist` (:issue:`9344`): Return list of group ids that
+    specified user belongs to.
 
-  * Add some extra posix functions to the os module (:issue:`10812`):
-
-    * :func:`~os.fexecve`
-    * :func:`~os.futimens`
-    * :func:`~os.futimes`
-    * :func:`~os.lockf`
-    * :func:`~os.lutimes`
-    * :func:`~os.posix_fadvise`
-    * :func:`~os.posix_fallocate`
-    * :func:`~os.pread`
-    * :func:`~os.pwrite`
-    * :func:`~os.readv`
-    * :func:`~os.sync`
-    * :func:`~os.truncate`
-    * :func:`~os.waitid`
-    * :func:`~os.writev`
-
-  * Other new functions:
-
-    * :func:`~os.flistdir` (:issue:`10755`)
-    * :func:`~os.getgrouplist` (:issue:`9344`)
+* :func:`~os.times` and :func:`~os.uname`: Return type changed from a tuple to
+  a tuple-like object with named attributes.
 
 
 pdb
@@ -1614,6 +1689,16 @@
 * The behaviour of :func:`time.clock` depends on the platform: use the new
   :func:`time.perf_counter` or :func:`time.process_time` function instead,
   depending on your requirements, to have a well defined behaviour.
+* The :func:`os.stat_float_times` function is deprecated.
+* :mod:`abc` module:
+
+  * :class:`abc.abstractproperty` has been deprecated, use :class:`property`
+    with :func:`abc.abstractmethod` instead.
+  * :class:`abc.abstractclassmethod` has been deprecated, use
+    :class:`classmethod` with :func:`abc.abstractmethod` instead.
+  * :class:`abc.abstractstaticmethod` has been deprecated, use
+    :class:`staticmethod` with :func:`abc.abstractmethod` instead.
+
 
 
 Deprecated functions and types of the C API
@@ -1690,7 +1775,9 @@
 Porting Python code
 -------------------
 
-.. XXX add a point about hash randomization and that it's always on in 3.3
+* Hash randomization is enabled by default. Set the :envvar:`PYTHONHASHSEED`
+  environment variable to ``0`` to disable hash randomization. See also the
+  :meth:`object.__hash__` method.
 
 * :issue:`12326`: On Linux, sys.platform doesn't contain the major version
   anymore. It is now always 'linux', instead of 'linux2' or 'linux3' depending
diff --git a/Lib/gzip.py b/Lib/gzip.py
--- a/Lib/gzip.py
+++ b/Lib/gzip.py
@@ -413,8 +413,10 @@
             if self.fileobj is None:
                 return b''
             try:
-                # 1024 is the same buffering heuristic used in read()
-                self._read(max(n, 1024))
+                # Ensure that we don't return b"" if we haven't reached EOF.
+                while self.extrasize == 0:
+                    # 1024 is the same buffering heuristic used in read()
+                    self._read(max(n, 1024))
             except EOFError:
                 pass
         offset = self.offset - self.extrastart
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.
@@ -511,9 +512,6 @@
             and '/' in str(address)):
             raise AddressValueError("Unexpected '/' in %r" % address)
 
-    def __index__(self):
-        return self._ip
-
     def __int__(self):
         return self._ip
 
@@ -571,12 +569,6 @@
     def __init__(self, address):
         self._cache = {}
 
-    def __index__(self):
-        return int(self.network_address) ^ self.prefixlen
-
-    def __int__(self):
-        return int(self.network_address)
-
     def __repr__(self):
         return '%s(%r)' % (self.__class__.__name__, str(self))
 
@@ -943,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:
 
@@ -1100,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):
 
@@ -1242,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):
 
@@ -1292,10 +1331,6 @@
         return self._ip ^ self._prefixlen ^ int(self.network.network_address)
 
     @property
-    def prefixlen(self):
-        return self._prefixlen
-
-    @property
     def ip(self):
         return IPv4Address(self._ip)
 
@@ -1669,7 +1704,7 @@
         hex_str = '%032x' % ip_int
         parts = [hex_str[x:x+4] for x in range(0, 32, 4)]
         if isinstance(self, (_BaseNetwork, IPv6Interface)):
-            return '%s/%d' % (':'.join(parts), self.prefixlen)
+            return '%s/%d' % (':'.join(parts), self._prefixlen)
         return ':'.join(parts)
 
     @property
@@ -1680,162 +1715,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):
 
@@ -1884,6 +1763,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):
 
@@ -1932,10 +1943,6 @@
         return self._ip ^ self._prefixlen ^ int(self.network.network_address)
 
     @property
-    def prefixlen(self):
-        return self._prefixlen
-
-    @property
     def ip(self):
         return IPv6Address(self._ip)
 
@@ -1952,6 +1959,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):
 
@@ -2060,3 +2075,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_httpservers.py b/Lib/test/test_httpservers.py
--- a/Lib/test/test_httpservers.py
+++ b/Lib/test/test_httpservers.py
@@ -313,6 +313,8 @@
     class request_handler(NoLogRequestHandler, CGIHTTPRequestHandler):
         pass
 
+    linesep = os.linesep.encode('ascii')
+
     def setUp(self):
         BaseTestCase.setUp(self)
         self.cwd = os.getcwd()
@@ -410,7 +412,7 @@
 
     def test_headers_and_content(self):
         res = self.request('/cgi-bin/file1.py')
-        self.assertEqual((b'Hello World\n', 'text/html', 200),
+        self.assertEqual((b'Hello World' + self.linesep, 'text/html', 200),
             (res.read(), res.getheader('Content-type'), res.status))
 
     def test_post(self):
@@ -419,7 +421,7 @@
         headers = {'Content-type' : 'application/x-www-form-urlencoded'}
         res = self.request('/cgi-bin/file2.py', 'POST', params, headers)
 
-        self.assertEqual(res.read(), b'1, python, 123456\n')
+        self.assertEqual(res.read(), b'1, python, 123456' + self.linesep)
 
     def test_invaliduri(self):
         res = self.request('/cgi-bin/invalid')
@@ -430,20 +432,20 @@
         headers = {b'Authorization' : b'Basic ' +
                    base64.b64encode(b'username:pass')}
         res = self.request('/cgi-bin/file1.py', 'GET', headers=headers)
-        self.assertEqual((b'Hello World\n', 'text/html', 200),
+        self.assertEqual((b'Hello World' + self.linesep, 'text/html', 200),
                 (res.read(), res.getheader('Content-type'), res.status))
 
     def test_no_leading_slash(self):
         # http://bugs.python.org/issue2254
         res = self.request('cgi-bin/file1.py')
-        self.assertEqual((b'Hello World\n', 'text/html', 200),
+        self.assertEqual((b'Hello World' + self.linesep, 'text/html', 200),
              (res.read(), res.getheader('Content-type'), res.status))
 
     def test_os_environ_is_not_altered(self):
         signature = "Test CGI Server"
         os.environ['SERVER_SOFTWARE'] = signature
         res = self.request('/cgi-bin/file1.py')
-        self.assertEqual((b'Hello World\n', 'text/html', 200),
+        self.assertEqual((b'Hello World' + self.linesep, 'text/html', 200),
                 (res.read(), res.getheader('Content-type'), res.status))
         self.assertEqual(os.environ['SERVER_SOFTWARE'], signature)
 
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
@@ -7,6 +7,7 @@
 import unittest
 import re
 import contextlib
+import operator
 import ipaddress
 
 class BaseTestCase(unittest.TestCase):
@@ -72,6 +73,14 @@
         with self.assertAddressError(re.escape(repr("1.0"))):
             self.factory(1.0)
 
+    def test_not_an_index_issue15559(self):
+        # Implementing __index__ makes for a very nasty interaction with the
+        # bytes constructor. Thus, we disallow implicit use as an integer
+        self.assertRaises(TypeError, operator.index, self.factory(1))
+        self.assertRaises(TypeError, hex, self.factory(1))
+        self.assertRaises(TypeError, bytes, self.factory(1))
+
+
 class CommonTestMixin_v4(CommonTestMixin):
 
     def test_leading_zeros(self):
@@ -599,7 +608,6 @@
         self.assertEqual(first, last)
         self.assertEqual(128, ipaddress._count_righthand_zero_bits(0, 128))
         self.assertEqual("IPv4Network('1.2.3.0/24')", repr(self.ipv4_network))
-        self.assertEqual('0x1020318', hex(self.ipv4_network))
 
     def testMissingAddressVersion(self):
         class Broken(ipaddress._BaseAddress):
@@ -639,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,
@@ -723,8 +731,8 @@
                          '2001:658:22a:cafe:ffff:ffff:ffff:ffff')
 
     def testGetPrefixlen(self):
-        self.assertEqual(self.ipv4_interface.prefixlen, 24)
-        self.assertEqual(self.ipv6_interface.prefixlen, 64)
+        self.assertEqual(self.ipv4_interface.network.prefixlen, 24)
+        self.assertEqual(self.ipv6_interface.network.prefixlen, 64)
 
     def testGetSupernet(self):
         self.assertEqual(self.ipv4_network.supernet().prefixlen, 23)
@@ -1545,13 +1553,6 @@
         self.assertEqual(42540616829182469433547762482097946625,
                          int(self.ipv6_address))
 
-    def testHexRepresentation(self):
-        self.assertEqual(hex(0x1020304),
-                         hex(self.ipv4_address))
-
-        self.assertEqual(hex(0x20010658022ACAFE0200000000000001),
-                         hex(self.ipv6_address))
-
     def testForceVersion(self):
         self.assertEqual(ipaddress.ip_network(1).version, 4)
         self.assertEqual(ipaddress.IPv6Network(1).version, 6)
diff --git a/Misc/NEWS b/Misc/NEWS
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -77,8 +77,12 @@
 Library
 -------
 
-- Issue #15546: Fix handling of pathological input data in the read1() method of
-  the BZ2File, GzipFile and LZMAFile classes.
+- Issue #15559: To avoid a problematic failure mode when passed to the bytes
+  constructor, objects in the ipaddress module no longer implement __index__
+  (they still implement __int__ as appropriate)
+
+- Issue #15546: Fix handling of pathological input data in the peek() and
+  read1() methods of the BZ2File, GzipFile and LZMAFile classes.
 
 - Issue #13052: Fix IDLE crashing when replace string in Search/Replace dialog
   ended with '\'. Patch by Roger Serwy.

-- 
Repository URL: http://hg.python.org/cpython


More information about the Python-checkins mailing list